c77bef2e2597aa5c37343fcb3d7c4b2deafc74f0
[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                                 if (cs->user.tri != no) {
234                                         conf_warning("%s creates inconsistent choice state", sym->name);
235                                         cs->flags |= SYMBOL_NEW;
236                                 } else
237                                         cs->user.val = sym;
238                                 break;
239                         }
240                         cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
241                 }
242         }
243         fclose(in);
244
245         return 0;
246 }
247
248 int conf_read_simple(const char *name, int load_config)
249 {
250         FILE *in = NULL;
251         FILE *defaults = NULL;
252         struct symbol *sym;
253         int i;
254         char *home_dir = getenv("HOME");
255         char *default_config_path = NULL;
256         
257         if(home_dir){
258                         default_config_path = malloc(strlen(home_dir) + sizeof(LOCAL_BUILD_SETTINGS) + 1);
259                         sprintf(default_config_path, "%s%s", home_dir, LOCAL_BUILD_SETTINGS);
260                         defaults = zconf_fopen(default_config_path);
261                         if(defaults)
262                                         printf("# using buildsystem predefines from %s\n", default_config_path);
263                         free(default_config_path);
264         }
265         
266         if(load_config){
267                 if (name) {
268                         in = zconf_fopen(name);
269                 } else {
270                         const char **names = conf_confnames;
271                         while ((name = *names++)) {
272                                 name = conf_expand_value(name);
273                                 in = zconf_fopen(name);
274                                 if (in) {
275                                         printf(_("#\n"
276                                                  "# using defaults found in %s\n"
277                                                  "#\n"), name);
278                                         break;
279                                 }
280                         }
281                 }
282         }
283
284         if (!in && !defaults)
285                 return 1;
286
287         conf_filename = name;
288         conf_lineno = 0;
289         conf_warnings = 0;
290         conf_unsaved = 0;
291         
292         for_all_symbols(i, sym) {
293                 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
294                 if (sym_is_choice(sym))
295                         sym->flags &= ~SYMBOL_NEW;
296                 sym->flags &= ~SYMBOL_VALID;
297                 switch (sym->type) {
298                 case S_INT:
299                 case S_HEX:
300                 case S_STRING:
301                         if (sym->user.val)
302                                 free(sym->user.val);
303                 default:
304                         sym->user.val = NULL;
305                         sym->user.tri = no;
306                 }
307         }
308
309         if(defaults)
310                 conf_read_file(defaults, sym);
311         
312         if(in)
313                 conf_read_file(in, sym);
314         
315         if (modules_sym)
316                 sym_calc_value(modules_sym);
317
318         return 0;       
319 }
320
321 int conf_read(const char *name)
322 {
323         struct symbol *sym;
324         struct property *prop;
325         struct expr *e;
326         int i;
327
328         if (conf_read_simple(name, 1))
329                 return 1;
330
331         for_all_symbols(i, sym) {
332                 sym_calc_value(sym);
333                 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
334                         goto sym_ok;
335                 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
336                         /* check that calculated value agrees with saved value */
337                         switch (sym->type) {
338                         case S_BOOLEAN:
339                         case S_TRISTATE:
340                                 if (sym->user.tri != sym_get_tristate_value(sym))
341                                         break;
342                                 if (!sym_is_choice(sym))
343                                         goto sym_ok;
344                         default:
345                                 if (!strcmp(sym->curr.val, sym->user.val))
346                                         goto sym_ok;
347                                 break;
348                         }
349                 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
350                         /* no previous value and not saved */
351                         goto sym_ok;
352                 conf_unsaved++;
353                 /* maybe print value in verbose mode... */
354         sym_ok:
355                 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
356                         if (sym->visible == no)
357                                 sym->flags |= SYMBOL_NEW;
358                         switch (sym->type) {
359                         case S_STRING:
360                         case S_INT:
361                         case S_HEX:
362                                 if (!sym_string_within_range(sym, sym->user.val)) {
363                                         sym->flags |= SYMBOL_NEW;
364                                         sym->flags &= ~SYMBOL_VALID;
365                                 }
366                         default:
367                                 break;
368                         }
369                 }
370                 if (!sym_is_choice(sym))
371                         continue;
372                 prop = sym_get_choice_prop(sym);
373                 for (e = prop->expr; e; e = e->left.expr)
374                         if (e->right.sym->visible != no)
375                                 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
376         }
377
378         sym_change_count = conf_warnings && conf_unsaved;
379
380         return 0;
381 }
382
383 int conf_write(const char *name)
384 {
385         FILE *out;
386         struct symbol *sym;
387         struct menu *menu;
388         const char *basename;
389         char dirname[128], tmpname[128], newname[128];
390         int type, l;
391         const char *str;
392         time_t now;
393         int use_timestamp = 1;
394         char *env;
395
396         dirname[0] = 0;
397         if (name && name[0]) {
398                 struct stat st;
399                 char *slash;
400
401                 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
402                         strcpy(dirname, name);
403                         strcat(dirname, "/");
404                         basename = conf_def_filename;
405                 } else if ((slash = strrchr(name, '/'))) {
406                         int size = slash - name + 1;
407                         memcpy(dirname, name, size);
408                         dirname[size] = 0;
409                         if (slash[1])
410                                 basename = slash + 1;
411                         else
412                                 basename = conf_def_filename;
413                 } else
414                         basename = name;
415         } else
416                 basename = conf_def_filename;
417
418         sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
419         out = fopen(newname, "w");
420         if (!out)
421                 return 1;
422         sym = sym_lookup("OPENWRTVERSION", 0);
423         sym_calc_value(sym);
424         time(&now);
425         env = getenv("KCONFIG_NOTIMESTAMP");
426         if (env && *env)
427                 use_timestamp = 0;
428
429         fprintf(out, _("#\n"
430                        "# Automatically generated make config: don't edit\n"
431                        "# OpenWrt version: %s\n"
432                        "%s%s"
433                        "#\n"),
434                      sym_get_string_value(sym),
435                      use_timestamp ? "# " : "",
436                      use_timestamp ? ctime(&now) : "");
437
438         if (!sym_change_count)
439                 sym_clear_all_valid();
440
441         menu = rootmenu.list;
442         while (menu) {
443                 sym = menu->sym;
444                 if (!sym) {
445                         if (!menu_is_visible(menu))
446                                 goto next;
447                         str = menu_get_prompt(menu);
448                         fprintf(out, "\n"
449                                      "#\n"
450                                      "# %s\n"
451                                      "#\n", str);
452                 } else if (!(sym->flags & SYMBOL_CHOICE)) {
453                         sym_calc_value(sym);
454                         if (!(sym->flags & SYMBOL_WRITE))
455                                 goto next;
456                         sym->flags &= ~SYMBOL_WRITE;
457                         type = sym->type;
458                         if (type == S_TRISTATE) {
459                                 sym_calc_value(modules_sym);
460 /* tristate always enabled */
461 #if 0
462                                 if (modules_sym->curr.tri == no)
463                                         type = S_BOOLEAN;
464 #endif
465                         }
466                         switch (type) {
467                         case S_BOOLEAN:
468                         case S_TRISTATE:
469                                 switch (sym_get_tristate_value(sym)) {
470                                 case no:
471                                         fprintf(out, "# CONFIG_%s is not set\n", sym->name);
472                                         break;
473                                 case mod:
474                                         fprintf(out, "CONFIG_%s=m\n", sym->name);
475                                         break;
476                                 case yes:
477                                         fprintf(out, "CONFIG_%s=y\n", sym->name);
478                                         break;
479                                 }
480                                 break;
481                         case S_STRING:
482                                 // fix me
483                                 str = sym_get_string_value(sym);
484                                 fprintf(out, "CONFIG_%s=\"", sym->name);
485                                 do {
486                                         l = strcspn(str, "\"\\");
487                                         if (l) {
488                                                 fwrite(str, l, 1, out);
489                                         }
490                                         str += l;
491                                         while (*str == '\\' || *str == '"') {
492                                                 fprintf(out, "\\%c", *str);
493                                                 str++;
494                                         }
495                                 } while (*str);
496                                 fputs("\"\n", out);
497                                 break;
498                         case S_HEX:
499                                 str = sym_get_string_value(sym);
500                                 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
501                                         fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
502                                         break;
503                                 }
504                         case S_INT:
505                                 str = sym_get_string_value(sym);
506                                 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
507                                 break;
508                         }
509                 }
510
511         next:
512                 if (menu->list) {
513                         menu = menu->list;
514                         continue;
515                 }
516                 if (menu->next)
517                         menu = menu->next;
518                 else while ((menu = menu->parent)) {
519                         if (menu->next) {
520                                 menu = menu->next;
521                                 break;
522                         }
523                 }
524         }
525         fclose(out);
526         if (!name || basename != conf_def_filename) {
527                 if (!name)
528                         name = conf_def_filename;
529                 sprintf(tmpname, "%s.old", name);
530                 rename(name, tmpname);
531         }
532         sprintf(tmpname, "%s%s", dirname, basename);
533         if (rename(newname, tmpname))
534                 return 1;
535
536         sym_change_count = 0;
537
538         return 0;
539 }