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

Archive Download this file

Revision: 1931