Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/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 "libsaio.h"
30#include "bootstruct.h"
31#include "platform.h"
32#include "xml.h"
33
34static char * AllocInitStringWithLength(const char * oldString, int len);
35static char * AllocInitZeroEndedStringWithLength(const char * oldString, int len);
36
37#ifndef MIN
38#define MIN(x, y) ((x) < (y) ? (x) : (y))
39#endif
40
41#define ASSERT_CONFIG \
42if (config == DEFAULT_BOOT_CONFIG) \
43config = &bootInfo->bootConfig ; \
44else if (config == DEFAULT_SYSTEM_CONFIG) \
45config = &bootInfo->SystemConfig ; \
46else if (config == DEFAULT_OVERRIDE_CONFIG) \
47config = &bootInfo->overrideConfig ; \
48else if (config == DEFAULT_SMBIOS_CONFIG) \
49config = &bootInfo->smbiosConfig ; \
50else if (config == DEFAULT_HELPER_CONFIG) \
51config = &bootInfo->helperConfig ;
52
53#if UNUSED
54/*
55 * Compare a string to a key with quoted characters
56 */
57static inline int
58keyncmp(const char *str, const char *key, int n)
59{
60 int c;
61 while (n--) {
62c = *key++;
63if (c == '\\') {
64switch(c = *key++) {
65case 'n':
66c = '\n';
67break;
68case 'r':
69c = '\r';
70break;
71case 't':
72c = '\t';
73break;
74default:
75break;
76}
77} else if (c == '\"') {
78/* Premature end of key */
79return 1;
80}
81if (c != *str++) {
82return 1;
83}
84 }
85 return 0;
86}
87
88static void eatThru(char val, const char **table_p)
89{
90register const char *table = *table_p;
91register bool found = false;
92
93while (*table && !found)
94{
95if (*table == '\\') table += 2;
96else
97{
98if (*table == val) found = true;
99table++;
100}
101}
102*table_p = table;
103}
104
105/* Remove key and its associated value from the table. */
106
107bool
108removeKeyFromTable(const char *key, char *table)
109{
110 register int len;
111 register char *tab;
112 char *buf;
113
114 len = strlen(key);
115 tab = (char *)table;
116 buf = (char *)calloc(len + 3, sizeof(char));
117if (!buf) {
118 return false;
119 }
120 snprintf(buf, len + 3,"\"%s\"", key);
121 len = strlen(buf);
122
123 while(*tab) {
124 if(strncmp(buf, tab, len) == 0) {
125 char c;
126
127 while((c = *(tab + len)) != ';') {
128 if(c == 0) {
129 len = -1;
130 goto out;
131 }
132 len++;
133 }
134 len++;
135 if(*(tab + len) == '\n') len++;
136 goto out;
137 }
138 tab++;
139 }
140 len = -1;
141out:
142 free(buf);
143
144 if(len == -1) return false;
145
146 while((*tab = *(tab + len))) {
147 tab++;
148 }
149
150 return true;
151}
152
153char *
154newStringFromList(
155 char **list,
156 int *size
157 )
158{
159 char *begin = *list, *end;
160 char *newstr;
161 int newsize = *size;
162 int bufsize;
163
164 while (*begin && newsize && isspace(*begin)) {
165begin++;
166newsize--;
167 }
168 end = begin;
169 while (*end && newsize && !isspace(*end)) {
170end++;
171newsize--;
172 }
173 if (begin == end)
174return 0;
175 bufsize = end - begin + 1;
176 newstr = calloc(bufsize, sizeof(char));
177 if (!newstr) {
178 return 0;
179 }
180 strlcpy(newstr, begin, bufsize);
181 *list = end;
182 *size = newsize;
183 return newstr;
184}
185
186/*
187 * compress == compress escaped characters to one character
188 */
189int stringLength(const char *table, int compress)
190{
191int ret = 0;
192
193while (*table)
194{
195if (*table == '\\')
196{
197table += 2;
198ret += 1 + (compress ? 0 : 1);
199}
200else
201{
202if (*table == '\"') return ret;
203ret++;
204table++;
205}
206}
207return ret;
208}
209#endif
210
211bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)
212{
213 ASSERT_CONFIG
214
215if (config->dictionary != 0 ) {
216// Look up key in XML dictionary
217TagPtr value;
218value = XMLGetProperty(config->dictionary, key);
219if (value != 0) {
220if (value->type != kTagTypeString) {
221error("Non-string tag '%s' found in config file\n",
222 key);
223return false;
224}
225*val = value->string;
226*size = strlen(value->string);
227return true;
228}
229} else {
230
231// Legacy plist-style table
232
233}
234
235return false;
236}
237
238#if UNUSED
239
240/*
241 * Returns a new malloc'ed string if one is found
242 * in the string table matching 'key'. Also translates
243 * \n escapes in the string.
244 */
245char *newStringForStringTableKey(
246 char *table,
247 char *key,
248 config_file_t *config
249 )
250{
251 const char *val;
252 char *newstr, *p;
253 int size;
254
255 ASSERT_CONFIG
256
257 if (getValueForConfigTableKey(config, key, &val, &size)) {
258newstr = (char *)calloc(size+1,sizeof(char));
259 if (!newstr) {
260 return 0;
261 }
262for (p = newstr; size; size--, p++, val++) {
263if ((*p = *val) == '\\') {
264switch (*++val) {
265case 'r':
266*p = '\r';
267break;
268case 'n':
269*p = '\n';
270break;
271case 't':
272*p = '\t';
273break;
274default:
275*p = *val;
276break;
277}
278size--;
279}
280}
281*p = '\0';
282return newstr;
283 } else {
284return 0;
285 }
286}
287
288#endif
289
290char *
291newStringForKey(char *key, config_file_t *config)
292{
293 const char *val;
294 char *newstr;
295 int size;
296
297 ASSERT_CONFIG
298
299 if (getValueForKey(key, &val, &size, config) && size) {
300newstr = (char *)calloc(size + 1, sizeof(char));
301 if (!newstr) {
302 return 0;
303 }
304strlcpy(newstr, val, size + 1);
305return newstr;
306 } else {
307return 0;
308 }
309}
310
311/* parse a command line
312 * in the form: [<argument> ...] [<option>=<value> ...]
313 * both <option> and <value> must be either composed of
314 * non-whitespace characters, or enclosed in quotes.
315 */
316
317static const char *getToken(const char *line, const char **begin, int *len)
318{
319 if (*line == '\"') {
320*begin = ++line;
321while (*line && *line != '\"')
322line++;
323*len = line++ - *begin;
324 } else {
325*begin = line;
326while (*line && !isspace(*line) && *line != '=')
327line++;
328*len = line - *begin;
329 }
330 return line;
331}
332
333bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
334{
335 const char *key, *value;
336 int key_len, value_len;
337 bool retval = false;
338
339 while (*line) {
340/* look for keyword or argument */
341while (isspace(*line)) line++;
342
343/* now look for '=' or whitespace */
344line = getToken(line, &key, &key_len);
345/* line now points to '=' or space */
346if (*line && !isspace(*line)) {
347line = getToken(++line, &value, &value_len);
348} else {
349value = line;
350value_len = 0;
351}
352if ((strlen(match) == key_len)
353&& strncmp(match, key, key_len) == 0) {
354*matchval = value;
355*len = value_len;
356retval = true;
357 /* Continue to look for this key; last one wins. */
358}
359 }
360 return retval;
361}
362
363/* Return NULL if no option has been successfully retrieved, or the string otherwise */
364const char * getStringForKey(const char * key, config_file_t *config)
365{
366static const char* value =0;
367int len=0;
368
369 ASSERT_CONFIG
370
371if(!getValueForKey(key, &value, &len, config)) value = 0;
372return value;
373}
374
375
376/* Returns TRUE if a value was found, FALSE otherwise.
377 * The boolean value of the key is stored in 'val'.
378 */
379
380bool getBoolForKey( const char *key, bool *result_val, config_file_t *config )
381{
382 const char *key_val;
383 int size;
384
385 ASSERT_CONFIG
386
387 if (getValueForKey(key, &key_val, &size, config)) {
388 if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {
389 *result_val = true;
390 } else {
391 *result_val = false;
392 }
393 return true;
394 }
395 return false;
396}
397
398bool getIntForKey( const char *key, int *value, config_file_t *config )
399{
400 const char *val;
401 int size, sum;
402 bool negative = false;
403
404 ASSERT_CONFIG
405
406 if (getValueForKey(key, &val, &size, config))
407{
408if ( size )
409{
410if (*val == '-')
411{
412negative = true;
413val++;
414size--;
415}
416
417for (sum = 0; size > 0; size--)
418{
419if (*val < '0' || *val > '9')
420return false;
421
422sum = (sum * 10) + (*val++ - '0');
423}
424
425if (negative)
426sum = -sum;
427
428*value = sum;
429return true;
430}
431}
432 return false;
433}
434
435config_file_t *resolveConfig(config_file_t *config)
436{
437ASSERT_CONFIG
438config_file_t *new_config = config;
439return new_config;
440}
441#if UNUSED
442/*
443 *
444 */
445
446bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
447{
448const char *val;
449
450 int size = 0;
451int sum = 0;
452
453bool negative = false;
454bool percentage = false;
455
456 ASSERT_CONFIG
457
458 if (getValueForKey(key, &val, &size, config))
459{
460if ( size )
461{
462if (*val == '-')
463{
464negative = true;
465val++;
466size--;
467}
468
469if (val[size-1] == '%')
470{
471percentage = true;
472size--;
473}
474
475// convert string to integer
476for (sum = 0; size > 0; size--)
477{
478if (*val < '0' || *val > '9')
479return false;
480
481sum = (sum * 10) + (*val++ - '0');
482}
483
484if (percentage)
485sum = ( dimension_max * sum ) / 100;
486
487// calculate offset from opposite origin
488if (negative)
489sum = ( ( dimension_max - object_size ) - sum );
490
491} else {
492
493// null value calculate center
494sum = ( dimension_max - object_size ) / 2;
495
496}
497
498*value = (uint16_t) sum;
499return true;
500}
501
502// key not found
503 return false;
504}
505
506/*
507 *get color value from plist format #RRGGBB
508 */
509
510bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
511{
512 const char *val;
513 int size;
514
515 ASSERT_CONFIG
516
517 if (getValueForKey(key, &val, &size, config))
518{
519if (*val == '#')
520{
521 val++;
522*value = strtol(val, NULL, 16);
523return true;
524 }
525 }
526 return false;
527}
528#endif
529
530bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
531{
532 const char *overrideVal;
533 int overrideSize;
534 bool ret;
535
536 if (getValueForBootKey(bootArgs->CommandLine, key, val, size))
537 return true;
538
539 ASSERT_CONFIG
540
541 ret = getValueForConfigTableKey(config, key, val, size);
542
543 // Try to find alternate keys in bootInfo->overrideConfig
544 // and prefer its values with the exceptions for
545 // "Kernel"="mach_kernel" and "Kernel Flags"="".
546
547 if (config->canOverride)
548 {
549 if (getValueForConfigTableKey(&bootInfo->overrideConfig, key, &overrideVal, &overrideSize) && overrideSize)
550 {
551 *val = overrideVal;
552 *size = overrideSize;
553 return true;
554 }
555 else if (getValueForConfigTableKey(&bootInfo->SystemConfig, key, &overrideVal, &overrideSize) && overrideSize)
556 {
557 *val = overrideVal;
558 *size = overrideSize;
559 return true;
560 }
561 else if (getValueForConfigTableKey(&bootInfo->bootConfig, key, &overrideVal, &overrideSize) && overrideSize)
562 {
563 *val = overrideVal;
564 *size = overrideSize;
565 return true;
566 }
567 }
568
569 return ret;
570}
571
572
573#if UNUSED
574void
575printSystemConfig(char *p1)
576{
577 char *p2 = p1, tmp;
578
579 while (*p1 != '\0') {
580while (*p2 != '\0' && *p2 != '\n') p2++;
581tmp = *p2;
582*p2 = '\0';
583printf("%s\n", p1);
584*p2 = tmp;
585if (tmp == '\0') break;
586p1 = ++p2;
587 }
588}
589#endif
590
591//==========================================================================
592// ParseXMLFile
593// Modifies the input buffer.
594// Expects to see one dictionary in the XML file.
595// Puts the first dictionary it finds in the
596// tag pointer and returns 0, or returns -1 if not found
597// (and does not modify dict pointer).
598// Prints an error message if there is a parsing error.
599//
600int ParseXMLFile( char * buffer, TagPtr * dict )
601{
602 long length, pos;
603 TagPtr tag = 0;
604 pos = 0;
605 char *configBuffer;
606
607length = strlen(buffer) + 1;
608
609 configBuffer = (char*)calloc(length,sizeof(char));
610 if (!configBuffer) {
611 return -1;
612 }
613
614 strlcpy(configBuffer, buffer, length );
615
616 while (1)
617 {
618 length = XMLParseNextTag(configBuffer + pos, &tag);
619 if (length == -1) break;
620
621 pos += length;
622
623 if (tag == 0) continue;
624 if (tag->type == kTagTypeDict) break;
625
626 XMLFreeTag(tag);
627 }
628 free(configBuffer);
629 if (length < 0) {
630 error ("Error parsing plist file\n");
631 return -1;
632 }
633 *dict = tag;
634 return 0;
635}
636
637/* loadConfigFile
638 *
639 * Returns 0 - successful.
640 * -1 - unsuccesful.
641 */
642int loadConfigFile (const char *configFile, config_file_t *config)
643{
644int fd, count, fixedsize;
645
646 ASSERT_CONFIG
647
648if ((fd = open(configFile, 0)) < 0) {
649return -1;
650}
651
652 fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
653
654// read file
655count = read(fd, config->plist, fixedsize);
656close(fd);
657 if (count != fixedsize) return -1;
658
659// build xml dictionary
660return ParseXMLFile(config->plist, &config->dictionary);
661}
662
663/* loadBooterConfig
664 *
665 * Returns 0 - successful.
666 * -1 - unsuccesful.
667 */
668int loadBooterConfig(void)
669{
670char *dirspec[] = {
671"rd(0,0)/Extra/com.apple.Boot.plist",
672"/Extra/com.apple.Boot.plist",
673"bt(0,0)/Extra/com.apple.Boot.plist",
674"rd(0,0)/Extra/org.chameleon.Boot.plist", // Add compatibility with the trunk
675"/Extra/org.chameleon.Boot.plist", // Add compatibility with the trunk
676"bt(0,0)/Extra/org.chameleon.Boot.plist" // Add compatibility with the trunk
677
678};
679
680 config_file_t *config = &bootInfo->bootConfig;
681
682int i, fd, count, ret=-1, fixedsize;
683
684for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
685{
686if ((fd = open(dirspec[i], 0)) >= 0)
687{
688// read file
689 fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
690count = read(fd, config->plist, fixedsize);
691close(fd);
692 if (count != fixedsize) continue;
693
694// build xml dictionary
695ParseXMLFile(config->plist, &config->dictionary);
696 safe_set_env(envSysConfigValid,true);
697ret=0;
698
699// enable canOverride flag
700config->canOverride = true;
701
702break;
703}
704}
705#ifdef BOOT_HELPER_SUPPORT
706if(ret == -1)
707{
708ret = loadHelperConfig();
709}
710#endif
711
712return ret;
713}
714
715/* loadOverrideConfig
716 *
717 * Returns 0 - successful.
718 * -1 - unsuccesful.
719 */
720int loadOverrideConfig(void)
721{
722char *dirspec[] = {
723"/Extra/com.apple.Boot.plist",
724"/Extra/org.chameleon.Boot.plist"
725};
726
727 config_file_t *config = &bootInfo->overrideConfig;
728
729
730int i, fd, count, ret=-1, fixedsize;
731
732for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
733{
734if ((fd = open(dirspec[i], 0)) >= 0)
735{
736// read file
737fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
738count = read(fd, config->plist, fixedsize);
739close(fd);
740 if (count != fixedsize) continue;
741
742// build xml dictionary
743ParseXMLFile(config->plist, &config->dictionary);
744 safe_set_env(envSysConfigValid,true);
745ret=0;
746break;
747}
748}
749#ifdef BOOT_HELPER_SUPPORT
750if(ret == -1)
751{
752ret = loadHelperConfig();
753}
754#endif
755
756return ret;
757}
758
759/* loadSystemConfig
760 *
761 * Returns 0 - successful.
762 * -1 - unsuccesful.
763 */
764int loadSystemConfig(void)
765{
766char *dirspec[] = {
767 "rd(0,0)/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
768"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
769"bt(0,0)/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
770};
771
772char *dirspecInstall[] = {
773 "rd(0,0)/%s/com.apple.Boot.plist",
774"/%s/com.apple.Boot.plist",
775"bt(0,0)/%s/com.apple.Boot.plist"
776};
777char tmp[60];
778
779 config_file_t *config = &bootInfo->SystemConfig;
780
781
782int i, fd, count, fixedsize;
783
784for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
785{
786if ((fd = open(dirspec[i], 0)) >= 0)
787{
788// read file
789fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
790count = read(fd, config->plist, fixedsize);
791close(fd);
792 if (count != fixedsize) continue;
793
794// build xml dictionary
795ParseXMLFile(config->plist, &config->dictionary);
796 safe_set_env(envSysConfigValid,true);
797return 0;
798}
799}
800
801BVRef bvr = ((BVRef)(uint32_t)get_env(envgBootVolume));
802
803for(i = 0; (unsigned)i< sizeof(dirspecInstall)/sizeof(dirspecInstall[0]); i++)
804{
805snprintf(tmp, sizeof(tmp),dirspecInstall[i], bvr->OSInstall);
806
807if ((fd = open(tmp, 0)) >= 0)
808{
809// read file
810fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
811count = read(fd, config->plist, fixedsize);
812close(fd);
813 if (count != fixedsize) continue;
814
815// build xml dictionary
816ParseXMLFile(config->plist, &config->dictionary);
817 safe_set_env(envSysConfigValid,true);
818return 0;
819}
820}
821
822return -1;
823}
824
825#ifdef BOOT_HELPER_SUPPORT
826
827/* loadHelperConfig
828 *
829 * Returns 0 - successful.
830 * -1 - unsuccesful.
831 */
832int loadHelperConfig(void)
833{
834int rfd, pfd, sfd, count, ret=-1, fixedsize;
835
836char *dirspec[] = {
837"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
838"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
839"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
840};
841
842 config_file_t *config = &bootInfo->helperConfig;
843
844
845// This is a simple rock - paper scissors algo. R beats S, P beats R, S beats P
846// If all three, S is used for now. This should be change dto something else (say, timestamp?)
847
848pfd = open(dirspec[0], 0);
849if(pfd >= 0)// com.apple.boot.P exists
850{
851sfd = open(dirspec[2], 0); // com.apple.boot.S takes precidence if it also exists
852if(sfd >= 0)
853{
854// Use sfd
855 fixedsize = MIN(file_size(sfd),IO_CONFIG_DATA_SIZE);
856count = read(sfd, config->plist, fixedsize);
857close(sfd);
858close(pfd);
859 if (count != fixedsize) return -1;
860
861// build xml dictionary
862ParseXMLFile(config->plist, &config->dictionary);
863 safe_set_env(envSysConfigValid,true);
864ret=0;
865
866}
867else
868{
869// used pfd
870 fixedsize = MIN(file_size(pfd),IO_CONFIG_DATA_SIZE);
871count = read(pfd, config->plist, fixedsize);
872close(pfd);
873 if (count != fixedsize) return -1;
874
875// build xml dictionary
876ParseXMLFile(config->plist, &config->dictionary);
877 safe_set_env(envSysConfigValid,true);
878ret=0;
879}
880
881}
882else
883{
884rfd = open(dirspec[1], 0); // com.apple.boot.R exists
885if(rfd >= 0)
886{
887pfd = open(dirspec[2], 0); // com.apple.boot.P takes recidence if it exists
888if(pfd >= 0)
889{
890// use sfd
891 fixedsize = MIN(file_size(pfd),IO_CONFIG_DATA_SIZE);
892count = read(pfd, config->plist, fixedsize);
893close(pfd);
894close(rfd);
895 if (count != fixedsize) return -1;
896
897// build xml dictionary
898ParseXMLFile(config->plist, &config->dictionary);
899 safe_set_env(envSysConfigValid,true);
900ret=0;
901
902}
903else
904{
905// use rfd
906 fixedsize = MIN(file_size(rfd),IO_CONFIG_DATA_SIZE);
907count = read(rfd, config->plist, fixedsize);
908close(rfd);
909 if (count != fixedsize) return -1;
910
911// build xml dictionary
912ParseXMLFile(config->plist, &config->dictionary);
913 safe_set_env(envSysConfigValid,true);
914ret=0;
915
916}
917
918}
919else
920{
921sfd = open(dirspec[2], 0); // com.apple.boot.S exists, but nothing else does
922if(sfd >= 0)
923{
924// use sfd
925 fixedsize = MIN(file_size(sfd),IO_CONFIG_DATA_SIZE);
926count = read(sfd, config->plist, fixedsize);
927close(sfd);
928 if (count != fixedsize) return -1;
929
930// build xml dictionary
931ParseXMLFile(config->plist, &config->dictionary);
932 safe_set_env(envSysConfigValid,true);
933ret=0;
934
935}
936}
937
938}
939
940return ret;
941}
942#endif
943
944static char * AllocInitStringWithLength(const char * oldString, int len)
945{
946char *Buf = NULL;
947Buf = (char*)calloc(len,sizeof(char));
948if (Buf == NULL) return NULL;
949
950if (oldString != NULL)
951strlcpy(Buf, oldString,len);
952
953return Buf;
954}
955
956static char * AllocInitZeroEndedStringWithLength(const char * oldString, int len)
957{
958if (len > 0)
959{
960return AllocInitStringWithLength( oldString, len + 1);
961}
962return NULL;
963}
964
965char * newString(const char * oldString)
966{
967 if ( oldString )
968{
969int len = strlen(oldString);
970
971if (len > 0)
972{
973return AllocInitZeroEndedStringWithLength(oldString, len);
974}
975}
976 return NULL;
977}
978
979char * newStringWithLength(const char * oldString, int len)
980{
981if (len > 0)
982{
983return AllocInitZeroEndedStringWithLength(oldString, len);
984}
985 return NULL;
986}
987
988char * newEmptyStringWithLength(int len)
989{
990if (len > 0)
991{
992return AllocInitZeroEndedStringWithLength(NULL, len);
993}
994 return NULL;
995}
996
997/*
998 * Extracts the next argument from the command line, double quotes are allowed here.
999 */
1000char * getNextArg(char ** argPtr, char * val)
1001{
1002char * ptr = *argPtr;
1003const char * strStart;
1004int len = 0;
1005bool isQuoted = false;
1006
1007*val = '\0';
1008
1009// Scan for the next non-whitespace character.
1010while ( *ptr && (*ptr == ' ' || *ptr == '=') )
1011{
1012ptr++;
1013}
1014
1015strStart = ptr;
1016
1017// Skip the leading double quote character.
1018if (*ptr == '\"')
1019{
1020isQuoted = true;
1021ptr++;
1022strStart++;
1023}
1024
1025// Scan for the argument terminator character.
1026// This can be either a NULL character - in case we reach the end of the string,
1027// a double quote in case of quoted argument,
1028// or a whitespace character (' ' or '=') for non-quoted argument.
1029while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
1030 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
1031 )
1032{
1033ptr++;
1034}
1035
1036len = ptr - strStart;
1037
1038// Skip the closing double quote character and adjust
1039// the starting pointer for the next getNextArg call.
1040if (*ptr && isQuoted && *ptr == '\"')
1041ptr++;
1042
1043// Copy the extracted argument to val.
1044strncat(val, strStart, len);
1045
1046// Set command line pointer.
1047*argPtr = ptr;
1048
1049return ptr;
1050}
1051

Archive Download this file

Revision: HEAD