Adding upstream version 4.00~pre55+dfsg.
[syslinux-debian/hramrach.git] / com32 / menu / readconfig.c
blob5685e6f93109576ad8ab83cc0315f6dec6b46044
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
9 * Boston MA 02110-1301, USA; either version 2 of the License, or
10 * (at your option) any later version; incorporated herein by reference.
12 * ----------------------------------------------------------------------- */
14 #include <stdio.h>
15 #include <stdbool.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <minmax.h>
19 #include <alloca.h>
20 #include <inttypes.h>
21 #include <colortbl.h>
22 #include <com32.h>
23 #include <syslinux/adv.h>
24 #include <syslinux/config.h>
26 #include "menu.h"
28 /* Empty refstring */
29 const char *empty_string;
31 /* Root menu, starting menu, hidden menu, and list of all menus */
32 struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
34 /* These are global parameters regardless of which menu we're displaying */
35 int shiftkey = 0; /* Only display menu if shift key pressed */
36 int hiddenmenu = 0;
37 int clearmenu = 0;
38 long long totaltimeout = 0;
40 /* Keep track of global default */
41 static int has_ui = 0; /* DEFAULT only counts if UI is found */
42 static const char *globaldefault = NULL;
43 static bool menusave = false; /* True if there is any "menu save" */
45 /* Linked list of all entires, hidden or not; used by unlabel() */
46 static struct menu_entry *all_entries;
47 static struct menu_entry **all_entries_end = &all_entries;
49 static const struct messages messages[MSG_COUNT] = {
50 [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
51 [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
52 [MSG_NOTAB] = {"notabmsg", ""},
53 [MSG_PASSPROMPT] = {"passprompt", "Password required"},
56 #define astrdup(x) ({ char *__x = (x); \
57 size_t __n = strlen(__x) + 1; \
58 char *__p = alloca(__n); \
59 if ( __p ) memcpy(__p, __x, __n); \
60 __p; })
62 /* Must match enum kernel_type */
63 const char *const kernel_types[] = {
64 "none",
65 "localboot",
66 "kernel",
67 "linux",
68 "boot",
69 "bss",
70 "pxe",
71 "fdimage",
72 "comboot",
73 "com32",
74 "config",
75 NULL
79 * Search the list of all menus for a specific label
81 static struct menu *find_menu(const char *label)
83 struct menu *m;
85 for (m = menu_list; m; m = m->next) {
86 if (!strcmp(label, m->label))
87 return m;
90 return NULL;
93 #define MAX_LINE 4096
95 static char *skipspace(char *p)
97 while (*p && my_isspace(*p))
98 p++;
100 return p;
103 /* Strip ^ from a string, returning a new reference to the same refstring
104 if none present */
105 static const char *strip_caret(const char *str)
107 const char *p, *r;
108 char *q;
109 int carets = 0;
111 p = str;
112 for (;;) {
113 p = strchr(p, '^');
114 if (!p)
115 break;
116 carets++;
117 p++;
120 if (!carets)
121 return refstr_get(str);
123 r = q = refstr_alloc(strlen(str) - carets);
124 for (p = str; *p; p++)
125 if (*p != '^')
126 *q++ = *p;
128 *q = '\0'; /* refstr_alloc() already did this... */
130 return r;
133 /* Check to see if we are at a certain keyword (case insensitive) */
134 /* Returns a pointer to the first character past the keyword */
135 static char *looking_at(char *line, const char *kwd)
137 char *p = line;
138 const char *q = kwd;
140 while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
141 p++;
142 q++;
145 if (*q)
146 return NULL; /* Didn't see the keyword */
148 return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
151 static struct menu *new_menu(struct menu *parent,
152 struct menu_entry *parent_entry, const char *label)
154 struct menu *m = calloc(1, sizeof(struct menu));
155 int i;
157 m->label = label;
158 m->title = refstr_get(empty_string);
160 if (parent) {
161 /* Submenu */
162 m->parent = parent;
163 m->parent_entry = parent_entry;
164 parent_entry->action = MA_SUBMENU;
165 parent_entry->submenu = m;
167 for (i = 0; i < MSG_COUNT; i++)
168 m->messages[i] = refstr_get(parent->messages[i]);
170 memcpy(m->mparm, parent->mparm, sizeof m->mparm);
172 m->allowedit = parent->allowedit;
173 m->timeout = parent->timeout;
174 m->save = parent->save;
175 m->immediate = parent->immediate;
177 m->ontimeout = refstr_get(parent->ontimeout);
178 m->onerror = refstr_get(parent->onerror);
179 m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
180 m->menu_background = refstr_get(parent->menu_background);
182 m->color_table = copy_color_table(parent->color_table);
184 for (i = 0; i < 12; i++) {
185 m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
186 m->fkeyhelp[i].background =
187 refstr_get(parent->fkeyhelp[i].background);
189 } else {
190 /* Root menu */
191 for (i = 0; i < MSG_COUNT; i++)
192 m->messages[i] = refstrdup(messages[i].defmsg);
193 for (i = 0; i < NPARAMS; i++)
194 m->mparm[i] = mparm[i].value;
196 m->allowedit = true; /* Allow edits of the command line */
197 m->color_table = default_color_table();
200 m->next = menu_list;
201 menu_list = m;
203 return m;
206 struct labeldata {
207 const char *label;
208 const char *kernel;
209 enum kernel_type type;
210 const char *append;
211 const char *initrd;
212 const char *menulabel;
213 const char *passwd;
214 char *helptext;
215 unsigned int ipappend;
216 unsigned int menuhide;
217 unsigned int menudefault;
218 unsigned int menuseparator;
219 unsigned int menudisabled;
220 unsigned int menuindent;
221 enum menu_action action;
222 int save;
223 int immediate;
224 struct menu *submenu;
227 /* Menu currently being parsed */
228 static struct menu *current_menu;
230 static void clear_label_data(struct labeldata *ld)
232 refstr_put(ld->label);
233 refstr_put(ld->kernel);
234 refstr_put(ld->append);
235 refstr_put(ld->initrd);
236 refstr_put(ld->menulabel);
237 refstr_put(ld->passwd);
239 memset(ld, 0, sizeof *ld);
242 static struct menu_entry *new_entry(struct menu *m)
244 struct menu_entry *me;
246 if (m->nentries >= m->nentries_space) {
247 if (!m->nentries_space)
248 m->nentries_space = 1;
249 else
250 m->nentries_space <<= 1;
252 m->menu_entries = realloc(m->menu_entries, m->nentries_space *
253 sizeof(struct menu_entry *));
256 me = calloc(1, sizeof(struct menu_entry));
257 me->menu = m;
258 me->entry = m->nentries;
259 m->menu_entries[m->nentries++] = me;
260 *all_entries_end = me;
261 all_entries_end = &me->next;
263 return me;
266 static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
268 const char *p = strchr(me->displayname, '^');
270 if (me->action != MA_DISABLED) {
271 if (p && p[1]) {
272 unsigned char hotkey = p[1] & ~0x20;
273 if (!m->menu_hotkeys[hotkey]) {
274 me->hotkey = hotkey;
275 m->menu_hotkeys[hotkey] = me;
281 static void record(struct menu *m, struct labeldata *ld, const char *append)
283 int i;
284 struct menu_entry *me;
285 const struct syslinux_ipappend_strings *ipappend;
287 if (!ld->label)
288 return; /* Nothing defined */
290 /* Hidden entries are recorded on a special "hidden menu" */
291 if (ld->menuhide)
292 m = hide_menu;
294 if (ld->label) {
295 char ipoptions[4096], *ipp;
296 const char *a;
297 char *s;
299 me = new_entry(m);
301 me->displayname = ld->menulabel
302 ? refstr_get(ld->menulabel) : refstr_get(ld->label);
303 me->label = refstr_get(ld->label);
304 me->passwd = refstr_get(ld->passwd);
305 me->helptext = ld->helptext;
306 me->hotkey = 0;
307 me->action = ld->action ? ld->action : MA_CMD;
308 me->save = ld->save ? (ld->save > 0) : m->save;
309 me->immediate = ld->immediate ? (ld->immediate > 0) : m->immediate;
311 if (ld->menuindent) {
312 const char *dn;
314 rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
315 refstr_put(me->displayname);
316 me->displayname = dn;
319 if (ld->menuseparator) {
320 refstr_put(me->displayname);
321 me->displayname = refstr_get(empty_string);
324 if (ld->menuseparator || ld->menudisabled) {
325 me->action = MA_DISABLED;
326 refstr_put(me->label);
327 me->label = NULL;
328 refstr_put(me->passwd);
329 me->passwd = NULL;
332 if (ld->menulabel)
333 consider_for_hotkey(m, me);
335 switch (me->action) {
336 case MA_CMD:
337 ipp = ipoptions;
338 *ipp = '\0';
340 if (ld->initrd)
341 ipp += sprintf(ipp, " initrd=%s", ld->initrd);
343 if (ld->ipappend) {
344 ipappend = syslinux_ipappend_strings();
345 for (i = 0; i < ipappend->count; i++) {
346 if ((ld->ipappend & (1U << i)) && ipappend->ptr[i])
347 ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
351 a = ld->append;
352 if (!a)
353 a = append;
354 if (!a || (a[0] == '-' && !a[1]))
355 a = "";
356 s = a[0] ? " " : "";
357 if (ld->type == KT_KERNEL) {
358 rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
359 } else {
360 rsprintf(&me->cmdline, ".%s %s%s%s%s",
361 kernel_types[ld->type], ld->kernel, s, a, ipoptions);
363 break;
365 case MA_GOTO_UNRES:
366 case MA_EXIT_UNRES:
367 me->cmdline = refstr_get(ld->kernel);
368 break;
370 case MA_GOTO:
371 case MA_EXIT:
372 me->submenu = ld->submenu;
373 break;
375 default:
376 break;
379 if (ld->menudefault && me->action == MA_CMD)
380 m->defentry = m->nentries - 1;
383 clear_label_data(ld);
386 static struct menu *begin_submenu(const char *tag)
388 struct menu_entry *me;
390 if (!tag[0])
391 tag = NULL;
393 me = new_entry(current_menu);
394 me->displayname = refstrdup(tag);
395 return new_menu(current_menu, me, refstr_get(me->displayname));
398 static struct menu *end_submenu(void)
400 return current_menu->parent ? current_menu->parent : current_menu;
403 static struct menu_entry *find_label(const char *str)
405 const char *p;
406 struct menu_entry *me;
407 int pos;
409 p = str;
410 while (*p && !my_isspace(*p))
411 p++;
413 /* p now points to the first byte beyond the kernel name */
414 pos = p - str;
416 for (me = all_entries; me; me = me->next) {
417 if (!strncmp(str, me->label, pos) && !me->label[pos])
418 return me;
421 return NULL;
424 static const char *unlabel(const char *str)
426 /* Convert a CLI-style command line to an executable command line */
427 const char *p;
428 const char *q;
429 struct menu_entry *me;
430 int pos;
432 p = str;
433 while (*p && !my_isspace(*p))
434 p++;
436 /* p now points to the first byte beyond the kernel name */
437 pos = p - str;
439 for (me = all_entries; me; me = me->next) {
440 if (!strncmp(str, me->label, pos) && !me->label[pos]) {
441 /* Found matching label */
442 rsprintf(&q, "%s%s", me->cmdline, p);
443 refstr_put(str);
444 return q;
448 return str;
451 static const char *refdup_word(char **p)
453 char *sp = *p;
454 char *ep = sp;
456 while (*ep && !my_isspace(*ep))
457 ep++;
459 *p = ep;
460 return refstrndup(sp, ep - sp);
463 int my_isxdigit(char c)
465 unsigned int uc = c;
467 return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
470 unsigned int hexval(char c)
472 unsigned char uc = c | 0x20;
473 unsigned int v;
475 v = uc - '0';
476 if (v < 10)
477 return v;
479 return uc - 'a' + 10;
482 unsigned int hexval2(const char *p)
484 return (hexval(p[0]) << 4) + hexval(p[1]);
487 uint32_t parse_argb(char **p)
489 char *sp = *p;
490 char *ep;
491 uint32_t argb;
492 size_t len, dl;
494 if (*sp == '#')
495 sp++;
497 ep = sp;
499 while (my_isxdigit(*ep))
500 ep++;
502 *p = ep;
503 len = ep - sp;
505 switch (len) {
506 case 3: /* #rgb */
507 argb =
508 0xff000000 +
509 (hexval(sp[0]) * 0x11 << 16) +
510 (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
511 break;
512 case 4: /* #argb */
513 argb =
514 (hexval(sp[0]) * 0x11 << 24) +
515 (hexval(sp[1]) * 0x11 << 16) +
516 (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
517 break;
518 case 6: /* #rrggbb */
519 case 9: /* #rrrgggbbb */
520 case 12: /* #rrrrggggbbbb */
521 dl = len / 3;
522 argb =
523 0xff000000 +
524 (hexval2(sp + 0) << 16) +
525 (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
526 break;
527 case 8: /* #aarrggbb */
528 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
529 assume the latter is a more common format */
530 case 16: /* #aaaarrrrggggbbbb */
531 dl = len / 4;
532 argb =
533 (hexval2(sp + 0) << 24) +
534 (hexval2(sp + dl) << 16) +
535 (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
536 break;
537 default:
538 argb = 0xffff0000; /* Bright red (error indication) */
539 break;
542 return argb;
546 * Parser state. This is global so that including multiple
547 * files work as expected, which is that everything works the
548 * same way as if the files had been concatenated together.
550 static const char *append = NULL;
551 static unsigned int ipappend = 0;
552 static struct labeldata ld;
554 static int parse_one_config(const char *filename);
556 static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
558 const char *const *p;
559 char *q;
560 enum kernel_type t = KT_NONE;
562 for (p = kernel_types; *p; p++, t++) {
563 if ((q = looking_at(cmdstr, *p))) {
564 *type = t;
565 return q;
569 return NULL;
572 static char *is_message_name(char *cmdstr, enum message_number *msgnr)
574 char *q;
575 enum message_number i;
577 for (i = 0; i < MSG_COUNT; i++) {
578 if ((q = looking_at(cmdstr, messages[i].name))) {
579 *msgnr = i;
580 return q;
584 return NULL;
587 static char *is_fkey(char *cmdstr, int *fkeyno)
589 char *q;
590 int no;
592 if ((cmdstr[0] | 0x20) != 'f')
593 return NULL;
595 no = strtoul(cmdstr + 1, &q, 10);
596 if (!my_isspace(*q))
597 return NULL;
599 if (no < 0 || no > 12)
600 return NULL;
602 *fkeyno = (no == 0) ? 10 : no - 1;
603 return q;
606 static void parse_config_file(FILE * f)
608 char line[MAX_LINE], *p, *ep, ch;
609 enum kernel_type type = -1;
610 enum message_number msgnr = -1;
611 int fkeyno = 0;
612 struct menu *m = current_menu;
614 while (fgets(line, sizeof line, f)) {
615 p = strchr(line, '\r');
616 if (p)
617 *p = '\0';
618 p = strchr(line, '\n');
619 if (p)
620 *p = '\0';
622 p = skipspace(line);
624 if (looking_at(p, "menu")) {
625 p = skipspace(p + 4);
627 if (looking_at(p, "label")) {
628 if (ld.label) {
629 refstr_put(ld.menulabel);
630 ld.menulabel = refstrdup(skipspace(p + 5));
631 } else if (m->parent_entry) {
632 refstr_put(m->parent_entry->displayname);
633 m->parent_entry->displayname = refstrdup(skipspace(p + 5));
634 consider_for_hotkey(m->parent, m->parent_entry);
635 if (!m->title[0]) {
636 /* MENU LABEL -> MENU TITLE on submenu */
637 refstr_put(m->title);
638 m->title = strip_caret(m->parent_entry->displayname);
641 } else if (looking_at(p, "title")) {
642 refstr_put(m->title);
643 m->title = refstrdup(skipspace(p + 5));
644 if (m->parent_entry) {
645 /* MENU TITLE -> MENU LABEL on submenu */
646 if (m->parent_entry->displayname == m->label) {
647 refstr_put(m->parent_entry->displayname);
648 m->parent_entry->displayname = refstr_get(m->title);
651 } else if (looking_at(p, "default")) {
652 if (ld.label) {
653 ld.menudefault = 1;
654 } else if (m->parent_entry) {
655 m->parent->defentry = m->parent_entry->entry;
657 } else if (looking_at(p, "hide")) {
658 ld.menuhide = 1;
659 } else if (looking_at(p, "passwd")) {
660 if (ld.label) {
661 refstr_put(ld.passwd);
662 ld.passwd = refstrdup(skipspace(p + 6));
663 } else if (m->parent_entry) {
664 refstr_put(m->parent_entry->passwd);
665 m->parent_entry->passwd = refstrdup(skipspace(p + 6));
667 } else if (looking_at(p, "shiftkey")) {
668 shiftkey = 1;
669 } else if (looking_at(p, "save")) {
670 menusave = true;
671 if (ld.label)
672 ld.save = 1;
673 else
674 m->save = true;
675 } else if (looking_at(p, "nosave")) {
676 if (ld.label)
677 ld.save = -1;
678 else
679 m->save = false;
680 } else if (looking_at(p, "immediate")) {
681 if (ld.label)
682 ld.immediate = 1;
683 else
684 m->immediate = true;
685 } else if (looking_at(p, "noimmediate")) {
686 if (ld.label)
687 ld.immediate = -1;
688 else
689 m->immediate = false;
690 } else if (looking_at(p, "onerror")) {
691 refstr_put(m->onerror);
692 m->onerror = refstrdup(skipspace(p + 7));
693 } else if (looking_at(p, "master")) {
694 p = skipspace(p + 6);
695 if (looking_at(p, "passwd")) {
696 refstr_put(m->menu_master_passwd);
697 m->menu_master_passwd = refstrdup(skipspace(p + 6));
699 } else if ((ep = looking_at(p, "include"))) {
700 goto do_include;
701 } else if ((ep = looking_at(p, "background"))) {
702 p = skipspace(ep);
703 refstr_put(m->menu_background);
704 m->menu_background = refdup_word(&p);
705 } else if ((ep = looking_at(p, "hidden"))) {
706 hiddenmenu = 1;
707 } else if ((ep = looking_at(p, "clear"))) {
708 clearmenu = 1;
709 } else if ((ep = is_message_name(p, &msgnr))) {
710 refstr_put(m->messages[msgnr]);
711 m->messages[msgnr] = refstrdup(skipspace(ep));
712 } else if ((ep = looking_at(p, "color")) ||
713 (ep = looking_at(p, "colour"))) {
714 int i;
715 struct color_table *cptr;
716 p = skipspace(ep);
717 cptr = m->color_table;
718 for (i = 0; i < menu_color_table_size; i++) {
719 if ((ep = looking_at(p, cptr->name))) {
720 p = skipspace(ep);
721 if (*p) {
722 if (looking_at(p, "*")) {
723 p++;
724 } else {
725 refstr_put(cptr->ansi);
726 cptr->ansi = refdup_word(&p);
729 p = skipspace(p);
730 if (*p) {
731 if (looking_at(p, "*"))
732 p++;
733 else
734 cptr->argb_fg = parse_argb(&p);
736 p = skipspace(p);
737 if (*p) {
738 if (looking_at(p, "*"))
739 p++;
740 else
741 cptr->argb_bg = parse_argb(&p);
743 /* Parse a shadow mode */
744 p = skipspace(p);
745 ch = *p | 0x20;
746 if (ch == 'n') /* none */
747 cptr->shadow = SHADOW_NONE;
748 else if (ch == 's') /* std, standard */
749 cptr->shadow = SHADOW_NORMAL;
750 else if (ch == 'a') /* all */
751 cptr->shadow = SHADOW_ALL;
752 else if (ch == 'r') /* rev, reverse */
753 cptr->shadow = SHADOW_REVERSE;
757 break;
759 cptr++;
761 } else if ((ep = looking_at(p, "msgcolor")) ||
762 (ep = looking_at(p, "msgcolour"))) {
763 unsigned int fg_mask = MSG_COLORS_DEF_FG;
764 unsigned int bg_mask = MSG_COLORS_DEF_BG;
765 enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
767 p = skipspace(ep);
768 if (*p) {
769 if (!looking_at(p, "*"))
770 fg_mask = parse_argb(&p);
772 p = skipspace(p);
773 if (*p) {
774 if (!looking_at(p, "*"))
775 bg_mask = parse_argb(&p);
777 p = skipspace(p);
778 switch (*p | 0x20) {
779 case 'n':
780 shadow = SHADOW_NONE;
781 break;
782 case 's':
783 shadow = SHADOW_NORMAL;
784 break;
785 case 'a':
786 shadow = SHADOW_ALL;
787 break;
788 case 'r':
789 shadow = SHADOW_REVERSE;
790 break;
791 default:
792 /* go with default */
793 break;
797 set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
798 } else if (looking_at(p, "separator")) {
799 record(m, &ld, append);
800 ld.label = refstr_get(empty_string);
801 ld.menuseparator = 1;
802 record(m, &ld, append);
803 } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
804 ld.menudisabled = 1;
805 } else if (looking_at(p, "indent")) {
806 ld.menuindent = atoi(skipspace(p + 6));
807 } else if (looking_at(p, "begin")) {
808 record(m, &ld, append);
809 m = current_menu = begin_submenu(skipspace(p + 5));
810 } else if (looking_at(p, "end")) {
811 record(m, &ld, append);
812 m = current_menu = end_submenu();
813 } else if (looking_at(p, "quit")) {
814 if (ld.label)
815 ld.action = MA_QUIT;
816 } else if (looking_at(p, "goto")) {
817 if (ld.label) {
818 ld.action = MA_GOTO_UNRES;
819 refstr_put(ld.kernel);
820 ld.kernel = refstrdup(skipspace(p + 4));
822 } else if (looking_at(p, "exit")) {
823 p = skipspace(p + 4);
824 if (ld.label && m->parent) {
825 if (*p) {
826 /* This is really just a goto, except for the marker */
827 ld.action = MA_EXIT_UNRES;
828 refstr_put(ld.kernel);
829 ld.kernel = refstrdup(p);
830 } else {
831 ld.action = MA_EXIT;
832 ld.submenu = m->parent;
835 } else if (looking_at(p, "start")) {
836 start_menu = m;
837 } else if ((ep = looking_at(p, "resolution"))) {
838 int x, y;
839 x = strtoul(ep, &ep, 0);
840 y = strtoul(skipspace(ep), NULL, 0);
841 set_resolution(x, y);
842 } else {
843 /* Unknown, check for layout parameters */
844 enum parameter_number mp;
845 for (mp = 0; mp < NPARAMS; mp++) {
846 if ((ep = looking_at(p, mparm[mp].name))) {
847 m->mparm[mp] = atoi(skipspace(ep));
848 break;
852 } else if (looking_at(p, "text")) {
853 enum text_cmd {
854 TEXT_UNKNOWN,
855 TEXT_HELP
856 } cmd = TEXT_UNKNOWN;
857 int len = ld.helptext ? strlen(ld.helptext) : 0;
858 int xlen;
860 p = skipspace(p + 4);
862 if (looking_at(p, "help"))
863 cmd = TEXT_HELP;
865 while (fgets(line, sizeof line, f)) {
866 p = skipspace(line);
867 if (looking_at(p, "endtext"))
868 break;
870 xlen = strlen(line);
872 switch (cmd) {
873 case TEXT_UNKNOWN:
874 break;
875 case TEXT_HELP:
876 ld.helptext = realloc(ld.helptext, len + xlen + 1);
877 memcpy(ld.helptext + len, line, xlen + 1);
878 len += xlen;
879 break;
882 } else if ((ep = is_fkey(p, &fkeyno))) {
883 p = skipspace(ep);
884 if (m->fkeyhelp[fkeyno].textname) {
885 refstr_put(m->fkeyhelp[fkeyno].textname);
886 m->fkeyhelp[fkeyno].textname = NULL;
888 if (m->fkeyhelp[fkeyno].background) {
889 refstr_put(m->fkeyhelp[fkeyno].background);
890 m->fkeyhelp[fkeyno].background = NULL;
893 refstr_put(m->fkeyhelp[fkeyno].textname);
894 m->fkeyhelp[fkeyno].textname = refdup_word(&p);
895 if (*p) {
896 p = skipspace(p);
897 m->fkeyhelp[fkeyno].background = refdup_word(&p);
899 } else if ((ep = looking_at(p, "include"))) {
900 do_include:
902 const char *file;
903 p = skipspace(ep);
904 file = refdup_word(&p);
905 p = skipspace(p);
906 if (*p) {
907 record(m, &ld, append);
908 m = current_menu = begin_submenu(p);
909 parse_one_config(file);
910 record(m, &ld, append);
911 m = current_menu = end_submenu();
912 } else {
913 parse_one_config(file);
915 refstr_put(file);
917 } else if (looking_at(p, "append")) {
918 const char *a = refstrdup(skipspace(p + 6));
919 if (ld.label) {
920 refstr_put(ld.append);
921 ld.append = a;
922 } else {
923 refstr_put(append);
924 append = a;
926 } else if (looking_at(p, "initrd")) {
927 const char *a = refstrdup(skipspace(p + 6));
928 if (ld.label) {
929 refstr_put(ld.initrd);
930 ld.initrd = a;
931 } else {
932 /* Ignore */
934 } else if (looking_at(p, "label")) {
935 p = skipspace(p + 5);
936 record(m, &ld, append);
937 ld.label = refstrdup(p);
938 ld.kernel = refstrdup(p);
939 ld.type = KT_KERNEL;
940 ld.passwd = NULL;
941 ld.append = NULL;
942 ld.initrd = NULL;
943 ld.menulabel = NULL;
944 ld.helptext = NULL;
945 ld.ipappend = ipappend;
946 ld.menudefault = ld.menuhide = ld.menuseparator =
947 ld.menudisabled = ld.menuindent = 0;
948 } else if ((ep = is_kernel_type(p, &type))) {
949 if (ld.label) {
950 refstr_put(ld.kernel);
951 ld.kernel = refstrdup(skipspace(ep));
952 ld.type = type;
954 } else if (looking_at(p, "timeout")) {
955 m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
956 } else if (looking_at(p, "totaltimeout")) {
957 totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
958 } else if (looking_at(p, "ontimeout")) {
959 m->ontimeout = refstrdup(skipspace(p + 9));
960 } else if (looking_at(p, "allowoptions")) {
961 m->allowedit = !!atoi(skipspace(p + 12));
962 } else if (looking_at(p, "ipappend")) {
963 if (ld.label)
964 ld.ipappend = atoi(skipspace(p + 8));
965 else
966 ipappend = atoi(skipspace(p + 8));
967 } else if (looking_at(p, "default")) {
968 refstr_put(globaldefault);
969 globaldefault = refstrdup(skipspace(p + 7));
970 } else if (looking_at(p, "ui")) {
971 has_ui = 1;
976 static int parse_one_config(const char *filename)
978 FILE *f;
980 if (!strcmp(filename, "~"))
981 filename = syslinux_config_file();
983 dprintf("Opening config file: %s ", filename);
985 f = fopen(filename, "r");
986 dprintf("%s\n", f ? "ok" : "failed");
988 if (!f)
989 return -1;
991 parse_config_file(f);
992 fclose(f);
994 return 0;
997 static void resolve_gotos(void)
999 struct menu_entry *me;
1000 struct menu *m;
1002 for (me = all_entries; me; me = me->next) {
1003 if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
1004 m = find_menu(me->cmdline);
1005 refstr_put(me->cmdline);
1006 me->cmdline = NULL;
1007 if (m) {
1008 me->submenu = m;
1009 me->action--; /* Drop the _UNRES */
1010 } else {
1011 me->action = MA_DISABLED;
1017 void parse_configs(char **argv)
1019 const char *filename;
1020 struct menu *m;
1021 struct menu_entry *me;
1023 empty_string = refstrdup("");
1025 /* Initialize defaults for the root and hidden menus */
1026 hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
1027 root_menu = new_menu(NULL, NULL, refstrdup(".top"));
1028 start_menu = root_menu;
1030 /* Other initialization */
1031 memset(&ld, 0, sizeof(struct labeldata));
1033 /* Actually process the files */
1034 current_menu = root_menu;
1035 if (!*argv) {
1036 parse_one_config("~");
1037 } else {
1038 while ((filename = *argv++))
1039 parse_one_config(filename);
1042 /* On final EOF process the last label statement */
1043 record(current_menu, &ld, append);
1045 /* Common postprocessing */
1046 resolve_gotos();
1048 /* Handle global default */
1049 if (has_ui && globaldefault) {
1050 me = find_label(globaldefault);
1051 if (me && me->menu != hide_menu) {
1052 me->menu->defentry = me->entry;
1053 start_menu = me->menu;
1057 /* If "menu save" is active, let the ADV override the global default */
1058 if (menusave) {
1059 size_t len;
1060 const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
1061 char *lstr;
1062 if (lbl && len) {
1063 lstr = refstr_alloc(len);
1064 memcpy(lstr, lbl, len); /* refstr_alloc() adds the final null */
1065 me = find_label(lstr);
1066 if (me && me->menu != hide_menu) {
1067 me->menu->defentry = me->entry;
1068 start_menu = me->menu;
1070 refstr_put(lstr);
1074 /* Final per-menu initialization, with all labels known */
1075 for (m = menu_list; m; m = m->next) {
1076 m->curentry = m->defentry; /* All menus start at their defaults */
1078 if (m->ontimeout)
1079 m->ontimeout = unlabel(m->ontimeout);
1080 if (m->onerror)
1081 m->onerror = unlabel(m->onerror);