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

Last change on this file since 39 was 24, checked in by umoeller, 25 years ago

New configsys helpers.

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