]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/stringTable.c
322832cb458f5cec02fc6e4c492b3ccc9c34c20d
[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 "kernBootStruct.h"
31 #include "stringConstants.h"
32 #include "drivers.h"
33 #include "legacy/configTablePrivate.h"
34
35 extern KERNBOOTSTRUCT *kernBootStruct;
36 extern char *Language;
37 extern char *LoadableFamilies;
38
39 static void eatThru(char val, char **table_p);
40
41 static inline int isspace(char c)
42 {
43 return (c == ' ' || c == '\t');
44 }
45
46 /*
47 * Compare a string to a key with quoted characters
48 */
49 static inline int
50 keyncmp(char *str, char *key, int n)
51 {
52 int c;
53 while (n--) {
54 c = *key++;
55 if (c == '\\') {
56 switch(c = *key++) {
57 case 'n':
58 c = '\n';
59 break;
60 case 'r':
61 c = '\r';
62 break;
63 case 't':
64 c = '\t';
65 break;
66 default:
67 break;
68 }
69 } else if (c == '\"') {
70 /* Premature end of key */
71 return 1;
72 }
73 if (c != *str++) {
74 return 1;
75 }
76 }
77 return 0;
78 }
79
80 static void eatThru(char val, char **table_p)
81 {
82 register char *table = *table_p;
83 register BOOL found = NO;
84
85 while (*table && !found)
86 {
87 if (*table == '\\') table += 2;
88 else
89 {
90 if (*table == val) found = YES;
91 table++;
92 }
93 }
94 *table_p = table;
95 }
96
97 /* Remove key and its associated value from the table. */
98
99 BOOL
100 removeKeyFromTable(const char *key, char *table)
101 {
102 register int len;
103 register char *tab;
104 char *buf;
105
106 len = strlen(key);
107 tab = (char *)table;
108 buf = (char *)malloc(len + 3);
109
110 sprintf(buf, "\"%s\"", key);
111 len = strlen(buf);
112
113 while(*tab) {
114 if(strncmp(buf, tab, len) == 0) {
115 char c;
116
117 while((c = *(tab + len)) != ';') {
118 if(c == 0) {
119 len = -1;
120 goto out;
121 }
122 len++;
123 }
124 len++;
125 if(*(tab + len) == '\n') len++;
126 goto out;
127 }
128 tab++;
129 }
130 len = -1;
131 out:
132 free(buf);
133
134 if(len == -1) return NO;
135
136 while((*tab = *(tab + len))) {
137 tab++;
138 }
139
140 return YES;
141 }
142
143 char *
144 newStringFromList(
145 char **list,
146 int *size
147 )
148 {
149 char *begin = *list, *end;
150 char *newstr;
151 int newsize = *size;
152
153 while (*begin && newsize && isspace(*begin)) {
154 begin++;
155 newsize--;
156 }
157 end = begin;
158 while (*end && newsize && !isspace(*end)) {
159 end++;
160 newsize--;
161 }
162 if (begin == end)
163 return 0;
164 newstr = malloc(end - begin + 1);
165 strncpy(newstr, begin, end - begin);
166 *list = end;
167 *size = newsize;
168 return newstr;
169 }
170
171 /*
172 * compress == compress escaped characters to one character
173 */
174 int stringLength(char *table, int compress)
175 {
176 int ret = 0;
177
178 while (*table)
179 {
180 if (*table == '\\')
181 {
182 table += 2;
183 ret += 1 + (compress ? 0 : 1);
184 }
185 else
186 {
187 if (*table == '\"') return ret;
188 ret++;
189 table++;
190 }
191 }
192 return ret;
193 }
194
195 // looks in table for strings of format << "key" = "value"; >>
196 // or << "key"; >>
197 BOOL getValueForStringTableKey(char *table, char *key, char **val, int *size)
198 {
199 int keyLength;
200 char *tableKey;
201
202 do
203 {
204 eatThru('\"',&table);
205 tableKey = table;
206 keyLength = strlen(key);
207 if (keyLength &&
208 (stringLength(table,1) == keyLength) &&
209 (keyncmp(key, table, keyLength) == 0))
210 {
211 int c;
212
213 /* found the key; now look for either
214 * '=' or ';'
215 */
216 while (c = *table) {
217 ++table;
218 if (c == '\\') {
219 ++table;
220 continue;
221 } else if (c == '=' || c == ';') {
222 break;
223 }
224 }
225 if (c == ';') {
226 table = tableKey;
227 } else {
228 eatThru('\"',&table);
229 }
230 *val = table;
231 *size = stringLength(table,0);
232 return YES;
233 }
234
235 eatThru(';',&table);
236
237 } while (*table);
238
239 return NO;
240 }
241
242
243 /*
244 * Returns a new malloc'ed string if one is found
245 * in the string table matching 'key'. Also translates
246 * \n escapes in the string.
247 */
248 char *newStringForStringTableKey(
249 char *table,
250 char *key
251 )
252 {
253 char *val, *newstr, *p;
254 int size;
255
256 if (getValueForStringTableKey(table, key, &val, &size)) {
257 newstr = malloc(size+1);
258 for (p = newstr; size; size--, p++, val++) {
259 if ((*p = *val) == '\\') {
260 switch (*++val) {
261 case 'r':
262 *p = '\r';
263 break;
264 case 'n':
265 *p = '\n';
266 break;
267 case 't':
268 *p = '\t';
269 break;
270 default:
271 *p = *val;
272 break;
273 }
274 size--;
275 }
276 }
277 *p = '\0';
278 return newstr;
279 } else {
280 return 0;
281 }
282 }
283
284 char *
285 newStringForKey(char *key)
286 {
287 char *val, *newstr;
288 int size;
289
290 if (getValueForKey(key, &val, &size) && size) {
291 newstr = 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 char *getToken(char *line, 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(char *line, char *match, char **matchval, int *len)
322 {
323 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 char *key
351 )
352 {
353 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 char *key,
364 int *value
365 )
366 {
367 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 char *key,
382 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 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 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( char *configFile, 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 char *bundleName, // bundle directory name (e.g. "System")
535 BOOL useDefault, // use Default.table instead of instance tables
536 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 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 char *which,
603 int size
604 )
605 {
606 char *buf, *bp, *cp;
607 int ret, len, doDefault=0;
608 char *device_dir = usrDevices();
609
610 #if 0
611 printf("In Load system config which=%d ; size=%d\n", which, size);
612 //sleep(1);
613 #endif 1
614 buf = bp = malloc(256);
615 if (which && size)
616 {
617 #if 0
618 printf("In Load system config alt\n");
619 //sleep(1);
620 #endif 1
621 for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ;
622 if (*cp == LP) {
623 while (len-- && *cp && *cp++ != RP) ;
624 /* cp now points past device */
625 strncpy(buf,which,cp - which);
626 bp += cp - which;
627 } else {
628 cp = which;
629 len = size;
630 }
631 if (*cp != '/') {
632 strcpy(bp, device_dir);
633 strcat(bp, "/System.config/");
634 strncat(bp, cp, len);
635 if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION),
636 IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0)
637 strcat(bp, IO_TABLE_EXTENSION);
638 } else {
639 strncpy(bp, cp, len);
640 bp[size] = '\0';
641 }
642 if ((strcmp(bp, USR_SYSTEM_DEFAULT_FILE) == 0) ||
643 (strcmp(bp, ARCH_SYSTEM_DEFAULT_FILE) == 0))
644 doDefault = 1;
645 ret = loadConfigFile(bp = buf, 0, 0);
646 } else {
647 #if 0
648 printf("In default SYSTEM_CONFIG LOAD\n");
649 //sleep(1);
650 #endif 1
651 ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0);
652 #if 0
653 printf("come back from SYSTEM_CONFIG loadConfigDir\n");
654 //sleep(1);
655 #endif 1
656 }
657 sysconfig_dev = currentdev();
658 if (ret < 0) {
659 error("System config file '%s' not found\n", bp);
660 } else
661 sysConfigValid = 1;
662 free(buf);
663 return (ret < 0 ? ret : doDefault);
664 }
665
666 #ifdef DISABLED
667 int
668 loadOtherConfigs(
669 int useDefault
670 )
671 {
672 char *val, *table;
673 char *path = malloc(256);
674 char *hintTable;
675 char *installVersion = NULL, *thisVersion;
676 char *longName, *tableName;
677 int count;
678 char *string;
679 int ret;
680 int old_dev = currentdev();
681
682 if (sysconfig_dev)
683 switchdev(sysconfig_dev);
684 if (getValueForKey( "Boot Drivers", &val, &count))
685 {
686 #if 0
687 printf("Loading Boot Drivers\n");
688 sleep(1);
689 #endif 1
690 while (string = newStringFromList(&val, &count)) {
691 /* Check installation hints... */
692 sprintf(path, "%s/System.config/" INSTALL_HINTS
693 "/%s.table", usrDevices(), string);
694
695 if (getBoolForKey("Ignore Hints") == NO &&
696 loadConfigFile(path, &hintTable, YES) == 0) {
697 installVersion = newStringForStringTableKey(
698 hintTable, "Version");
699 longName = newStringForStringTableKey(
700 hintTable, "Long Name");
701 tableName = newStringForStringTableKey(
702 hintTable, "Default Table");
703 free(hintTable);
704 } else {
705 installVersion = longName = tableName = NULL;
706 }
707
708 ret = loadConfigDir(string, useDefault, &table, YES);
709 if (ret >= 0) {
710 thisVersion = newStringForStringTableKey(
711 table, "Version");
712 if (installVersion && thisVersion &&
713 (strcmp(thisVersion, installVersion) != 0)) {
714 /* Versions do not match */
715 driverIsMissing(string, installVersion, longName,
716 tableName, DRIVER_VERSION_MISMATCH);
717 } else {
718 struct driver_load_data dl;
719
720 dl.name = string;
721 if ((openDriverReloc(&dl)) >= 0) {
722 verbose("Loading binary for %s device driver.\n",string);
723 if (loadDriver(&dl) < 0) /// need to stop if error
724 error("Error loading %s device driver.\n",string);
725 #if 0
726 printf("Calling link driver for %s\n", string);
727 #endif 1
728 if (linkDriver(&dl) < 0)
729 error("Error linking %s device Driver.\n",string);
730 }
731 loadConfigDir(string, useDefault, NULL, NO);
732 driverWasLoaded(string, table, NULL);
733 free(table);
734 free(string);
735 free(installVersion); free(longName);
736 free(tableName);
737 }
738 free(thisVersion);
739 } else {
740 /* driver not found */
741 driverIsMissing(string, installVersion, longName,
742 tableName, DRIVER_NOT_FOUND);
743 }
744 #if 0
745 if (ret == 1)
746 useDefault = 1; // use defaults from now on
747 #endif
748 }
749 } else {
750 error("Warning: No Boot drivers specified in system config.\n");
751 }
752
753 kernBootStruct->first_addr0 =
754 (int)kernBootStruct->configEnd + 1024;
755 free(path);
756 switchdev(old_dev);
757 return 0;
758 }
759 #endif /* DISABLED */