]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/stringTable.c
1d917316bae9cfe86deb63b1d108b5d2eb38570b
[apple/boot.git] / i386 / libsaio / stringTable.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29 #include "libsaio.h"
30 #include "stringConstants.h"
31 #include "legacy/configTablePrivate.h"
32
33 extern KERNBOOTSTRUCT *kernBootStruct;
34 extern char *Language;
35 extern char *LoadableFamilies;
36
37 static void eatThru(char val, const char **table_p);
38
39 static inline int isspace(char c)
40 {
41 return (c == ' ' || c == '\t');
42 }
43
44 /*
45 * Compare a string to a key with quoted characters
46 */
47 static inline int
48 keyncmp(const char *str, const char *key, int n)
49 {
50 int c;
51 while (n--) {
52 c = *key++;
53 if (c == '\\') {
54 switch(c = *key++) {
55 case 'n':
56 c = '\n';
57 break;
58 case 'r':
59 c = '\r';
60 break;
61 case 't':
62 c = '\t';
63 break;
64 default:
65 break;
66 }
67 } else if (c == '\"') {
68 /* Premature end of key */
69 return 1;
70 }
71 if (c != *str++) {
72 return 1;
73 }
74 }
75 return 0;
76 }
77
78 static void eatThru(char val, const char **table_p)
79 {
80 register const char *table = *table_p;
81 register BOOL found = NO;
82
83 while (*table && !found)
84 {
85 if (*table == '\\') table += 2;
86 else
87 {
88 if (*table == val) found = YES;
89 table++;
90 }
91 }
92 *table_p = table;
93 }
94
95 /* Remove key and its associated value from the table. */
96
97 BOOL
98 removeKeyFromTable(const char *key, char *table)
99 {
100 register int len;
101 register char *tab;
102 char *buf;
103
104 len = strlen(key);
105 tab = (char *)table;
106 buf = (char *)malloc(len + 3);
107
108 sprintf(buf, "\"%s\"", key);
109 len = strlen(buf);
110
111 while(*tab) {
112 if(strncmp(buf, tab, len) == 0) {
113 char c;
114
115 while((c = *(tab + len)) != ';') {
116 if(c == 0) {
117 len = -1;
118 goto out;
119 }
120 len++;
121 }
122 len++;
123 if(*(tab + len) == '\n') len++;
124 goto out;
125 }
126 tab++;
127 }
128 len = -1;
129 out:
130 free(buf);
131
132 if(len == -1) return NO;
133
134 while((*tab = *(tab + len))) {
135 tab++;
136 }
137
138 return YES;
139 }
140
141 char *
142 newStringFromList(
143 char **list,
144 int *size
145 )
146 {
147 char *begin = *list, *end;
148 char *newstr;
149 int newsize = *size;
150
151 while (*begin && newsize && isspace(*begin)) {
152 begin++;
153 newsize--;
154 }
155 end = begin;
156 while (*end && newsize && !isspace(*end)) {
157 end++;
158 newsize--;
159 }
160 if (begin == end)
161 return 0;
162 newstr = malloc(end - begin + 1);
163 strncpy(newstr, begin, end - begin);
164 *list = end;
165 *size = newsize;
166 return newstr;
167 }
168
169 /*
170 * compress == compress escaped characters to one character
171 */
172 int stringLength(const char *table, int compress)
173 {
174 int ret = 0;
175
176 while (*table)
177 {
178 if (*table == '\\')
179 {
180 table += 2;
181 ret += 1 + (compress ? 0 : 1);
182 }
183 else
184 {
185 if (*table == '\"') return ret;
186 ret++;
187 table++;
188 }
189 }
190 return ret;
191 }
192
193 // looks in table for strings of format << "key" = "value"; >>
194 // or << "key"; >>
195 BOOL getValueForStringTableKey(const char *table, const char *key, const char **val, int *size)
196 {
197 int keyLength;
198 const char *tableKey;
199
200 do
201 {
202 eatThru('\"',&table);
203 tableKey = table;
204 keyLength = strlen(key);
205 if (keyLength &&
206 (stringLength(table,1) == keyLength) &&
207 (keyncmp(key, table, keyLength) == 0))
208 {
209 int c;
210
211 /* found the key; now look for either
212 * '=' or ';'
213 */
214 while (c = *table) {
215 ++table;
216 if (c == '\\') {
217 ++table;
218 continue;
219 } else if (c == '=' || c == ';') {
220 break;
221 }
222 }
223 if (c == ';') {
224 table = tableKey;
225 } else {
226 eatThru('\"',&table);
227 }
228 *val = table;
229 *size = stringLength(table,0);
230 return YES;
231 }
232
233 eatThru(';',&table);
234
235 } while (*table);
236
237 return NO;
238 }
239
240
241 /*
242 * Returns a new malloc'ed string if one is found
243 * in the string table matching 'key'. Also translates
244 * \n escapes in the string.
245 */
246 char *newStringForStringTableKey(
247 char *table,
248 char *key
249 )
250 {
251 const char *val;
252 char *newstr, *p;
253 int size;
254
255 if (getValueForStringTableKey(table, key, &val, &size)) {
256 newstr = (char *)malloc(size+1);
257 for (p = newstr; size; size--, p++, val++) {
258 if ((*p = *val) == '\\') {
259 switch (*++val) {
260 case 'r':
261 *p = '\r';
262 break;
263 case 'n':
264 *p = '\n';
265 break;
266 case 't':
267 *p = '\t';
268 break;
269 default:
270 *p = *val;
271 break;
272 }
273 size--;
274 }
275 }
276 *p = '\0';
277 return newstr;
278 } else {
279 return 0;
280 }
281 }
282
283 char *
284 newStringForKey(char *key)
285 {
286 const char *val;
287 char *newstr;
288 int size;
289
290 if (getValueForKey(key, &val, &size) && size) {
291 newstr = (char *)malloc(size + 1);
292 strncpy(newstr, val, size);
293 return newstr;
294 } else {
295 return 0;
296 }
297 }
298
299 /* parse a command line
300 * in the form: [<argument> ...] [<option>=<value> ...]
301 * both <option> and <value> must be either composed of
302 * non-whitespace characters, or enclosed in quotes.
303 */
304
305 static const char *getToken(const char *line, const char **begin, int *len)
306 {
307 if (*line == '\"') {
308 *begin = ++line;
309 while (*line && *line != '\"')
310 line++;
311 *len = line++ - *begin;
312 } else {
313 *begin = line;
314 while (*line && !isspace(*line) && *line != '=')
315 line++;
316 *len = line - *begin;
317 }
318 return line;
319 }
320
321 BOOL getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
322 {
323 const char *key, *value;
324 int key_len, value_len;
325
326 while (*line) {
327 /* look for keyword or argument */
328 while (isspace(*line)) line++;
329
330 /* now look for '=' or whitespace */
331 line = getToken(line, &key, &key_len);
332 /* line now points to '=' or space */
333 if (*line && !isspace(*line)) {
334 line = getToken(++line, &value, &value_len);
335 } else {
336 value = line;
337 value_len = 0;
338 }
339 if ((strlen(match) == key_len)
340 && strncmp(match, key, key_len) == 0) {
341 *matchval = value;
342 *len = value_len;
343 return YES;
344 }
345 }
346 return NO;
347 }
348
349 BOOL getBoolForKey(
350 const char *key
351 )
352 {
353 const char *val;
354 int size;
355
356 if (getValueForKey(key, &val, &size) && (size >= 1) &&
357 val[0] == 'Y' || val[0] == 'y')
358 return YES;
359 return NO;
360 }
361
362 BOOL getIntForKey(
363 const char *key,
364 int *value
365 )
366 {
367 const char *val;
368 int size, sum;
369
370 if (getValueForKey(key, &val, &size)) {
371 for (sum = 0; size > 0; size--) {
372 sum = (sum * 10) + (*val++ - '0');
373 }
374 *value = sum;
375 return YES;
376 }
377 return NO;
378 }
379
380 BOOL getValueForKey(
381 const char *key,
382 const char **val,
383 int *size
384 )
385 {
386 if (getValueForBootKey(kernBootStruct->bootString, key, val, size))
387 return YES;
388 else if (getValueForStringTableKey(kernBootStruct->config, key, val, size))
389 return YES;
390
391 return NO;
392 }
393
394 #if 0
395 #define LOCALIZABLE_PATH \
396 "%s/%s.config/%s.lproj/%s.strings"
397 char *
398 loadLocalizableStrings(
399 char *name,
400 char *tableName
401 )
402 {
403 char buf[256], *config;
404 register int count, fd = -1;
405 const char *device_dir = usrDevices();
406
407 sprintf(buf, LOCALIZABLE_PATH, device_dir, name,
408 Language, tableName);
409 if ((fd = open(buf, 0)) < 0) {
410 sprintf(buf, LOCALIZABLE_PATH, device_dir, name,
411 "English", tableName);
412 if ((fd = open(buf,0)) < 0) {
413 return 0;
414 }
415 }
416 count = file_size(fd);
417 config = malloc(count);
418 count = read(fd, config, count);
419 close(fd);
420 if (count <= 0) {
421 free(config);
422 return 0;
423 }
424 return config;
425 }
426 #endif
427
428 #if 0 // XXX
429 char *
430 bundleLongName(
431 char *bundleName,
432 char *tableName
433 )
434 {
435 char *table, *name, *version, *newName;
436 char *path = malloc(256);
437
438 #define LONG_NAME_FORMAT "%s (v%s)"
439 sprintf(path, "%s/%s.config/%s.table",
440 usrDevices(), bundleName, tableName ? tableName : "Default");
441 if (loadConfigFile(path, &table, YES) == 0) {
442 version = newStringForStringTableKey(table, "Version");
443 free(table);
444 } else {
445 version = newString("0.0");
446 }
447 table = loadLocalizableStrings(bundleName,
448 tableName ? tableName : "Localizable");
449 if (table) {
450 name = newStringForStringTableKey(table, "Long Name");
451 free(table);
452 } else {
453 name = newString(bundleName);
454 }
455 newName = malloc(strlen(name)+strlen(version)+strlen(LONG_NAME_FORMAT));
456 sprintf(newName, LONG_NAME_FORMAT, name, version);
457 free(name); free(version);
458 return newName;
459 }
460 #endif
461
462 int sysConfigValid;
463
464 void
465 addConfig(
466 const char *config
467 )
468 {
469 char *configPtr = kernBootStruct->configEnd;
470 int len = strlen(config);
471
472 if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) {
473 error("No room in memory for config files\n");
474 return;
475 }
476 strcpy(configPtr, config);
477 configPtr += (len + 1);
478 *configPtr = 0;
479 kernBootStruct->configEnd = configPtr;
480 }
481
482 #define TABLE_EXPAND_SIZE 192
483
484 /*
485 * Returns 0 if file loaded OK,
486 * -1 if file was not loaded
487 * Does not print error messages.
488 * Returns pointer to table in memory in *table.
489 * Allocates an extra number of bytes for table expansion.
490 */
491 int
492 loadConfigFile(const char *configFile, const char **table, BOOL allocTable)
493 {
494 char *configPtr = kernBootStruct->configEnd;
495 int fd, count;
496
497 /* Read config file into memory */
498 if ((fd = open(configFile, 0)) >= 0)
499 {
500 if (allocTable) {
501 configPtr = malloc(file_size(fd)+2+TABLE_EXPAND_SIZE);
502 } else {
503 if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) {
504 error("No room in memory for config files\n");
505 close(fd);
506 return -1;
507 }
508 verbose("Reading configuration file '%s'.\n",configFile);
509 }
510 if (table) *table = configPtr;
511 count = read(fd, configPtr, IO_CONFIG_DATA_SIZE);
512 close(fd);
513
514 configPtr += count;
515 *configPtr++ = 0;
516 *configPtr = 0;
517 if (!allocTable)
518 kernBootStruct->configEnd = configPtr;
519
520 return 0;
521 } else {
522 return -1;
523 }
524 }
525
526 /* Returns 0 if requested config files were loaded,
527 * 1 if default files were loaded,
528 * -1 if no files were loaded.
529 * Prints error message if files cannot be loaded.
530 */
531
532 int
533 loadConfigDir(
534 const char *bundleName, // bundle directory name (e.g. "System")
535 BOOL useDefault, // use Default.table instead of instance tables
536 const char **table, // returns pointer to config table
537 BOOL allocTable // malloc the table and return in *table
538 )
539 {
540 char *buf;
541 int i, max, ret;
542 const char *device_dir = usrDevices();
543
544 buf = malloc(256);
545 ret = 0;
546
547 // load up to 99 instance tables
548 if (allocTable)
549 max = 1;
550 else
551 max = 99;
552 for (i=0; i < max; i++) {
553 sprintf(buf, "%s/%s.config/Instance%d.table",
554 device_dir,
555 bundleName, i);
556 if (useDefault || (loadConfigFile(buf, table, allocTable) != 0)) {
557 if (i == 0) {
558 // couldn't load first instance table;
559 // try the default table
560 sprintf(buf, "%s/%s.config/%s",
561 device_dir,
562 bundleName,
563 IO_DEFAULT_TABLE_FILENAME);
564 if (loadConfigFile(buf, table, allocTable) == 0) {
565 ret = 1;
566 } else {
567 if (!allocTable)
568 error("Config file \"%s\" not found\n", buf);
569 ret = -1;
570 }
571 }
572 // we must be done.
573 break;
574 }
575 }
576 free(buf);
577 return ret;
578 }
579
580
581 #define USR_SYSTEM_CONFIG \
582 USR_DEVICES "/System.config"
583 #define USR_SYSTEM_DEFAULT_FILE \
584 USR_SYSTEM_CONFIG "/Default.table"
585 #define ARCH_SYSTEM_CONFIG \
586 ARCH_DEVICES "/System.config"
587 #define ARCH_SYSTEM_DEFAULT_FILE \
588 ARCH_SYSTEM_CONFIG "/Default.table"
589 #define SYSTEM_CONFIG "System"
590 #define LP '('
591 #define RP ')'
592
593 static int sysconfig_dev;
594
595 /* Returns 0 if requested config files were loaded,
596 * 1 if default files were loaded,
597 * -1 if no files were loaded.
598 * Prints error message if files cannot be loaded.
599 */
600 int
601 loadSystemConfig(
602 const char *which,
603 int size
604 )
605 {
606 char *buf, *bp;
607 const char *cp;
608 int ret, len, doDefault=0;
609 const char *device_dir = usrDevices();
610
611 #if 0
612 printf("In Load system config which=%d ; size=%d\n", which, size);
613 //sleep(1);
614 #endif 1
615 buf = bp = malloc(256);
616 if (which && size)
617 {
618 #if 0
619 printf("In Load system config alt\n");
620 //sleep(1);
621 #endif 1
622 for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ;
623 if (*cp == LP) {
624 while (len-- && *cp && *cp++ != RP) ;
625 /* cp now points past device */
626 strncpy(buf,which,cp - which);
627 bp += cp - which;
628 } else {
629 cp = which;
630 len = size;
631 }
632 if (*cp != '/') {
633 strcpy(bp, device_dir);
634 strcat(bp, "/System.config/");
635 strncat(bp, cp, len);
636 if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION),
637 IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0)
638 strcat(bp, IO_TABLE_EXTENSION);
639 } else {
640 strncpy(bp, cp, len);
641 bp[size] = '\0';
642 }
643 if ((strcmp(bp, USR_SYSTEM_DEFAULT_FILE) == 0) ||
644 (strcmp(bp, ARCH_SYSTEM_DEFAULT_FILE) == 0))
645 doDefault = 1;
646 ret = loadConfigFile(bp = buf, 0, 0);
647 } else {
648 #if 0
649 printf("In default SYSTEM_CONFIG LOAD\n");
650 //sleep(1);
651 #endif 1
652 ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0);
653 #if 0
654 printf("come back from SYSTEM_CONFIG loadConfigDir\n");
655 //sleep(1);
656 #endif 1
657 }
658 sysconfig_dev = currentdev();
659 if (ret < 0) {
660 error("System config file '%s' not found\n", bp);
661 } else
662 sysConfigValid = 1;
663 free(buf);
664 return (ret < 0 ? ret : doDefault);
665 }
666
667 #ifdef DISABLED
668 int
669 loadOtherConfigs(
670 int useDefault
671 )
672 {
673 char *val, *table;
674 char *path = malloc(256);
675 char *hintTable;
676 char *installVersion = NULL, *thisVersion;
677 char *longName, *tableName;
678 int count;
679 char *string;
680 int ret;
681 int old_dev = currentdev();
682
683 if (sysconfig_dev)
684 switchdev(sysconfig_dev);
685 if (getValueForKey( "Boot Drivers", &val, &count))
686 {
687 #if 0
688 printf("Loading Boot Drivers\n");
689 sleep(1);
690 #endif 1
691 while (string = newStringFromList(&val, &count)) {
692 /* Check installation hints... */
693 sprintf(path, "%s/System.config/" INSTALL_HINTS
694 "/%s.table", usrDevices(), string);
695
696 if (getBoolForKey("Ignore Hints") == NO &&
697 loadConfigFile(path, &hintTable, YES) == 0) {
698 installVersion = newStringForStringTableKey(
699 hintTable, "Version");
700 longName = newStringForStringTableKey(
701 hintTable, "Long Name");
702 tableName = newStringForStringTableKey(
703 hintTable, "Default Table");
704 free(hintTable);
705 } else {
706 installVersion = longName = tableName = NULL;
707 }
708
709 ret = loadConfigDir(string, useDefault, &table, YES);
710 if (ret >= 0) {
711 thisVersion = newStringForStringTableKey(
712 table, "Version");
713 if (installVersion && thisVersion &&
714 (strcmp(thisVersion, installVersion) != 0)) {
715 /* Versions do not match */
716 driverIsMissing(string, installVersion, longName,
717 tableName, DRIVER_VERSION_MISMATCH);
718 } else {
719 struct driver_load_data dl;
720
721 dl.name = string;
722 if ((openDriverReloc(&dl)) >= 0) {
723 verbose("Loading binary for %s device driver.\n",string);
724 if (loadDriver(&dl) < 0) /// need to stop if error
725 error("Error loading %s device driver.\n",string);
726 #if 0
727 printf("Calling link driver for %s\n", string);
728 #endif 1
729 if (linkDriver(&dl) < 0)
730 error("Error linking %s device Driver.\n",string);
731 }
732 loadConfigDir(string, useDefault, NULL, NO);
733 driverWasLoaded(string, table, NULL);
734 free(table);
735 free(string);
736 free(installVersion); free(longName);
737 free(tableName);
738 }
739 free(thisVersion);
740 } else {
741 /* driver not found */
742 driverIsMissing(string, installVersion, longName,
743 tableName, DRIVER_NOT_FOUND);
744 }
745 #if 0
746 if (ret == 1)
747 useDefault = 1; // use defaults from now on
748 #endif
749 }
750 } else {
751 error("Warning: No Boot drivers specified in system config.\n");
752 }
753
754 kernBootStruct->first_addr0 =
755 (int)kernBootStruct->configEnd + 1024;
756 free(path);
757 switchdev(old_dev);
758 return 0;
759 }
760 #endif /* DISABLED */