]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/stringTable.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / stringTable.c
1 /*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 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 2.0 (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 "bootstruct.h"
30 #include "libsaio.h"
31 #include "stringConstants.h"
32 #include "legacy/configTablePrivate.h"
33 #include "xml.h"
34
35 extern char *Language;
36 extern char *LoadableFamilies;
37
38 static TagPtr gConfigDict;
39
40 static void eatThru(char val, const char **table_p);
41
42 static inline int isspace(char c)
43 {
44 return (c == ' ' || c == '\t');
45 }
46
47 /*
48 * Compare a string to a key with quoted characters
49 */
50 static inline int
51 keyncmp(const char *str, const char *key, int n)
52 {
53 int c;
54 while (n--) {
55 c = *key++;
56 if (c == '\\') {
57 switch(c = *key++) {
58 case 'n':
59 c = '\n';
60 break;
61 case 'r':
62 c = '\r';
63 break;
64 case 't':
65 c = '\t';
66 break;
67 default:
68 break;
69 }
70 } else if (c == '\"') {
71 /* Premature end of key */
72 return 1;
73 }
74 if (c != *str++) {
75 return 1;
76 }
77 }
78 return 0;
79 }
80
81 static void eatThru(char val, const char **table_p)
82 {
83 register const char *table = *table_p;
84 register BOOL found = NO;
85
86 while (*table && !found)
87 {
88 if (*table == '\\') table += 2;
89 else
90 {
91 if (*table == val) found = YES;
92 table++;
93 }
94 }
95 *table_p = table;
96 }
97
98 #if UNUSED
99
100 /* Remove key and its associated value from the table. */
101
102 BOOL
103 removeKeyFromTable(const char *key, char *table)
104 {
105 register int len;
106 register char *tab;
107 char *buf;
108
109 len = strlen(key);
110 tab = (char *)table;
111 buf = (char *)malloc(len + 3);
112
113 sprintf(buf, "\"%s\"", key);
114 len = strlen(buf);
115
116 while(*tab) {
117 if(strncmp(buf, tab, len) == 0) {
118 char c;
119
120 while((c = *(tab + len)) != ';') {
121 if(c == 0) {
122 len = -1;
123 goto out;
124 }
125 len++;
126 }
127 len++;
128 if(*(tab + len) == '\n') len++;
129 goto out;
130 }
131 tab++;
132 }
133 len = -1;
134 out:
135 free(buf);
136
137 if(len == -1) return NO;
138
139 while((*tab = *(tab + len))) {
140 tab++;
141 }
142
143 return YES;
144 }
145
146 char *
147 newStringFromList(
148 char **list,
149 int *size
150 )
151 {
152 char *begin = *list, *end;
153 char *newstr;
154 int newsize = *size;
155 int bufsize;
156
157 while (*begin && newsize && isspace(*begin)) {
158 begin++;
159 newsize--;
160 }
161 end = begin;
162 while (*end && newsize && !isspace(*end)) {
163 end++;
164 newsize--;
165 }
166 if (begin == end)
167 return 0;
168 bufsize = end - begin + 1;
169 newstr = malloc(bufsize);
170 strlcpy(newstr, begin, bufsize);
171 *list = end;
172 *size = newsize;
173 return newstr;
174 }
175
176 #endif
177
178 /*
179 * compress == compress escaped characters to one character
180 */
181 int stringLength(const char *table, int compress)
182 {
183 int ret = 0;
184
185 while (*table)
186 {
187 if (*table == '\\')
188 {
189 table += 2;
190 ret += 1 + (compress ? 0 : 1);
191 }
192 else
193 {
194 if (*table == '\"') return ret;
195 ret++;
196 table++;
197 }
198 }
199 return ret;
200 }
201
202 BOOL getValueForConfigTableKey(const char *table, const char *key, const char **val, int *size)
203 {
204 int keyLength;
205 const char *tableKey;
206
207 if (gConfigDict != 0 ) {
208 /* Look up key in XML dictionary */
209 TagPtr value;
210 value = XMLGetProperty(gConfigDict, key);
211 if (value != 0) {
212 if (value->type != kTagTypeString) {
213 error("Non-string tag '%s' found in config file\n",
214 key);
215 return NO;
216 }
217 *val = value->string;
218 *size = strlen(value->string);
219 return YES;
220 }
221 } else {
222 /* Legacy plist-style table */
223 do
224 {
225 eatThru('\"',&table);
226 tableKey = table;
227 keyLength = strlen(key);
228 if (keyLength &&
229 (stringLength(table,1) == keyLength) &&
230 (keyncmp(key, table, keyLength) == 0))
231 {
232 int c;
233
234 /* found the key; now look for either
235 * '=' or ';'
236 */
237 while (c = *table) {
238 ++table;
239 if (c == '\\') {
240 ++table;
241 continue;
242 } else if (c == '=' || c == ';') {
243 break;
244 }
245 }
246 if (c == ';') {
247 table = tableKey;
248 } else {
249 eatThru('\"',&table);
250 }
251 *val = table;
252 *size = stringLength(table,0);
253 return YES;
254 }
255
256 eatThru(';',&table);
257
258 } while (*table);
259 }
260
261 return NO;
262 }
263
264 #if UNUSED
265
266 /*
267 * Returns a new malloc'ed string if one is found
268 * in the string table matching 'key'. Also translates
269 * \n escapes in the string.
270 */
271 char *newStringForStringTableKey(
272 char *table,
273 char *key
274 )
275 {
276 const char *val;
277 char *newstr, *p;
278 int size;
279
280 if (getValueForConfigTableKey(table, key, &val, &size)) {
281 newstr = (char *)malloc(size+1);
282 for (p = newstr; size; size--, p++, val++) {
283 if ((*p = *val) == '\\') {
284 switch (*++val) {
285 case 'r':
286 *p = '\r';
287 break;
288 case 'n':
289 *p = '\n';
290 break;
291 case 't':
292 *p = '\t';
293 break;
294 default:
295 *p = *val;
296 break;
297 }
298 size--;
299 }
300 }
301 *p = '\0';
302 return newstr;
303 } else {
304 return 0;
305 }
306 }
307
308 #endif
309
310 char *
311 newStringForKey(char *key)
312 {
313 const char *val;
314 char *newstr;
315 int size;
316
317 if (getValueForKey(key, &val, &size) && size) {
318 newstr = (char *)malloc(size + 1);
319 strlcpy(newstr, val, size + 1);
320 return newstr;
321 } else {
322 return 0;
323 }
324 }
325
326 /* parse a command line
327 * in the form: [<argument> ...] [<option>=<value> ...]
328 * both <option> and <value> must be either composed of
329 * non-whitespace characters, or enclosed in quotes.
330 */
331
332 static const char *getToken(const char *line, const char **begin, int *len)
333 {
334 if (*line == '\"') {
335 *begin = ++line;
336 while (*line && *line != '\"')
337 line++;
338 *len = line++ - *begin;
339 } else {
340 *begin = line;
341 while (*line && !isspace(*line) && *line != '=')
342 line++;
343 *len = line - *begin;
344 }
345 return line;
346 }
347
348 BOOL getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
349 {
350 const char *key, *value;
351 int key_len, value_len;
352 BOOL retval = NO;
353
354 while (*line) {
355 /* look for keyword or argument */
356 while (isspace(*line)) line++;
357
358 /* now look for '=' or whitespace */
359 line = getToken(line, &key, &key_len);
360 /* line now points to '=' or space */
361 if (*line && !isspace(*line)) {
362 line = getToken(++line, &value, &value_len);
363 } else {
364 value = line;
365 value_len = 0;
366 }
367 if ((strlen(match) == key_len)
368 && strncmp(match, key, key_len) == 0) {
369 *matchval = value;
370 *len = value_len;
371 retval = YES;
372 /* Continue to look for this key; last one wins. */
373 }
374 }
375 return retval;
376 }
377
378 /* Returns TRUE if a value was found, FALSE otherwise.
379 * The boolean value of the key is stored in 'val'.
380 */
381 BOOL getBoolForKey(
382 const char *key,
383 BOOL *result_val
384 )
385 {
386 const char *key_val;
387 int size;
388
389 if (getValueForKey(key, &key_val, &size)) {
390 if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {
391 *result_val = YES;
392 } else {
393 *result_val = NO;
394 }
395 return YES;
396 }
397 return NO;
398 }
399
400 BOOL getIntForKey(
401 const char *key,
402 int *value
403 )
404 {
405 const char *val;
406 int size, sum;
407 BOOL negative = NO;
408
409 if (getValueForKey(key, &val, &size)) {
410 if (*val == '-') {
411 negative = YES;
412 val++;
413 }
414 for (sum = 0; size > 0; size--) {
415 if (*val < '0' || *val > '9') return NO;
416 sum = (sum * 10) + (*val++ - '0');
417 }
418 if (negative) sum = -sum;
419 *value = sum;
420 return YES;
421 }
422 return NO;
423 }
424
425 BOOL getValueForKey(
426 const char *key,
427 const char **val,
428 int *size
429 )
430 {
431 if (getValueForBootKey(bootArgs->CommandLine, key, val, size))
432 return YES;
433 else if (getValueForConfigTableKey(bootInfo->config, key, val, size))
434 return YES;
435
436 return NO;
437 }
438
439 int sysConfigValid;
440
441 #define TABLE_EXPAND_SIZE 192
442
443 /*
444 * Returns 0 if file loaded OK,
445 * -1 if file was not loaded
446 * Does not print error messages.
447 * Returns pointer to table in memory in *table.
448 * Allocates an extra number of bytes for table expansion.
449 */
450 int
451 loadConfigFile(const char *configFile)
452 {
453 char *configPtr = bootInfo->config;
454 int fd, count;
455
456 /* Read config file into memory */
457 if ((fd = open(configFile, 0)) >= 0)
458 {
459 if ((configPtr - bootInfo->config) > CONFIG_SIZE) {
460 error("No room in memory for config files\n");
461 close(fd);
462 return -1;
463 }
464 verbose("Reading configuration file '%s'.\n",configFile);
465
466 count = read(fd, configPtr, IO_CONFIG_DATA_SIZE);
467 close(fd);
468
469 configPtr += count;
470 *configPtr++ = 0;
471 *configPtr = 0;
472
473 bootInfo->configEnd = configPtr;
474
475 return 0;
476 } else {
477 return -1;
478 }
479 }
480
481 #define LP '('
482 #define RP ')'
483
484 #define SYSTEM_CONFIG_DIR "/Library/Preferences/SystemConfiguration"
485 #define SYSTEM_CONFIG_FILE "/com.apple.Boot.plist"
486 #define LRE_CONFIG_FILE "/com.apple.lre.Boot.plist"
487 #define SYSTEM_CONFIG_PATH SYSTEM_CONFIG_DIR SYSTEM_CONFIG_FILE
488 #define CONFIG_EXT ".plist"
489
490 #if UNUSED
491 void
492 printSystemConfig(void)
493 {
494 char *p1 = bootInfo->config;
495 char *p2 = p1, tmp;
496
497 while (*p1 != '\0') {
498 while (*p2 != '\0' && *p2 != '\n') p2++;
499 tmp = *p2;
500 *p2 = '\0';
501 printf("%s\n", p1);
502 *p2 = tmp;
503 if (tmp == '\0') break;
504 p1 = ++p2;
505 }
506 }
507 #endif
508
509 //==========================================================================
510 // ParseXMLFile
511 // Modifies the input buffer.
512 // Expects to see one dictionary in the XML file.
513 // Puts the first dictionary it finds in the
514 // tag pointer and returns 0, or returns -1 if not found
515 // (and does not modify dict pointer).
516 // Prints an error message if there is a parsing error.
517 //
518 static long
519 ParseXMLFile( char * buffer, TagPtr * dict )
520 {
521 long length, pos;
522 TagPtr tag;
523 pos = 0;
524 char *configBuffer;
525
526 configBuffer = malloc(strlen(buffer)+1);
527 strcpy(configBuffer, buffer);
528
529 while (1)
530 {
531 length = XMLParseNextTag(configBuffer + pos, &tag);
532 if (length == -1) break;
533
534 pos += length;
535
536 if (tag == 0) continue;
537 if (tag->type == kTagTypeDict) break;
538
539 XMLFreeTag(tag);
540 }
541 free(configBuffer);
542 if (length < 0) {
543 error ("Error parsing plist file");
544 return -1;
545 }
546 *dict = tag;
547 return 0;
548 }
549
550 /* Returns 0 if requested config files were loaded,
551 * 1 if default files were loaded,
552 * -1 if no files were loaded.
553 * Prints error message if files cannot be loaded.
554 */
555 int
556 loadSystemConfig(
557 const char *which,
558 int size
559 )
560 {
561 char *buf, *bp;
562 const char *cp;
563 int ret, len, doDefault=0;
564
565 buf = bp = malloc(512);
566 if (which && size) {
567 for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ;
568 if (*cp == LP) {
569 while (len-- && *cp && *cp++ != RP) ;
570 /* cp now points past device */
571 strlcpy(buf,which,cp - which + 1);
572 bp += cp - which;
573 } else {
574 cp = which;
575 len = size;
576 }
577 if (*cp != '/') {
578 strcpy(bp, systemConfigDir());
579 strcat(bp, "/");
580 strncat(bp, cp, len);
581 if (strncmp(cp + len - strlen(CONFIG_EXT),
582 CONFIG_EXT, strlen(CONFIG_EXT)) != 0)
583 strcat(bp, CONFIG_EXT);
584 } else {
585 strlcpy(bp, cp, len + 1);
586 }
587 if ((strcmp(bp, SYSTEM_CONFIG_PATH) == 0)) {
588 doDefault = 1;
589 }
590 bp = buf;
591 ret = loadConfigFile(bp);
592 } else {
593 /* First try LRE file */
594 strcpy(bp, systemConfigDir());
595 strcat(bp, LRE_CONFIG_FILE);
596 ret = loadConfigFile(bp);
597
598 if (ret < 0) {
599 /* If not found, try default file */
600 strcpy(bp, systemConfigDir());
601 strcat(bp, SYSTEM_CONFIG_FILE);
602 ret = loadConfigFile(bp);
603 }
604 }
605 if (ret < 0) {
606 error("System config file '%s' not found\n", bp);
607 sleep(1);
608 } else {
609 sysConfigValid = 1;
610 // Check for XML file;
611 // if not XML, gConfigDict will remain 0.
612 ParseXMLFile(bootInfo->config, &gConfigDict);
613 }
614 free(buf);
615 return (ret < 0 ? ret : doDefault);
616 }
617
618
619 char * newString(const char * oldString)
620 {
621 if ( oldString )
622 return strcpy(malloc(strlen(oldString)+1), oldString);
623 else
624 return NULL;
625 }