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 }
543
544 return ret;
545}
546
547
548#if UNUSED
549void
550printSystemConfig(char *p1)
551{
552 char *p2 = p1, tmp;
553
554 while (*p1 != '\0') {
555while (*p2 != '\0' && *p2 != '\n') p2++;
556tmp = *p2;
557*p2 = '\0';
558printf("%s\n", p1);
559*p2 = tmp;
560if (tmp == '\0') break;
561p1 = ++p2;
562 }
563}
564#endif
565
566//==========================================================================
567// ParseXMLFile
568// Modifies the input buffer.
569// Expects to see one dictionary in the XML file.
570// Puts the first dictionary it finds in the
571// tag pointer and returns 0, or returns -1 if not found
572// (and does not modify dict pointer).
573// Prints an error message if there is a parsing error.
574//
575int ParseXMLFile( char * buffer, TagPtr * dict )
576{
577 long length, pos;
578 TagPtr tag;
579 pos = 0;
580 char *configBuffer;
581
582 configBuffer = malloc(strlen(buffer)+1);
583 if (!configBuffer) {
584 return -1;
585 }
586
587 strcpy(configBuffer, buffer);
588
589 while (1)
590 {
591 length = XMLParseNextTag(configBuffer + pos, &tag);
592 if (length == -1) break;
593
594 pos += length;
595
596 if (tag == 0) continue;
597 if (tag->type == kTagTypeDict) break;
598
599 XMLFreeTag(tag);
600 }
601 free(configBuffer);
602 if (length < 0) {
603 error ("Error parsing plist file\n");
604 return -1;
605 }
606 *dict = tag;
607 return 0;
608}
609
610/* loadConfigFile
611 *
612 * Returns 0 - successful.
613 * -1 - unsuccesful.
614 */
615int loadConfigFile (const char *configFile, config_file_t *config)
616{
617int fd, count, fixedsize;
618
619 ASSERT_CONFIG
620
621if ((fd = open(configFile)) < 0) {
622return -1;
623}
624
625 fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
626
627// read file
628count = read(fd, config->plist, fixedsize);
629close(fd);
630 if (count != fixedsize) return -1;
631
632// build xml dictionary
633return ParseXMLFile(config->plist, &config->dictionary);
634}
635
636/* loadBooterConfig
637 *
638 * Returns 0 - successful.
639 * -1 - unsuccesful.
640 */
641int loadBooterConfig(void)
642{
643char *dirspec[] = {
644"rd(0,0)/Extra/com.apple.Boot.plist",
645"/Extra/com.apple.Boot.plist",
646"bt(0,0)/Extra/com.apple.Boot.plist",
647"rd(0,0)/Extra/org.chameleon.Boot.plist", // Add compatibility with the trunk
648"/Extra/org.chameleon.Boot.plist", // Add compatibility with the trunk
649"bt(0,0)/Extra/org.chameleon.Boot.plist" // Add compatibility with the trunk
650
651};
652
653 config_file_t *config = &bootInfo->bootConfig;
654
655int i, fd, count, ret=-1, fixedsize;
656
657for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
658{
659if ((fd = open(dirspec[i])) >= 0)
660{
661// read file
662 fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
663count = read(fd, config->plist, fixedsize);
664close(fd);
665 if (count != fixedsize) continue;
666
667// build xml dictionary
668ParseXMLFile(config->plist, &config->dictionary);
669 safe_set_env(envSysConfigValid,true);
670ret=0;
671
672// enable canOverride flag
673config->canOverride = true;
674
675break;
676}
677}
678#ifdef BOOT_HELPER_SUPPORT
679if(ret == -1)
680{
681ret = loadHelperConfig();
682}
683#endif
684
685return ret;
686}
687
688/* loadOverrideConfig
689 *
690 * Returns 0 - successful.
691 * -1 - unsuccesful.
692 */
693int loadOverrideConfig(void)
694{
695char *dirspec[] = {
696"/Extra/com.apple.Boot.plist",
697"/Extra/org.chameleon.Boot.plist"
698};
699
700 config_file_t *config = &bootInfo->overrideConfig;
701
702
703int i, fd, count, ret=-1, fixedsize;
704
705for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
706{
707if ((fd = open(dirspec[i])) >= 0)
708{
709// read file
710fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
711count = read(fd, config->plist, fixedsize);
712close(fd);
713 if (count != fixedsize) continue;
714
715// build xml dictionary
716ParseXMLFile(config->plist, &config->dictionary);
717 safe_set_env(envSysConfigValid,true);
718ret=0;
719break;
720}
721}
722#ifdef BOOT_HELPER_SUPPORT
723if(ret == -1)
724{
725ret = loadHelperConfig();
726}
727#endif
728
729return ret;
730}
731
732/* loadSystemConfig
733 *
734 * Returns 0 - successful.
735 * -1 - unsuccesful.
736 */
737int loadSystemConfig(void)
738{
739char *dirspec[] = {
740 "rd(0,0)/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
741"/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
742"bt(0,0)/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
743 "rd(0,0)/OS X Install Data/com.apple.Boot.plist",
744"/OS X Install Data/com.apple.Boot.plist",
745"bt(0,0)/OS X Install Data/com.apple.Boot.plist",
746 "rd(0,0)/Mac OS X Install Data/com.apple.Boot.plist",
747"/Mac OS X Install Data/com.apple.Boot.plist",
748"bt(0,0)/Mac OS X Install Data/com.apple.Boot.plist"
749};
750
751 config_file_t *config = &bootInfo->SystemConfig;
752
753
754int i, fd, count, ret=-1, fixedsize;
755
756for(i = 0; (unsigned)i< sizeof(dirspec)/sizeof(dirspec[0]); i++)
757{
758if ((fd = open(dirspec[i])) >= 0)
759{
760// read file
761fixedsize = MIN(file_size(fd),IO_CONFIG_DATA_SIZE);
762count = read(fd, config->plist, fixedsize);
763close(fd);
764 if (count != fixedsize) continue;
765
766// build xml dictionary
767ParseXMLFile(config->plist, &config->dictionary);
768 safe_set_env(envSysConfigValid,true);
769ret=0;
770break;
771}
772}
773
774return ret;
775}
776
777#ifdef BOOT_HELPER_SUPPORT
778
779/* loadHelperConfig
780 *
781 * Returns 0 - successful.
782 * -1 - unsuccesful.
783 */
784int loadHelperConfig(void)
785{
786int rfd, pfd, sfd, count, ret=-1, fixedsize;
787
788char *dirspec[] = {
789"/com.apple.boot.P/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
790"/com.apple.boot.R/Library/Preferences/SystemConfiguration/com.apple.Boot.plist",
791"/com.apple.boot.S/Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
792};
793
794 config_file_t *config = &bootInfo->helperConfig;
795
796
797// This is a simple rock - paper scissors algo. R beats S, P beats R, S beats P
798// If all three, S is used for now. This should be change dto something else (say, timestamp?)
799
800pfd = open(dirspec[0]);
801if(pfd >= 0)// com.apple.boot.P exists
802{
803sfd = open(dirspec[2]); // com.apple.boot.S takes precidence if it also exists
804if(sfd >= 0)
805{
806// Use sfd
807 fixedsize = MIN(file_size(sfd),IO_CONFIG_DATA_SIZE);
808count = read(sfd, config->plist, fixedsize);
809close(sfd);
810close(pfd);
811 if (count != fixedsize) return -1;
812
813// build xml dictionary
814ParseXMLFile(config->plist, &config->dictionary);
815 safe_set_env(envSysConfigValid,true);
816ret=0;
817
818}
819else
820{
821// used pfd
822 fixedsize = MIN(file_size(pfd),IO_CONFIG_DATA_SIZE);
823count = read(pfd, config->plist, fixedsize);
824close(pfd);
825 if (count != fixedsize) return -1;
826
827// build xml dictionary
828ParseXMLFile(config->plist, &config->dictionary);
829 safe_set_env(envSysConfigValid,true);
830ret=0;
831}
832
833}
834else
835{
836rfd = open(dirspec[1]); // com.apple.boot.R exists
837if(rfd >= 0)
838{
839pfd = open(dirspec[2]); // com.apple.boot.P takes recidence if it exists
840if(pfd >= 0)
841{
842// use sfd
843 fixedsize = MIN(file_size(pfd),IO_CONFIG_DATA_SIZE);
844count = read(pfd, config->plist, fixedsize);
845close(pfd);
846close(rfd);
847 if (count != fixedsize) return -1;
848
849// build xml dictionary
850ParseXMLFile(config->plist, &config->dictionary);
851 safe_set_env(envSysConfigValid,true);
852ret=0;
853
854}
855else
856{
857// use rfd
858 fixedsize = MIN(file_size(rfd),IO_CONFIG_DATA_SIZE);
859count = read(rfd, config->plist, fixedsize);
860close(rfd);
861 if (count != fixedsize) return -1;
862
863// build xml dictionary
864ParseXMLFile(config->plist, &config->dictionary);
865 safe_set_env(envSysConfigValid,true);
866ret=0;
867
868}
869
870}
871else
872{
873sfd = open(dirspec[2]); // com.apple.boot.S exists, but nothing else does
874if(sfd >= 0)
875{
876// use sfd
877 fixedsize = MIN(file_size(sfd),IO_CONFIG_DATA_SIZE);
878count = read(sfd, config->plist, fixedsize);
879close(sfd);
880 if (count != fixedsize) return -1;
881
882// build xml dictionary
883ParseXMLFile(config->plist, &config->dictionary);
884 safe_set_env(envSysConfigValid,true);
885ret=0;
886
887}
888}
889
890}
891
892return ret;
893}
894#endif
895
896static char * AllocInitStringWithLength(const char * oldString, int len)
897{
898char *Buf = NULL;
899Buf = malloc(len);
900if (Buf == NULL) return NULL;
901
902if (oldString != NULL)
903strlcpy(Buf, oldString,len);
904
905return Buf;
906}
907
908static char * AllocInitZeroEndedStringWithLength(const char * oldString, int len)
909{
910if (len > 0)
911{
912return AllocInitStringWithLength( oldString, len + 1);
913}
914return NULL;
915}
916
917char * newString(const char * oldString)
918{
919 if ( oldString )
920{
921int len = strlen(oldString);
922
923if (len > 0)
924{
925return AllocInitZeroEndedStringWithLength(oldString, len);
926}
927}
928 return NULL;
929}
930
931char * newStringWithLength(const char * oldString, int len)
932{
933if (len > 0)
934{
935return AllocInitZeroEndedStringWithLength(oldString, len);
936}
937 return NULL;
938}
939
940char * newEmptyStringWithLength(int len)
941{
942if (len > 0)
943{
944return AllocInitZeroEndedStringWithLength(NULL, len);
945}
946 return NULL;
947}
948
949/*
950 * Extracts the next argument from the command line, double quotes are allowed here.
951 */
952char * getNextArg(char ** argPtr, char * val)
953{
954char * ptr = *argPtr;
955const char * strStart;
956int len = 0;
957bool isQuoted = false;
958
959*val = '\0';
960
961// Scan for the next non-whitespace character.
962while ( *ptr && (*ptr == ' ' || *ptr == '=') )
963{
964ptr++;
965}
966
967strStart = ptr;
968
969// Skip the leading double quote character.
970if (*ptr == '\"')
971{
972isQuoted = true;
973ptr++;
974strStart++;
975}
976
977// Scan for the argument terminator character.
978// This can be either a NULL character - in case we reach the end of the string,
979// a double quote in case of quoted argument,
980// or a whitespace character (' ' or '=') for non-quoted argument.
981while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
982 (!isQuoted && (*ptr == ' ' || *ptr == '=')) )
983 )
984{
985ptr++;
986}
987
988len = ptr - strStart;
989
990// Skip the closing double quote character and adjust
991// the starting pointer for the next getNextArg call.
992if (*ptr && isQuoted && *ptr == '\"')
993ptr++;
994
995// Copy the extracted argument to val.
996strncat(val, strStart, len);
997
998// Set command line pointer.
999*argPtr = ptr;
1000
1001return ptr;
1002}
1003

Archive Download this file

Revision: 1919