Allow specifying * instead of any of the MENU COLOR fields.
[syslinux.git] / com32 / modules / readconfig.c
blob24057b1be45dc7997c56d5bf0ef0a0718ae89dda
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2006 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., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, 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 */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <minmax.h>
18 #include <alloca.h>
19 #include <colortbl.h>
20 #ifdef __COM32__
21 # include <com32.h>
22 #endif
24 #include "menu.h"
26 int nentries = 0;
27 int nhidden = 0;
28 int defentry = 0;
29 int allowedit = 1; /* Allow edits of the command line */
30 int timeout = 0;
31 int shiftkey = 0; /* Only display menu if shift key pressed */
32 long long totaltimeout = 0;
34 char *menu_title = "";
35 char *ontimeout = NULL;
36 char *onerror = NULL;
38 char *menu_master_passwd = NULL;
40 char *menu_background = NULL;
42 struct menu_entry menu_entries[MAX_ENTRIES];
43 struct menu_entry hide_entries[MAX_ENTRIES];
44 struct menu_entry *menu_hotkeys[256];
46 #define astrdup(x) ({ char *__x = (x); \
47 size_t __n = strlen(__x) + 1; \
48 char *__p = alloca(__n); \
49 if ( __p ) memcpy(__p, __x, __n); \
50 __p; })
52 const char *ipappends[32];
54 static void
55 get_ipappend(void)
57 #ifdef __COM32__
58 static com32sys_t r;
59 uint16_t *ipp;
60 int i;
61 int nipappends;
63 r.eax.w[0] = 0x000F;
64 __intcall(0x22, &r, &r);
66 nipappends = min(r.ecx.w[0], 32);
67 ipp = MK_PTR(r.es, r.ebx.w[0]);
68 for ( i = 0 ; i < nipappends ; i++ ) {
69 ipappends[i] = MK_PTR(r.es, *ipp++);
71 #else
72 ipappends[0] = "ip=foo:bar:baz:quux";
73 ipappends[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff";
74 #endif
77 static const char *
78 get_config(void)
80 #ifdef __COM32__
81 static com32sys_t r;
83 r.eax.w[0] = 0x000E;
84 __intcall(0x22, &r, &r);
86 return MK_PTR(r.es, r.ebx.w[0]);
87 #else
88 return "syslinux.cfg"; /* Dummy default name */
89 #endif
92 #define MAX_LINE 512
94 static char *
95 skipspace(char *p)
97 while (*p && my_isspace(*p))
98 p++;
100 return p;
103 /* Check to see if we are at a certain keyword (case insensitive) */
104 /* Returns a pointer to the first character past the keyword */
105 static char *
106 looking_at(char *line, const char *kwd)
108 char *p = line;
109 const char *q = kwd;
111 while ( *p && *q && ((*p^*q) & ~0x20) == 0 ) {
112 p++;
113 q++;
116 if ( *q )
117 return NULL; /* Didn't see the keyword */
119 return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
122 struct labeldata {
123 char *label;
124 char *kernel;
125 char *append;
126 char *menulabel;
127 char *passwd;
128 unsigned int ipappend;
129 unsigned int menuhide;
130 unsigned int menudefault;
133 static void
134 record(struct labeldata *ld, char *append)
136 char ipoptions[256], *ipp;
137 int i;
138 struct menu_entry *me = &menu_entries[nentries];
140 if ( ld->label ) {
141 char *a, *s;
142 me->displayname = ld->menulabel ? ld->menulabel : ld->label;
143 me->label = ld->label;
144 me->passwd = ld->passwd;
145 me->hotkey = 0;
147 if ( ld->menulabel ) {
148 unsigned char *p = (unsigned char *)strchr(ld->menulabel, '^');
149 if ( p && p[1] ) {
150 int hotkey = p[1] & ~0x20;
151 if ( !menu_hotkeys[hotkey] ) {
152 me->hotkey = hotkey;
157 ipp = ipoptions;
158 *ipp = '\0';
159 for ( i = 0 ; i < 32 ; i++ ) {
160 if ( (ld->ipappend & (1U << i)) && ipappends[i] )
161 ipp += sprintf(ipp, " %s", ipappends[i]);
164 a = ld->append;
165 if ( !a ) a = append;
166 if ( !a || (a[0] == '-' && !a[1]) ) a = "";
167 s = a[0] ? " " : "";
168 asprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
170 ld->label = NULL;
171 ld->passwd = NULL;
173 free(ld->kernel);
174 ld->kernel = NULL;
176 if ( ld->append ) {
177 free(ld->append);
178 ld->append = NULL;
181 if ( !ld->menuhide ) {
182 if ( me->hotkey )
183 menu_hotkeys[me->hotkey] = me;
185 if ( ld->menudefault )
186 defentry = nentries;
188 nentries++;
190 else {
191 hide_entries[nhidden].displayname = me->displayname;
192 hide_entries[nhidden].label = me->label;
193 hide_entries[nhidden].cmdline = me->cmdline;
194 hide_entries[nhidden].passwd = me->passwd;
196 me->displayname = NULL;
197 me->label = NULL;
198 me->cmdline = NULL;
199 me->passwd = NULL;
201 nhidden++;
206 static char *
207 unlabel(char *str)
209 /* Convert a CLI-style command line to an executable command line */
210 const char *p;
211 char *q;
212 struct menu_entry *me;
213 int i, pos;
215 p = str;
216 while ( *p && !my_isspace(*p) )
217 p++;
219 /* p now points to the first byte beyond the kernel name */
220 pos = p-str;
222 for ( i = 0 ; i < nentries ; i++ ) {
223 me = &menu_entries[i];
225 if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
226 /* Found matching label */
227 q = malloc(strlen(me->cmdline) + strlen(p) + 1);
228 strcpy(q, me->cmdline);
229 strcat(q, p);
231 free(str);
233 return q;
237 for ( i = 0 ; i < nhidden ; i++ ) {
238 me = &hide_entries[i];
240 if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
241 /* Found matching label */
242 q = malloc(strlen(me->cmdline) + strlen(p) + 1);
243 strcpy(q, me->cmdline);
244 strcat(q, p);
246 free(str);
248 return q;
252 return str;
255 static char *
256 dup_word(char **p)
258 char *sp = *p;
259 char *ep = sp;
260 char *dp;
261 size_t len;
263 while (*ep && !my_isspace(*ep))
264 ep++;
266 *p = ep;
267 len = ep-sp;
269 dp = malloc(len+1);
270 memcpy(dp, sp, len);
271 dp[len] = '\0';
273 return dp;
276 static int my_isxdigit(char c)
278 unsigned char uc = c | 0x20;
280 return (uc-'0') < 10 || (uc-'a') < 6;
283 static unsigned int hexval(char c)
285 unsigned char uc = c | 0x20;
287 if (uc & 0x40)
288 return uc-'a'+10;
289 else
290 return uc-'0';
293 static unsigned int hexval2(char *p)
295 return (hexval(p[0]) << 4)+hexval(p[1]);
298 static unsigned int parse_argb(char **p)
300 char *sp = *p;
301 char *ep;
302 unsigned int argb;
303 size_t len, dl;
305 if (*sp == '#')
306 sp++;
308 ep = sp;
310 while (my_isxdigit(*ep))
311 ep++;
313 *p = ep;
314 len = ep-sp;
316 switch(len) {
317 case 3: /* #rgb */
318 argb =
319 0xff000000 |
320 (hexval(sp[0])*0x11 << 16)|
321 (hexval(sp[1])*0x11 << 8) |
322 (hexval(sp[2])*0x11 << 0);
323 break;
324 case 4: /* #argb */
325 argb =
326 (hexval(sp[0])*0x11 << 24)|
327 (hexval(sp[1])*0x11 << 16)|
328 (hexval(sp[2])*0x11 << 8) |
329 (hexval(sp[3])*0x11 << 0);
330 break;
331 case 6: /* #rrggbb */
332 case 9: /* #rrrgggbbb */
333 case 12: /* #rrrrggggbbbb */
334 dl = len/3;
335 argb =
336 0xff000000 |
337 (hexval2(sp+0) << 16) |
338 (hexval2(sp+dl) << 8)|
339 (hexval2(sp+dl*2) << 0);
340 break;
341 case 8: /* #aarrggbb */
342 /* 12 is indistinguishable from #rrrrggggbbbb,
343 assume that is a more common format */
344 case 16: /* #aaaarrrrggggbbbb */
345 dl = len/4;
346 argb =
347 (hexval2(sp+0) << 24) |
348 (hexval2(sp+dl) << 16) |
349 (hexval2(sp+dl*2) << 8)|
350 (hexval2(sp+dl*3) << 0);
351 break;
352 default:
353 argb = 0;
354 break;
357 return argb;
360 void parse_config(const char *filename)
362 char line[MAX_LINE], *p, *ep;
363 FILE *f;
364 char *append = NULL;
365 unsigned int ipappend = 0;
366 static struct labeldata ld;
368 get_ipappend();
370 if ( !filename )
371 filename = get_config();
373 f = fopen(filename, "r");
374 if ( !f )
375 return;
377 while ( fgets(line, sizeof line, f) ) {
378 p = strchr(line, '\r');
379 if ( p )
380 *p = '\0';
381 p = strchr(line, '\n');
382 if ( p )
383 *p = '\0';
385 p = skipspace(line);
387 if ( looking_at(p, "menu") ) {
388 p = skipspace(p+4);
390 if ( looking_at(p, "title") ) {
391 menu_title = strdup(skipspace(p+5));
392 } else if ( looking_at(p, "label") ) {
393 if ( ld.label )
394 ld.menulabel = strdup(skipspace(p+5));
395 } else if ( looking_at(p, "default") ) {
396 ld.menudefault = 1;
397 } else if ( looking_at(p, "hide") ) {
398 ld.menuhide = 1;
399 } else if ( looking_at(p, "passwd") ) {
400 ld.passwd = strdup(skipspace(p+6));
401 } else if ( looking_at(p, "shiftkey") ) {
402 shiftkey = 1;
403 } else if ( looking_at(p, "onerror") ) {
404 onerror = strdup(skipspace(p+7));
405 } else if ( looking_at(p, "master") ) {
406 p = skipspace(p+6);
407 if ( looking_at(p, "passwd") ) {
408 menu_master_passwd = strdup(skipspace(p+6));
410 } else if ( (ep = looking_at(p, "background")) ) {
411 p = skipspace(ep);
412 menu_background = dup_word(&p);
413 } else if ((ep = looking_at(p, "color")) ||
414 (ep = looking_at(p, "colour"))) {
415 int i;
416 struct color_table *cptr;
417 p = skipspace(ep);
418 cptr = console_color_table;
419 for ( i = 0; i < console_color_table_size; i++ ) {
420 if ( (ep = looking_at(p, cptr->name)) ) {
421 p = skipspace(ep);
422 if (*p) {
423 if (!strcmp(p, "*")) {
424 p++;
425 } else {
426 free((void *)cptr->ansi);
427 cptr->ansi = dup_word(&p);
430 p = skipspace(p);
431 if (*p) {
432 if (!strcmp(p, "*")) {
433 p++;
434 } else {
435 cptr->argb_fg = parse_argb(&p);
438 p = skipspace(p);
439 if (*p) {
440 if (strcmp(p, "*"))
441 cptr->argb_bg = parse_argb(&p);
445 break;
448 } else {
449 /* Unknown, check for layout parameters */
450 struct menu_parameter *pp;
451 for ( pp = mparm ; pp->name ; pp++ ) {
452 if ( (ep = looking_at(p, pp->name)) ) {
453 pp->value = atoi(skipspace(ep));
454 break;
458 } else if ( looking_at(p, "append") ) {
459 char *a = strdup(skipspace(p+6));
460 if ( ld.label )
461 ld.append = a;
462 else
463 append = a;
464 } else if ( looking_at(p, "label") ) {
465 p = skipspace(p+5);
466 record(&ld, append);
467 ld.label = strdup(p);
468 ld.kernel = strdup(p);
469 ld.passwd = NULL;
470 ld.append = NULL;
471 ld.menulabel = NULL;
472 ld.ipappend = ipappend;
473 ld.menudefault = ld.menuhide = 0;
474 } else if ( looking_at(p, "kernel") ) {
475 if ( ld.label ) {
476 free(ld.kernel);
477 ld.kernel = strdup(skipspace(p+6));
479 } else if ( looking_at(p, "timeout") ) {
480 timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
481 } else if ( looking_at(p, "totaltimeout") ) {
482 totaltimeout = (atoll(skipspace(p+13))*CLK_TCK+9)/10;
483 } else if ( looking_at(p, "ontimeout") ) {
484 ontimeout = strdup(skipspace(p+9));
485 } else if ( looking_at(p, "allowoptions") ) {
486 allowedit = atoi(skipspace(p+12));
487 } else if ( looking_at(p, "ipappend") ) {
488 if (ld.label)
489 ld.ipappend = atoi(skipspace(p+8));
490 else
491 ipappend = atoi(skipspace(p+8));
492 } else if ( looking_at(p, "localboot") ) {
493 ld.kernel = strdup(".localboot");
494 ld.append = strdup(skipspace(p+9));
498 record(&ld, append);
499 fclose(f);
501 if ( ontimeout )
502 ontimeout = unlabel(ontimeout);
503 if ( onerror )
504 onerror = unlabel(onerror);