Bug Summary

File:subcmd/unitools/cfgfile.c
Warning:line 133, column 2
Value stored to 'head' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cfgfile.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/kfp/aldor/aldor/aldor/subcmd/unitools -fcoverage-compilation-dir=/home/kfp/aldor/aldor/aldor/subcmd/unitools -resource-dir /usr/local/lib/clang/18 -D PACKAGE_NAME="aldor" -D PACKAGE_TARNAME="aldor" -D PACKAGE_VERSION="1.4.0" -D PACKAGE_STRING="aldor 1.4.0" -D PACKAGE_BUGREPORT="aldor@xinutec.org" -D PACKAGE_URL="" -D PACKAGE="aldor" -D VERSION="1.4.0" -D YYTEXT_POINTER=1 -D HAVE_STDIO_H=1 -D HAVE_STDLIB_H=1 -D HAVE_STRING_H=1 -D HAVE_INTTYPES_H=1 -D HAVE_STDINT_H=1 -D HAVE_STRINGS_H=1 -D HAVE_SYS_STAT_H=1 -D HAVE_SYS_TYPES_H=1 -D HAVE_UNISTD_H=1 -D STDC_HEADERS=1 -D HAVE_LIBREADLINE=1 -D HAVE_READLINE_READLINE_H=1 -D HAVE_READLINE_HISTORY=1 -D HAVE_READLINE_HISTORY_H=1 -D USE_GLOOP_SHELL=1 -D GENERATOR_COROUTINES=0 -D HAVE_DLFCN_H=1 -D LT_OBJDIR=".libs/" -I . -I ./../../src -I ../../src -internal-isystem /usr/local/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2026-01-15-223856-845667-1 -x c cfgfile.c
1/*****************************************************************************
2 *
3 * cfgfile.h: Configuration file handling
4 *
5 * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org).
6 *
7 ****************************************************************************/
8
9#include "cfgfile.h"
10#include "debug.h"
11#include "file.h"
12#include "opsys.h"
13#include "stdio.h0"
14#include "store.h"
15#include "strops.h"
16
17Bool cfgDebug = false((int) 0);
18
19#define cfgDEBUGif (!cfgDebug) { } else afprintf DEBUG_IF(cfg)if (!cfgDebug) { } else afprintf
20
21static String cfgGetLine(FILE *file, Bool *atEof);
22static Bool cfgIsSection(char *line, char *name);
23static void cfgReadAddError(String);
24static void cfgReadDupItemError(ConfigItem, String);
25static Bool cfgEqual(ConfigItem, ConfigItem);
26static ConfigItemList cfgGetKeys(FILE *file, String section);
27static ConfigItem cfgParseLine(String line);
28
29CREATE_LIST(ConfigItem)struct ConfigItem_listOpsStruct const *ConfigItem_listPointer
= (struct ConfigItem_listOpsStruct const *) &ptrlistOps
;
30
31/*********************************************************************************
32 *
33 * :: Extracting config information
34 *
35 *********************************************************************************/
36#define IsWhiteSpace(c)((c)==' ' || (c)=='\n' || (c) == '\t') ((c)==' ' || (c)=='\n' || (c) == '\t')
37
38static StringList cfgExpandList (StringList *plst,
39 StringList **end,
40 ConfigItemList lst,
41 Bool keep);
42static Bool cfgCheckCondition(String name, ConfigItemList cfg);
43static ConfigItem cfgExpandVar(ConfigItem, ConfigItemList);
44
45static String cfgKeyNameValue(String str);
46static String cfgStringValue(String str);
47static StringList cfgStringListValue(String str);
48static Bool cfgBooleanValue(String str);
49static String cfgKeyNameValue(String str);
50
51static ConfigItem
52cfgExpandVar(ConfigItem item, ConfigItemList lst)
53{
54 char c;
55 int i;
56
57 if (!item) return NULL((void*)0);
58 i = 0;
59 while ( (c = cfgVal(item)((item)->optVal)[i]) == ' ' || c == '\t') i++;
60 if (cfgVal(item)((item)->optVal)[i] == '$') {
61 item = cfgLookup(cfgKeyNameValue(&cfgVal(item)((item)->optVal)[i+1]), lst);
62 return cfgExpandVar(item, lst);
63 }
64 return item;
65}
66
67ConfigItemList
68cfgLookupList(char *string, ConfigItemList lst)
69{
70 ConfigItemList result = listNil(ConfigItem)((ConfigItemList) 0);
71
72 cfgDEBUGif (!cfgDebug) { } else afprintf(dbOut, "Getting key list: %s\n", string);
73
74 while (lst != listNil(ConfigItem)((ConfigItemList) 0)) {
75 if (strEqual(string, cfgName(car(lst))((((lst)->first))->optName)))
76 result = listCons(ConfigItem)(ConfigItem_listPointer->Cons)(car(lst)((lst)->first), result);
77 lst = cdr(lst)((lst)->rest);
78 }
79 return listNReverse(ConfigItem)(ConfigItem_listPointer->NReverse)(result);
80}
81
82ConfigItem
83cfgLookup(char *string, ConfigItemList lst)
84{
85 cfgDEBUGif (!cfgDebug) { } else afprintf(dbOut, "Getting key: %s\n", string);
86
87 while (lst != listNil(ConfigItem)((ConfigItemList) 0)) {
88 if (strEqual(string, cfgName(car(lst))((((lst)->first))->optName)))
89 return car(lst)((lst)->first);
90 lst = cdr(lst)((lst)->rest);
91 }
92 return NULL((void*)0);
93}
94
95static StringList
96cfgLookupUnexpandedStringList(String str, ConfigItemList lst)
97{
98 ConfigItem item = cfgLookup(str, lst);
99
100 /*
101 * Ought to store this for the client to report just as we
102 * do for cfgRead().
103 */
104 if (!item) {
105 printf("config file: failed to find key `%s'\n", str);
106 return NULL((void*)0);
107 }
108 return cfgStringListValue(cfgVal(item)((item)->optVal));
109}
110
111
112StringList
113cfgLookupStringList(String str, ConfigItemList lst)
114{
115 StringList ll, *foo;
116 ll = cfgLookupUnexpandedStringList(str, lst);
117
118 if (ll == listNil(String)((StringList) 0))
119 return NULL((void*)0);
120 ll = cfgExpandList(&ll, &foo, lst, true1);
121 return ll;
122}
123
124#define cfgIfTerminator(x)((x)[1] == '\0' && ((x)[0] == ':' || (x)[0] == ';')) ((x)[1] == '\0' && ((x)[0] == ':' || (x)[0] == ';'))
125
126static StringList
127cfgExpandList(StringList *plst, StringList **end, ConfigItemList cfg, Bool keep)
128{
129 StringList *pp;
130 StringList head;
131 String error = NULL((void*)0);
132 pp = plst;
133 head = *plst;
Value stored to 'head' is never read
134 while (*pp != listNil(String)((StringList) 0) && !cfgIfTerminator(car(*pp))((((*pp)->first))[1] == '\0' && ((((*pp)->first
))[0] == ':' || (((*pp)->first))[0] == ';'))
) {
135 String name;
136 if (car(*pp)((*pp)->first)[0] != '$') {
137 if (keep) pp = &cdr(*pp)((*pp)->rest);
138 else *pp = cdr(*pp)((*pp)->rest);
139 continue;
140 }
141 name = &(car(*pp)((*pp)->first)[1]);
142 if (name[0] == '?') {
143 Bool flg = cfgCheckCondition(&name[1], cfg);
144 StringList *iend;
145 *pp = cdr(*pp)((*pp)->rest);
146 *pp = cfgExpandList(pp, &iend, cfg, flg && keep);
147 if (car(*iend)((*iend)->first)[0] != ':')
148 error = "Missing `:'";
149 if (cdr(*iend)((*iend)->rest)) *iend = cdr(*iend)((*iend)->rest);
150 else
151 error = "Nothing after `:'.";
152 cfgExpandList(iend, &iend, cfg, !flg && keep);
153 /* Should check for ';' */
154 *iend = cdr(*iend)((*iend)->rest);
155 pp = iend;
156 }
157 else {
158 StringList ll;
159 if (!keep) *pp = cdr(*pp)((*pp)->rest);
160 else {
161 ll = cfgLookupUnexpandedStringList(name, cfg);
162 *pp = listNConcat(String)(String_listPointer->NConcat)(ll, cdr(*pp)((*pp)->rest));
163 }
164 }
165 }
166 if (error)
167 printf("Error in cfg: %s\n", error);
168 *end = pp;
169 return *plst;
170}
171
172
173String
174cfgLookupKeyName(String str, ConfigItemList lst)
175{
176 ConfigItem item = cfgLookup(str, lst);
177 item = cfgExpandVar(item, lst);
178
179 if (!item) {
180 return NULL((void*)0);
181 }
182 return cfgKeyNameValue(cfgVal(item)((item)->optVal));
183}
184
185StringList
186cfgLookupKeyNameList(String str, ConfigItemList lst)
187{
188 ConfigItemList items = cfgLookupList(str, lst);
189 StringList result = listNil(String)((StringList) 0);
190
191
192 /* Process each item in the list */
193 for (; items; items = cdr(items)((items)->rest)) {
194 String value;
195 ConfigItem item;
196
197
198 /* Get the next item */
199 item = car(items)((items)->first);
200
201
202 /* Expand variables */
203 item = cfgExpandVar(item, lst);
204
205
206 /* Try the next one if no value found */
207 if (!item) continue;
208
209
210 /* Convert key into a value */
211 value = cfgKeyNameValue(cfgVal(item)((item)->optVal));
212
213
214 /* Add it to the result list */
215 result = listCons(String)(String_listPointer->Cons)(value, result);
216 }
217
218 return listNReverse(String)(String_listPointer->NReverse)(result);
219}
220
221String
222cfgLookupString(String str, ConfigItemList lst)
223{
224 ConfigItem item = cfgLookup(str, lst);
225 item = cfgExpandVar(item, lst);
226
227 if (!item) {
228 return NULL((void*)0);
229 }
230 return cfgStringValue(cfgVal(item)((item)->optVal));
231}
232
233Bool
234cfgLookupBoolean(String str, ConfigItemList lst)
235{
236 ConfigItem item = cfgLookup(str, lst);
237 item = cfgExpandVar(item, lst);
238
239 if (!item) {
240 return 0; /* Hmmm */
241 }
242 return cfgBooleanValue(cfgVal(item)((item)->optVal));
243}
244
245static StringList
246cfgStringListValue(String str)
247{
248 int argc;
249 char **argv;
250 StringList lst;
251 int i;
252
253 if (str[0] == ',')
254 cstrParseCommaified(str+1, &argc, &argv);
255 else
256 cstrParseUnquoted(str, &argc, &argv);
257
258 lst = listNil(String)((StringList) 0);
259 for (i=0; i<argc; i++) lst = listCons(String)(String_listPointer->Cons)(argv[argc - i - 1], lst);
260
261 return lst;
262}
263
264static Bool
265cfgBooleanValue(String str)
266{
267 String s = cfgKeyNameValue(str);
268
269 if (strEqual(s, "yes")) return true1;
270 if (strEqual(s, "no")) return false((int) 0);
271 if (strEqual(s, "true")) return true1;
272 if (strEqual(s, "false")) return false((int) 0);
273
274 printf("Illegal value for boolean: %s\n", s);
275 return false((int) 0);
276}
277
278static String
279cfgKeyNameValue(String str)
280{
281 char **argv;
282 int argc;
283 cstrParseUnquoted(str, &argc, &argv);
284 if (argc != 1) {
285 printf("Bad identifier format: `%s'\n", str);
286 return "";
287 }
288
289 str = argv[0];
290 stoFree(argv);
291 return str;
292}
293
294static String
295cfgStringValue(String str)
296{
297 char *p, *start, *new;
298 /* Strip spaces front and rear, ignore leading and trailing quotes */
299 p = str;
300 while (IsWhiteSpace(*p)((*p)==' ' || (*p)=='\n' || (*p) == '\t') && *p != '\0') p++;
301 if (*p == '"') p++;
302 if (*p == '\0') return strCopy("");
303 start = p;
304 p = start + strlen(start) - 1;
305 while (IsWhiteSpace(*p)((*p)==' ' || (*p)=='\n' || (*p) == '\t') && p != start) p--;
306 if (*p == '"') p--;
307 new = strCopy(start);
308 new[p - start +1] = '\0';
309 return new;
310}
311
312/*************************************************************************************
313 *
314 * :: Parsing input strings
315 *
316 *************************************************************************************/
317
318
319
320void
321cstrParseUnquoted(char *str, int *pargc, char ***pargv)
322{
323 char *p = str;
324 char *wstart;
325 char **argv;
326 char c;
327 int n, lim;
328
329 n = 0;
330 lim = 0;
331 argv = NULL((void*)0);
332 while (1) {
333 while (IsWhiteSpace(*p)((*p)==' ' || (*p)=='\n' || (*p) == '\t') && *p != '\0') p++;
334 if (*p == '\0') break;
335 wstart = p;
336 /* May want to be clever here wrt to '"' */
337 while (!IsWhiteSpace(*p)((*p)==' ' || (*p)=='\n' || (*p) == '\t') && *p != '\0') p++;
338 c = *p;
339 *p = '\0';
340 if (n==lim) {
341 char **targv = argv;
342 int i;
343 argv = (char **) stoAlloc(OB_Other0, (n + 5)*sizeof(char *));
344 lim += 5;
345 for (i=0; i<n; i++) argv[i] = targv[i];
346 if (targv) stoFree(targv);
347 }
348 argv[n++] = strCopy(wstart);
349 *p = c;
350 if (c == '\0') break;
351 }
352
353 *pargc = n;
354 *pargv = argv;
355}
356
357
358void
359cstrParseCommaified(char *opts, int *pargc, char ***pargv)
360{
361 String str = strCopy(opts);
362 char **argv;
363 char *p, *q;
364 int argc, i;
365
366 p = str;
367 q = p;
368 argc = 1;
369 while (*p != '\0') {
370 if (*p == '\\')
371 p++;
372 else if (*p == ',') {
373 *p = '\0';
374 argc++;
375 }
376 *q = *p;
377 p++; q++;
378 }
379 *q = '\0';
380 p = str;
381 argv = (char **) stoAlloc(OB_Other0, argc * sizeof(char *));
382 for (i=0; i<argc; i++) {
383 argv[i] = p;
384 while (*p != '\0') p++;
385 p++;
386 }
387
388 *pargc = argc;
389 *pargv = argv;
390}
391
392/**********************************************************************************
393 *
394 * :: Conditions
395 *
396 **********************************************************************************/
397
398/*
399 * Function should return 1 for true, 0 for false, and -1 if
400 * not set
401 */
402
403static int (*cfgCondFn)(String);
404
405localstatic void cfgFreeConfPath(void);
406
407void
408cfgSetCondFunc(int (*check)(String))
409{
410 cfgCondFn = check;
411}
412
413static Bool
414cfgCheckCondition(String name, ConfigItemList cfg)
415{
416 int val;
417 if ( (val = (*cfgCondFn)(name)) != -1)
418 return val;
419
420 return cfgLookupBoolean(name, cfg);
421}
422
423/**********************************************************************************
424 *
425 * :: Reading information
426 *
427 **********************************************************************************/
428
429static StringList cfgPath;
430
431ConfigItem
432cfgNew(char *key, char *val)
433{
434 ConfigItem item;
435 int nkey, nval;
436 nkey = strlen(key);
437 nval = strlen(val);
438
439 item = (ConfigItem) stoAlloc(OB_Other0, fullsizeof(struct _ConfigItem, nkey + nval + 2, char)(sizeof(struct _ConfigItem) + (nkey + nval + 2) * sizeof(char
) - 10 * sizeof(char))
);
440 item->optName = item->content;
441 strcpy(item->optName, key);
442 item->optVal = item->content + nkey + 1;
443 strcpy(item->optVal, val);
444
445 return item;
446}
447
448void cfgFree(ConfigItem item)
449{
450 stoFree(item);
451}
452
453void cfgSetConfPath(char *path)
454{
455 Bool done;
456 String s = strCopy(path);
457 char *start, *p;
458 p = s;
459 cfgPath = listNil(String)((StringList) 0);
460 done = false((int) 0);
461 while (!done) {
462 char c;
463 start = p;
464 while (*p != '\0' && *p != osPathSeparator())
465 p++;
466 c = *p;
467 *p = '\0';
468 cfgPath = listCons(String)(String_listPointer->Cons)(start, cfgPath);
469 if (c == '\0') done = true1;
470 p++;
471 }
472}
473
474localstatic void
475cfgFreeConfPath(void)
476{
477 if (cfgPath) strFree(car(cfgPath)((cfgPath)->first));
478 listFree(String)(String_listPointer->Free)(cfgPath);
479}
480
481FileName
482cfgFindFile(String basename, String ext)
483{
484 StringList lst;
485
486 lst = cfgPath;
487 while (lst != listNil(String)((StringList) 0)) {
488 FileName name = fnameNew(car(lst)((lst)->first), basename, ext);
489 if (fileIsOpenable(name, osIoRdMode))
490 return name;
491 lst = cdr(lst)((lst)->rest);
492 }
493
494 return NULL((void*)0);
495}
496
497
498/*
499 * List of errors discovered during cfgRead(). The list is
500 * reset to nothing each time cfgRead() is invoked and may
501 * be accessed by calling cfgReadGetErrors().
502 */
503static StringList CfgReadErrs = listNil(String)((StringList) 0);
504
505
506ConfigItemList
507cfgRead(FILE *file, char *name)
508{
509 Bool done = false((int) 0);
510
511 /* Discard the previous error list */
512 cfgReadClearErrors();
513
514
515 /* Locate, and then read, the specified section */
516 while (!done) {
517 String line = cfgGetLine(file, &done);
518 if (cfgIsSection(line, name))
519 return cfgGetKeys(file, name);
520 }
521 return NULL((void*)0);
522}
523
524
525/* Return the list of errors from the previous cfgRead() call */
526StringList
527cfgReadGetErrors(void)
528{
529 return CfgReadErrs;
530}
531
532
533/* Reset the error list */
534void
535cfgReadClearErrors(void)
536{
537 /* Discard the previous error list */
538 listFreeDeeply(String)(String_listPointer->FreeDeeply)(CfgReadErrs, strFree);
539
540
541 /* Start a new error list */
542 CfgReadErrs = listNil(String)((StringList) 0);
543}
544
545
546/* Add a new error to the list */
547static void
548cfgReadAddError(String error)
549{
550 CfgReadErrs = listCons(String)(String_listPointer->Cons)(strCopy(error), CfgReadErrs);
551}
552
553
554/* Report that we've seen this item before */
555static void
556cfgReadDupItemError(ConfigItem item, String section)
557{
558 String msg;
559
560 /* Compose the error message */
561 msg = strlConcat(
562 "Duplicate key `", cfgName(item)((item)->optName),
563 "' found in section [", section, "]",
564 " of the compiler configuration file.",
565 (String)NULL((void*)0)
566 );
567
568
569 /* Add the error to the list */
570 cfgReadAddError(msg);
571}
572
573
574/* Equality based on key name */
575static Bool
576cfgEqual(ConfigItem itemA, ConfigItem itemB)
577{
578 return strEqual(cfgName(itemA)((itemA)->optName), cfgName(itemB)((itemB)->optName));
579}
580
581static Bool
582cfgIsSection(char *line, char *name)
583{
584 char *p = line;
585 while (*p != ']' && *p != '\0') p++;
586 *p = 0;
587 return (strEqual(line+1, name));
588}
589
590
591static ConfigItemList
592cfgGetKeys(FILE *file, String section)
593{
594 ConfigItemList lst;
595 Bool atEof;
596
597 atEof = false((int) 0);
598 lst = listNil(ConfigItem)((ConfigItemList) 0);
599 while (true1) {
600 ConfigItem item;
601 String line = cfgGetLine(file, &atEof);
602
603
604 /* Stop if we hit the next section */
605 if (line[0] == '[') break;
606
607
608 /* Parse the line to see if contains an item */
609 item = cfgParseLine(line);
610
611
612 /* Check for duplicates (allow `inherit') */
613 if (item && !strEqual(cfgName(item)((item)->optName), "inherit"))
614 {
615 if (listMember(ConfigItem)(ConfigItem_listPointer->Member)(lst, item, cfgEqual))
616 cfgReadDupItemError(item, section);
617 }
618
619
620 /*
621 * We always add the item to the list even if one with
622 * the same key exists already. The client may wish to
623 * deal with duplicate keys themselves (e.g. inherit).
624 */
625 if (item) lst = listCons(ConfigItem)(ConfigItem_listPointer->Cons)(item, lst);
626
627
628 /* Stop if we've reached the end of the file */
629 if (atEof) break;
630
631
632 /* Release temporary storage */
633 strFree(line);
634 }
635 return lst;
636}
637
638static ConfigItem
639cfgParseLine(String line)
640{
641 String key;
642 String val;
643 char *p = line, *keyEnd;
644 /* skip whitespace */
645 while (*p == ' ' || *p == '\t') p++;
646
647 if (*p == '#') return NULL((void*)0);
648 key = p;
649
650 while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0') p++;
651 keyEnd = p;
652
653 if (*p == '\0') return NULL((void*)0);
654
655 while (*p != '=') p++;
656
657 p++;
658 val = p;
659 *keyEnd = '\0';
660
661 return cfgNew(key, val);
662}
663
664static String
665cfgGetLine(FILE *file, Bool *atEof)
666{
667 String s;
668 int n, lim, c;
669
670 lim = 50;
671 s = strAlloc(lim);
672 n = 0;
673
674 c = fgetc(file);
675 while (c != '\n' && c != EOF(-1)) {
676 if (n == lim) {
677 int const incr = 20;
678 String tmp = s;
679 s = strAlloc(lim + incr);
680 strncpy(s, tmp, n);
681 strFree(tmp);
682 lim += incr;
683 }
684 s[n] = c;
685 c = fgetc(file);
686 n++;
687 }
688 while (n < lim)
689 s[n++] = '\0';
690 if (c == EOF(-1)) *atEof = true1;
691 return s;
692}
693