1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2011 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 * ----------------------------------------------------------------------- */
24 #include <syslinux/adv.h>
25 #include <syslinux/config.h>
30 const char *empty_string
;
32 /* Root menu, starting menu, hidden menu, and list of all menus */
33 struct menu
*root_menu
, *start_menu
, *hide_menu
, *menu_list
;
35 /* These are global parameters regardless of which menu we're displaying */
36 int shiftkey
= 0; /* Only display menu if shift key pressed */
39 long long totaltimeout
= 0;
40 const char *hide_key
[KEY_MAX
];
42 /* Keep track of global default */
43 static int has_ui
= 0; /* DEFAULT only counts if UI is found */
44 static const char *globaldefault
= NULL
;
45 static bool menusave
= false; /* True if there is any "menu save" */
47 /* Linked list of all entires, hidden or not; used by unlabel() */
48 static struct menu_entry
*all_entries
;
49 static struct menu_entry
**all_entries_end
= &all_entries
;
51 static const struct messages messages
[MSG_COUNT
] = {
52 [MSG_AUTOBOOT
] = {"autoboot", "Automatic boot in # second{,s}..."},
53 [MSG_TAB
] = {"tabmsg", "Press [Tab] to edit options"},
54 [MSG_NOTAB
] = {"notabmsg", ""},
55 [MSG_PASSPROMPT
] = {"passprompt", "Password required"},
58 #define astrdup(x) ({ char *__x = (x); \
59 size_t __n = strlen(__x) + 1; \
60 char *__p = alloca(__n); \
61 if ( __p ) memcpy(__p, __x, __n); \
64 /* Must match enum kernel_type */
65 static const char *const kernel_types
[] = {
81 * Search the list of all menus for a specific label
83 static struct menu
*find_menu(const char *label
)
87 for (m
= menu_list
; m
; m
= m
->next
) {
88 if (!strcmp(label
, m
->label
))
97 /* Strip ^ from a string, returning a new reference to the same refstring
99 static const char *strip_caret(const char *str
)
115 return refstr_get(str
);
117 r
= q
= refstr_alloc(strlen(str
) - carets
);
118 for (p
= str
; *p
; p
++)
122 *q
= '\0'; /* refstr_alloc() already did this... */
127 /* Check to see if we are at a certain keyword (case insensitive) */
128 /* Returns a pointer to the first character past the keyword */
129 static char *looking_at(char *line
, const char *kwd
)
134 while (*p
&& *q
&& ((*p
^ *q
) & ~0x20) == 0) {
140 return NULL
; /* Didn't see the keyword */
142 return my_isspace(*p
) ? p
: NULL
; /* Must be EOL or whitespace */
145 /* Get a single word into a new refstr; advances the input pointer */
146 static char *get_word(char *str
, char **word
)
151 while (*p
&& !my_isspace(*p
))
154 *word
= q
= refstr_alloc(p
- str
);
155 memcpy(q
, str
, p
- str
);
156 /* refstr_alloc() already inserted a terminating NUL */
161 static struct menu
*new_menu(struct menu
*parent
,
162 struct menu_entry
*parent_entry
, const char *label
)
164 struct menu
*m
= calloc(1, sizeof(struct menu
));
168 m
->title
= refstr_get(empty_string
);
173 m
->parent_entry
= parent_entry
;
174 parent_entry
->action
= MA_SUBMENU
;
175 parent_entry
->submenu
= m
;
177 for (i
= 0; i
< MSG_COUNT
; i
++)
178 m
->messages
[i
] = refstr_get(parent
->messages
[i
]);
180 memcpy(m
->mparm
, parent
->mparm
, sizeof m
->mparm
);
182 m
->allowedit
= parent
->allowedit
;
183 m
->timeout
= parent
->timeout
;
184 m
->save
= parent
->save
;
185 m
->immediate
= parent
->immediate
;
187 m
->ontimeout
= refstr_get(parent
->ontimeout
);
188 m
->onerror
= refstr_get(parent
->onerror
);
189 m
->menu_master_passwd
= refstr_get(parent
->menu_master_passwd
);
190 m
->menu_background
= refstr_get(parent
->menu_background
);
192 m
->color_table
= copy_color_table(parent
->color_table
);
194 for (i
= 0; i
< 12; i
++) {
195 m
->fkeyhelp
[i
].textname
= refstr_get(parent
->fkeyhelp
[i
].textname
);
196 m
->fkeyhelp
[i
].background
=
197 refstr_get(parent
->fkeyhelp
[i
].background
);
201 for (i
= 0; i
< MSG_COUNT
; i
++)
202 m
->messages
[i
] = refstrdup(messages
[i
].defmsg
);
203 for (i
= 0; i
< NPARAMS
; i
++)
204 m
->mparm
[i
] = mparm
[i
].value
;
206 m
->allowedit
= true; /* Allow edits of the command line */
207 m
->color_table
= default_color_table();
219 enum kernel_type type
;
222 const char *menulabel
;
225 unsigned int ipappend
;
226 unsigned int menuhide
;
227 unsigned int menudefault
;
228 unsigned int menuseparator
;
229 unsigned int menudisabled
;
230 unsigned int menuindent
;
231 enum menu_action action
;
234 struct menu
*submenu
;
237 /* Menu currently being parsed */
238 static struct menu
*current_menu
;
240 static void clear_label_data(struct labeldata
*ld
)
242 refstr_put(ld
->label
);
243 refstr_put(ld
->kernel
);
244 refstr_put(ld
->append
);
245 refstr_put(ld
->initrd
);
246 refstr_put(ld
->menulabel
);
247 refstr_put(ld
->passwd
);
249 memset(ld
, 0, sizeof *ld
);
252 static struct menu_entry
*new_entry(struct menu
*m
)
254 struct menu_entry
*me
;
256 if (m
->nentries
>= m
->nentries_space
) {
257 if (!m
->nentries_space
)
258 m
->nentries_space
= 1;
260 m
->nentries_space
<<= 1;
262 m
->menu_entries
= realloc(m
->menu_entries
, m
->nentries_space
*
263 sizeof(struct menu_entry
*));
266 me
= calloc(1, sizeof(struct menu_entry
));
268 me
->entry
= m
->nentries
;
269 m
->menu_entries
[m
->nentries
++] = me
;
270 *all_entries_end
= me
;
271 all_entries_end
= &me
->next
;
276 static void consider_for_hotkey(struct menu
*m
, struct menu_entry
*me
)
278 const char *p
= strchr(me
->displayname
, '^');
280 if (me
->action
!= MA_DISABLED
) {
282 unsigned char hotkey
= p
[1] & ~0x20;
283 if (!m
->menu_hotkeys
[hotkey
]) {
285 m
->menu_hotkeys
[hotkey
] = me
;
292 * Copy a string, converting whitespace characters to underscores
293 * and compacting them. Return a pointer to the final null.
295 static char *copy_sysappend_string(char *dst
, const char *src
)
297 bool was_space
= true; /* Kill leading whitespace */
301 while ((c
= *src
++)) {
302 if (c
<= ' ' && c
== '\x7f') {
316 static void record(struct menu
*m
, struct labeldata
*ld
, const char *append
)
319 struct menu_entry
*me
;
320 const struct syslinux_ipappend_strings
*ipappend
;
323 return; /* Nothing defined */
325 /* Hidden entries are recorded on a special "hidden menu" */
330 char ipoptions
[4096], *ipp
;
336 me
->displayname
= ld
->menulabel
337 ? refstr_get(ld
->menulabel
) : refstr_get(ld
->label
);
338 me
->label
= refstr_get(ld
->label
);
339 me
->passwd
= refstr_get(ld
->passwd
);
340 me
->helptext
= ld
->helptext
;
342 me
->action
= ld
->action
? ld
->action
: MA_CMD
;
343 me
->save
= ld
->save
? (ld
->save
> 0) : m
->save
;
344 me
->immediate
= ld
->immediate
? (ld
->immediate
> 0) : m
->immediate
;
346 if (ld
->menuindent
) {
349 rsprintf(&dn
, "%*s%s", ld
->menuindent
, "", me
->displayname
);
350 refstr_put(me
->displayname
);
351 me
->displayname
= dn
;
354 if (ld
->menuseparator
) {
355 refstr_put(me
->displayname
);
356 me
->displayname
= refstr_get(empty_string
);
359 if (ld
->menuseparator
|| ld
->menudisabled
) {
360 me
->action
= MA_DISABLED
;
361 refstr_put(me
->label
);
363 refstr_put(me
->passwd
);
368 consider_for_hotkey(m
, me
);
370 switch (me
->action
) {
376 ipp
+= sprintf(ipp
, " initrd=%s", ld
->initrd
);
379 ipappend
= syslinux_ipappend_strings();
380 for (i
= 0; i
< ipappend
->count
; i
++) {
381 if ((ld
->ipappend
& (1U << i
)) &&
382 ipappend
->ptr
[i
] && ipappend
->ptr
[i
][0]) {
384 ipp
= copy_sysappend_string(ipp
, ipappend
->ptr
[i
]);
392 if (!a
|| (a
[0] == '-' && !a
[1]))
395 if (ld
->type
== KT_KERNEL
) {
396 rsprintf(&me
->cmdline
, "%s%s%s%s", ld
->kernel
, s
, a
, ipoptions
);
398 rsprintf(&me
->cmdline
, ".%s %s%s%s%s",
399 kernel_types
[ld
->type
], ld
->kernel
, s
, a
, ipoptions
);
405 me
->cmdline
= refstr_get(ld
->kernel
);
410 me
->submenu
= ld
->submenu
;
414 me
->cmdline
= refstr_get(ld
->kernel
);
415 me
->background
= refstr_get(ld
->append
);
422 if (ld
->menudefault
&& (me
->action
== MA_CMD
||
423 me
->action
== MA_GOTO
||
424 me
->action
== MA_GOTO_UNRES
))
425 m
->defentry
= m
->nentries
- 1;
428 clear_label_data(ld
);
431 static struct menu
*begin_submenu(const char *tag
)
433 struct menu_entry
*me
;
438 me
= new_entry(current_menu
);
439 me
->displayname
= refstrdup(tag
);
440 return new_menu(current_menu
, me
, refstr_get(me
->displayname
));
443 static struct menu
*end_submenu(void)
445 return current_menu
->parent
? current_menu
->parent
: current_menu
;
448 static struct menu_entry
*find_label(const char *str
)
451 struct menu_entry
*me
;
455 while (*p
&& !my_isspace(*p
))
458 /* p now points to the first byte beyond the kernel name */
461 for (me
= all_entries
; me
; me
= me
->next
) {
462 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
])
469 static const char *unlabel(const char *str
)
471 /* Convert a CLI-style command line to an executable command line */
474 struct menu_entry
*me
;
478 while (*p
&& !my_isspace(*p
))
481 /* p now points to the first byte beyond the kernel name */
484 for (me
= all_entries
; me
; me
= me
->next
) {
485 if (!strncmp(str
, me
->label
, pos
) && !me
->label
[pos
]) {
486 /* Found matching label */
487 rsprintf(&q
, "%s%s", me
->cmdline
, p
);
496 static const char *refdup_word(char **p
)
501 while (*ep
&& !my_isspace(*ep
))
505 return refstrndup(sp
, ep
- sp
);
508 int my_isxdigit(char c
)
512 return (uc
- '0') < 10 || ((uc
| 0x20) - 'a') < 6;
515 unsigned int hexval(char c
)
517 unsigned char uc
= c
| 0x20;
524 return uc
- 'a' + 10;
527 unsigned int hexval2(const char *p
)
529 return (hexval(p
[0]) << 4) + hexval(p
[1]);
532 uint32_t parse_argb(char **p
)
544 while (my_isxdigit(*ep
))
554 (hexval(sp
[0]) * 0x11 << 16) +
555 (hexval(sp
[1]) * 0x11 << 8) + (hexval(sp
[2]) * 0x11);
559 (hexval(sp
[0]) * 0x11 << 24) +
560 (hexval(sp
[1]) * 0x11 << 16) +
561 (hexval(sp
[2]) * 0x11 << 8) + (hexval(sp
[3]) * 0x11);
563 case 6: /* #rrggbb */
564 case 9: /* #rrrgggbbb */
565 case 12: /* #rrrrggggbbbb */
569 (hexval2(sp
+ 0) << 16) +
570 (hexval2(sp
+ dl
) << 8) + hexval2(sp
+ dl
* 2);
572 case 8: /* #aarrggbb */
573 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
574 assume the latter is a more common format */
575 case 16: /* #aaaarrrrggggbbbb */
578 (hexval2(sp
+ 0) << 24) +
579 (hexval2(sp
+ dl
) << 16) +
580 (hexval2(sp
+ dl
* 2) << 8) + hexval2(sp
+ dl
* 3);
583 argb
= 0xffff0000; /* Bright red (error indication) */
591 * Parser state. This is global so that including multiple
592 * files work as expected, which is that everything works the
593 * same way as if the files had been concatenated together.
595 static const char *append
= NULL
;
596 static unsigned int ipappend
= 0;
597 static struct labeldata ld
;
599 static int parse_one_config(const char *filename
);
601 static char *is_kernel_type(char *cmdstr
, enum kernel_type
*type
)
603 const char *const *p
;
605 enum kernel_type t
= KT_NONE
;
607 for (p
= kernel_types
; *p
; p
++, t
++) {
608 if ((q
= looking_at(cmdstr
, *p
))) {
617 static char *is_message_name(char *cmdstr
, enum message_number
*msgnr
)
620 enum message_number i
;
622 for (i
= 0; i
< MSG_COUNT
; i
++) {
623 if ((q
= looking_at(cmdstr
, messages
[i
].name
))) {
632 static char *is_fkey(char *cmdstr
, int *fkeyno
)
637 if ((cmdstr
[0] | 0x20) != 'f')
640 no
= strtoul(cmdstr
+ 1, &q
, 10);
644 if (no
< 0 || no
> 12)
647 *fkeyno
= (no
== 0) ? 10 : no
- 1;
651 static void parse_config_file(FILE * f
)
653 char line
[MAX_LINE
], *p
, *ep
, ch
;
654 enum kernel_type type
= -1;
655 enum message_number msgnr
= -1;
657 struct menu
*m
= current_menu
;
659 while (fgets(line
, sizeof line
, f
)) {
660 p
= strchr(line
, '\r');
663 p
= strchr(line
, '\n');
669 if (looking_at(p
, "menu")) {
670 p
= skipspace(p
+ 4);
672 if (looking_at(p
, "label")) {
674 refstr_put(ld
.menulabel
);
675 ld
.menulabel
= refstrdup(skipspace(p
+ 5));
676 } else if (m
->parent_entry
) {
677 refstr_put(m
->parent_entry
->displayname
);
678 m
->parent_entry
->displayname
= refstrdup(skipspace(p
+ 5));
679 consider_for_hotkey(m
->parent
, m
->parent_entry
);
681 /* MENU LABEL -> MENU TITLE on submenu */
682 refstr_put(m
->title
);
683 m
->title
= strip_caret(m
->parent_entry
->displayname
);
686 } else if (looking_at(p
, "title")) {
687 refstr_put(m
->title
);
688 m
->title
= refstrdup(skipspace(p
+ 5));
689 if (m
->parent_entry
) {
690 /* MENU TITLE -> MENU LABEL on submenu */
691 if (m
->parent_entry
->displayname
== m
->label
) {
692 refstr_put(m
->parent_entry
->displayname
);
693 m
->parent_entry
->displayname
= refstr_get(m
->title
);
696 } else if (looking_at(p
, "default")) {
699 } else if (m
->parent_entry
) {
700 m
->parent
->defentry
= m
->parent_entry
->entry
;
702 } else if (looking_at(p
, "hide")) {
704 } else if (looking_at(p
, "passwd")) {
706 refstr_put(ld
.passwd
);
707 ld
.passwd
= refstrdup(skipspace(p
+ 6));
708 } else if (m
->parent_entry
) {
709 refstr_put(m
->parent_entry
->passwd
);
710 m
->parent_entry
->passwd
= refstrdup(skipspace(p
+ 6));
712 } else if (looking_at(p
, "shiftkey")) {
714 } else if (looking_at(p
, "save")) {
720 } else if (looking_at(p
, "nosave")) {
725 } else if (looking_at(p
, "immediate")) {
730 } else if (looking_at(p
, "noimmediate")) {
734 m
->immediate
= false;
735 } else if (looking_at(p
, "onerror")) {
736 refstr_put(m
->onerror
);
737 m
->onerror
= refstrdup(skipspace(p
+ 7));
738 } else if (looking_at(p
, "master")) {
739 p
= skipspace(p
+ 6);
740 if (looking_at(p
, "passwd")) {
741 refstr_put(m
->menu_master_passwd
);
742 m
->menu_master_passwd
= refstrdup(skipspace(p
+ 6));
744 } else if ((ep
= looking_at(p
, "include"))) {
746 } else if ((ep
= looking_at(p
, "background"))) {
748 refstr_put(m
->menu_background
);
749 m
->menu_background
= refdup_word(&p
);
750 } else if ((ep
= looking_at(p
, "hidden"))) {
752 } else if (looking_at(p
, "hiddenkey")) {
753 char *key_name
, *k
, *ek
;
756 p
= get_word(skipspace(p
+ 9), &key_name
);
757 command
= refstrdup(skipspace(p
));
760 ek
= strchr(k
+1, ',');
763 key
= key_name_to_code(k
);
765 refstr_put(hide_key
[key
]);
766 hide_key
[key
] = refstr_get(command
);
772 refstr_put(key_name
);
774 } else if ((ep
= looking_at(p
, "clear"))) {
776 } else if ((ep
= is_message_name(p
, &msgnr
))) {
777 refstr_put(m
->messages
[msgnr
]);
778 m
->messages
[msgnr
] = refstrdup(skipspace(ep
));
779 } else if ((ep
= looking_at(p
, "color")) ||
780 (ep
= looking_at(p
, "colour"))) {
782 struct color_table
*cptr
;
784 cptr
= m
->color_table
;
785 for (i
= 0; i
< menu_color_table_size
; i
++) {
786 if ((ep
= looking_at(p
, cptr
->name
))) {
789 if (looking_at(p
, "*")) {
792 refstr_put(cptr
->ansi
);
793 cptr
->ansi
= refdup_word(&p
);
798 if (looking_at(p
, "*"))
801 cptr
->argb_fg
= parse_argb(&p
);
805 if (looking_at(p
, "*"))
808 cptr
->argb_bg
= parse_argb(&p
);
810 /* Parse a shadow mode */
813 if (ch
== 'n') /* none */
814 cptr
->shadow
= SHADOW_NONE
;
815 else if (ch
== 's') /* std, standard */
816 cptr
->shadow
= SHADOW_NORMAL
;
817 else if (ch
== 'a') /* all */
818 cptr
->shadow
= SHADOW_ALL
;
819 else if (ch
== 'r') /* rev, reverse */
820 cptr
->shadow
= SHADOW_REVERSE
;
828 } else if ((ep
= looking_at(p
, "msgcolor")) ||
829 (ep
= looking_at(p
, "msgcolour"))) {
830 unsigned int fg_mask
= MSG_COLORS_DEF_FG
;
831 unsigned int bg_mask
= MSG_COLORS_DEF_BG
;
832 enum color_table_shadow shadow
= MSG_COLORS_DEF_SHADOW
;
836 if (!looking_at(p
, "*"))
837 fg_mask
= parse_argb(&p
);
841 if (!looking_at(p
, "*"))
842 bg_mask
= parse_argb(&p
);
847 shadow
= SHADOW_NONE
;
850 shadow
= SHADOW_NORMAL
;
856 shadow
= SHADOW_REVERSE
;
859 /* go with default */
864 set_msg_colors_global(m
->color_table
, fg_mask
, bg_mask
, shadow
);
865 } else if (looking_at(p
, "separator")) {
866 record(m
, &ld
, append
);
867 ld
.label
= refstr_get(empty_string
);
868 ld
.menuseparator
= 1;
869 record(m
, &ld
, append
);
870 } else if (looking_at(p
, "disable") || looking_at(p
, "disabled")) {
872 } else if (looking_at(p
, "indent")) {
873 ld
.menuindent
= atoi(skipspace(p
+ 6));
874 } else if (looking_at(p
, "begin")) {
875 record(m
, &ld
, append
);
876 m
= current_menu
= begin_submenu(skipspace(p
+ 5));
877 } else if (looking_at(p
, "end")) {
878 record(m
, &ld
, append
);
879 m
= current_menu
= end_submenu();
880 } else if (looking_at(p
, "quit")) {
883 } else if (looking_at(p
, "goto")) {
885 ld
.action
= MA_GOTO_UNRES
;
886 refstr_put(ld
.kernel
);
887 ld
.kernel
= refstrdup(skipspace(p
+ 4));
889 } else if (looking_at(p
, "exit")) {
890 p
= skipspace(p
+ 4);
891 if (ld
.label
&& m
->parent
) {
893 /* This is really just a goto, except for the marker */
894 ld
.action
= MA_EXIT_UNRES
;
895 refstr_put(ld
.kernel
);
896 ld
.kernel
= refstrdup(p
);
899 ld
.submenu
= m
->parent
;
902 } else if (looking_at(p
, "start")) {
904 } else if (looking_at(p
, "help")) {
907 p
= skipspace(p
+ 4);
909 refstr_put(ld
.kernel
);
910 ld
.kernel
= refdup_word(&p
);
913 refstr_put(ld
.append
);
919 ld
.append
= refdup_word(&p
); /* Background */
922 } else if ((ep
= looking_at(p
, "resolution"))) {
924 x
= strtoul(ep
, &ep
, 0);
925 y
= strtoul(skipspace(ep
), NULL
, 0);
926 set_resolution(x
, y
);
928 /* Unknown, check for layout parameters */
929 enum parameter_number mp
;
930 for (mp
= 0; mp
< NPARAMS
; mp
++) {
931 if ((ep
= looking_at(p
, mparm
[mp
].name
))) {
932 m
->mparm
[mp
] = atoi(skipspace(ep
));
937 } else if (looking_at(p
, "text")) {
941 } cmd
= TEXT_UNKNOWN
;
942 int len
= ld
.helptext
? strlen(ld
.helptext
) : 0;
945 p
= skipspace(p
+ 4);
947 if (looking_at(p
, "help"))
950 while (fgets(line
, sizeof line
, f
)) {
952 if (looking_at(p
, "endtext"))
961 ld
.helptext
= realloc(ld
.helptext
, len
+ xlen
+ 1);
962 memcpy(ld
.helptext
+ len
, line
, xlen
+ 1);
967 } else if ((ep
= is_fkey(p
, &fkeyno
))) {
969 if (m
->fkeyhelp
[fkeyno
].textname
) {
970 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
971 m
->fkeyhelp
[fkeyno
].textname
= NULL
;
973 if (m
->fkeyhelp
[fkeyno
].background
) {
974 refstr_put(m
->fkeyhelp
[fkeyno
].background
);
975 m
->fkeyhelp
[fkeyno
].background
= NULL
;
978 refstr_put(m
->fkeyhelp
[fkeyno
].textname
);
979 m
->fkeyhelp
[fkeyno
].textname
= refdup_word(&p
);
982 m
->fkeyhelp
[fkeyno
].background
= refdup_word(&p
);
984 } else if ((ep
= looking_at(p
, "include"))) {
989 file
= refdup_word(&p
);
992 record(m
, &ld
, append
);
993 m
= current_menu
= begin_submenu(p
);
994 parse_one_config(file
);
995 record(m
, &ld
, append
);
996 m
= current_menu
= end_submenu();
998 parse_one_config(file
);
1002 } else if (looking_at(p
, "append")) {
1003 const char *a
= refstrdup(skipspace(p
+ 6));
1005 refstr_put(ld
.append
);
1011 } else if (looking_at(p
, "initrd")) {
1012 const char *a
= refstrdup(skipspace(p
+ 6));
1014 refstr_put(ld
.initrd
);
1019 } else if (looking_at(p
, "label")) {
1020 p
= skipspace(p
+ 5);
1021 record(m
, &ld
, append
);
1022 ld
.label
= refstrdup(p
);
1023 ld
.kernel
= refstrdup(p
);
1024 ld
.type
= KT_KERNEL
;
1028 ld
.menulabel
= NULL
;
1030 ld
.ipappend
= ipappend
;
1031 ld
.menudefault
= ld
.menuhide
= ld
.menuseparator
=
1032 ld
.menudisabled
= ld
.menuindent
= 0;
1033 } else if ((ep
= is_kernel_type(p
, &type
))) {
1035 refstr_put(ld
.kernel
);
1036 ld
.kernel
= refstrdup(skipspace(ep
));
1039 } else if (looking_at(p
, "timeout")) {
1040 m
->timeout
= (atoi(skipspace(p
+ 7)) * CLK_TCK
+ 9) / 10;
1041 } else if (looking_at(p
, "totaltimeout")) {
1042 totaltimeout
= (atoll(skipspace(p
+ 13)) * CLK_TCK
+ 9) / 10;
1043 } else if (looking_at(p
, "ontimeout")) {
1044 m
->ontimeout
= refstrdup(skipspace(p
+ 9));
1045 } else if (looking_at(p
, "allowoptions")) {
1046 m
->allowedit
= !!atoi(skipspace(p
+ 12));
1047 } else if ((ep
= looking_at(p
, "ipappend")) ||
1048 (ep
= looking_at(p
, "sysappend"))) {
1049 uint32_t s
= strtoul(skipspace(ep
), NULL
, 0);
1054 } else if (looking_at(p
, "default")) {
1055 refstr_put(globaldefault
);
1056 globaldefault
= refstrdup(skipspace(p
+ 7));
1057 } else if (looking_at(p
, "ui")) {
1063 static int parse_one_config(const char *filename
)
1067 if (!strcmp(filename
, "~"))
1068 filename
= syslinux_config_file();
1070 dprintf("Opening config file: %s ", filename
);
1072 f
= fopen(filename
, "r");
1073 dprintf("%s\n", f
? "ok" : "failed");
1078 parse_config_file(f
);
1084 static void resolve_gotos(void)
1086 struct menu_entry
*me
;
1089 for (me
= all_entries
; me
; me
= me
->next
) {
1090 if (me
->action
== MA_GOTO_UNRES
|| me
->action
== MA_EXIT_UNRES
) {
1091 m
= find_menu(me
->cmdline
);
1092 refstr_put(me
->cmdline
);
1096 me
->action
--; /* Drop the _UNRES */
1098 me
->action
= MA_DISABLED
;
1104 void parse_configs(char **argv
)
1106 const char *filename
;
1108 struct menu_entry
*me
;
1111 empty_string
= refstrdup("");
1113 /* Initialize defaults for the root and hidden menus */
1114 hide_menu
= new_menu(NULL
, NULL
, refstrdup(".hidden"));
1115 root_menu
= new_menu(NULL
, NULL
, refstrdup(".top"));
1116 start_menu
= root_menu
;
1118 /* Other initialization */
1119 memset(&ld
, 0, sizeof(struct labeldata
));
1121 /* Actually process the files */
1122 current_menu
= root_menu
;
1124 parse_one_config("~");
1126 while ((filename
= *argv
++))
1127 parse_one_config(filename
);
1130 /* On final EOF process the last label statement */
1131 record(current_menu
, &ld
, append
);
1133 /* Common postprocessing */
1136 /* Handle global default */
1137 if (has_ui
&& globaldefault
) {
1138 me
= find_label(globaldefault
);
1139 if (me
&& me
->menu
!= hide_menu
) {
1140 me
->menu
->defentry
= me
->entry
;
1141 start_menu
= me
->menu
;
1145 /* If "menu save" is active, let the ADV override the global default */
1148 const char *lbl
= syslinux_getadv(ADV_MENUSAVE
, &len
);
1151 lstr
= refstr_alloc(len
);
1152 memcpy(lstr
, lbl
, len
); /* refstr_alloc() adds the final null */
1153 me
= find_label(lstr
);
1154 if (me
&& me
->menu
!= hide_menu
) {
1155 me
->menu
->defentry
= me
->entry
;
1156 start_menu
= me
->menu
;
1162 /* Final per-menu initialization, with all labels known */
1163 for (m
= menu_list
; m
; m
= m
->next
) {
1164 m
->curentry
= m
->defentry
; /* All menus start at their defaults */
1167 m
->ontimeout
= unlabel(m
->ontimeout
);
1169 m
->onerror
= unlabel(m
->onerror
);
1172 /* Final global initialization, with all labels known */
1173 for (k
= 0; k
< KEY_MAX
; k
++) {
1175 hide_key
[k
] = unlabel(hide_key
[k
]);