source: trunk/src/helpers/configsys.c@ 67

Last change on this file since 67 was 63, checked in by umoeller, 24 years ago

Misc. fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1
2/*
3 *@@sourcefile configsys.c:
4 * contains helper functions for parsing and changing lines
5 * in the CONFIG.SYS file.
6 *
7 * Some of these used to be in stringh.c. However, that
8 * code was really old and was largely rewritten. Besides,
9 * this fixes some bugs that have popped up in WarpIN.
10 *
11 * Usage: All OS/2 programs.
12 *
13 * Function prefixes (new with V0.81):
14 * -- csys* CONFIG.SYS helper functions.
15 *
16 * Note: Version numbering in this file relates to XWorkplace version
17 * numbering.
18 *
19 *@@added V0.9.7 (2001-01-15) [umoeller]
20 *@@header "helpers\configsys.h"
21 */
22
23/*
24 * Copyright (C) 1997-2001 Ulrich M”ller.
25 * This file is part of the "XWorkplace helpers" source package.
26 * This is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published
28 * by the Free Software Foundation, in version 2 as it comes in the
29 * "COPYING" file of the XWorkplace main distribution.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 */
35
36#define OS2EMX_PLAIN_CHAR
37 // this is needed for "os2emx.h"; if this is defined,
38 // emx will define PSZ as _signed_ char, otherwise
39 // as unsigned char
40
41#define INCL_DOSERRORS
42#include <os2.h>
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <ctype.h>
48#include <math.h>
49
50#include "setup.h" // code generation and debugging options
51
52#include "helpers\dosh.h"
53#include "helpers\stringh.h"
54#include "helpers\xstring.h" // extended string helpers
55
56#include "helpers\configsys.h" // CONFIG.SYS helpers
57
58#pragma hdrstop
59
60/*
61 *@@category: Helpers\Control program helpers\CONFIG.SYS
62 * CONFIG.SYS parsing and manipulation. See configsys.c.
63 */
64
65/*
66 *@@ csysLoadConfigSys:
67 * loads a CONFIG.SYS file.
68 *
69 * If pcszFile is specified, that file is loaded.
70 * If (pcszFile == NULL), this loads the system CONFIG.SYS
71 * file (?:\CONFIG.SYS on the boot drive).
72 *
73 * If this returns NO_ERROR, the contents of the file
74 * are put into ppszContents, which will then point
75 * to a new buffer (which must be free()'d by the caller).
76 *
77 * Note that in that buffer, all \r\n pairs have been
78 * converted to \n (as with fopen()).
79 */
80
81APIRET csysLoadConfigSys(const char *pcszFile, // in: CONFIG.SYS filename or NULL
82 PSZ *ppszContents)
83{
84 APIRET arc = NO_ERROR;
85
86 CHAR szFile[CCHMAXPATH];
87 if (pcszFile == NULL)
88 {
89 sprintf(szFile, "%c:\\CONFIG.SYS", doshQueryBootDrive());
90 pcszFile = szFile;
91 }
92
93 arc = doshLoadTextFile(pcszFile,
94 ppszContents);
95
96 if (arc == NO_ERROR)
97 {
98 // convert all \r\n to \n
99 XSTRING strBuf;
100 xstrInitSet(&strBuf, *ppszContents);
101 xstrConvertLineFormat(&strBuf,
102 TRUE); // to C format
103 *ppszContents = strBuf.psz;
104 }
105
106 return (arc);
107}
108
109/*
110 *@@ csysWriteConfigSys:
111 *
112 *@@added V0.9.7 (2001-01-15) [umoeller]
113 */
114
115APIRET csysWriteConfigSys(const char *pcszFile, // in: CONFIG.SYS filename or NULL
116 const char *pcszContents,
117 PSZ pszBackup)
118{
119 APIRET arc = NO_ERROR;
120
121 XSTRING strBuf;
122
123 CHAR szFile[CCHMAXPATH];
124 if (pcszFile == NULL)
125 {
126 sprintf(szFile, "%c:\\CONFIG.SYS", doshQueryBootDrive());
127 pcszFile = szFile;
128 }
129
130 // convert all \n to \r\n
131 xstrInitCopy(&strBuf, pcszContents, 0);
132 xstrConvertLineFormat(&strBuf,
133 FALSE); // C to OS/2 format
134
135 arc = doshWriteTextFile(pcszFile,
136 strBuf.psz,
137 NULL,
138 pszBackup);
139
140 xstrClear(&strBuf);
141
142 return (arc);
143}
144
145/*
146 *@@ csysFindKey:
147 * finds pcszKey in pcszSearchIn.
148 *
149 * This is similar to strhistr, but this one makes sure the
150 * key is at the beginning of a line. Spaces and tabs before
151 * the key are tolerated.
152 *
153 * Returns NULL if the key was not found. Otherwise this
154 * returns the exact pointer to pcszKey in pcszSearchIn
155 * and puts the address of the first character of the line
156 * (after \r or \n) into ppStartOfLine.
157 *
158 * Used by csysGetParameter/csysSetParameter; useful
159 * for analyzing CONFIG.SYS settings.
160 *
161 *@@changed V0.9.0 [umoeller]: fixed bug in that this would also return something if only the first chars matched
162 *@@changed V0.9.0 [umoeller]: fixed bug which could cause character before pszSearchIn to be examined
163 *@@changed V0.9.7 (2001-01-15) [umoeller]: moved this here from stringh.c; renamed from strhFindKey
164 *@@changed V0.9.7 (2001-01-15) [umoeller]: now checking for tabs too
165 *@@changed V0.9.11 (2001-04-25) [umoeller]: this never found lines which had leading spaces, fixed
166 */
167
168PSZ csysFindKey(const char *pcszSearchIn, // in: text buffer to search
169 const char *pcszKey, // in: key to search for (e.g. "PATH=")
170 PSZ *ppStartOfLine, // out: start of line which contains pcszKey;
171 // ptr can be NULL
172 PBOOL pfIsAllUpperCase) // out: TRUE if key is completely in upper
173 // case; ptr can be NULL
174{
175 const char *p = pcszSearchIn;
176 PSZ pReturn = NULL;
177 ULONG ulKeyLength = strlen(pcszKey);
178
179 do
180 {
181 p = strhistr(p, pcszKey);
182
183 if ( (p)
184 && (p >= pcszSearchIn)
185 )
186 {
187 // make sure the key is at the beginning of a line
188 // by going backwards until we find a char != " "
189 const char *pStartOfLine = p;
190
191 // fixed this V0.9.11 (2001-04-25) [umoeller]
192 while ( (pStartOfLine > pcszSearchIn)
193 && ( (*(pStartOfLine - 1) == ' ')
194 || (*(pStartOfLine - 1) == '\t') // allow tabs too
195 )
196 )
197 --pStartOfLine;
198
199 // if we're at the beginning of a line or
200 // at the beginning of the buffer at all,
201 // let's go on
202 if ( (pStartOfLine == pcszSearchIn) // order fixed V0.9.0, Rdiger Ihle
203 || (*(pStartOfLine - 1) == '\r')
204 || (*(pStartOfLine - 1) == '\n')
205 )
206 {
207 // OK, we're at the start of a line:
208
209 // return address of key
210 pReturn = (PSZ)p;
211 // return start of line
212 if (ppStartOfLine)
213 *ppStartOfLine = (PSZ)pStartOfLine;
214
215 // test for all upper case?
216 if (pfIsAllUpperCase)
217 {
218 ULONG ul = 0;
219 *pfIsAllUpperCase = TRUE;
220
221 for (ul = 0;
222 ul < ulKeyLength;
223 ul++)
224 {
225 if (islower(*(p + ul)))
226 {
227 *pfIsAllUpperCase = FALSE;
228 break; // for
229 }
230 }
231 }
232
233 break; // do
234 } // else search next key
235
236 p++; // search on after this key
237 }
238 else
239 // nothing more found:
240 break;
241 } while ((!pReturn) && (p != NULL) && (p != pcszSearchIn));
242
243 return (pReturn);
244}
245
246/*
247 *@@ csysGetParameter:
248 * searches pcszSearchIn for the key pcszKey and gets
249 * its parameter.
250 *
251 * If found, it returns a pointer to the following
252 * characters in pcszSearchIn and, if pszCopyTo != NULL,
253 * copies the rest of the line to that buffer, of which
254 * cbCopyTo specified the size.
255 *
256 * If the key is not found, NULL is returned.
257 * String search is done by calling csysFindKey.
258 * This is useful for querying CONFIG.SYS settings.
259 *
260 * <B>Example:</B>
261 *
262 * For the CONFIG.SYS line
263 *
264 + PAUSEONERROR=YES
265 *
266 * this would return "YES" if you searched for "PAUSEONERROR=".
267 */
268
269PSZ csysGetParameter(const char *pcszSearchIn, // in: text buffer to search
270 const char *pcszKey, // in: key to search for (e.g. "PATH=")
271 PSZ pszCopyTo, // out: key value
272 ULONG cbCopyTo) // out: sizeof(*pszCopyTo)
273{
274 PSZ p = csysFindKey(pcszSearchIn, pcszKey, NULL, NULL),
275 prc = NULL;
276
277 if (p)
278 {
279 prc = p + strlen(pcszKey);
280 if (pszCopyTo)
281 {
282 // copy to pszCopyTo
283 ULONG cb;
284 PSZ pEOL = strhFindEOL(prc, &cb);
285 if (pEOL)
286 {
287 if (cb > cbCopyTo)
288 cb = cbCopyTo-1;
289 strhncpy0(pszCopyTo, prc, cb);
290 }
291 }
292 }
293
294 return (prc);
295}
296
297/*
298 *@@ csysSetParameter:
299 * searches *ppszBuf for the key pszKey; if found, it
300 * replaces the characters following this key up to the
301 * end of the line with pszParam. If pszKey is not found in
302 * *ppszBuf, it is appended to the file in a new line.
303 *
304 * If any changes are made, *ppszBuf is re-allocated.
305 *
306 * This function searches w/out case sensitivity.
307 *
308 * Returns a pointer to the new parameter inside the
309 * reallocated buffer, or NULL if the key was not found
310 * (and a new item was added).
311 *
312 * NOTE: This assumes that the file uses \n for line
313 * breaks only (not \r\n).
314 *
315 *@@changed V0.9.0 [umoeller]: changed function prototype to PSZ* ppszSearchIn
316 *@@changed V0.9.7 (2001-01-15) [umoeller]: fixed various bugs with the mem buffers
317 */
318
319PSZ csysSetParameter(PSZ* ppszBuf, // in: text buffer to search
320 const char *pcszKey, // in: key to search for (e.g. "PATH=")
321 const char *pcszNewParam, // in: new parameter to set for key
322 BOOL fRespectCase) // in: if TRUE, pszNewParam will
323 // be converted to upper case if the found key is
324 // in upper case also. pszNewParam should be in
325 // lower case if you use this.
326{
327 BOOL fIsAllUpperCase = FALSE;
328 PSZ pKey = csysFindKey(*ppszBuf,
329 pcszKey,
330 NULL,
331 &fIsAllUpperCase),
332 pReturn = NULL;
333 if (pKey)
334 {
335 // key found in file:
336 ULONG ulOfs;
337
338 // replace existing parameter
339 PSZ pOldParam = pKey + strlen(pcszKey);
340 // pOldParam now has the old parameter, which we
341 // will overwrite now; pOldParam points into *ppszBuf
342
343 if (pOldParam)
344 {
345 ULONG ulOldParamOfs = pOldParam - *ppszBuf;
346
347 PSZ pEOL = strhFindEOL(pOldParam, NULL);
348 // pEOL now has first end-of-line after the parameter
349
350 if (pEOL)
351 {
352 // char count to replace
353 ULONG ulToReplace = pEOL - pOldParam;
354
355 XSTRING strBuf,
356 strReplaceWith;
357
358 // ULONG ulOfs = 0;
359 // PSZ pszOldParamCopy = strhSubstr(pOldParam, pEOL);
360 /* (PSZ)malloc(cbOldParam+1);
361 strncpy(pszOldCopy, pOldParam, cbOldParam);
362 pszOldCopy[cbOldParam] = '\0'; */
363
364 xstrInitSet(&strBuf, *ppszBuf);
365 // this must not be freed!
366
367 xstrInitCopy(&strReplaceWith, pcszNewParam, 0);
368 // check for upper case desired?
369 if ((fRespectCase) && (fIsAllUpperCase))
370 strupr(strReplaceWith.psz);
371
372 xstrrpl(&strBuf,
373 ulOldParamOfs,
374 ulToReplace,
375 strReplaceWith.psz,
376 strReplaceWith.ulLength); // adjusted V0.9.11 (2001-04-22) [umoeller]
377
378 xstrClear(&strReplaceWith);
379
380 /* xstrFindReplaceC(&strBuf,
381 &ulOfs,
382 pszOldParamCopy,
383 pszNewParam); */
384
385 // free(pszOldParamCopy);
386
387 // replace output buffer
388 *ppszBuf = strBuf.psz;
389 // return ptr into that
390 pReturn = *ppszBuf + ulOldParamOfs;
391 }
392 }
393 }
394 else
395 {
396 // key not found: append to end of file
397 XSTRING strContents;
398 xstrInitCopy(&strContents, *ppszBuf, 0);
399 /* PSZ pszNew = (PSZ)malloc(strlen(*ppszBuf)
400 + strlen(pcszKey)
401 + strlen(pszNewParam)
402 + 5); // 2 * \r\n + null byte
403 */
404
405 xstrcatc(&strContents, '\n');
406 xstrcat(&strContents, pcszKey, 0);
407 xstrcat(&strContents, pcszNewParam, 0);
408 xstrcatc(&strContents, '\n');
409 /* sprintf(pszNew, "%s\r\n%s%s\r\n",
410 *ppszBuf, pcszKey, pszNewParam); */
411
412 free(*ppszBuf);
413 *ppszBuf = strContents.psz;
414 }
415
416 return (pReturn);
417}
418
419/*
420 *@@ csysDeleteLine:
421 * this deletes the line in pszSearchIn which starts with
422 * the key pszKey. Returns TRUE if the line was found and
423 * deleted.
424 *
425 * This copies within pszSearchIn.
426 *
427 *@@changed V0.9.7 (2001-01-15) [umoeller]: fixed wrong beginning of line
428 */
429
430BOOL csysDeleteLine(PSZ pszSearchIn, // in: buffer to search
431 PSZ pszKey) // in: key to find
432{
433 BOOL fIsAllUpperCase = FALSE;
434 PSZ pStartOfLine = NULL;
435 PSZ pKey = csysFindKey(pszSearchIn,
436 pszKey,
437 &pStartOfLine,
438 &fIsAllUpperCase);
439 BOOL brc = FALSE;
440
441 if (pKey)
442 {
443 PSZ pEOL = strhFindEOL(pKey, NULL);
444 // pEOL now has first end-of-line after the key
445 if (pEOL)
446 {
447 // go to first character after EOL
448 while ( (*pEOL)
449 && ( (*pEOL == '\n')
450 || (*pEOL == '\r')
451 )
452 )
453 pEOL++;
454
455 // delete line by overwriting it with
456 // the next line
457 strcpy(pStartOfLine,
458 pEOL);
459 }
460 else
461 {
462 // EOL not found: we must be at the end of the file
463 *pKey = '\0';
464 }
465 brc = TRUE;
466 }
467
468 return (brc);
469}
470
471/*
472 *@@ csysManipulate:
473 * makes a single CONFIG.SYS change according to the
474 * CONFIGMANIP which was passed in.
475 *
476 * If the manipulation succeeded, NO_ERROR is returned
477 * and *ppszChanged receives a new string describing
478 * what was changed. This can be:
479 *
480 * -- "DLL xxx": deleted a line containing "xxx".
481 *
482 * -- "DLP xxx": deleted part of line.
483 *
484 * -- "NWL xxx": added an all new line.
485 *
486 * -- "NWP xxx": added a new part to an existing line.
487 *
488 * This has been moved here from WarpIN so that C programs
489 * can use these features as well.
490 *
491 * This returns:
492 *
493 * -- NO_ERROR: changed OK, or nothing happened.
494 *
495 * -- CFGERR_NOSEPARATOR: with CFGRPL_ADDLEFT or CFGRPL_ADDRIGHT
496 * modes, no "=" character was found.
497 *
498 * -- CFGERR_MANIPULATING: error in string handling. This should
499 * never happen, and if it does, it's a bug.
500 *
501 * Preconditions:
502 *
503 * -- This assumes that the line breaks are represented
504 * by \r\n items ONLY.
505 */
506
507APIRET csysManipulate(PSZ *ppszContents, // in/out: CONFIG.SYS text (reallocated)
508 PCONFIGMANIP pManip, // in: CONFIG.SYS manipulation instructions
509 PBOOL pfDirty, // out: set to TRUE if something was changed
510 PXSTRING pstrChanged) // out: new string describing changes (must be free'd)
511{
512 APIRET arc = NO_ERROR;
513
514 PSZ pszCommand = 0,
515 pszArgNew = 0;
516 BOOL fIsAllUpperCase = FALSE;
517
518 // The CONFIG.SYS manipulation is a six-step process,
519 // depending on the data in the BSCfgSysManip instance.
520 // This is an outline what needs to be done when;
521 // the implementation follows below.
522
523 // 1) First find out if a line needs to be updated or deleted
524 // or if we only need to write a new line.
525 // This depends on BSCfgSysManip.iReplaceMode.
526 BOOL fFindLine = FALSE;
527
528 // 2) If we need to find a line, find the
529 // line and copy it into pszLineToUpdate.
530 // Set pInsertAt to the original line, if found.
531 // If not found, set fInsertWRTVertical to TRUE.
532 PSZ pInsertAt = 0;
533 // address of that line in original buffer if (fFindLine == TRUE) and
534 // found
535 BOOL fInsertWRTVertical = FALSE;
536 // TRUE means set a new pInsertAt depending on Manip.iVertical;
537 // this is set to TRUE if (fFindLine == FALSE) or line not found
538
539 // 3) If a line needs to be deleted, well, delete it then.
540 PSZ pLineToDelete = 0;
541 // pointer to start of original line (pLineToUpdate);
542 // points to character right after \n
543 PSZ pszDeletedLine = 0;
544 // copy of that line if deleted (this has the stuff between
545 // the EOL chars, not including those)
546
547 // 4) If (fInsertWRTVertical == TRUE), set pInsertAt to a position in
548 // the original buffer, depending on Manip.iVertical.
549
550 // 5) Compose a new line to be inserted at pInsertAt.
551 PSZ pszLineToInsert = 0;
552
553 // 6) Insert that line at pInsertAt.
554
555 /*
556 * Prepare data
557 *
558 */
559
560 // First, check if the new-line string has a "=" char
561 PSZ pSep = strchr(pManip->pszNewLine, '=');
562 if (pSep)
563 {
564 // yes: separate in two strings
565 pszCommand = strhSubstr(pManip->pszNewLine, pSep);
566 pszArgNew = strdup(pSep+1);
567 }
568 else
569 {
570 // no:
571 pszCommand = strdup(pManip->pszNewLine);
572 pszArgNew = 0;
573 }
574
575 /*
576 * GO!!
577 *
578 */
579
580 // **** 1): do we need to search for a line?
581 switch (pManip->iReplaceMode)
582 {
583 case CFGRPL_ADD:
584 fFindLine = FALSE;
585 fInsertWRTVertical = TRUE; // always find new position
586 break;
587
588 case CFGRPL_UNIQUE:
589 case CFGRPL_ADDLEFT:
590 case CFGRPL_ADDRIGHT:
591 case CFGRPL_REMOVELINE:
592 case CFGRPL_REMOVEPART:
593 fFindLine = TRUE; // search line first; this sets
594 // fInsertWRTVertical if not found
595 break;
596 }
597
598 // **** 2): search line, if needed
599 if (fFindLine)
600 {
601 PSZ pKeyFound = 0,
602 // address of key found
603 pStartOfLineWithKeyFound = 0,
604 // pointer to that line in original buffer; NULL if not found
605 pszSearch = *ppszContents;
606
607 do // while ((pManip->pszUniqueSearchString2) && (pszSearch));
608 {
609 pKeyFound = csysFindKey(pszSearch, // CONFIG.SYS text
610 pszCommand, // stuff to search for
611 &pStartOfLineWithKeyFound,
612 &fIsAllUpperCase);
613
614 if (!pKeyFound)
615 break;
616 else
617 if (pManip->pszUniqueSearchString2)
618 {
619 // UNIQUE(xxx) mode:
620 // find end of line
621 PSZ pEOL = strhFindEOL(pKeyFound, NULL);
622
623 // find "="
624 PSZ p = strchr(pKeyFound, '=');
625 if (p && p < pEOL)
626 {
627 // find UNIQUE(xxx) substring in line
628 p = strhistr(p, pManip->pszUniqueSearchString2);
629 if (p && p < pEOL)
630 // found: OK, keep pLineToUpdate
631 break;
632 else
633 pKeyFound = NULL; // V0.9.7 (2001-01-15) [umoeller]
634 }
635
636 // else: search on
637 pszSearch = pEOL;
638 }
639 } while ((pManip->pszUniqueSearchString2) && (pszSearch));
640
641 if (pKeyFound)
642 {
643 // line found:
644 pLineToDelete = pStartOfLineWithKeyFound;
645 pInsertAt = pStartOfLineWithKeyFound;
646 }
647 else
648 // line not found:
649 // insert new line then,
650 // respecting the iVertical flag,
651 // unless we are in "remove" mode
652 if ( (pManip->iReplaceMode != CFGRPL_REMOVELINE)
653 && (pManip->iReplaceMode != CFGRPL_REMOVEPART)
654 )
655 fInsertWRTVertical = TRUE;
656 }
657
658 // **** 3): delete original line (OK)
659 if (pLineToDelete)
660 {
661 // pLineToDelete is only != NULL if we searched and found a line above
662 // and points to the character right after \n;
663 // find end of this line
664 PSZ pEOL = strhFindEOL(pLineToDelete, NULL);
665
666 // make a copy of the line to be deleted;
667 // this might be needed later
668 pszDeletedLine = strhSubstr(pLineToDelete, pEOL);
669
670 // pEOL now points to the \n char or the terminating 0 byte;
671 // if not null byte, advance pointer
672 while (*pEOL == '\n')
673 pEOL++;
674
675 // overwrite beginning of line with next line;
676 // the buffers overlap, but this works
677 strcpy(pLineToDelete, pEOL);
678
679 // we've made changes...
680 *pfDirty = TRUE;
681 }
682
683 // **** 4):
684 if (fInsertWRTVertical)
685 {
686 // this is only TRUE if a) we didn't search for a line
687 // or b) we did search, but we didn't find a line
688 // (but never with CFGRPL_REMOVE* mode);
689 // we need to find a new vertical position in CONFIG.SYS then
690 // and set pInsertAt to the beginning of a line (after \n)
691 switch (pManip->iVertical)
692 {
693 case CFGVRT_BOTTOM:
694 // insert at the very bottom (default)
695 pInsertAt = *ppszContents + strlen(*ppszContents);
696 break;
697
698 case CFGVRT_TOP:
699 // insert at the very top
700 pInsertAt = *ppszContents;
701 break;
702
703 case CFGVRT_BEFORE:
704 {
705 // Manip.pszSearchString has the search string
706 // before whose line we must insert
707 PSZ pFound = strhistr(*ppszContents,
708 pManip->pszVerticalSearchString);
709 if (pFound)
710 {
711 // search string found:
712 // find beginning of line
713 while ( (pFound > *ppszContents)
714 && (*pFound != '\n')
715 )
716 pFound--;
717
718 if (pFound > *ppszContents)
719 // we're on the \n char now:
720 pFound++;
721
722 pInsertAt = pFound;
723 }
724 else
725 // search string not found: insert at top then
726 pInsertAt = *ppszContents;
727 break; }
728
729 case CFGVRT_AFTER:
730 {
731 // Manip.pszSearchString has the search string
732 // after whose line we must insert
733 PSZ pFound = strhistr(*ppszContents, pManip->pszVerticalSearchString);
734 if (pFound)
735 {
736 // search string found:
737 // find end of line
738 pInsertAt = strhFindNextLine(pFound, NULL);
739 }
740 else
741 // search string not found: insert at bottom then
742 pInsertAt = *ppszContents + strlen(*ppszContents);
743 break; }
744 }
745 }
746
747 // **** 5): compose new line
748 switch (pManip->iReplaceMode)
749 {
750 case CFGRPL_ADD:
751 case CFGRPL_UNIQUE:
752 // that's easy, the new line is simply given
753 pszLineToInsert = strdup(pManip->pszNewLine);
754 break;
755
756 case CFGRPL_REMOVELINE:
757 // that's easy, just leave pszLineToInsert = 0;
758 break;
759
760 case CFGRPL_REMOVEPART:
761 if (pszDeletedLine)
762 {
763 // parse the line which we removed above,
764 // find the part which was to be removed,
765 // and set pszLineToInsert to the rest of that
766 PSZ pArgToDel = 0;
767 // find the subpart to look for
768 if ((pArgToDel = strhistr(pszDeletedLine, pszArgNew)))
769 {
770 ULONG ulOfs = 0;
771 // pArgToDel now has the position of the
772 // part to be deleted in the old part
773 pszLineToInsert = strdup(pszDeletedLine);
774 strhFindReplace(&pszLineToInsert,
775 &ulOfs,
776 pszArgNew, // search string
777 ""); // replacement string
778 }
779 else
780 // subpart not found:
781 // reinsert the old line
782 pszLineToInsert = strdup(pszDeletedLine);
783 }
784 // else line to be deleted was not found: leave pszLineToInsert = 0;
785 break;
786
787 case CFGRPL_ADDLEFT:
788 case CFGRPL_ADDRIGHT:
789 // add something to the left or right of the existing
790 // argument:
791 // check if we found a line above
792 if (pszDeletedLine)
793 {
794 PSZ pszCommandOld = 0,
795 pszArgOld = 0;
796 // yes: split the existing line
797 pSep = strchr(pszDeletedLine, '=');
798 if (pSep)
799 {
800 // "=" found: separate in two strings
801 pszCommandOld = strhSubstr(pszDeletedLine, pSep);
802 pszArgOld = strdup(pSep+1);
803 }
804 else
805 {
806 // no "=" found: that's strange
807 /* throw(BSConfigExcpt(CFGEXCPT_NOSEPARATOR,
808 strdup(pszDeletedLine))); */
809 arc = CFGERR_NOSEPARATOR;
810 break;
811 }
812
813 if ((pszCommandOld) && (pszArgOld))
814 {
815 // does the new arg exist in old arg already?
816 if (strhistr(pszArgOld, pszArgNew) == 0)
817 {
818 // no: go!
819 ULONG cbCommandOld = strlen(pszCommandOld);
820 ULONG cbArgOld = strlen(pszArgOld);
821 ULONG cbArgNew = strlen(pszArgNew); // created at the very top
822
823 // compose new line
824 pszLineToInsert = (PSZ)malloc(cbCommandOld
825 + cbArgOld
826 + cbArgNew
827 + 5);
828
829 if (pManip->iReplaceMode == CFGRPL_ADDLEFT)
830 // add new arg to the left:
831 sprintf(pszLineToInsert,
832 "%s=%s;%s",
833 pszCommandOld,
834 pszArgNew,
835 pszArgOld);
836 else
837 // add new arg to the right:
838 if (*(pszArgOld + cbArgOld - 1) == ';')
839 // old arg has terminating ";" already:
840 sprintf(pszLineToInsert,
841 "%s=%s%s",
842 pszCommandOld,
843 pszArgOld,
844 pszArgNew);
845 else
846 // we need to append a ";":
847 sprintf(pszLineToInsert,
848 "%s=%s;%s",
849 pszCommandOld,
850 pszArgOld,
851 pszArgNew);
852 } // end if (stristr(pszArgOld, pszArgNew) == 0)
853 else
854 // exists already:
855 // reinsert the line we deleted above
856 pszLineToInsert = strdup(pszDeletedLine);
857
858 free(pszCommandOld);
859 free(pszArgOld);
860 }
861 } // end if (pszDeletedLine)
862 else
863 // line was not found: add a new one then
864 // (the position has been determined above)
865 pszLineToInsert = strdup(pManip->pszNewLine);
866 break;
867 }
868
869 // **** 6): insert new line at pInsertAt
870 if ((pszLineToInsert) && (arc == NO_ERROR))
871 {
872 PSZ pszInsert2 = NULL;
873 PSZ pszNew = NULL;
874 ULONG cbInsert = strlen(pszLineToInsert);
875 BOOL fLineBreakNeeded = FALSE;
876
877 // check if the char before pInsertAt is EOL
878 if (pInsertAt > *ppszContents)
879 if (*(pInsertAt-1) != '\n')
880 fLineBreakNeeded = TRUE;
881
882 if (fLineBreakNeeded)
883 {
884 // not EOL (this might be the case if we're
885 // appending to the very bottom of CONFIG.SYS)
886 pszInsert2 = (PSZ)malloc(cbInsert + 5);
887 // insert an extra line break then
888 *pszInsert2 = '\n';
889 memcpy(pszInsert2 + 1, pszLineToInsert, cbInsert);
890 strcpy(pszInsert2 + cbInsert + 1, "\n");
891 }
892 else
893 {
894 // OK:
895 pszInsert2 = (PSZ)malloc(cbInsert + 3);
896 memcpy(pszInsert2, pszLineToInsert, cbInsert);
897 strcpy(pszInsert2 + cbInsert, "\n");
898 }
899
900 pszNew = strhins(*ppszContents, // source
901 (pInsertAt - *ppszContents), // offset
902 pszInsert2); // insertion string
903 if (pszNew)
904 {
905 free(pszInsert2);
906 free(*ppszContents);
907 *ppszContents = pszNew;
908
909 // we've made changes...
910 *pfDirty = TRUE;
911 }
912 else
913 arc = CFGERR_MANIPULATING;
914 }
915 else
916 if ( (pManip->iReplaceMode != CFGRPL_REMOVELINE)
917 && (pManip->iReplaceMode != CFGRPL_REMOVEPART)
918 )
919 arc = CFGERR_MANIPULATING;
920
921 if (arc == NO_ERROR)
922 {
923 // finally, create log entries for Undo().
924 // This uses the first three characters of the
925 // each log entry to signify what happend:
926 // -- "DLL": deleted line
927 // -- "DLP": deleted part of line
928 // -- "NWL": added an all new line
929 // -- "NWP": added a new part to an existing line
930 // There may be several log entries per manipulator
931 // if a line was deleted and then re-inserted (i.e. updated).
932
933 if (pstrChanged)
934 {
935 switch (pManip->iReplaceMode)
936 {
937 case CFGRPL_UNIQUE:
938 if (pszDeletedLine)
939 {
940 // did we delete a line?
941 xstrcat(pstrChanged, "DLL ", 0);
942 xstrcat(pstrChanged, pszDeletedLine, 0);
943 xstrcatc(pstrChanged, '\n');
944 }
945
946 // no break, because we also added something
947 goto LABEL_CFGRPL_ADD ;
948 // VAC gives us warnings otherwise...
949
950 case CFGRPL_ADD:
951LABEL_CFGRPL_ADD:
952 if (pszLineToInsert)
953 {
954 // added a line:
955 xstrcat(pstrChanged, "NWL ", 0);
956 xstrcat(pstrChanged, pszLineToInsert, 0);
957 xstrcatc(pstrChanged, '\n');
958 }
959 break;
960
961 case CFGRPL_ADDLEFT:
962 case CFGRPL_ADDRIGHT:
963 if (pszDeletedLine)
964 {
965 // a line was found and updated:
966 // store the new part only
967 xstrcat(pstrChanged, "NWP ", 0);
968 xstrcat(pstrChanged, pManip->pszNewLine, 0);
969 }
970 else
971 {
972 xstrcat(pstrChanged, "NWL ", 0);
973 xstrcat(pstrChanged, pszLineToInsert, 0);
974 }
975 xstrcatc(pstrChanged, '\n');
976 break;
977
978 case CFGRPL_REMOVELINE:
979 if (pszDeletedLine)
980 {
981 // did we delete a line?
982 xstrcat(pstrChanged, "DLL ", 0);
983 xstrcat(pstrChanged, pszDeletedLine, 0);
984 xstrcatc(pstrChanged, '\n');
985 }
986 break;
987
988 case CFGRPL_REMOVEPART:
989 if (pszDeletedLine)
990 {
991 // did we delete a part?
992 xstrcat(pstrChanged, "DLP ", 0);
993 xstrcat(pstrChanged, pManip->pszNewLine, 0);
994 xstrcatc(pstrChanged, '\n');
995 }
996 break;
997 }
998 } // end if (pstrChanged)
999 }
1000
1001 // clean up
1002 if (pszCommand)
1003 free(pszCommand);
1004 if (pszArgNew)
1005 free(pszArgNew);
1006 if (pszDeletedLine)
1007 free(pszDeletedLine);
1008 if (pszLineToInsert)
1009 free(pszLineToInsert);
1010
1011 return (arc);
1012}
1013
1014// testcase
1015
1016/* int main()
1017{
1018 PSZ pszContents = NULL;
1019 if (0 == csysLoadConfigSys(NULL, &pszContents))
1020 {
1021 CHAR szValue[1000];
1022 PSZ pszValue = csysGetParameter(pszContents,
1023 "IFS=",
1024 szValue,
1025 sizeof(szValue));
1026 if (pszValue)
1027 printf("Value: %s", szValue);
1028 }
1029
1030 return (0);
1031} */
Note: See TracBrowser for help on using the repository browser.