]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/stringTable.c
65ef09ec8a1f73cd6422e1055a5f1c87ec48d017
[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
408 if (getValueForKey(key, &val, &size)) {
409 for (sum = 0; size > 0; size--) {
410 sum = (sum * 10) + (*val++ - '0');
411 }
412 *value = sum;
413 return YES;
414 }
415 return NO;
416 }
417
418 BOOL getValueForKey(
419 const char *key,
420 const char **val,
421 int *size
422 )
423 {
424 if (getValueForBootKey(bootArgs->bootString, key, val, size))
425 return YES;
426 else if (getValueForConfigTableKey(bootArgs->config, key, val, size))
427 return YES;
428
429 return NO;
430 }
431
432 int sysConfigValid;
433
434 #define TABLE_EXPAND_SIZE 192
435
436 /*
437 * Returns 0 if file loaded OK,
438 * -1 if file was not loaded
439 * Does not print error messages.
440 * Returns pointer to table in memory in *table.
441 * Allocates an extra number of bytes for table expansion.
442 */
443 int
444 loadConfigFile(const char *configFile)
445 {
446 char *configPtr = bootArgs->config;
447 int fd, count;
448
449 /* Read config file into memory */
450 if ((fd = open(configFile, 0)) >= 0)
451 {
452 if ((configPtr - bootArgs->config) > CONFIG_SIZE) {
453 error("No room in memory for config files\n");
454 close(fd);
455 return -1;
456 }
457 verbose("Reading configuration file '%s'.\n",configFile);
458
459 count = read(fd, configPtr, IO_CONFIG_DATA_SIZE);
460 close(fd);
461
462 configPtr += count;
463 *configPtr++ = 0;
464 *configPtr = 0;
465
466 bootArgs->configEnd = configPtr;
467
468 return 0;
469 } else {
470 return -1;
471 }
472 }
473
474 #define LP '('
475 #define RP ')'
476
477 #define SYSTEM_CONFIG_DIR "/Library/Preferences/SystemConfiguration"
478 #define SYSTEM_CONFIG_FILE "/com.apple.Boot.plist"
479 #define LRE_CONFIG_FILE "/com.apple.lre.Boot.plist"
480 #define SYSTEM_CONFIG_PATH SYSTEM_CONFIG_DIR SYSTEM_CONFIG_FILE
481 #define CONFIG_EXT ".plist"
482
483 #if UNUSED
484 void
485 printSystemConfig(void)
486 {
487 char *p1 = bootArgs->config;
488 char *p2 = p1, tmp;
489
490 while (*p1 != '\0') {
491 while (*p2 != '\0' && *p2 != '\n') p2++;
492 tmp = *p2;
493 *p2 = '\0';
494 printf("%s\n", p1);
495 *p2 = tmp;
496 if (tmp == '\0') break;
497 p1 = ++p2;
498 }
499 }
500 #endif
501
502 //==========================================================================
503 // ParseXMLFile
504 // Modifies the input buffer.
505 // Expects to see one dictionary in the XML file.
506 // Puts the first dictionary it finds in the
507 // tag pointer and returns 0, or returns -1 if not found
508 // (and does not modify dict pointer).
509 // Prints an error message if there is a parsing error.
510 //
511 static long
512 ParseXMLFile( char * buffer, TagPtr * dict )
513 {
514 long length, pos;
515 TagPtr tag;
516 pos = 0;
517 char *configBuffer;
518
519 configBuffer = malloc(strlen(buffer)+1);
520 strcpy(configBuffer, buffer);
521
522 while (1)
523 {
524 length = XMLParseNextTag(configBuffer + pos, &tag);
525 if (length == -1) break;
526
527 pos += length;
528
529 if (tag == 0) continue;
530 if (tag->type == kTagTypeDict) break;
531
532 XMLFreeTag(tag);
533 }
534 free(configBuffer);
535 if (length < 0) {
536 error ("Error parsing plist file");
537 return -1;
538 }
539 *dict = tag;
540 return 0;
541 }
542
543 /* Returns 0 if requested config files were loaded,
544 * 1 if default files were loaded,
545 * -1 if no files were loaded.
546 * Prints error message if files cannot be loaded.
547 */
548 int
549 loadSystemConfig(
550 const char *which,
551 int size
552 )
553 {
554 char *buf, *bp;
555 const char *cp;
556 int ret, len, doDefault=0;
557
558 buf = bp = malloc(512);
559 if (which && size) {
560 for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ;
561 if (*cp == LP) {
562 while (len-- && *cp && *cp++ != RP) ;
563 /* cp now points past device */
564 strlcpy(buf,which,cp - which + 1);
565 bp += cp - which;
566 } else {
567 cp = which;
568 len = size;
569 }
570 if (*cp != '/') {
571 strcpy(bp, systemConfigDir());
572 strcat(bp, "/");
573 strncat(bp, cp, len);
574 if (strncmp(cp + len - strlen(CONFIG_EXT),
575 CONFIG_EXT, strlen(CONFIG_EXT)) != 0)
576 strcat(bp, CONFIG_EXT);
577 } else {
578 strlcpy(bp, cp, len + 1);
579 }
580 if ((strcmp(bp, SYSTEM_CONFIG_PATH) == 0)) {
581 doDefault = 1;
582 }
583 bp = buf;
584 ret = loadConfigFile(bp);
585 } else {
586 /* First try LRE file */
587 strcpy(bp, systemConfigDir());
588 strcat(bp, LRE_CONFIG_FILE);
589 ret = loadConfigFile(bp);
590
591 if (ret < 0) {
592 /* If not found, try default file */
593 strcpy(bp, systemConfigDir());
594 strcat(bp, SYSTEM_CONFIG_FILE);
595 ret = loadConfigFile(bp);
596 }
597 }
598 if (ret < 0) {
599 error("System config file '%s' not found\n", bp);
600 sleep(1);
601 } else {
602 sysConfigValid = 1;
603 // Check for XML file;
604 // if not XML, gConfigDict will remain 0.
605 ParseXMLFile(bootArgs->config, &gConfigDict);
606 }
607 free(buf);
608 return (ret < 0 ? ret : doDefault);
609 }
610
611
612 char * newString(const char * oldString)
613 {
614 if ( oldString )
615 return strcpy(malloc(strlen(oldString)+1), oldString);
616 else
617 return NULL;
618 }