f2d0015decd886e07e08ba3a46840f088866a6ec
[people/mcb30/busybox.git] / scripts / config / symbol.c
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  */
5
6 #include <ctype.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/utsname.h>
10
11 #define LKC_DIRECT_LINK
12 #include "lkc.h"
13
14 struct symbol symbol_yes = {
15         name: "y",
16         curr: { "y", yes },
17         flags: SYMBOL_YES|SYMBOL_VALID,
18 }, symbol_mod = {
19         name: "m",
20         curr: { "m", mod },
21         flags: SYMBOL_MOD|SYMBOL_VALID,
22 }, symbol_no = {
23         name: "n",
24         curr: { "n", no },
25         flags: SYMBOL_NO|SYMBOL_VALID,
26 }, symbol_empty = {
27         name: "",
28         curr: { "", no },
29         flags: SYMBOL_VALID,
30 };
31
32 int sym_change_count;
33 struct symbol *modules_sym;
34
35 void sym_add_default(struct symbol *sym, const char *def)
36 {
37         struct property *prop = create_prop(P_DEFAULT);
38         struct property **propp;
39
40         prop->sym = sym;
41         prop->def = sym_lookup(def, 1);
42
43         /* append property to the prop list of symbol */
44         if (prop->sym) {
45                 for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
46                         ;
47                 *propp = prop;
48         }
49 }
50
51 void sym_init(void)
52 {
53         struct symbol *sym;
54         struct utsname uts;
55         char *p;
56         static bool inited = false;
57
58         if (inited)
59                 return;
60         inited = true;
61
62         uname(&uts);
63
64 #if 0
65         sym = sym_lookup("ARCH", 0);
66         sym->type = S_STRING;
67         sym->flags |= SYMBOL_AUTO;
68         p = getenv("ARCH");
69         if (p)
70                 sym_add_default(sym, p);
71 #endif
72
73         sym = sym_lookup("VERSION", 0);
74         sym->type = S_STRING;
75         sym->flags |= SYMBOL_AUTO;
76         p = getenv("VERSION");
77         if (p)
78                 sym_add_default(sym, p);
79
80 #if 0
81         sym = sym_lookup("UNAME_RELEASE", 0);
82         sym->type = S_STRING;
83         sym->flags |= SYMBOL_AUTO;
84         sym_add_default(sym, uts.release);
85 #endif
86
87         sym = sym_lookup("TARGET_ARCH", 0);
88         sym->type = S_STRING;
89         sym->flags |= SYMBOL_AUTO;
90         p = getenv("TARGET_ARCH");
91         if (p)
92                 sym_add_default(sym, p);
93 }
94
95 int sym_get_type(struct symbol *sym)
96 {
97         int type = sym->type;
98         if (type == S_TRISTATE) {
99                 if (sym_is_choice_value(sym) && sym->visible == yes)
100                         type = S_BOOLEAN;
101                 else {
102                         sym_calc_value(modules_sym);
103                         if (S_TRI(modules_sym->curr) == no)
104                                 type = S_BOOLEAN;
105                 }
106         }
107         return type;
108 }
109
110 const char *sym_type_name(int type)
111 {
112         switch (type) {
113         case S_BOOLEAN:
114                 return "boolean";
115         case S_TRISTATE:
116                 return "tristate";
117         case S_INT:
118                 return "integer";
119         case S_HEX:
120                 return "hex";
121         case S_STRING:
122                 return "string";
123         case S_UNKNOWN:
124                 return "unknown";
125         }
126         return "???";
127 }
128
129 struct property *sym_get_choice_prop(struct symbol *sym)
130 {
131         struct property *prop;
132
133         for_all_choices(sym, prop)
134                 return prop;
135         return NULL;
136 }
137
138 struct property *sym_get_default_prop(struct symbol *sym)
139 {
140         struct property *prop;
141         tristate visible;
142
143         for_all_defaults(sym, prop) {
144                 visible = E_CALC(prop->visible);
145                 if (visible != no)
146                         return prop;
147         }
148         return NULL;
149 }
150
151 void sym_calc_visibility(struct symbol *sym)
152 {
153         struct property *prop;
154         tristate visible, oldvisible;
155
156         /* any prompt visible? */
157         oldvisible = sym->visible;
158         visible = no;
159         for_all_prompts(sym, prop)
160                 visible = E_OR(visible, E_CALC(prop->visible));
161         if (oldvisible != visible) {
162                 sym->visible = visible;
163                 sym->flags |= SYMBOL_CHANGED;
164         }
165 }
166
167 void sym_calc_value(struct symbol *sym)
168 {
169         struct symbol_value newval, oldval;
170         struct property *prop, *def_prop;
171         struct symbol *def_sym;
172         struct expr *e;
173
174         if (sym->flags & SYMBOL_VALID)
175                 return;
176
177         oldval = sym->curr;
178
179         switch (sym->type) {
180         case S_INT:
181         case S_HEX:
182         case S_STRING:
183                 newval = symbol_empty.curr;
184                 break;
185         case S_BOOLEAN:
186         case S_TRISTATE:
187                 newval = symbol_no.curr;
188                 break;
189         default:
190                 S_VAL(newval) = sym->name;
191                 S_TRI(newval) = no;
192                 if (sym->flags & SYMBOL_CONST) {
193                         goto out;
194                 }
195                 //newval = symbol_empty.curr;
196                 // generate warning somewhere here later
197                 //S_TRI(newval) = yes;
198                 goto out;
199         }
200         sym->flags |= SYMBOL_VALID;
201         if (!sym_is_choice_value(sym))
202                 sym->flags &= ~SYMBOL_WRITE;
203
204         sym_calc_visibility(sym);
205
206         /* set default if recursively called */
207         sym->curr = newval;
208
209         if (sym->visible != no) {
210                 sym->flags |= SYMBOL_WRITE;
211                 if (!sym_has_value(sym)) {
212                         if (!sym_is_choice(sym)) {
213                                 prop = sym_get_default_prop(sym);
214                                 if (prop) {
215                                         sym_calc_value(prop->def);
216                                         newval = prop->def->curr;
217                                 }
218                         }
219                 } else
220                         newval = sym->def;
221
222                 S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);
223                 /* if the symbol is visible and not optionial,
224                  * possibly ignore old user choice. */
225                 if (!sym_is_optional(sym) && S_TRI(newval) == no)
226                         S_TRI(newval) = sym->visible;
227                 if (sym_is_choice_value(sym) && sym->visible == yes) {
228                         prop = sym_get_choice_prop(sym);
229                         S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;
230                 }
231         } else {
232                 prop = sym_get_default_prop(sym);
233                 if (prop) {
234                         sym->flags |= SYMBOL_WRITE;
235                         sym_calc_value(prop->def);
236                         newval = prop->def->curr;
237                 }
238         }
239
240         switch (sym_get_type(sym)) {
241         case S_TRISTATE:
242                 if (S_TRI(newval) != mod)
243                         break;
244                 sym_calc_value(modules_sym);
245                 if (S_TRI(modules_sym->curr) == no)
246                         S_TRI(newval) = yes;
247                 break;
248         case S_BOOLEAN:
249                 if (S_TRI(newval) == mod)
250                         S_TRI(newval) = yes;
251         }
252
253 out:
254         sym->curr = newval;
255
256         if (sym_is_choice(sym) && S_TRI(newval) == yes) {
257                 def_sym = S_VAL(sym->def);
258                 if (def_sym) {
259                         sym_calc_visibility(def_sym);
260                         if (def_sym->visible == no)
261                                 def_sym = NULL;
262                 }
263                 if (!def_sym) {
264                         for_all_defaults(sym, def_prop) {
265                                 if (E_CALC(def_prop->visible) == no)
266                                         continue;
267                                 sym_calc_visibility(def_prop->def);
268                                 if (def_prop->def->visible != no) {
269                                         def_sym = def_prop->def;
270                                         break;
271                                 }
272                         }
273                 }
274
275                 if (!def_sym) {
276                         prop = sym_get_choice_prop(sym);
277                         for (e = prop->dep; e; e = e->left.expr) {
278                                 sym_calc_visibility(e->right.sym);
279                                 if (e->right.sym->visible != no) {
280                                         def_sym = e->right.sym;
281                                         break;
282                                 }
283                         }
284                 }
285
286                 S_VAL(newval) = def_sym;
287         }
288
289         if (memcmp(&oldval, &newval, sizeof(newval)))
290                 sym->flags |= SYMBOL_CHANGED;
291         sym->curr = newval;
292
293         if (sym_is_choice(sym)) {
294                 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
295                 prop = sym_get_choice_prop(sym);
296                 for (e = prop->dep; e; e = e->left.expr)
297                         e->right.sym->flags |= flags;
298         }
299 }
300
301 void sym_clear_all_valid(void)
302 {
303         struct symbol *sym;
304         int i;
305
306         for_all_symbols(i, sym)
307                 sym->flags &= ~SYMBOL_VALID;
308         sym_change_count++;
309 }
310
311 void sym_set_all_changed(void)
312 {
313         struct symbol *sym;
314         int i;
315
316         for_all_symbols(i, sym)
317                 sym->flags |= SYMBOL_CHANGED;
318 }
319
320 bool sym_tristate_within_range(struct symbol *sym, tristate val)
321 {
322         int type = sym_get_type(sym);
323
324         if (sym->visible == no)
325                 return false;
326
327         if (type != S_BOOLEAN && type != S_TRISTATE)
328                 return false;
329
330         switch (val) {
331         case no:
332                 if (sym_is_choice_value(sym) && sym->visible == yes)
333                         return false;
334                 return sym_is_optional(sym);
335         case mod:
336                 if (sym_is_choice_value(sym) && sym->visible == yes)
337                         return false;
338                 return type == S_TRISTATE;
339         case yes:
340                 return type == S_BOOLEAN || sym->visible == yes;
341         }
342         return false;
343 }
344
345 bool sym_set_tristate_value(struct symbol *sym, tristate val)
346 {
347         tristate oldval = sym_get_tristate_value(sym);
348
349         if (oldval != val && !sym_tristate_within_range(sym, val))
350                 return false;
351
352         if (sym->flags & SYMBOL_NEW) {
353                 sym->flags &= ~SYMBOL_NEW;
354                 sym->flags |= SYMBOL_CHANGED;
355         }
356         if (sym_is_choice_value(sym) && val == yes) {
357                 struct property *prop = sym_get_choice_prop(sym);
358
359                 S_VAL(prop->def->def) = sym;
360                 prop->def->flags &= ~SYMBOL_NEW;
361         }
362
363         S_TRI(sym->def) = val;
364         if (oldval != val) {
365                 sym_clear_all_valid();
366                 if (sym == modules_sym)
367                         sym_set_all_changed();
368         }
369
370         return true;
371 }
372
373 tristate sym_toggle_tristate_value(struct symbol *sym)
374 {
375         tristate oldval, newval;
376
377         oldval = newval = sym_get_tristate_value(sym);
378         do {
379                 switch (newval) {
380                 case no:
381                         newval = mod;
382                         break;
383                 case mod:
384                         newval = yes;
385                         break;
386                 case yes:
387                         newval = no;
388                         break;
389                 }
390                 if (sym_set_tristate_value(sym, newval))
391                         break;
392         } while (oldval != newval);
393         return newval;
394 }
395
396 bool sym_string_valid(struct symbol *sym, const char *str)
397 {
398         char ch;
399
400         switch (sym->type) {
401         case S_STRING:
402                 return true;
403         case S_INT:
404                 ch = *str++;
405                 if (ch == '-')
406                         ch = *str++;
407                 if (!isdigit((int)ch))
408                         return false;
409                 if (ch == '0' && *str != 0)
410                         return false;
411                 while ((ch = *str++)) {
412                         if (!isdigit((int)ch))
413                                 return false;
414                 }
415                 return true;
416         case S_HEX:
417                 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
418                         str += 2;
419                 ch = *str++;
420                 do {
421                         if (!isxdigit((int)ch))
422                                 return false;
423                 } while ((ch = *str++));
424                 return true;
425         case S_BOOLEAN:
426         case S_TRISTATE:
427                 switch (str[0]) {
428                 case 'y':
429                 case 'Y':
430                         return sym_tristate_within_range(sym, yes);
431                 case 'm':
432                 case 'M':
433                         return sym_tristate_within_range(sym, mod);
434                 case 'n':
435                 case 'N':
436                         return sym_tristate_within_range(sym, no);
437                 }
438                 return false;
439         default:
440                 return false;
441         }
442 }
443
444 bool sym_set_string_value(struct symbol *sym, const char *newval)
445 {
446         const char *oldval;
447         char *val;
448         int size;
449
450         switch (sym->type) {
451         case S_BOOLEAN:
452         case S_TRISTATE:
453                 switch (newval[0]) {
454                 case 'y':
455                 case 'Y':
456                         return sym_set_tristate_value(sym, yes);
457                 case 'm':
458                 case 'M':
459                         return sym_set_tristate_value(sym, mod);
460                 case 'n':
461                 case 'N':
462                         return sym_set_tristate_value(sym, no);
463                 }
464                 return false;
465         default:
466                 ;
467         }
468
469         if (!sym_string_valid(sym, newval))
470                 return false;
471
472         if (sym->flags & SYMBOL_NEW) {
473                 sym->flags &= ~SYMBOL_NEW;
474                 sym->flags |= SYMBOL_CHANGED;
475         }
476
477         oldval = S_VAL(sym->def);
478         size = strlen(newval) + 1;
479         if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
480                 size += 2;
481                 S_VAL(sym->def) = val = malloc(size);
482                 *val++ = '0';
483                 *val++ = 'x';
484         } else if (!oldval || strcmp(oldval, newval))
485                 S_VAL(sym->def) = val = malloc(size);
486         else
487                 return true;
488
489         strcpy(val, newval);
490         free((void *)oldval);
491         sym_clear_all_valid();
492
493         return true;
494 }
495
496 const char *sym_get_string_value(struct symbol *sym)
497 {
498         tristate val;
499
500         switch (sym->type) {
501         case S_BOOLEAN:
502         case S_TRISTATE:
503                 val = sym_get_tristate_value(sym);
504                 switch (val) {
505                 case no:
506                         return "n";
507                 case mod:
508                         return "m";
509                 case yes:
510                         return "y";
511                 }
512                 break;
513         default:
514                 ;
515         }
516         return (const char *)S_VAL(sym->curr);
517 }
518
519 bool sym_is_changable(struct symbol *sym)
520 {
521         if (sym->visible == no)
522                 return false;
523         /* at least 'n' and 'y'/'m' is selectable */
524         if (sym_is_optional(sym))
525                 return true;
526         /* no 'n', so 'y' and 'm' must be selectable */
527         if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
528                 return true;
529         return false;
530 }
531
532 struct symbol *sym_lookup(const char *name, int isconst)
533 {
534         struct symbol *symbol;
535         const char *ptr;
536         char *new_name;
537         int hash = 0;
538
539         //printf("lookup: %s -> ", name);
540         if (name) {
541                 if (name[0] && !name[1]) {
542                         switch (name[0]) {
543                         case 'y': return &symbol_yes;
544                         case 'm': return &symbol_mod;
545                         case 'n': return &symbol_no;
546                         }
547                 }
548                 for (ptr = name; *ptr; ptr++)
549                         hash += *ptr;
550                 hash &= 0xff;
551
552                 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
553                         if (!strcmp(symbol->name, name)) {
554                                 if ((isconst && symbol->flags & SYMBOL_CONST) ||
555                                     (!isconst && !(symbol->flags & SYMBOL_CONST))) {
556                                         //printf("h:%p\n", symbol);
557                                         return symbol;
558                                 }
559                         }
560                 }
561                 new_name = strdup(name);
562         } else {
563                 new_name = NULL;
564                 hash = 256;
565         }
566
567         symbol = malloc(sizeof(*symbol));
568         memset(symbol, 0, sizeof(*symbol));
569         symbol->name = new_name;
570         symbol->type = S_UNKNOWN;
571         symbol->flags = SYMBOL_NEW;
572         if (isconst)
573                 symbol->flags |= SYMBOL_CONST;
574
575         symbol->next = symbol_hash[hash];
576         symbol_hash[hash] = symbol;
577
578         //printf("n:%p\n", symbol);
579         return symbol;
580 }
581
582 struct symbol *sym_find(const char *name)
583 {
584         struct symbol *symbol = NULL;
585         const char *ptr;
586         int hash = 0;
587
588         if (!name)
589                 return NULL;
590
591         if (name[0] && !name[1]) {
592                 switch (name[0]) {
593                 case 'y': return &symbol_yes;
594                 case 'm': return &symbol_mod;
595                 case 'n': return &symbol_no;
596                 }
597         }
598         for (ptr = name; *ptr; ptr++)
599                 hash += *ptr;
600         hash &= 0xff;
601
602         for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
603                 if (!strcmp(symbol->name, name) &&
604                     !(symbol->flags & SYMBOL_CONST))
605                                 break;
606         }
607
608         return symbol;
609 }
610
611 const char *prop_get_type_name(enum prop_type type)
612 {
613         switch (type) {
614         case P_PROMPT:
615                 return "prompt";
616         case P_COMMENT:
617                 return "comment";
618         case P_MENU:
619                 return "menu";
620         case P_ROOTMENU:
621                 return "rootmenu";
622         case P_DEFAULT:
623                 return "default";
624         case P_CHOICE:
625                 return "choice";
626         default:
627                 return "unknown";
628         }
629 }