1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/ini.c,v 1.7 2011/05/16 16:21:58 william Exp $
19 */
20
21 #define _INCLUDE_FROM_INI_C_
22
23 #include "tgifdefs.h"
24
25 #include "dialog.e"
26 #include "ini.e"
27 #include "msg.e"
28 #include "strtbl.e"
29 #include "util.e"
30
31 typedef struct TgIniEntryInfoStruct {
32 char *pszEntry;
33 char *pszValue;
34 int bScanned;
35 struct TgIniEntryInfoStruct *pNextEntry, *pPrevEntry;
36 } TGINIENTRYINFO;
37
38 typedef struct TgIniSectionInfoStruct {
39 char *pszSection;
40 int bAllowDupKey;
41 int bValuelessKey;
42 TGINIENTRYINFO *pFirstEntry, *pLastEntry;
43 struct TgIniSectionInfoStruct *pNextSection, *pPrevSection;
44 } TGINISECTIONINFO;
45
46 typedef struct TgIniFileInfoStruct {
47 char *pszFile;
48 int bModified;
49 int bStripQuotes;
50 int bCheckFileTime;
51 time_t stFileTime;
52 TGINISECTIONINFO *pFirstSection, *pLastSection;
53 struct TgIniFileInfoStruct *pNextInfo, *pPrevInfo;
54 } TGINIFILEINFO;
55
56 typedef struct TgIniStruct {
57 TGINIFILEINFO *pFirstInfo, *pLastInfo;
58 } TGINI;
59
60 static TGINI tgIni;
61
62 /* -------------------- Utility Functions -------------------- */
63
64 static
InvalidPath(pszFile)65 int InvalidPath(pszFile)
66 char *pszFile;
67 {
68 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_PATH_MUST_FULL), pszFile);
69 fprintf(stderr, "%s\n", gszMsgBox);
70 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
71 return FALSE;
72 }
73
74 static
GetLastModifiedTime(pszFile,pFileTime)75 int GetLastModifiedTime(pszFile, pFileTime)
76 char *pszFile;
77 time_t *pFileTime;
78 {
79 struct stat stat_buf;
80
81 if (stat(pszFile, &stat_buf) == 0) {
82 memcpy(pFileTime, &stat_buf.st_mtime, sizeof(time_t));
83 return TRUE;
84 }
85 return FALSE;
86 }
87
88 static
CompareFileTime(pNewFileTime,pOldFileTime)89 int CompareFileTime(pNewFileTime, pOldFileTime)
90 time_t *pNewFileTime, *pOldFileTime;
91 {
92 long lval=((long)(*pNewFileTime)) - ((long)(*pOldFileTime));
93 int ival=(int)lval;
94
95 if (lval > 0) {
96 if (ival < 0) return (-ival);
97 } else if (lval < 0) {
98 if (ival > 0) return (-ival);
99 } else {
100 ival = 0;
101 }
102 return ival;
103 }
104
105 /* -------------------- Discard Functions -------------------- */
106
107 static
UnlinkFileInfo(ptifi)108 void UnlinkFileInfo(ptifi)
109 TGINIFILEINFO *ptifi;
110 {
111 if (ptifi->pPrevInfo != NULL) {
112 ptifi->pPrevInfo->pNextInfo = ptifi->pNextInfo;
113 } else {
114 tgIni.pFirstInfo = ptifi->pNextInfo;
115 }
116 if (ptifi->pNextInfo != NULL) {
117 ptifi->pNextInfo->pPrevInfo = ptifi->pPrevInfo;
118 } else {
119 tgIni.pLastInfo = ptifi->pPrevInfo;
120 }
121 }
122
123 static
DiscardEntryInfo(ptiei)124 void DiscardEntryInfo(ptiei)
125 TGINIENTRYINFO *ptiei;
126 {
127 UtilFree(ptiei->pszEntry);
128 UtilFree(ptiei->pszValue);
129 }
130
131 static
DiscardSectionInfo(ptisi)132 void DiscardSectionInfo(ptisi)
133 TGINISECTIONINFO *ptisi;
134 {
135 TGINIENTRYINFO *ptiei=NULL, *ptiei_next;
136
137 for (ptiei=ptisi->pFirstEntry; ptiei != NULL; ptiei=ptiei_next) {
138 ptiei_next = ptiei->pNextEntry;
139 DiscardEntryInfo(ptiei);
140 free(ptiei);
141 }
142 UtilFree(ptisi->pszSection);
143 }
144
145 static
WriteOutIniFile(ptifi,pszAltFile)146 int WriteOutIniFile(ptifi, pszAltFile)
147 TGINIFILEINFO *ptifi;
148 char *pszAltFile;
149 {
150 int ok=TRUE;
151 char *pszFile=(pszAltFile==NULL ? ptifi->pszFile : pszAltFile);
152 char *c_ptr=strchr(pszFile, DIR_SEP);
153 FILE *pFile=NULL;
154 TGINISECTIONINFO *ptisi=NULL;
155
156 if (c_ptr == NULL) {
157 return InvalidPath(pszFile);
158 }
159 if ((pFile=fopen(pszFile, "w")) == NULL) {
160 return FailToWriteFileMessage(pszFile);
161 }
162 for (ptisi=ptifi->pFirstSection; ok && ptisi != NULL;
163 ptisi=ptisi->pNextSection) {
164 int bValuelessKey=ptisi->bValuelessKey;
165 TGINIENTRYINFO *ptiei=NULL;
166
167 /* do not translate -- program constants */
168 if (fprintf(pFile, "[%s]\n", ptisi->pszSection) <= 0) {
169 ok = FALSE;
170 break;
171 }
172 for (ptiei=ptisi->pFirstEntry; ok && ptiei != NULL;
173 ptiei=ptiei->pNextEntry) {
174 /* remember that the key is ";" for a comment line */
175 if (strcmp(ptiei->pszEntry, ";") == 0) {
176 if (fprintf(pFile, "%s\n", ptiei->pszValue) <= 0) {
177 ok = FailToWriteFileMessage(pszFile);
178 break;
179 }
180 } else if (bValuelessKey) {
181 if (fprintf(pFile, "%s\n", ptiei->pszEntry) <= 0) {
182 ok = FailToWriteFileMessage(pszFile);
183 break;
184 }
185 } else {
186 if (fprintf(pFile, "%s=%s\n", ptiei->pszEntry,
187 ptiei->pszValue) <= 0) {
188 ok = FailToWriteFileMessage(pszFile);
189 break;
190 }
191 }
192 }
193 if (ok && ptisi->pNextSection != NULL) {
194 if (fprintf(pFile, "\n") <= 0) {
195 ok = FailToWriteFileMessage(pszFile);
196 break;
197 }
198 }
199 }
200 if (fclose(pFile) == EOF) {
201 return FailToWriteFileMessage(pszFile);
202 }
203 ptifi->bModified = FALSE;
204 return ok;
205 }
206
207 static
DiscardFileInfo(ptifi)208 int DiscardFileInfo(ptifi)
209 TGINIFILEINFO *ptifi;
210 {
211 TGINISECTIONINFO *ptisi=NULL, *ptisi_next;
212 int ok=TRUE;
213
214 if (ptifi->bModified) {
215 ok = WriteOutIniFile(ptifi, NULL);
216 }
217 for (ptisi=ptifi->pFirstSection; ptisi != NULL; ptisi=ptisi_next) {
218 ptisi_next = ptisi->pNextSection;
219 DiscardSectionInfo(ptisi);
220 free(ptisi);
221 }
222 UtilFree(ptifi->pszFile);
223 return ok;
224 }
225
226 /* -------------------- Allocation Functions -------------------- */
227
228 static
AllocEntryInfo(ptisi,pszEntry,pszValue)229 TGINIENTRYINFO *AllocEntryInfo(ptisi, pszEntry, pszValue)
230 TGINISECTIONINFO *ptisi;
231 char *pszEntry, *pszValue;
232 {
233 /* for a comment line, make the key to be ";" */
234 char *buf1=UtilStrDup(pszEntry==NULL ? ";" : pszEntry);
235 char *buf2=UtilStrDup(pszValue);
236 TGINIENTRYINFO *ptiei=
237 (TGINIENTRYINFO*)malloc(sizeof(TGINIENTRYINFO));
238
239 if (buf1 == NULL || buf2 == NULL || ptiei == NULL) {
240 UtilFree(buf1);
241 UtilFree(buf2);
242 free(ptiei);
243 FailAllocMessage();
244 return NULL;
245 }
246 memset(ptiei, 0, sizeof(TGINIENTRYINFO));
247
248 /* first-in-first-out */
249 ptiei->pNextEntry = NULL;
250 ptiei->pPrevEntry = ptisi->pLastEntry;
251 if (ptisi->pLastEntry == NULL) {
252 ptisi->pFirstEntry = ptiei;
253 } else {
254 ptisi->pLastEntry->pNextEntry = ptiei;
255 }
256 ptisi->pLastEntry = ptiei;
257
258 ptiei->pszEntry = buf1;
259 ptiei->pszValue = buf2;
260 ptiei->bScanned = FALSE;
261 return ptiei;
262 }
263
264 static
AllocSectionInfo(ptifi,pszSection,bValuelessKey)265 TGINISECTIONINFO *AllocSectionInfo(ptifi, pszSection, bValuelessKey)
266 TGINIFILEINFO *ptifi;
267 char *pszSection;
268 int bValuelessKey;
269 {
270 char *buf=UtilStrDup(pszSection);
271 TGINISECTIONINFO *ptisi=
272 (TGINISECTIONINFO*)malloc(sizeof(TGINISECTIONINFO));
273
274 if (buf == NULL || ptisi == NULL) {
275 UtilFree(buf);
276 free(ptisi);
277 FailAllocMessage();
278 return NULL;
279 }
280 memset(ptisi, 0, sizeof(TGINISECTIONINFO));
281
282 /* first-in-first-out */
283 ptisi->pNextSection = NULL;
284 ptisi->pPrevSection = ptifi->pLastSection;
285 if (ptifi->pLastSection == NULL) {
286 ptifi->pFirstSection = ptisi;
287 } else {
288 ptifi->pLastSection->pNextSection = ptisi;
289 }
290 ptifi->pLastSection = ptisi;
291
292 ptisi->pszSection = buf;
293 ptisi->bAllowDupKey = FALSE;
294 ptisi->bValuelessKey = bValuelessKey;
295 return ptisi;
296 }
297
298 static
AllocFileInfo(pszFile)299 TGINIFILEINFO *AllocFileInfo(pszFile)
300 char *pszFile;
301 {
302 char *buf=UtilStrDup(pszFile);
303 TGINIFILEINFO *ptifi=(TGINIFILEINFO*)malloc(sizeof(TGINIFILEINFO));
304 if (buf == NULL || ptifi == NULL) {
305 UtilFree(buf);
306 free(ptifi);
307 FailAllocMessage();
308 return NULL;
309 }
310 memset(ptifi, 0, sizeof(TGINIFILEINFO));
311
312 /* last-in-first-out */
313 ptifi->pNextInfo = tgIni.pFirstInfo;
314 ptifi->pPrevInfo = NULL;
315 if (tgIni.pFirstInfo == NULL) {
316 tgIni.pLastInfo = ptifi;
317 } else {
318 tgIni.pFirstInfo->pPrevInfo = ptifi;
319 }
320 tgIni.pFirstInfo = ptifi;
321
322 ptifi->pszFile = buf;
323 ptifi->bModified = FALSE;
324 ptifi->bStripQuotes = TRUE;
325 ptifi->bCheckFileTime = TRUE;
326 memset(&ptifi->stFileTime, 0, sizeof(time_t));
327
328 if (!GetLastModifiedTime(pszFile, &ptifi->stFileTime)) {
329 memset(&ptifi->stFileTime, 0, sizeof(time_t));
330 }
331 return ptifi;
332 }
333
334 /* -------------------- Parse Functions -------------------- */
335
336 static
ParseFile(ptifi)337 int ParseFile(ptifi)
338 TGINIFILEINFO *ptifi;
339 {
340 char *buf;
341 TGINISECTIONINFO *ptisi=NULL;
342 char *pszFile=ptifi->pszFile;
343 char *c_ptr=strchr(pszFile, DIR_SEP);
344 FILE *pFile=NULL;
345
346 if (c_ptr == NULL) {
347 return InvalidPath(pszFile);
348 }
349 if ((pFile=fopen(pszFile, "r")) == NULL) return TRUE;
350
351 while ((buf=UtilGetALine(pFile)) != NULL) {
352 char *c_ptr;
353
354 UtilTrimBlanks(buf);
355 if (*buf == ';') {
356 /* handle comments, remember that the key is ";" for a comment line */
357 if (ptisi != NULL) {
358 if (AllocEntryInfo(ptisi, NULL, buf) == NULL) return FALSE;
359 }
360 } else if (*buf == '[') {
361 if ((c_ptr=strchr(&buf[1], ']')) == NULL) {
362 ptisi = NULL;
363 } else {
364 *c_ptr = '\0';
365 /*
366 * Don't need to call UtilTrimBlanks(&buf[1]) because that's how
367 * GetProfileString() works!
368 */
369 if ((ptisi=AllocSectionInfo(ptifi, &buf[1], FALSE)) == NULL) {
370 return FALSE;
371 }
372 }
373 } else if (ptisi != NULL) {
374 if ((c_ptr=strchr(buf, '=')) != NULL) {
375 char *psz=(&c_ptr[1]);
376
377 *c_ptr = '\0';
378 c_ptr = psz;
379 UtilTrimBlanks(buf);
380 UtilTrimBlanks(c_ptr);
381 if (AllocEntryInfo(ptisi, buf, c_ptr) == NULL) return FALSE;
382 if (ptisi->bValuelessKey) {
383 #ifdef _DEBUG /* debug, do not translate */
384 fprintf(stderr, "%s [%s] of '%s'.\n",
385 "WARNING: Ambiguous valueless key section",
386 ptisi->pszSection, pszFile);
387 #endif /* _DEBUG */
388 }
389 } else if (*buf != '\0') {
390 char cNull='\0';
391
392 if (AllocEntryInfo(ptisi, buf, &cNull) == NULL) return FALSE;
393 ptisi->bValuelessKey = TRUE;
394 }
395 }
396 UtilFree(buf);
397 }
398 fclose(pFile);
399 return TRUE;
400 }
401
402 /* -------------------- External Functions -------------------- */
403
404 static
FindEntryInfo(ptisi,pszEntry)405 TGINIENTRYINFO *FindEntryInfo(ptisi, pszEntry)
406 TGINISECTIONINFO *ptisi;
407 char *pszEntry;
408 {
409 if (ptisi == NULL) return NULL;
410
411 /* finding a comment line is not allowed */
412 if (pszEntry == NULL || strcmp(pszEntry, ";") == 0) return NULL;
413
414 if (ptisi->bAllowDupKey) {
415 TGINIENTRYINFO *ptiei=NULL;
416
417 for (ptiei=ptisi->pFirstEntry; ptiei != NULL;
418 ptiei=ptiei->pNextEntry) {
419 if (!ptiei->bScanned && UtilStrICmp(pszEntry, ptiei->pszEntry) == 0) {
420 ptiei->bScanned = TRUE;
421 return ptiei;
422 }
423 }
424 } else {
425 TGINIENTRYINFO *ptiei=NULL;
426
427 for (ptiei=ptisi->pFirstEntry; ptiei != NULL;
428 ptiei=ptiei->pNextEntry) {
429 if (UtilStrICmp(pszEntry, ptiei->pszEntry) == 0) {
430 return ptiei;
431 }
432 }
433 }
434 return NULL;
435 }
436
437 static
FindSectionInfo(ptifi,pszSection)438 TGINISECTIONINFO *FindSectionInfo(ptifi, pszSection)
439 TGINIFILEINFO *ptifi;
440 char *pszSection;
441 {
442 TGINISECTIONINFO *ptisi=NULL;
443
444 if (ptifi == NULL) return NULL;
445
446 for (ptisi=ptifi->pFirstSection; ptisi != NULL;
447 ptisi=ptisi->pNextSection) {
448 if (UtilStrICmp(pszSection, ptisi->pszSection) == 0) {
449 return ptisi;
450 }
451 }
452 return NULL;
453 }
454
455 static
TgIniFindFileInfo(pszFile,bAutoLoad)456 TGINIFILEINFO *TgIniFindFileInfo(pszFile, bAutoLoad)
457 char *pszFile;
458 int bAutoLoad;
459 {
460 TGINIFILEINFO *ptifi=NULL;
461
462 if (pszFile == NULL) return NULL;
463
464 for (ptifi=tgIni.pFirstInfo; ptifi != NULL; ptifi=ptifi->pNextInfo) {
465 if (UtilStrICmp(pszFile, ptifi->pszFile) == 0) {
466 if (ptifi->bCheckFileTime) {
467 time_t stFileTime;
468
469 memset(&stFileTime, 0, sizeof(time_t));
470 if (!GetLastModifiedTime(pszFile, &stFileTime) ||
471 CompareFileTime(&stFileTime, &ptifi->stFileTime) > 0) {
472 DiscardFileInfo(ptifi);
473 UnlinkFileInfo(ptifi);
474 free(ptifi);
475 ptifi = NULL;
476 break;
477 }
478 }
479 if (ptifi != NULL) return ptifi;
480 }
481 }
482 if (!bAutoLoad) return NULL;
483 if ((ptifi=AllocFileInfo(pszFile)) == NULL) return NULL;
484 if (!ParseFile(ptifi)) {
485 DiscardFileInfo(ptifi);
486 UnlinkFileInfo(ptifi);
487 free(ptifi);
488 return NULL;
489 }
490 return ptifi;
491 }
492
493 static
TgIniDiscardFileInfo(pszFile)494 int TgIniDiscardFileInfo(pszFile)
495 char *pszFile;
496 {
497 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, FALSE);
498 int ok=TRUE;
499
500 if (ptifi == NULL) return TRUE;
501
502 ok = DiscardFileInfo(ptifi);
503
504 UnlinkFileInfo(ptifi);
505 free(ptifi);
506 return ok;
507 }
508
509 static
TgIniBeginFastProfile(ptifi)510 void TgIniBeginFastProfile(ptifi)
511 TGINIFILEINFO *ptifi;
512 {
513 if (ptifi != NULL) ptifi->bCheckFileTime = FALSE;
514 }
515
516 static
TgIniEndFastProfile(ptifi)517 void TgIniEndFastProfile(ptifi)
518 TGINIFILEINFO *ptifi;
519 {
520 if (ptifi != NULL) ptifi->bCheckFileTime = TRUE;
521 }
522
523 static
TgIniSetProfileStripQuotes(ptifi,bStripQuotes)524 int TgIniSetProfileStripQuotes(ptifi, bStripQuotes)
525 TGINIFILEINFO *ptifi;
526 int bStripQuotes;
527 {
528 if (ptifi != NULL) {
529 int bReturn=ptifi->bStripQuotes;
530
531 ptifi->bStripQuotes = bStripQuotes;
532 return bReturn;
533 }
534 return FALSE;
535 }
536
537 static
TgIniGetProfileString(pszSection,pszEntry,ptifi)538 char *TgIniGetProfileString(pszSection, pszEntry, ptifi)
539 char *pszSection, *pszEntry;
540 TGINIFILEINFO *ptifi;
541 {
542 char *buf=NULL;
543 int buf_sz=0, cur_len=0;
544
545 if (pszSection == NULL) {
546 TGINISECTIONINFO *ptisi=NULL;
547
548 for (ptisi=ptifi->pFirstSection; ptisi != NULL;
549 ptisi=ptisi->pNextSection) {
550 int len=strlen(ptisi->pszSection);
551
552 while (len+cur_len+6 >= buf_sz) {
553 buf_sz += 0x100;
554 if (buf == NULL) {
555 buf = (char*)malloc(buf_sz);
556 } else {
557 buf = (char*)realloc(buf, (size_t)buf_sz);
558 }
559 if (buf == NULL) {
560 FailAllocMessage();
561 return NULL;
562 }
563 }
564 strcpy(&buf[cur_len], ptisi->pszSection);
565 cur_len = (int)((&buf[len+cur_len+1]) - buf);
566 }
567 if (buf != NULL) buf[cur_len] = '\0';
568 } else if (pszEntry == NULL) {
569 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
570
571 if (ptisi != NULL) {
572 TGINIENTRYINFO *ptiei=NULL;
573
574 for (ptiei=ptisi->pFirstEntry; ptiei != NULL;
575 ptiei=ptiei->pNextEntry) {
576 int len=0;
577
578 if (strcmp(ptiei->pszEntry, ";") == 0) {
579 /*
580 * skip comments, remember that the key is ";"
581 * for a comment line
582 */
583 continue;
584 }
585 len = strlen(ptiei->pszEntry);
586
587 while (len+cur_len+6 >= buf_sz) {
588 buf_sz += 0x100;
589 if (buf == NULL) {
590 buf = (char*)malloc(buf_sz);
591 } else {
592 buf = (char*)realloc(buf, (size_t)buf_sz);
593 }
594 if (buf == NULL) {
595 FailAllocMessage();
596 return NULL;
597 }
598 }
599 strcpy(&buf[cur_len], ptiei->pszEntry);
600 cur_len = (int)((&buf[len+cur_len+1]) - buf);
601 }
602 }
603 if (buf != NULL) buf[cur_len] = '\0';
604 } else {
605 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
606
607 if (ptisi != NULL) {
608 TGINIENTRYINFO *ptiei=FindEntryInfo(ptisi, pszEntry);
609
610 if (ptiei != NULL) {
611 buf = UtilStrDup(ptiei->pszValue);
612 if (buf != NULL && ptifi->bStripQuotes) {
613 int nNumChars=strlen(buf);
614
615 if (nNumChars > 1 && buf[0] == buf[nNumChars-1]) {
616 char *pszLastChar=(&buf[nNumChars-1]);
617
618 if (*buf == '\'' || *buf == '"') {
619 char *pby=buf, *pby1=(&buf[1]);
620
621 while (pby1 != pszLastChar) {
622 *pby++ = *pby1++;
623 }
624 *((char*)pby) = '\0';
625 }
626 }
627 }
628 }
629 }
630 }
631 return buf;
632 }
633
634 static
TgIniWriteProfileString(pszSection,pszEntry,pszValue,ptifi)635 int TgIniWriteProfileString(pszSection, pszEntry, pszValue, ptifi)
636 char *pszSection, *pszEntry, *pszValue;
637 TGINIFILEINFO *ptifi;
638 {
639 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
640
641 if (ptisi == NULL) {
642 /* append */
643 if ((ptisi=AllocSectionInfo(ptifi, pszSection, FALSE)) == NULL) {
644 return FALSE;
645 }
646 }
647 if (pszEntry == NULL) {
648 TGINIENTRYINFO *ptiei=NULL, *ptiei_next;
649
650 for (ptiei=ptisi->pFirstEntry; ptiei != NULL; ptiei=ptiei_next) {
651 ptiei_next = ptiei->pNextEntry;
652 DiscardEntryInfo(ptiei);
653 free(ptiei);
654 }
655 ptisi->pFirstEntry = ptisi->pLastEntry = NULL;
656 } else if (strcmp(pszEntry, ";") == 0) {
657 /* can't write a comment line into an INI file */
658 return FALSE;
659 } else {
660 TGINIENTRYINFO *ptiei=NULL;
661
662 if (!ptisi->bAllowDupKey) {
663 ptiei = FindEntryInfo(ptisi, pszEntry);
664 }
665 if (ptiei == NULL) {
666 /* append */
667 if (AllocEntryInfo(ptisi, pszEntry,
668 (pszValue==NULL ? "" : pszValue)) == NULL) {
669 return FALSE;
670 }
671 } else if (pszValue == NULL) {
672 if (ptiei->pPrevEntry == NULL) {
673 ptisi->pFirstEntry = ptiei->pNextEntry;
674 } else {
675 ptiei->pPrevEntry->pNextEntry = ptiei->pNextEntry;
676 }
677 if (ptiei->pNextEntry == NULL) {
678 ptisi->pLastEntry = ptiei->pPrevEntry;
679 } else {
680 ptiei->pNextEntry->pPrevEntry = ptiei->pPrevEntry;
681 }
682 DiscardEntryInfo(ptiei);
683 free(ptiei);
684 } else {
685 if (ptisi->bValuelessKey) {
686 #ifdef _DEBUG /* debug, do not translate */
687 fprintf(stderr, "%s %s section [%s] of '%s'.\n",
688 "WARNING: tgWriteProfileString() is called with a",
689 "non-NULL pszValue for a valueless key",
690 ptisi->pszSection, ptifi->pszFile);
691 #endif /* _DEBUG */
692 }
693 /* replace */
694 UtilFree(ptiei->pszValue);
695 if ((ptiei->pszValue=UtilStrDup(pszValue)) ==
696 NULL) {
697 return FALSE;
698 }
699 }
700 }
701 ptifi->bModified = TRUE;
702 return TRUE;
703 }
704
705 static
TgIniBeginDupKeySection(pszSection,ptifi)706 void TgIniBeginDupKeySection(pszSection, ptifi)
707 char *pszSection;
708 TGINIFILEINFO *ptifi;
709 {
710 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
711 TGINIENTRYINFO *ptiei=NULL;
712
713 if (ptisi == NULL) return;
714
715 for (ptiei=ptisi->pFirstEntry; ptiei != NULL; ptiei=ptiei->pNextEntry) {
716 ptiei->bScanned = FALSE;
717 }
718 ptisi->bAllowDupKey = TRUE;
719 }
720
721 static
TgIniEndDupKeySection(pszSection,ptifi)722 void TgIniEndDupKeySection(pszSection, ptifi)
723 char *pszSection;
724 TGINIFILEINFO *ptifi;
725 {
726 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
727
728 if (ptisi == NULL) return;
729
730 ptisi->bAllowDupKey = FALSE;
731 }
732
733 static
TgIniBeginValuelessKeySection(pszSection,ptifi)734 int TgIniBeginValuelessKeySection(pszSection, ptifi)
735 char *pszSection;
736 TGINIFILEINFO *ptifi;
737 {
738 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
739 int bValuelessKey=FALSE;
740
741 if (ptisi == NULL) {
742 if ((ptisi=AllocSectionInfo(ptifi, pszSection, TRUE)) == NULL) {
743 return FALSE;
744 }
745 }
746 if (ptisi->pFirstEntry == NULL) {
747 if (!ptisi->bValuelessKey) {
748 ptisi->bValuelessKey = TRUE;
749 }
750 } else {
751 if (!ptisi->bValuelessKey) {
752 #ifdef _DEBUG /* debug, do not translate */
753 fprintf(stderr, "%s non-valueless section [%s] of '%s'.\n",
754 "WARNING: tgBeginValuelessKeySection() is called for a",
755 pszSection, ptifi->pszFile);
756 #endif /* _DEBUG */
757 }
758 }
759 bValuelessKey = ptisi->bValuelessKey;
760
761 ptisi->bValuelessKey = TRUE;
762 return bValuelessKey;
763 }
764
765 static
TgIniEndValuelessKeySection(pszSection,ptifi,bValuelessKey)766 void TgIniEndValuelessKeySection(pszSection, ptifi, bValuelessKey)
767 char *pszSection;
768 TGINIFILEINFO *ptifi;
769 int bValuelessKey;
770 {
771 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
772
773 if (ptisi == NULL) return;
774
775 if (ptisi->bValuelessKey != bValuelessKey) {
776 #ifdef _DEBUG /* debug, do not translate */
777 fprintf(stderr, "%s valuess-ness for section [%s] of '%s'.\n",
778 "WARNING: tgEndValuelessKeySection() changes the",
779 pszSection, ptifi->pszFile);
780 #endif /* _DEBUG */
781 }
782 ptisi->bValuelessKey = bValuelessKey;
783 }
784
785 static
TgIniIsValuelessKeySection(pszSection,ptifi)786 int TgIniIsValuelessKeySection(pszSection, ptifi)
787 char *pszSection;
788 TGINIFILEINFO *ptifi;
789 {
790 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
791
792 if (ptisi == NULL) {
793 #ifdef _DEBUG /* debug, do not translate */
794 fprintf(stderr, "%s section [%s] of '%s'.\n",
795 "WARNING: tgIsValuelessKeySection() is called with a non-existant",
796 pszSection, ptifi->pszFile);
797 #endif /* _DEBUG */
798 return FALSE;
799 }
800 return ptisi->bValuelessKey;
801 }
802
803 static
TgIniDeleteDupKeyValue(pszSection,pszEntry,pszValue,ptifi)804 int TgIniDeleteDupKeyValue(pszSection, pszEntry, pszValue, ptifi)
805 char *pszSection, *pszEntry, *pszValue;
806 TGINIFILEINFO *ptifi;
807 {
808 TGINISECTIONINFO *ptisi=FindSectionInfo(ptifi, pszSection);
809 TGINIENTRYINFO *ptiei=NULL;
810
811 if (ptisi == NULL) {
812 return TRUE;
813 }
814 TgIniBeginDupKeySection(pszSection, ptifi);
815 for (ptiei=FindEntryInfo(ptisi, pszEntry); ptiei != NULL;
816 ptiei=FindEntryInfo(ptisi, pszEntry)) {
817 if (UtilStrICmp(pszValue, ptiei->pszValue) == 0) {
818 if (ptiei->pPrevEntry == NULL) {
819 ptisi->pFirstEntry = ptiei->pNextEntry;
820 } else {
821 ptiei->pPrevEntry->pNextEntry = ptiei->pNextEntry;
822 }
823 if (ptiei->pNextEntry == NULL) {
824 ptisi->pLastEntry = ptiei->pPrevEntry;
825 } else {
826 ptiei->pNextEntry->pPrevEntry = ptiei->pPrevEntry;
827 }
828 DiscardEntryInfo(ptiei);
829 free(ptiei);
830 ptifi->bModified = TRUE;
831 break;
832 }
833 }
834 TgIniEndDupKeySection(pszSection, ptifi);
835 return TRUE;
836 }
837
838 static
TgIniCleanUp()839 void TgIniCleanUp()
840 {
841 TGINIFILEINFO *ptifi=NULL, *ptifi_next;
842
843 for (ptifi=tgIni.pFirstInfo; ptifi != NULL; ptifi=ptifi_next) {
844 ptifi_next = ptifi->pNextInfo;
845 DiscardFileInfo(ptifi);
846 free(ptifi);
847 }
848 tgIni.pFirstInfo = tgIni.pLastInfo = NULL;
849 }
850
851 /* -------------------- Exported Functions -------------------- */
852
tgCleanUpProfile()853 void tgCleanUpProfile()
854 {
855 TgIniCleanUp();
856 }
857
tgFreeProfileString(pszStr)858 char *tgFreeProfileString(pszStr)
859 char *pszStr;
860 {
861 UtilFree(pszStr);
862 return NULL;
863 }
864
tgBeginFastProfile(pszFile)865 void tgBeginFastProfile(pszFile)
866 char *pszFile;
867 {
868 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, TRUE);
869
870 if (ptifi == NULL) return;
871
872 TgIniBeginFastProfile(ptifi);
873 }
874
tgEndFastProfile(pszFile)875 void tgEndFastProfile(pszFile)
876 char *pszFile;
877 {
878 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, TRUE);
879
880 if (ptifi == NULL) return;
881
882 TgIniEndFastProfile(ptifi);
883 }
884
tgSetProfileStripQuotes(pszFile,bStripQuotes)885 int tgSetProfileStripQuotes(pszFile, bStripQuotes)
886 char *pszFile;
887 int bStripQuotes;
888 {
889 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, TRUE);
890
891 if (ptifi == NULL) return FALSE;
892
893 return TgIniSetProfileStripQuotes(ptifi, bStripQuotes);
894 }
895
tgGetProfileString(pszSection,pszEntry,pszFile)896 char *tgGetProfileString(pszSection, pszEntry, pszFile)
897 char *pszSection, *pszEntry, *pszFile;
898 {
899 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, TRUE);
900
901 if (ptifi == NULL) return NULL;
902
903 return TgIniGetProfileString(pszSection, pszEntry, ptifi);
904 }
905
tgGetProfileInt(pszSection,pszEntry,nDefault,pszFile)906 int tgGetProfileInt(pszSection, pszEntry, nDefault, pszFile)
907 char *pszSection, *pszEntry, *pszFile;
908 int nDefault;
909 {
910 TGINIFILEINFO *ptifi=NULL;
911 char *c_ptr=NULL;
912 int rc=nDefault;
913
914 if (pszSection == NULL) {
915 int rc=(TgIniDiscardFileInfo(pszFile) ? nDefault : (int)(nDefault==0));
916
917 return rc;
918 }
919 ptifi = TgIniFindFileInfo(pszFile, TRUE);
920
921 if (ptifi == NULL) return nDefault;
922
923 c_ptr = TgIniGetProfileString(pszSection, pszEntry, ptifi);
924 rc = (c_ptr == NULL ? nDefault : (int)atoi(c_ptr));
925
926 UtilFree(c_ptr);
927 return rc;
928 }
929
tgWriteProfileString(pszSection,pszEntry,pszString,pszFile)930 int tgWriteProfileString(pszSection, pszEntry, pszString, pszFile)
931 char *pszSection, *pszEntry, *pszString, *pszFile;
932 {
933 TGINIFILEINFO *ptifi=TgIniFindFileInfo(pszFile, TRUE);
934
935 if (pszSection == NULL) {
936 if (ptifi == NULL || !ptifi->bModified) return TRUE;
937 return WriteOutIniFile(ptifi, NULL);
938 }
939 return TgIniWriteProfileString(pszSection, pszEntry, pszString, ptifi);
940 }
941
tgBeginDupKeySection(pszSection,pszFile)942 void tgBeginDupKeySection(pszSection, pszFile)
943 char *pszSection, *pszFile;
944 {
945 TGINIFILEINFO *ptifi=NULL;
946
947 if (pszSection == NULL) return;
948
949 ptifi = TgIniFindFileInfo(pszFile, TRUE);
950
951 if (ptifi == NULL) return;
952
953 TgIniBeginDupKeySection(pszSection, ptifi);
954 }
955
tgEndDupKeySection(pszSection,pszFile)956 void tgEndDupKeySection(pszSection, pszFile)
957 char *pszSection, *pszFile;
958 {
959 TGINIFILEINFO *ptifi=NULL;
960
961 if (pszSection == NULL) return;
962
963 ptifi = TgIniFindFileInfo(pszFile, TRUE);
964
965 if (ptifi == NULL) return;
966
967 TgIniEndDupKeySection(pszSection, ptifi);
968 }
969
tgBeginValuelessKeySection(pszSection,pszFile)970 int tgBeginValuelessKeySection(pszSection, pszFile)
971 char *pszSection, *pszFile;
972 {
973 TGINIFILEINFO *ptifi=NULL;
974
975 if (pszSection == NULL) return FALSE;
976
977 ptifi = TgIniFindFileInfo(pszFile, TRUE);
978
979 if (ptifi == NULL) return FALSE;
980
981 return TgIniBeginValuelessKeySection(pszSection, ptifi);
982 }
983
tgEndValuelessKeySection(pszSection,pszFile,bValuelessKey)984 void tgEndValuelessKeySection(pszSection, pszFile, bValuelessKey)
985 char *pszSection, *pszFile;
986 int bValuelessKey;
987 {
988 TGINIFILEINFO *ptifi=NULL;
989
990 if (pszSection == NULL) return;
991
992 ptifi = TgIniFindFileInfo(pszFile, TRUE);
993
994 if (ptifi == NULL) return;
995
996 TgIniEndValuelessKeySection(pszSection, ptifi, bValuelessKey);
997 }
998
tgIsValuelessKeySection(pszSection,pszFile)999 int tgIsValuelessKeySection(pszSection, pszFile)
1000 char *pszSection, *pszFile;
1001 {
1002 TGINIFILEINFO *ptifi=NULL;
1003
1004 if (pszSection == NULL) return FALSE;
1005
1006 ptifi = TgIniFindFileInfo(pszFile, TRUE);
1007
1008 if (ptifi == NULL) return FALSE;
1009
1010 return TgIniIsValuelessKeySection(pszSection, ptifi);
1011 }
1012
tgDeleteDupKeyValue(pszSection,pszEntry,pszValue,pszFile)1013 int tgDeleteDupKeyValue(pszSection, pszEntry, pszValue, pszFile)
1014 char *pszSection, *pszEntry, *pszValue, *pszFile;
1015 {
1016 TGINIFILEINFO *ptifi=NULL;
1017
1018 if (pszFile == NULL || pszSection == NULL || pszEntry == NULL ||
1019 pszValue == NULL) {
1020 return FALSE;
1021 }
1022 ptifi = TgIniFindFileInfo(pszFile, TRUE);
1023
1024 if (ptifi == NULL) return TRUE;
1025
1026 return TgIniDeleteDupKeyValue(pszSection, pszEntry, pszValue, ptifi);
1027 }
1028
1029