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 #define _GNU_SOURCE /* Needed for asprintf() on Linux */
30 int allowedit = 1; /* Allow edits of the command line */
32 int shiftkey = 0; /* Only display menu if shift key pressed */
34 long long totaltimeout = 0;
36 char *ontimeout = NULL;
39 char *menu_master_passwd = NULL;
40 char *menu_background = NULL;
42 struct fkey_help fkeyhelp[12];
44 struct menu_entry menu_entries[MAX_ENTRIES];
45 struct menu_entry hide_entries[MAX_ENTRIES];
46 struct menu_entry *menu_hotkeys[256];
48 struct messages messages[MSG_COUNT] = {
50 { "title", "", NULL },
52 { "autoboot", "Automatic boot in # second{,s}...", NULL },
54 { "tabmsg", "Press [Tab] to edit options", NULL },
56 { "notabmsg", "", NULL },
58 { "passprompt", "Password required", NULL },
61 #define astrdup(x) ({ char *__x = (x); \
62 size_t __n = strlen(__x) + 1; \
63 char *__p = alloca(__n); \
64 if ( __p ) memcpy(__p, __x, __n); \
67 /* Must match enum kernel_type */
68 const char *kernel_types[] = {
83 const char *ipappends[32];
95 __intcall(0x22, &r, &r);
97 nipappends = min(r.ecx.w[0], 32);
98 ipp = MK_PTR(r.es, r.ebx.w[0]);
99 for ( i = 0 ; i < nipappends ; i++ ) {
100 ipappends[i] = MK_PTR(r.es, *ipp++);
103 ipappends[0] = "ip=foo:bar:baz:quux";
104 ipappends[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff";
115 __intcall(0x22, &r, &r);
117 return MK_PTR(r.es, r.ebx.w[0]);
119 return "syslinux.cfg"; /* Dummy default name */
128 while (*p && my_isspace(*p))
134 /* Check to see if we are at a certain keyword (case insensitive) */
135 /* Returns a pointer to the first character past the keyword */
137 looking_at(char *line, const char *kwd)
142 while ( *p && *q && ((*p^*q) & ~0x20) == 0 ) {
148 return NULL; /* Didn't see the keyword */
150 return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
156 enum kernel_type type;
161 unsigned int ipappend;
162 unsigned int menuhide;
163 unsigned int menudefault;
164 unsigned int menuseparator;
165 unsigned int menudisabled;
166 unsigned int menuindent;
170 record(struct labeldata *ld, char *append)
172 char ipoptions[256], *ipp;
174 struct menu_entry *me = &menu_entries[nentries];
178 me->displayname = ld->menulabel ? ld->menulabel : ld->label;
179 me->label = ld->label;
180 me->passwd = ld->passwd;
181 me->helptext = ld->helptext;
185 if ( ld->menuindent ) {
186 char *n = (char *)malloc(ld->menuindent + strlen(me->displayname) + 1);
187 memset(n, 32, ld->menuindent);
188 strcpy(n + ld->menuindent, me->displayname);
192 if ( ld->menulabel ) {
193 unsigned char *p = (unsigned char *)strchr(ld->menulabel, '^');
195 int hotkey = p[1] & ~0x20;
196 if ( !menu_hotkeys[hotkey] ) {
204 for ( i = 0 ; i < 32 ; i++ ) {
205 if ( (ld->ipappend & (1U << i)) && ipappends[i] )
206 ipp += sprintf(ipp, " %s", ipappends[i]);
210 if ( !a ) a = append;
211 if ( !a || (a[0] == '-' && !a[1]) ) a = "";
213 if (ld->type == KT_KERNEL) {
214 asprintf(&me->cmdline, "%s%s%s%s",
215 ld->kernel, s, a, ipoptions);
217 asprintf(&me->cmdline, ".%s %s%s%s%s",
218 kernel_types[ld->type], ld->kernel, s, a, ipoptions);
221 if ( ld->menuseparator )
222 me->displayname = "";
224 if ( ld->menuseparator || ld->menudisabled ) {
246 if ( !ld->menuhide ) {
248 menu_hotkeys[me->hotkey] = me;
250 if ( ld->menudefault && !ld->menudisabled && !ld->menuseparator )
256 hide_entries[nhidden].displayname = me->displayname;
257 hide_entries[nhidden].label = me->label;
258 hide_entries[nhidden].cmdline = me->cmdline;
259 hide_entries[nhidden].passwd = me->passwd;
261 me->displayname = NULL;
274 /* Convert a CLI-style command line to an executable command line */
277 struct menu_entry *me;
281 while ( *p && !my_isspace(*p) )
284 /* p now points to the first byte beyond the kernel name */
287 for ( i = 0 ; i < nentries ; i++ ) {
288 me = &menu_entries[i];
290 if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
291 /* Found matching label */
292 q = malloc(strlen(me->cmdline) + strlen(p) + 1);
293 strcpy(q, me->cmdline);
302 for ( i = 0 ; i < nhidden ; i++ ) {
303 me = &hide_entries[i];
305 if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
306 /* Found matching label */
307 q = malloc(strlen(me->cmdline) + strlen(p) + 1);
308 strcpy(q, me->cmdline);
328 while (*ep && !my_isspace(*ep))
341 int my_isxdigit(char c)
345 return (uc-'0') < 10 ||
349 unsigned int hexval(char c)
351 unsigned char uc = c | 0x20;
361 unsigned int hexval2(const char *p)
363 return (hexval(p[0]) << 4)+hexval(p[1]);
366 uint32_t parse_argb(char **p)
378 while (my_isxdigit(*ep))
388 (hexval(sp[0])*0x11 << 16) +
389 (hexval(sp[1])*0x11 << 8) +
390 (hexval(sp[2])*0x11);
394 (hexval(sp[0])*0x11 << 24) +
395 (hexval(sp[1])*0x11 << 16) +
396 (hexval(sp[2])*0x11 << 8) +
397 (hexval(sp[3])*0x11);
399 case 6: /* #rrggbb */
400 case 9: /* #rrrgggbbb */
401 case 12: /* #rrrrggggbbbb */
405 (hexval2(sp+0) << 16) +
406 (hexval2(sp+dl) << 8) +
409 case 8: /* #aarrggbb */
410 /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
411 assume the latter is a more common format */
412 case 16: /* #aaaarrrrggggbbbb */
415 (hexval2(sp+0) << 24) +
416 (hexval2(sp+dl) << 16) +
417 (hexval2(sp+dl*2) << 8) +
421 argb = 0xffff0000; /* Bright red (error indication) */
429 * Parser state. This is global so that including multiple
430 * files work as expected, which is that everything works the
431 * same way as if the files had been concatenated together.
433 static char *append = NULL;
434 static unsigned int ipappend = 0;
435 static struct labeldata ld;
437 static int parse_one_config(const char *filename);
439 static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
443 enum kernel_type t = KT_NONE;
445 for (p = kernel_types; *p; p++, t++) {
446 if ((q = looking_at(cmdstr, *p))) {
455 static char *is_message_name(char *cmdstr, struct messages **msgptr)
460 for (i = 0; i < MSG_COUNT; i++) {
461 if ((q = looking_at(cmdstr, messages[i].name))) {
462 *msgptr = &messages[i];
470 static char *is_fkey(char *cmdstr, int *fkeyno)
475 if ((cmdstr[0]|0x20) != 'f')
478 no = strtoul(cmdstr+1, &q, 10);
482 if (no < 0 || no > 12)
485 *fkeyno = (no == 0) ? 10 : no-1;
489 static void parse_config_file(FILE *f)
491 char line[MAX_LINE], *p, *ep, ch;
492 enum kernel_type type;
493 struct messages *msgptr;
496 while ( fgets(line, sizeof line, f) ) {
497 p = strchr(line, '\r');
500 p = strchr(line, '\n');
506 if ( looking_at(p, "menu") ) {
509 if ( looking_at(p, "label") ) {
511 ld.menulabel = strdup(skipspace(p+5));
512 } else if ( looking_at(p, "default") ) {
514 } else if ( looking_at(p, "hide") ) {
516 } else if ( looking_at(p, "passwd") ) {
517 ld.passwd = strdup(skipspace(p+6));
518 } else if ( looking_at(p, "shiftkey") ) {
520 } else if ( looking_at(p, "onerror") ) {
521 onerror = strdup(skipspace(p+7));
522 } else if ( looking_at(p, "master") ) {
524 if ( looking_at(p, "passwd") ) {
525 menu_master_passwd = strdup(skipspace(p+6));
527 } else if ( (ep = looking_at(p, "include")) ) {
530 } else if ( (ep = looking_at(p, "background")) ) {
533 free(menu_background);
534 menu_background = dup_word(&p);
535 } else if ( (ep = looking_at(p, "hidden")) ) {
537 } else if ( (ep = is_message_name(p, &msgptr)) ) {
539 msgptr->msg = strdup(skipspace(ep));
540 } else if ((ep = looking_at(p, "color")) ||
541 (ep = looking_at(p, "colour"))) {
543 struct color_table *cptr;
545 cptr = console_color_table;
546 for ( i = 0; i < console_color_table_size; i++ ) {
547 if ( (ep = looking_at(p, cptr->name)) ) {
550 if (looking_at(p, "*")) {
553 free((void *)cptr->ansi);
554 cptr->ansi = dup_word(&p);
559 if (looking_at(p, "*"))
562 cptr->argb_fg = parse_argb(&p);
566 if (looking_at(p, "*"))
569 cptr->argb_bg = parse_argb(&p);
571 /* Parse a shadow mode */
574 if (ch == 'n') /* none */
575 cptr->shadow = SHADOW_NONE;
576 else if (ch == 's') /* std, standard */
577 cptr->shadow = SHADOW_NORMAL;
578 else if (ch == 'a') /* all */
579 cptr->shadow = SHADOW_ALL;
580 else if (ch == 'r') /* rev, reverse */
581 cptr->shadow = SHADOW_REVERSE;
589 } else if ((ep = looking_at(p, "msgcolor")) ||
590 (ep = looking_at(p, "msgcolour"))) {
591 unsigned int fg_mask = MSG_COLORS_DEF_FG;
592 unsigned int bg_mask = MSG_COLORS_DEF_BG;
593 enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
597 if (!looking_at(p, "*"))
598 fg_mask = parse_argb(&p);
602 if (!looking_at(p, "*"))
603 bg_mask = parse_argb(&p);
608 shadow = SHADOW_NONE;
611 shadow = SHADOW_NORMAL;
617 shadow = SHADOW_REVERSE;
620 /* go with default */
625 set_msg_colors_global(fg_mask, bg_mask, shadow);
626 } else if ( looking_at(p, "separator") ) {
628 memset(&ld, 0, sizeof(struct labeldata));
630 ld.menuseparator = 1;
632 memset(&ld, 0, sizeof(struct labeldata));
633 } else if ( looking_at(p, "disable") ||
634 looking_at(p, "disabled")) {
636 } else if ( looking_at(p, "indent") ) {
637 ld.menuindent = atoi(skipspace(p+6));
639 /* Unknown, check for layout parameters */
640 struct menu_parameter *pp;
641 for ( pp = mparm ; pp->name ; pp++ ) {
642 if ( (ep = looking_at(p, pp->name)) ) {
643 pp->value = atoi(skipspace(ep));
648 } else if ( looking_at(p, "text") ) {
652 } cmd = TEXT_UNKNOWN;
653 int len = ld.helptext ? strlen(ld.helptext) : 0;
658 if (looking_at(p, "help"))
661 while ( fgets(line, sizeof line, f) ) {
663 if (looking_at(p, "endtext"))
672 ld.helptext = realloc(ld.helptext, len+xlen+1);
673 memcpy(ld.helptext+len, line, xlen+1);
678 } else if ( (ep = is_fkey(p, &fkeyno)) ) {
680 if (fkeyhelp[fkeyno].textname) {
681 free((void *)fkeyhelp[fkeyno].textname);
682 fkeyhelp[fkeyno].textname = NULL;
684 if (fkeyhelp[fkeyno].background) {
685 free((void *)fkeyhelp[fkeyno].background);
686 fkeyhelp[fkeyno].background = NULL;
689 fkeyhelp[fkeyno].textname = dup_word(&p);
692 fkeyhelp[fkeyno].background = dup_word(&p);
694 } else if ( (ep = looking_at(p, "include")) ) {
697 } else if ( looking_at(p, "append") ) {
698 char *a = strdup(skipspace(p+6));
703 } else if ( looking_at(p, "label") ) {
706 ld.label = strdup(p);
707 ld.kernel = strdup(p);
713 ld.ipappend = ipappend;
714 ld.menudefault = ld.menuhide = ld.menuseparator =
715 ld.menudisabled = ld.menuindent = 0;
716 } else if ( (ep = is_kernel_type(p, &type)) ) {
719 ld.kernel = strdup(skipspace(ep));
722 } else if ( looking_at(p, "timeout") ) {
723 timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
724 } else if ( looking_at(p, "totaltimeout") ) {
725 totaltimeout = (atoll(skipspace(p+13))*CLK_TCK+9)/10;
726 } else if ( looking_at(p, "ontimeout") ) {
727 ontimeout = strdup(skipspace(p+9));
728 } else if ( looking_at(p, "allowoptions") ) {
729 allowedit = atoi(skipspace(p+12));
730 } else if ( looking_at(p, "ipappend") ) {
732 ld.ipappend = atoi(skipspace(p+8));
734 ipappend = atoi(skipspace(p+8));
739 static int parse_one_config(const char *filename)
743 if (!strcmp(filename, "~"))
744 filename = get_config();
746 f = fopen(filename, "r");
750 parse_config_file(f);
756 void parse_configs(char **argv)
758 const char *filename;
761 /* Initialize defaults */
763 for (i = 0; i < MSG_COUNT; i++) {
765 free(messages[i].msg);
766 messages[i].msg = strdup(messages[i].defmsg);
769 /* Other initialization */
772 memset(&ld, 0, sizeof(struct labeldata));
774 /* Actually process the files */
777 parse_one_config("~");
779 while ( (filename = *argv++) )
780 parse_one_config(filename);
783 /* On final EOF process the last label statement */
787 /* Common postprocessing */
790 ontimeout = unlabel(ontimeout);
792 onerror = unlabel(onerror);