menuconfig: don't generate inconsistencies when ~/.openwrt/defconfig specifies a...
[openwrt.git] / scripts / config / confdata.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 <sys/stat.h>
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <unistd.h>
13
14 #define LKC_DIRECT_LINK
15 #include "lkc.h"
16
17 #define LOCAL_BUILD_SETTINGS "/.openwrt/defconfig"
18
19 static void conf_warning(const char *fmt, ...)
20         __attribute__ ((format (printf, 1, 2)));
21
22 static const char *conf_filename;
23 static int conf_lineno, conf_warnings, conf_unsaved;
24
25 const char conf_def_filename[] = ".config";
26
27 const char conf_defname[] = "scripts/config/defconfig";
28
29 const char *conf_confnames[] = {
30         ".config",
31         conf_defname,
32         NULL,
33 };
34
35 static void conf_warning(const char *fmt, ...)
36 {
37         va_list ap;
38         va_start(ap, fmt);
39         fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
40         vfprintf(stderr, fmt, ap);
41         fprintf(stderr, "\n");
42         va_end(ap);
43         conf_warnings++;
44 }
45
46 static char *conf_expand_value(const char *in)
47 {
48         struct symbol *sym;
49         const char *src;
50         static char res_value[SYMBOL_MAXLENGTH];
51         char *dst, name[SYMBOL_MAXLENGTH];
52
53         res_value[0] = 0;
54         dst = name;
55         while ((src = strchr(in, '$'))) {
56                 strncat(res_value, in, src - in);
57                 src++;
58                 dst = name;
59                 while (isalnum(*src) || *src == '_')
60                         *dst++ = *src++;
61                 *dst = 0;
62                 sym = sym_lookup(name, 0);
63                 sym_calc_value(sym);
64                 strcat(res_value, sym_get_string_value(sym));
65                 in = src;
66         }
67         strcat(res_value, in);
68
69         return res_value;
70 }
71
72 char *conf_get_default_confname(void)
73 {
74         struct stat buf;
75         static char fullname[PATH_MAX+1];
76         char *env, *name;
77
78         name = conf_expand_value(conf_defname);
79         env = getenv(SRCTREE);
80         if (env) {
81                 sprintf(fullname, "%s/%s", env, name);
82                 if (!stat(fullname, &buf))
83                         return fullname;
84         }
85         return name;
86 }
87
88 void conf_reset(void)
89 {
90         struct symbol *sym;
91         int i;
92
93         for_all_symbols(i, sym) {
94                 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
95                 if (sym_is_choice(sym))
96                         sym->flags &= ~SYMBOL_NEW;
97                 sym->flags &= ~SYMBOL_VALID;
98                 switch (sym->type) {
99                 case S_INT:
100                 case S_HEX:
101                 case S_STRING:
102                         if (sym->user.val)
103                                 free(sym->user.val);
104                 default:
105                         sym->user.val = NULL;
106                         sym->user.tri = no;
107                 }
108         }
109         conf_read_simple(NULL, 0);
110 }
111
112 int conf_read_file(FILE *in, struct symbol *sym){
113         char line[1024];
114         char *p, *p2;
115
116         while (fgets(line, sizeof(line), in)) {
117                 conf_lineno++;
118                 sym = NULL;
119                 switch (line[0]) {
120                 case '#':
121                         if (memcmp(line + 2, "CONFIG_", 7))
122                                 continue;
123                         p = strchr(line + 9, ' ');
124                         if (!p)
125                                 continue;
126                         *p++ = 0;
127                         if (strncmp(p, "is not set", 10))
128                                 continue;
129                         sym = sym_find(line + 9);
130                         if (!sym) {
131                                 //conf_warning("trying to assign nonexistent symbol %s", line + 9);
132                                 break;
133                         } /*else if (!(sym->flags & SYMBOL_NEW)) {
134                                 //conf_warning("trying to reassign symbol %s", sym->name);
135                                 break;
136                         }*/
137                         switch (sym->type) {
138                         case S_BOOLEAN:
139                         case S_TRISTATE:
140                                 sym->user.tri = no;
141                                 sym->flags &= ~SYMBOL_NEW;
142                                 break;
143                         default:
144                                 ;
145                         }
146                         break;
147                 case 'C':
148                         if (memcmp(line, "CONFIG_", 7)) {
149                                 conf_warning("unexpected data");
150                                 continue;
151                         }
152                         p = strchr(line + 7, '=');
153                         if (!p)
154                                 continue;
155                         *p++ = 0;
156                         p2 = strchr(p, '\n');
157                         if (p2)
158                                 *p2 = 0;
159                         sym = sym_find(line + 7);
160                         if (!sym) {
161                                 //conf_warning("trying to assign nonexistent symbol %s", line + 7);
162                                 break;
163                         } /*else if (!(sym->flags & SYMBOL_NEW)) {
164                                 conf_warning("trying to reassign symbol %s", sym->name);
165                                 break;
166                         }*/
167                         switch (sym->type) {
168                         case S_TRISTATE:
169                                 if (p[0] == 'm') {
170                                         sym->user.tri = mod;
171                                         sym->flags &= ~SYMBOL_NEW;
172                                         break;
173                                 }
174                         case S_BOOLEAN:
175                                 if (p[0] == 'y') {
176                                         sym->user.tri = yes;
177                                         sym->flags &= ~SYMBOL_NEW;
178                                         break;
179                                 }
180                                 if (p[0] == 'n') {
181                                         sym->user.tri = no;
182                                         sym->flags &= ~SYMBOL_NEW;
183                                         break;
184                                 }
185                                 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
186                                 break;
187                         case S_STRING:
188                                 if (*p++ != '"')
189                                         break;
190                                 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
191                                         if (*p2 == '"') {
192                                                 *p2 = 0;
193                                                 break;
194                                         }
195                                         memmove(p2, p2 + 1, strlen(p2));
196                                 }
197                                 if (!p2) {
198                                         conf_warning("invalid string found");
199                                         continue;
200                                 }
201                         case S_INT:
202                         case S_HEX:
203                                 if (sym_string_valid(sym, p)) {
204                                         sym->user.val = strdup(p);
205                                         sym->flags &= ~SYMBOL_NEW;
206                                 } else {
207                                         conf_warning("symbol value '%s' invalid for %s", p, sym->name);
208                                         continue;
209                                 }
210                                 break;
211                         default:
212                                 ;
213                         }
214                         break;
215                 case '\n':
216                         break;
217                 default:
218                         conf_warning("unexpected data");
219                         continue;
220                 }
221                 if (sym && sym_is_choice_value(sym)) {
222                         struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
223                         switch (sym->user.tri) {
224                         case no:
225                                 break;
226                         case mod:
227                                 if (cs->user.tri == yes) {
228                                         conf_warning("%s creates inconsistent choice state", sym->name);
229                                         cs->flags |= SYMBOL_NEW;
230                                 }
231                                 break;
232                         case yes:
233                                 cs->user.val = sym;
234                                 break;
235                         }
236                         cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
237                 }
238         }
239         fclose(in);
240
241         return 0;
242 }
243
244 int conf_read_simple(const char *name, int load_config)
245 {
246         FILE *in = NULL;
247         FILE *defaults = NULL;
248         struct symbol *sym;
249         int i;
250         char *home_dir = getenv("HOME");
251         char *default_config_path = NULL;
252         
253         if(home_dir){
254                         default_config_path = malloc(strlen(home_dir) + sizeof(LOCAL_BUILD_SETTINGS) + 1);
255                         sprintf(default_config_path, "%s%s", home_dir, LOCAL_BUILD_SETTINGS);
256                         defaults = zconf_fopen(default_config_path);
257                         if(defaults)
258                                         printf("# using buildsystem predefines from %s\n", default_config_path);
259                         free(default_config_path);
260         }
261         
262         if(load_config){
263                 if (name) {
264                         in = zconf_fopen(name);
265                 } else {
266                         const char **names = conf_confnames;
267                         while ((name = *names++)) {
268                                 name = conf_expand_value(name);
269                                 in = zconf_fopen(name);
270                                 if (in) {
271                                         printf(_("#\n"
272                                                  "# using defaults found in %s\n"
273                                                  "#\n"), name);
274                                         break;
275                                 }
276                         }
277                 }
278         }
279
280         if (!in && !defaults)
281                 return 1;
282
283         conf_filename = name;
284         conf_lineno = 0;
285         conf_warnings = 0;
286         conf_unsaved = 0;
287         
288         for_all_symbols(i, sym) {
289                 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
290                 if (sym_is_choice(sym))
291                         sym->flags &= ~SYMBOL_NEW;
292                 sym->flags &= ~SYMBOL_VALID;
293                 switch (sym->type) {
294                 case S_INT:
295                 case S_HEX:
296                 case S_STRING:
297                         if (sym->user.val)
298                                 free(sym->user.val);
299                 default:
300                         sym->user.val = NULL;
301                         sym->user.tri = no;
302                 }
303         }
304
305         if(defaults)
306                 conf_read_file(defaults, sym);
307         
308         if(in)
309                 conf_read_file(in, sym);
310         
311         if (modules_sym)
312                 sym_calc_value(modules_sym);
313
314         return 0;       
315 }
316
317 int conf_read(const char *name)
318 {
319         struct symbol *sym;
320         struct property *prop;
321         struct expr *e;
322         int i;
323
324         if (conf_read_simple(name, 1))
325                 return 1;
326
327         for_all_symbols(i, sym) {
328                 sym_calc_value(sym);
329                 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
330                         goto sym_ok;
331                 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
332                         /* check that calculated value agrees with saved value */
333                         switch (sym->type) {
334                         case S_BOOLEAN:
335                         case S_TRISTATE:
336                                 if (sym->user.tri != sym_get_tristate_value(sym))
337                                         break;
338                                 if (!sym_is_choice(sym))
339                                         goto sym_ok;
340                         default:
341                                 if (!strcmp(sym->curr.val, sym->user.val))
342                                         goto sym_ok;
343                                 break;
344                         }
345                 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
346                         /* no previous value and not saved */
347                         goto sym_ok;
348                 conf_unsaved++;
349                 /* maybe print value in verbose mode... */
350         sym_ok:
351                 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
352                         if (sym->visible == no)
353                                 sym->flags |= SYMBOL_NEW;
354                         switch (sym->type) {
355                         case S_STRING:
356                         case S_INT:
357                         case S_HEX:
358                                 if (!sym_string_within_range(sym, sym->user.val)) {
359                                         sym->flags |= SYMBOL_NEW;
360                                         sym->flags &= ~SYMBOL_VALID;
361                                 }
362                         default:
363                                 break;
364                         }
365                 }
366                 if (!sym_is_choice(sym))
367                         continue;
368                 prop = sym_get_choice_prop(sym);
369                 for (e = prop->expr; e; e = e->left.expr)
370                         if (e->right.sym->visible != no)
371                                 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
372         }
373
374         sym_change_count = conf_warnings && conf_unsaved;
375
376         return 0;
377 }
378
379 int conf_write(const char *name)
380 {
381         FILE *out;
382         struct symbol *sym;
383         struct menu *menu;
384         const char *basename;
385         char dirname[128], tmpname[128], newname[128];
386         int type, l;
387         const char *str;
388         time_t now;
389         int use_timestamp = 1;
390         char *env;
391
392         dirname[0] = 0;
393         if (name && name[0]) {
394                 struct stat st;
395                 char *slash;
396
397                 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
398                         strcpy(dirname, name);
399                         strcat(dirname, "/");
400                         basename = conf_def_filename;
401                 } else if ((slash = strrchr(name, '/'))) {
402                         int size = slash - name + 1;
403                         memcpy(dirname, name, size);
404                         dirname[size] = 0;
405                         if (slash[1])
406                                 basename = slash + 1;
407                         else
408                                 basename = conf_def_filename;
409                 } else
410                         basename = name;
411         } else
412                 basename = conf_def_filename;
413
414         sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
415         out = fopen(newname, "w");
416         if (!out)
417                 return 1;
418         sym = sym_lookup("OPENWRTVERSION", 0);
419         sym_calc_value(sym);
420         time(&now);
421         env = getenv("KCONFIG_NOTIMESTAMP");
422         if (env && *env)
423                 use_timestamp = 0;
424
425         fprintf(out, _("#\n"
426                        "# Automatically generated make config: don't edit\n"
427                        "# OpenWrt version: %s\n"
428                        "%s%s"
429                        "#\n"),
430                      sym_get_string_value(sym),
431                      use_timestamp ? "# " : "",
432                      use_timestamp ? ctime(&now) : "");
433
434         if (!sym_change_count)
435                 sym_clear_all_valid();
436
437         menu = rootmenu.list;
438         while (menu) {
439                 sym = menu->sym;
440                 if (!sym) {
441                         if (!menu_is_visible(menu))
442                                 goto next;
443                         str = menu_get_prompt(menu);
444                         fprintf(out, "\n"
445                                      "#\n"
446                                      "# %s\n"
447                                      "#\n", str);
448                 } else if (!(sym->flags & SYMBOL_CHOICE)) {
449                         sym_calc_value(sym);
450                         if (!(sym->flags & SYMBOL_WRITE))
451                                 goto next;
452                         sym->flags &= ~SYMBOL_WRITE;
453                         type = sym->type;
454                         if (type == S_TRISTATE) {
455                                 sym_calc_value(modules_sym);
456 /* tristate always enabled */
457 #if 0
458                                 if (modules_sym->curr.tri == no)
459                                         type = S_BOOLEAN;
460 #endif
461                         }
462                         switch (type) {
463                         case S_BOOLEAN:
464                         case S_TRISTATE:
465                                 switch (sym_get_tristate_value(sym)) {
466                                 case no:
467                                         fprintf(out, "# CONFIG_%s is not set\n", sym->name);
468                                         break;
469                                 case mod:
470                                         fprintf(out, "CONFIG_%s=m\n", sym->name);
471                                         break;
472                                 case yes:
473                                         fprintf(out, "CONFIG_%s=y\n", sym->name);
474                                         break;
475                                 }
476                                 break;
477                         case S_STRING:
478                                 // fix me
479                                 str = sym_get_string_value(sym);
480                                 fprintf(out, "CONFIG_%s=\"", sym->name);
481                                 do {
482                                         l = strcspn(str, "\"\\");
483                                         if (l) {
484                                                 fwrite(str, l, 1, out);
485                                         }
486                                         str += l;
487                                         while (*str == '\\' || *str == '"') {
488                                                 fprintf(out, "\\%c", *str);
489                                                 str++;
490                                         }
491                                 } while (*str);
492                                 fputs("\"\n", out);
493                                 break;
494                         case S_HEX:
495                                 str = sym_get_string_value(sym);
496                                 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
497                                         fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
498                                         break;
499                                 }
500                         case S_INT:
501                                 str = sym_get_string_value(sym);
502                                 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
503                                 break;
504                         }
505                 }
506
507         next:
508                 if (menu->list) {
509                         menu = menu->list;
510                         continue;
511                 }
512                 if (menu->next)
513                         menu = menu->next;
514                 else while ((menu = menu->parent)) {
515                         if (menu->next) {
516                                 menu = menu->next;
517                                 break;
518                         }
519                 }
520         }
521         fclose(out);
522         if (!name || basename != conf_def_filename) {
523                 if (!name)
524                         name = conf_def_filename;
525                 sprintf(tmpname, "%s.old", name);
526                 rename(name, tmpname);
527         }
528         sprintf(tmpname, "%s%s", dirname, basename);
529         if (rename(newname, tmpname))
530                 return 1;
531
532         sym_change_count = 0;
533
534         return 0;
535 }