simple menu: make "menu default" work after "menu begin"
[syslinux.git] / com32 / menu / readconfig.c
blob0d3093b2073c1d65b6cf4ddaadb0a898475f5c6a
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8 * Boston MA 02110-1301, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <minmax.h>
17 #include <alloca.h>
18 #include <inttypes.h>
19 #include <colortbl.h>
20 #include <com32.h>
21 #include <syslinux/config.h>
23 #include "menu.h"
25 /* Empty refstring */
26 const char *empty_string;
28 /* Root menu, starting menu, hidden menu, and list of all menus */
29 struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
31 /* These are global parameters regardless of which menu we're displaying */
32 int shiftkey = 0; /* Only display menu if shift key pressed */
33 int hiddenmenu = 0;
34 long long totaltimeout = 0;
36 /* Linked list of all entires, hidden or not; used by unlabel() */
37 static struct menu_entry *all_entries;
38 static struct menu_entry **all_entries_end = &all_entries;
40 static const struct messages messages[MSG_COUNT] = {
41 [MSG_AUTOBOOT] = { "autoboot", "Automatic boot in # second{,s}..." },
42 [MSG_TAB] = { "tabmsg", "Press [Tab] to edit options" },
43 [MSG_NOTAB] = { "notabmsg", "" },
44 [MSG_PASSPROMPT] = { "passprompt", "Password required" },
47 #define astrdup(x) ({ char *__x = (x); \
48 size_t __n = strlen(__x) + 1; \
49 char *__p = alloca(__n); \
50 if ( __p ) memcpy(__p, __x, __n); \
51 __p; })
53 /* Must match enum kernel_type */
54 const char * const kernel_types[] = {
55 "none",
56 "localboot",
57 "kernel",
58 "linux",
59 "boot",
60 "bss",
61 "pxe",
62 "fdimage",
63 "comboot",
64 "com32",
65 "config",
66 NULL
70 * Search the list of all menus for a specific label
72 static struct menu *
73 find_menu(const char *label)
75 struct menu *m;
77 for (m = menu_list; m; m = m->next) {
78 if (!strcmp(label, m->label))
79 return m;
82 return NULL;
85 #define MAX_LINE 4096
87 static char *
88 skipspace(char *p)
90 while (*p && my_isspace(*p))
91 p++;
93 return p;
96 /* Strip ^ from a string, returning a new reference to the same refstring
97 if none present */
98 static const char *strip_caret(const char *str)
100 const char *p, *r;
101 char *q;
102 int carets = 0;
104 p = str;
105 for (;;) {
106 p = strchr(p, '^');
107 if (!p)
108 break;
109 carets++;
110 p++;
113 if (!carets)
114 return refstr_get(str);
116 r = q = refstr_alloc(strlen(str)-carets);
117 for (p = str; *p; p++)
118 if (*p != '^')
119 *q++ = *p;
121 *q = '\0'; /* refstr_alloc() already did this... */
123 return r;
126 /* Check to see if we are at a certain keyword (case insensitive) */
127 /* Returns a pointer to the first character past the keyword */
128 static char *
129 looking_at(char *line, const char *kwd)
131 char *p = line;
132 const char *q = kwd;
134 while ( *p && *q && ((*p^*q) & ~0x20) == 0 ) {
135 p++;
136 q++;
139 if ( *q )
140 return NULL; /* Didn't see the keyword */
142 return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
145 static struct menu * new_menu(struct menu *parent,
146 struct menu_entry *parent_entry,
147 const char *label)
149 struct menu *m = calloc(1, sizeof(struct menu));
150 int i;
152 m->label = label;
153 m->title = refstr_get(empty_string);
155 if (parent) {
156 /* Submenu */
157 m->parent = parent;
158 m->parent_entry = parent_entry;
159 parent_entry->action = MA_SUBMENU;
160 parent_entry->submenu = m;
162 for (i = 0; i < MSG_COUNT; i++)
163 m->messages[i] = refstr_get(parent->messages[i]);
165 memcpy(m->mparm, parent->mparm, sizeof m->mparm);
167 m->allowedit = parent->allowedit;
168 m->timeout = parent->timeout;
170 m->ontimeout = refstr_get(parent->ontimeout);
171 m->onerror = refstr_get(parent->onerror);
172 m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
173 m->menu_background = refstr_get(parent->menu_background);
175 m->color_table = copy_color_table(parent->color_table);
177 for (i = 0; i < 12; i++) {
178 m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
179 m->fkeyhelp[i].background = refstr_get(parent->fkeyhelp[i].background);
181 } else {
182 /* Root menu */
183 for (i = 0; i < MSG_COUNT; i++)
184 m->messages[i] = refstrdup(messages[i].defmsg);
185 for (i = 0; i < NPARAMS; i++)
186 m->mparm[i] = mparm[i].value;
188 m->allowedit = 1; /* Allow edits of the command line */
189 m->color_table = default_color_table();
192 m->next = menu_list;
193 menu_list = m;
195 return m;
198 struct labeldata {
199 const char *label;
200 const char *kernel;
201 enum kernel_type type;
202 const char *append;
203 const char *initrd;
204 const char *menulabel;
205 const char *passwd;
206 char *helptext;
207 unsigned int ipappend;
208 unsigned int menuhide;
209 unsigned int menudefault;
210 unsigned int menuseparator;
211 unsigned int menudisabled;
212 unsigned int menuindent;
213 enum menu_action action;
214 struct menu *submenu;
217 /* Menu currently being parsed */
218 static struct menu *current_menu;
220 static void
221 clear_label_data(struct labeldata *ld)
223 refstr_put(ld->label);
224 refstr_put(ld->kernel);
225 refstr_put(ld->append);
226 refstr_put(ld->initrd);
227 refstr_put(ld->menulabel);
228 refstr_put(ld->passwd);
230 memset(ld, 0, sizeof *ld);
233 static struct menu_entry *new_entry(struct menu *m)
235 struct menu_entry *me;
237 if (m->nentries >= m->nentries_space) {
238 if (!m->nentries_space)
239 m->nentries_space = 1;
240 else
241 m->nentries_space <<= 1;
243 m->menu_entries = realloc(m->menu_entries, m->nentries_space*
244 sizeof(struct menu_entry *));
247 me = calloc(1, sizeof(struct menu_entry));
248 me->entry = m->nentries;
249 m->menu_entries[m->nentries++] = me;
250 *all_entries_end = me;
251 all_entries_end = &me->next;
253 return me;
256 static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
258 const char *p = strchr(me->displayname, '^');
260 if (me->action != MA_DISABLED) {
261 if ( p && p[1] ) {
262 unsigned char hotkey = p[1] & ~0x20;
263 if ( !m->menu_hotkeys[hotkey] ) {
264 me->hotkey = hotkey;
265 m->menu_hotkeys[hotkey] = me;
271 static void
272 record(struct menu *m, struct labeldata *ld, const char *append)
274 int i;
275 struct menu_entry *me;
276 const struct syslinux_ipappend_strings *ipappend;
278 if (!ld->label)
279 return; /* Nothing defined */
281 /* Hidden entries are recorded on a special "hidden menu" */
282 if (ld->menuhide)
283 m = hide_menu;
285 if ( ld->label ) {
286 char ipoptions[4096], *ipp;
287 const char *a;
288 char *s;
290 me = new_entry(m);
292 me->displayname = ld->menulabel
293 ? refstr_get(ld->menulabel) : refstr_get(ld->label);
294 me->label = refstr_get(ld->label);
295 me->passwd = refstr_get(ld->passwd);
296 me->helptext = ld->helptext;
297 me->hotkey = 0;
298 me->action = ld->action ? ld->action : MA_CMD;
300 if ( ld->menuindent ) {
301 const char *dn;
303 rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
304 refstr_put(me->displayname);
305 me->displayname = dn;
308 if ( ld->menuseparator ) {
309 refstr_put(me->displayname);
310 me->displayname = refstr_get(empty_string);
313 if ( ld->menuseparator || ld->menudisabled ) {
314 me->action = MA_DISABLED;
315 refstr_put(me->label);
316 me->label = NULL;
317 refstr_put(me->passwd);
318 me->passwd = NULL;
321 if (ld->menulabel)
322 consider_for_hotkey(m, me);
324 switch (me->action) {
325 case MA_CMD:
326 ipp = ipoptions;
327 *ipp = '\0';
329 if (ld->initrd)
330 ipp += sprintf(ipp, " initrd=%s", ld->initrd);
332 if (ld->ipappend) {
333 ipappend = syslinux_ipappend_strings();
334 for (i = 0; i < ipappend->count; i++) {
335 if ( (ld->ipappend & (1U << i)) && ipappend->ptr[i] )
336 ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
340 a = ld->append;
341 if ( !a )
342 a = append;
343 if ( !a || (a[0] == '-' && !a[1]) )
344 a = "";
345 s = a[0] ? " " : "";
346 if (ld->type == KT_KERNEL) {
347 rsprintf(&me->cmdline, "%s%s%s%s",
348 ld->kernel, s, a, ipoptions);
349 } else {
350 rsprintf(&me->cmdline, ".%s %s%s%s%s",
351 kernel_types[ld->type], ld->kernel, s, a, ipoptions);
353 break;
355 case MA_GOTO_UNRES:
356 case MA_EXIT_UNRES:
357 me->cmdline = refstr_get(ld->kernel);
358 break;
360 case MA_GOTO:
361 case MA_EXIT:
362 me->submenu = ld->submenu;
363 break;
365 default:
366 break;
369 if ( ld->menudefault && me->action == MA_CMD )
370 m->defentry = m->nentries-1;
373 clear_label_data(ld);
376 static struct menu *begin_submenu(const char *tag)
378 struct menu_entry *me;
380 if (!tag[0])
381 tag = NULL;
383 me = new_entry(current_menu);
384 me->displayname = refstrdup(tag);
385 return new_menu(current_menu, me, refstr_get(me->displayname));
388 static struct menu *end_submenu(void)
390 return current_menu->parent ? current_menu->parent : current_menu;
393 static const char *unlabel(const char *str)
395 /* Convert a CLI-style command line to an executable command line */
396 const char *p;
397 const char *q;
398 struct menu_entry *me;
399 int pos;
401 p = str;
402 while ( *p && !my_isspace(*p) )
403 p++;
405 /* p now points to the first byte beyond the kernel name */
406 pos = p-str;
408 for (me = all_entries; me; me = me->next) {
409 if (!strncmp(str, me->label, pos) && !me->label[pos]) {
410 /* Found matching label */
411 rsprintf(&q, "%s%s", me->cmdline, p);
412 refstr_put(str);
413 return q;
417 return str;
420 static const char *
421 refdup_word(char **p)
423 char *sp = *p;
424 char *ep = sp;
426 while (*ep && !my_isspace(*ep))
427 ep++;
429 *p = ep;
430 return refstrndup(sp, ep-sp);
433 int my_isxdigit(char c)
435 unsigned int uc = c;
437 return (uc-'0') < 10 ||
438 ((uc|0x20)-'a') < 6;
441 unsigned int hexval(char c)
443 unsigned char uc = c | 0x20;
444 unsigned int v;
446 v = uc-'0';
447 if (v < 10)
448 return v;
450 return uc-'a'+10;
453 unsigned int hexval2(const char *p)
455 return (hexval(p[0]) << 4)+hexval(p[1]);
458 uint32_t parse_argb(char **p)
460 char *sp = *p;
461 char *ep;
462 uint32_t argb;
463 size_t len, dl;
465 if (*sp == '#')
466 sp++;
468 ep = sp;
470 while (my_isxdigit(*ep))
471 ep++;
473 *p = ep;
474 len = ep-sp;
476 switch(len) {
477 case 3: /* #rgb */
478 argb =
479 0xff000000 +
480 (hexval(sp[0])*0x11 << 16) +
481 (hexval(sp[1])*0x11 << 8) +
482 (hexval(sp[2])*0x11);
483 break;
484 case 4: /* #argb */
485 argb =
486 (hexval(sp[0])*0x11 << 24) +
487 (hexval(sp[1])*0x11 << 16) +
488 (hexval(sp[2])*0x11 << 8) +
489 (hexval(sp[3])*0x11);
490 break;
491 case 6: /* #rrggbb */
492 case 9: /* #rrrgggbbb */
493 case 12: /* #rrrrggggbbbb */
494 dl = len/3;
495 argb =
496 0xff000000 +
497 (hexval2(sp+0) << 16) +
498 (hexval2(sp+dl) << 8) +
499 hexval2(sp+dl*2);
500 break;
501 case 8: /* #aarrggbb */
502 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
503 assume the latter is a more common format */
504 case 16: /* #aaaarrrrggggbbbb */
505 dl = len/4;
506 argb =
507 (hexval2(sp+0) << 24) +
508 (hexval2(sp+dl) << 16) +
509 (hexval2(sp+dl*2) << 8) +
510 hexval2(sp+dl*3);
511 break;
512 default:
513 argb = 0xffff0000; /* Bright red (error indication) */
514 break;
517 return argb;
521 * Parser state. This is global so that including multiple
522 * files work as expected, which is that everything works the
523 * same way as if the files had been concatenated together.
525 static const char *append = NULL;
526 static unsigned int ipappend = 0;
527 static struct labeldata ld;
529 static int parse_one_config(const char *filename);
531 static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
533 const char * const *p;
534 char *q;
535 enum kernel_type t = KT_NONE;
537 for (p = kernel_types; *p; p++, t++) {
538 if ((q = looking_at(cmdstr, *p))) {
539 *type = t;
540 return q;
544 return NULL;
547 static char *is_message_name(char *cmdstr, enum message_number *msgnr)
549 char *q;
550 enum message_number i;
552 for (i = 0; i < MSG_COUNT; i++) {
553 if ((q = looking_at(cmdstr, messages[i].name))) {
554 *msgnr = i;
555 return q;
559 return NULL;
562 static char *is_fkey(char *cmdstr, int *fkeyno)
564 char *q;
565 int no;
567 if ((cmdstr[0]|0x20) != 'f')
568 return NULL;
570 no = strtoul(cmdstr+1, &q, 10);
571 if (!my_isspace(*q))
572 return NULL;
574 if (no < 0 || no > 12)
575 return NULL;
577 *fkeyno = (no == 0) ? 10 : no-1;
578 return q;
581 static void parse_config_file(FILE *f)
583 char line[MAX_LINE], *p, *ep, ch;
584 enum kernel_type type;
585 enum message_number msgnr;
586 int fkeyno;
587 struct menu *m = current_menu;
589 while ( fgets(line, sizeof line, f) ) {
590 p = strchr(line, '\r');
591 if ( p )
592 *p = '\0';
593 p = strchr(line, '\n');
594 if ( p )
595 *p = '\0';
597 p = skipspace(line);
599 if ( looking_at(p, "menu") ) {
600 p = skipspace(p+4);
602 if ( looking_at(p, "label") ) {
603 if ( ld.label ) {
604 refstr_put(ld.menulabel);
605 ld.menulabel = refstrdup(skipspace(p+5));
606 } else if ( m->parent_entry ) {
607 refstr_put(m->parent_entry->displayname);
608 m->parent_entry->displayname = refstrdup(skipspace(p+5));
609 consider_for_hotkey(m->parent, m->parent_entry);
610 if (!m->title[0]) {
611 /* MENU LABEL -> MENU TITLE on submenu */
612 refstr_put(m->title);
613 m->title = strip_caret(m->parent_entry->displayname);
616 } else if ( looking_at(p, "title") ) {
617 refstr_put(m->title);
618 m->title = refstrdup(skipspace(p+5));
619 if (m->parent_entry) {
620 /* MENU TITLE -> MENU LABEL on submenu */
621 if (m->parent_entry->displayname == m->label) {
622 refstr_put(m->parent_entry->displayname);
623 m->parent_entry->displayname = refstr_get(m->title);
626 } else if ( looking_at(p, "default") ) {
627 if (ld.label) {
628 ld.menudefault = 1;
629 } else if (m->parent_entry) {
630 m->parent->defentry = m->parent_entry->entry;
632 } else if ( looking_at(p, "hide") ) {
633 ld.menuhide = 1;
634 } else if ( looking_at(p, "passwd") ) {
635 if ( ld.label ) {
636 refstr_put(ld.passwd);
637 ld.passwd = refstrdup(skipspace(p+6));
638 } else if ( m->parent_entry ) {
639 refstr_put(m->parent_entry->passwd);
640 m->parent_entry->passwd = refstrdup(skipspace(p+6));
642 } else if ( looking_at(p, "shiftkey") ) {
643 shiftkey = 1;
644 } else if ( looking_at(p, "onerror") ) {
645 refstr_put(m->onerror);
646 m->onerror = refstrdup(skipspace(p+7));
647 } else if ( looking_at(p, "master") ) {
648 p = skipspace(p+6);
649 if ( looking_at(p, "passwd") ) {
650 refstr_put(m->menu_master_passwd);
651 m->menu_master_passwd = refstrdup(skipspace(p+6));
653 } else if ( (ep = looking_at(p, "include")) ) {
654 goto do_include;
655 } else if ( (ep = looking_at(p, "background")) ) {
656 p = skipspace(ep);
657 refstr_put(m->menu_background);
658 m->menu_background = refdup_word(&p);
659 } else if ( (ep = looking_at(p, "hidden")) ) {
660 hiddenmenu = 1;
661 } else if ( (ep = is_message_name(p, &msgnr)) ) {
662 refstr_put(m->messages[msgnr]);
663 m->messages[msgnr] = refstrdup(skipspace(ep));
664 } else if ((ep = looking_at(p, "color")) ||
665 (ep = looking_at(p, "colour"))) {
666 int i;
667 struct color_table *cptr;
668 p = skipspace(ep);
669 cptr = m->color_table;
670 for ( i = 0; i < menu_color_table_size; i++ ) {
671 if ( (ep = looking_at(p, cptr->name)) ) {
672 p = skipspace(ep);
673 if (*p) {
674 if (looking_at(p, "*")) {
675 p++;
676 } else {
677 refstr_put(cptr->ansi);
678 cptr->ansi = refdup_word(&p);
681 p = skipspace(p);
682 if (*p) {
683 if (looking_at(p, "*"))
684 p++;
685 else
686 cptr->argb_fg = parse_argb(&p);
688 p = skipspace(p);
689 if (*p) {
690 if (looking_at(p, "*"))
691 p++;
692 else
693 cptr->argb_bg = parse_argb(&p);
695 /* Parse a shadow mode */
696 p = skipspace(p);
697 ch = *p | 0x20;
698 if (ch == 'n') /* none */
699 cptr->shadow = SHADOW_NONE;
700 else if (ch == 's') /* std, standard */
701 cptr->shadow = SHADOW_NORMAL;
702 else if (ch == 'a') /* all */
703 cptr->shadow = SHADOW_ALL;
704 else if (ch == 'r') /* rev, reverse */
705 cptr->shadow = SHADOW_REVERSE;
709 break;
711 cptr++;
713 } else if ((ep = looking_at(p, "msgcolor")) ||
714 (ep = looking_at(p, "msgcolour"))) {
715 unsigned int fg_mask = MSG_COLORS_DEF_FG;
716 unsigned int bg_mask = MSG_COLORS_DEF_BG;
717 enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
719 p = skipspace(ep);
720 if (*p) {
721 if (!looking_at(p, "*"))
722 fg_mask = parse_argb(&p);
724 p = skipspace(p);
725 if (*p) {
726 if (!looking_at(p, "*"))
727 bg_mask = parse_argb(&p);
729 p = skipspace(p);
730 switch (*p | 0x20) {
731 case 'n':
732 shadow = SHADOW_NONE;
733 break;
734 case 's':
735 shadow = SHADOW_NORMAL;
736 break;
737 case 'a':
738 shadow = SHADOW_ALL;
739 break;
740 case 'r':
741 shadow = SHADOW_REVERSE;
742 break;
743 default:
744 /* go with default */
745 break;
749 set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
750 } else if ( looking_at(p, "separator") ) {
751 record(m, &ld, append);
752 ld.label = refstr_get(empty_string);
753 ld.menuseparator = 1;
754 record(m, &ld, append);
755 } else if ( looking_at(p, "disable") ||
756 looking_at(p, "disabled")) {
757 ld.menudisabled = 1;
758 } else if ( looking_at(p, "indent") ) {
759 ld.menuindent = atoi(skipspace(p+6));
760 } else if ( looking_at(p, "begin") ) {
761 record(m, &ld, append);
762 m = current_menu = begin_submenu(skipspace(p+5));
763 } else if ( looking_at(p, "end") ) {
764 record(m, &ld, append);
765 m = current_menu = end_submenu();
766 } else if ( looking_at(p, "quit") ) {
767 if (ld.label)
768 ld.action = MA_QUIT;
769 } else if ( looking_at(p, "goto") ) {
770 if (ld.label) {
771 ld.action = MA_GOTO_UNRES;
772 refstr_put(ld.kernel);
773 ld.kernel = refstrdup(skipspace(p+4));
775 } else if ( looking_at(p, "exit") ) {
776 p = skipspace(p+4);
777 if (ld.label && m->parent) {
778 if (*p) {
779 /* This is really just a goto, except for the marker */
780 ld.action = MA_EXIT_UNRES;
781 refstr_put(ld.kernel);
782 ld.kernel = refstrdup(p);
783 } else {
784 ld.action = MA_EXIT;
785 ld.submenu = m->parent;
788 } else if ( looking_at(p, "start") ) {
789 start_menu = m;
790 } else {
791 /* Unknown, check for layout parameters */
792 enum parameter_number mp;
793 for (mp = 0; mp < NPARAMS; mp++) {
794 if ( (ep = looking_at(p, mparm[mp].name)) ) {
795 m->mparm[mp] = atoi(skipspace(ep));
796 break;
800 } else if ( looking_at(p, "text") ) {
801 enum text_cmd {
802 TEXT_UNKNOWN,
803 TEXT_HELP
804 } cmd = TEXT_UNKNOWN;
805 int len = ld.helptext ? strlen(ld.helptext) : 0;
806 int xlen;
808 p = skipspace(p+4);
810 if (looking_at(p, "help"))
811 cmd = TEXT_HELP;
813 while ( fgets(line, sizeof line, f) ) {
814 p = skipspace(line);
815 if (looking_at(p, "endtext"))
816 break;
818 xlen = strlen(line);
820 switch (cmd) {
821 case TEXT_UNKNOWN:
822 break;
823 case TEXT_HELP:
824 ld.helptext = realloc(ld.helptext, len+xlen+1);
825 memcpy(ld.helptext+len, line, xlen+1);
826 len += xlen;
827 break;
830 } else if ( (ep = is_fkey(p, &fkeyno)) ) {
831 p = skipspace(ep);
832 if (m->fkeyhelp[fkeyno].textname) {
833 refstr_put(m->fkeyhelp[fkeyno].textname);
834 m->fkeyhelp[fkeyno].textname = NULL;
836 if (m->fkeyhelp[fkeyno].background) {
837 refstr_put(m->fkeyhelp[fkeyno].background);
838 m->fkeyhelp[fkeyno].background = NULL;
841 refstr_put(m->fkeyhelp[fkeyno].textname);
842 m->fkeyhelp[fkeyno].textname = refdup_word(&p);
843 if (*p) {
844 p = skipspace(p);
845 m->fkeyhelp[fkeyno].background = refdup_word(&p);
847 } else if ( (ep = looking_at(p, "include")) ) {
848 do_include:
850 const char *file;
851 p = skipspace(ep);
852 file = refdup_word(&p);
853 p = skipspace(p);
854 if (*p) {
855 record(m, &ld, append);
856 m = current_menu = begin_submenu(p);
857 parse_one_config(file);
858 record(m, &ld, append);
859 m = current_menu = end_submenu();
860 } else {
861 parse_one_config(file);
863 refstr_put(file);
865 } else if ( looking_at(p, "append") ) {
866 const char *a = refstrdup(skipspace(p+6));
867 if ( ld.label ) {
868 refstr_put(ld.append);
869 ld.append = a;
870 } else {
871 refstr_put(append);
872 append = a;
874 } else if ( looking_at(p, "initrd") ) {
875 const char *a = refstrdup(skipspace(p+6));
876 if ( ld.label ) {
877 refstr_put(ld.initrd);
878 ld.initrd = a;
879 } else {
880 /* Ignore */
882 } else if ( looking_at(p, "label") ) {
883 p = skipspace(p+5);
884 record(m, &ld, append);
885 ld.label = refstrdup(p);
886 ld.kernel = refstrdup(p);
887 ld.type = KT_KERNEL;
888 ld.passwd = NULL;
889 ld.append = NULL;
890 ld.initrd = NULL;
891 ld.menulabel = NULL;
892 ld.helptext = NULL;
893 ld.ipappend = ipappend;
894 ld.menudefault = ld.menuhide = ld.menuseparator =
895 ld.menudisabled = ld.menuindent = 0;
896 } else if ( (ep = is_kernel_type(p, &type)) ) {
897 if ( ld.label ) {
898 refstr_put(ld.kernel);
899 ld.kernel = refstrdup(skipspace(ep));
900 ld.type = type;
902 } else if ( looking_at(p, "timeout") ) {
903 m->timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
904 } else if ( looking_at(p, "totaltimeout") ) {
905 totaltimeout = (atoll(skipspace(p+13))*CLK_TCK+9)/10;
906 } else if ( looking_at(p, "ontimeout") ) {
907 m->ontimeout = refstrdup(skipspace(p+9));
908 } else if ( looking_at(p, "allowoptions") ) {
909 m->allowedit = atoi(skipspace(p+12));
910 } else if ( looking_at(p, "ipappend") ) {
911 if (ld.label)
912 ld.ipappend = atoi(skipspace(p+8));
913 else
914 ipappend = atoi(skipspace(p+8));
919 static int parse_one_config(const char *filename)
921 FILE *f;
923 if (!strcmp(filename, "~"))
924 filename = syslinux_config_file();
926 f = fopen(filename, "r");
927 if ( !f )
928 return -1;
930 parse_config_file(f);
931 fclose(f);
933 return 0;
936 static void resolve_gotos(void)
938 struct menu_entry *me;
939 struct menu *m;
941 for (me = all_entries; me; me = me->next) {
942 if (me->action == MA_GOTO_UNRES ||
943 me->action == MA_EXIT_UNRES) {
944 m = find_menu(me->cmdline);
945 refstr_put(me->cmdline);
946 me->cmdline = NULL;
947 if (m) {
948 me->submenu = m;
949 me->action--; /* Drop the _UNRES */
950 } else {
951 me->action = MA_DISABLED;
957 void parse_configs(char **argv)
959 const char *filename;
960 struct menu *m;
962 empty_string = refstrdup("");
964 /* Initialize defaults for the root and hidden menus */
965 hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
966 root_menu = new_menu(NULL, NULL, refstrdup(".top"));
967 start_menu = root_menu;
969 /* Other initialization */
970 memset(&ld, 0, sizeof(struct labeldata));
972 /* Actually process the files */
973 current_menu = root_menu;
974 if ( !*argv ) {
975 parse_one_config("~");
976 } else {
977 while ( (filename = *argv++) )
978 parse_one_config(filename);
981 /* On final EOF process the last label statement */
982 record(current_menu, &ld, append);
984 /* Common postprocessing */
985 resolve_gotos();
987 for (m = menu_list; m; m = m->next) {
988 m->curentry = m->defentry; /* All menus start at their defaults */
990 if ( m->ontimeout )
991 m->ontimeout = unlabel(m->ontimeout);
992 if ( m->onerror )
993 m->onerror = unlabel(m->onerror);