]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/stringTable.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / stringTable.c
CommitLineData
14c7c974 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
14c7c974
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the "License"). You may not use this file
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
f083c6c3 29#include "bootstruct.h"
14c7c974 30#include "libsaio.h"
14c7c974 31#include "stringConstants.h"
14c7c974 32#include "legacy/configTablePrivate.h"
f083c6c3 33#include "xml.h"
14c7c974 34
14c7c974
A
35extern char *Language;
36extern char *LoadableFamilies;
37
f083c6c3
A
38static TagPtr gConfigDict;
39
75b89a82 40static void eatThru(char val, const char **table_p);
14c7c974
A
41
42static 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 */
50static inline int
75b89a82 51keyncmp(const char *str, const char *key, int n)
14c7c974
A
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
75b89a82 81static void eatThru(char val, const char **table_p)
14c7c974 82{
75b89a82 83 register const char *table = *table_p;
14c7c974
A
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
57c72a9a
A
98#if UNUSED
99
14c7c974
A
100/* Remove key and its associated value from the table. */
101
102BOOL
103removeKeyFromTable(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;
134out:
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
146char *
147newStringFromList(
148 char **list,
149 int *size
150)
151{
152 char *begin = *list, *end;
153 char *newstr;
154 int newsize = *size;
f083c6c3 155 int bufsize;
14c7c974
A
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;
f083c6c3
A
168 bufsize = end - begin + 1;
169 newstr = malloc(bufsize);
170 strlcpy(newstr, begin, bufsize);
14c7c974
A
171 *list = end;
172 *size = newsize;
173 return newstr;
174}
175
57c72a9a
A
176#endif
177
14c7c974
A
178/*
179 * compress == compress escaped characters to one character
180 */
75b89a82 181int stringLength(const char *table, int compress)
14c7c974
A
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
f083c6c3 202BOOL getValueForConfigTableKey(const char *table, const char *key, const char **val, int *size)
14c7c974
A
203{
204 int keyLength;
75b89a82 205 const char *tableKey;
14c7c974 206
f083c6c3
A
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;
14c7c974 233
f083c6c3
A
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 }
14c7c974
A
260
261 return NO;
262}
263
57c72a9a
A
264#if UNUSED
265
14c7c974
A
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 */
271char *newStringForStringTableKey(
272 char *table,
273 char *key
274)
275{
75b89a82
A
276 const char *val;
277 char *newstr, *p;
14c7c974
A
278 int size;
279
f083c6c3 280 if (getValueForConfigTableKey(table, key, &val, &size)) {
75b89a82 281 newstr = (char *)malloc(size+1);
14c7c974
A
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
57c72a9a
A
308#endif
309
14c7c974
A
310char *
311newStringForKey(char *key)
312{
75b89a82
A
313 const char *val;
314 char *newstr;
14c7c974
A
315 int size;
316
317 if (getValueForKey(key, &val, &size) && size) {
75b89a82 318 newstr = (char *)malloc(size + 1);
f083c6c3 319 strlcpy(newstr, val, size + 1);
14c7c974
A
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
75b89a82 332static const char *getToken(const char *line, const char **begin, int *len)
14c7c974
A
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
75b89a82 348BOOL getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
14c7c974 349{
75b89a82 350 const char *key, *value;
14c7c974 351 int key_len, value_len;
57c72a9a 352 BOOL retval = NO;
14c7c974
A
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;
57c72a9a
A
371 retval = YES;
372 /* Continue to look for this key; last one wins. */
14c7c974
A
373 }
374 }
57c72a9a 375 return retval;
14c7c974
A
376}
377
57c72a9a
A
378/* Returns TRUE if a value was found, FALSE otherwise.
379 * The boolean value of the key is stored in 'val'.
380 */
14c7c974 381BOOL getBoolForKey(
57c72a9a
A
382 const char *key,
383 BOOL *result_val
14c7c974
A
384)
385{
57c72a9a 386 const char *key_val;
14c7c974
A
387 int size;
388
57c72a9a
A
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 }
14c7c974
A
397 return NO;
398}
399
400BOOL getIntForKey(
75b89a82 401 const char *key,
14c7c974
A
402 int *value
403)
404{
75b89a82 405 const char *val;
14c7c974 406 int size, sum;
bba600dd 407 BOOL negative = NO;
14c7c974
A
408
409 if (getValueForKey(key, &val, &size)) {
bba600dd
A
410 if (*val == '-') {
411 negative = YES;
412 val++;
413 }
14c7c974 414 for (sum = 0; size > 0; size--) {
bba600dd 415 if (*val < '0' || *val > '9') return NO;
14c7c974
A
416 sum = (sum * 10) + (*val++ - '0');
417 }
bba600dd 418 if (negative) sum = -sum;
14c7c974
A
419 *value = sum;
420 return YES;
421 }
422 return NO;
423}
424
425BOOL getValueForKey(
75b89a82
A
426 const char *key,
427 const char **val,
14c7c974
A
428 int *size
429)
430{
bba600dd 431 if (getValueForBootKey(bootArgs->CommandLine, key, val, size))
14c7c974 432 return YES;
bba600dd 433 else if (getValueForConfigTableKey(bootInfo->config, key, val, size))
14c7c974
A
434 return YES;
435
436 return NO;
437}
438
14c7c974
A
439int sysConfigValid;
440
14c7c974
A
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 */
450int
57c72a9a 451loadConfigFile(const char *configFile)
14c7c974 452{
bba600dd 453 char *configPtr = bootInfo->config;
14c7c974
A
454 int fd, count;
455
456 /* Read config file into memory */
457 if ((fd = open(configFile, 0)) >= 0)
458 {
bba600dd 459 if ((configPtr - bootInfo->config) > CONFIG_SIZE) {
57c72a9a
A
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
14c7c974
A
466 count = read(fd, configPtr, IO_CONFIG_DATA_SIZE);
467 close(fd);
468
469 configPtr += count;
470 *configPtr++ = 0;
471 *configPtr = 0;
57c72a9a 472
bba600dd 473 bootInfo->configEnd = configPtr;
14c7c974
A
474
475 return 0;
476 } else {
477 return -1;
478 }
479}
480
14c7c974
A
481#define LP '('
482#define RP ')'
483
f083c6c3
A
484#define SYSTEM_CONFIG_DIR "/Library/Preferences/SystemConfiguration"
485#define SYSTEM_CONFIG_FILE "/com.apple.Boot.plist"
57c72a9a 486#define LRE_CONFIG_FILE "/com.apple.lre.Boot.plist"
f083c6c3
A
487#define SYSTEM_CONFIG_PATH SYSTEM_CONFIG_DIR SYSTEM_CONFIG_FILE
488#define CONFIG_EXT ".plist"
489
57c72a9a 490#if UNUSED
f083c6c3
A
491void
492printSystemConfig(void)
493{
bba600dd 494 char *p1 = bootInfo->config;
f083c6c3
A
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
f083c6c3
A
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).
57c72a9a 516// Prints an error message if there is a parsing error.
f083c6c3
A
517//
518static long
519ParseXMLFile( 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) {
57c72a9a 543 error ("Error parsing plist file");
f083c6c3
A
544 return -1;
545 }
546 *dict = tag;
547 return 0;
548}
549
14c7c974
A
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 */
555int
556loadSystemConfig(
75b89a82 557 const char *which,
14c7c974
A
558 int size
559)
560{
75b89a82
A
561 char *buf, *bp;
562 const char *cp;
14c7c974 563 int ret, len, doDefault=0;
14c7c974 564
f083c6c3
A
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 */
57c72a9a 571 strlcpy(buf,which,cp - which + 1);
f083c6c3
A
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 {
57c72a9a 585 strlcpy(bp, cp, len + 1);
f083c6c3
A
586 }
587 if ((strcmp(bp, SYSTEM_CONFIG_PATH) == 0)) {
588 doDefault = 1;
589 }
57c72a9a
A
590 bp = buf;
591 ret = loadConfigFile(bp);
14c7c974 592 } else {
57c72a9a 593 /* First try LRE file */
f083c6c3 594 strcpy(bp, systemConfigDir());
57c72a9a
A
595 strcat(bp, LRE_CONFIG_FILE);
596 ret = loadConfigFile(bp);
597
f083c6c3 598 if (ret < 0) {
57c72a9a
A
599 /* If not found, try default file */
600 strcpy(bp, systemConfigDir());
601 strcat(bp, SYSTEM_CONFIG_FILE);
602 ret = loadConfigFile(bp);
f083c6c3
A
603 }
604 }
14c7c974
A
605 if (ret < 0) {
606 error("System config file '%s' not found\n", bp);
f083c6c3
A
607 sleep(1);
608 } else {
14c7c974 609 sysConfigValid = 1;
f083c6c3
A
610 // Check for XML file;
611 // if not XML, gConfigDict will remain 0.
bba600dd 612 ParseXMLFile(bootInfo->config, &gConfigDict);
f083c6c3 613 }
14c7c974
A
614 free(buf);
615 return (ret < 0 ? ret : doDefault);
616}
617
14c7c974 618
f083c6c3
A
619char * newString(const char * oldString)
620{
621 if ( oldString )
622 return strcpy(malloc(strlen(oldString)+1), oldString);
623 else
624 return NULL;
14c7c974 625}