Root/
Source at commit 1075 created 13 years 1 month ago. By meklort, Disk code | |
---|---|
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 "xml.h"␊ |
31 | ␊ |
32 | extern char *Language;␊ |
33 | extern char *LoadableFamilies;␊ |
34 | ␊ |
35 | bool sysConfigValid;␊ |
36 | ␊ |
37 | /*␊ |
38 | * Compare a string to a key with quoted characters␊ |
39 | */␊ |
40 | static inline int␊ |
41 | keyncmp(const char *str, const char *key, int n)␊ |
42 | {␊ |
43 | int c;␊ |
44 | while (n--) {␊ |
45 | ␉c = *key++;␊ |
46 | ␉if (c == '\\') {␊ |
47 | ␉ switch(c = *key++) {␊ |
48 | ␉ case 'n':␊ |
49 | ␉␉c = '\n';␊ |
50 | ␉␉break;␊ |
51 | ␉ case 'r':␊ |
52 | ␉␉c = '\r';␊ |
53 | ␉␉break;␊ |
54 | ␉ case 't':␊ |
55 | ␉␉c = '\t';␊ |
56 | ␉␉break;␊ |
57 | ␉ default:␊ |
58 | ␉␉break;␊ |
59 | ␉ }␊ |
60 | ␉} else if (c == '\"') {␊ |
61 | ␉ /* Premature end of key */␊ |
62 | ␉ return 1;␊ |
63 | ␉}␊ |
64 | ␉if (c != *str++) {␊ |
65 | ␉ return 1;␊ |
66 | ␉}␊ |
67 | }␊ |
68 | return 0;␊ |
69 | }␊ |
70 | ␊ |
71 | #if UNUSED␊ |
72 | ␊ |
73 | static void eatThru(char val, const char **table_p)␊ |
74 | {␊ |
75 | ␉register const char *table = *table_p;␊ |
76 | ␉register bool found = false;␊ |
77 | ␊ |
78 | ␉while (*table && !found)␊ |
79 | ␉{␊ |
80 | ␉␉if (*table == '\\') table += 2;␊ |
81 | ␉␉else␊ |
82 | ␉␉{␊ |
83 | ␉␉␉if (*table == val) found = true;␊ |
84 | ␉␉␉table++;␊ |
85 | ␉␉}␊ |
86 | ␉}␊ |
87 | ␉*table_p = table;␊ |
88 | }␊ |
89 | ␊ |
90 | /* Remove key and its associated value from the table. */␊ |
91 | ␊ |
92 | bool␊ |
93 | removeKeyFromTable(const char *key, char *table)␊ |
94 | {␊ |
95 | register int len;␊ |
96 | register char *tab;␊ |
97 | char *buf;␊ |
98 | ␊ |
99 | len = strlen(key);␊ |
100 | tab = (char *)table;␊ |
101 | buf = (char *)malloc(len + 3);␊ |
102 | ␊ |
103 | sprintf(buf, "\"%s\"", key);␊ |
104 | len = strlen(buf);␊ |
105 | ␊ |
106 | while(*tab) {␊ |
107 | if(strncmp(buf, tab, len) == 0) {␊ |
108 | char c;␊ |
109 | ␊ |
110 | while((c = *(tab + len)) != ';') {␊ |
111 | if(c == 0) {␊ |
112 | len = -1;␊ |
113 | goto out;␊ |
114 | }␊ |
115 | len++;␊ |
116 | }␊ |
117 | len++;␊ |
118 | if(*(tab + len) == '\n') len++;␊ |
119 | goto out;␊ |
120 | }␊ |
121 | tab++;␊ |
122 | }␊ |
123 | len = -1;␊ |
124 | out:␊ |
125 | free(buf);␊ |
126 | ␊ |
127 | if(len == -1) return false;␊ |
128 | ␊ |
129 | while((*tab = *(tab + len))) {␊ |
130 | tab++;␊ |
131 | }␊ |
132 | ␊ |
133 | return true;␊ |
134 | }␊ |
135 | ␊ |
136 | char *␊ |
137 | newStringFromList(␊ |
138 | char **list,␊ |
139 | int *size␊ |
140 | )␊ |
141 | {␊ |
142 | char *begin = *list, *end;␊ |
143 | char *newstr;␊ |
144 | int newsize = *size;␊ |
145 | int bufsize;␊ |
146 | ␊ |
147 | while (*begin && newsize && isspace(*begin)) {␊ |
148 | ␉begin++;␊ |
149 | ␉newsize--;␊ |
150 | }␊ |
151 | end = begin;␊ |
152 | while (*end && newsize && !isspace(*end)) {␊ |
153 | ␉end++;␊ |
154 | ␉newsize--;␊ |
155 | }␊ |
156 | if (begin == end)␊ |
157 | ␉return 0;␊ |
158 | bufsize = end - begin + 1;␊ |
159 | newstr = malloc(bufsize);␊ |
160 | strlcpy(newstr, begin, bufsize);␊ |
161 | *list = end;␊ |
162 | *size = newsize;␊ |
163 | return newstr;␊ |
164 | }␊ |
165 | ␊ |
166 | #endif␊ |
167 | ␊ |
168 | /* ␊ |
169 | * compress == compress escaped characters to one character␊ |
170 | */␊ |
171 | int stringLength(const char *table, int compress)␊ |
172 | {␊ |
173 | ␉int ret = 0;␊ |
174 | ␊ |
175 | ␉while (*table)␊ |
176 | ␉{␊ |
177 | ␉␉if (*table == '\\')␊ |
178 | ␉␉{␊ |
179 | ␉␉␉table += 2;␊ |
180 | ␉␉␉ret += 1 + (compress ? 0 : 1);␊ |
181 | ␉␉}␊ |
182 | ␉␉else␊ |
183 | ␉␉{␊ |
184 | ␉␉␉if (*table == '\"') return ret;␊ |
185 | ␉␉␉ret++;␊ |
186 | ␉␉␉table++;␊ |
187 | ␉␉}␊ |
188 | ␉}␊ |
189 | ␉return ret;␊ |
190 | }␊ |
191 | ␊ |
192 | ␊ |
193 | bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)␊ |
194 | {␊ |
195 | ␉if (config->dictionary != 0 ) {␊ |
196 | ␉␉// Look up key in XML dictionary␊ |
197 | ␉␉TagPtr value;␊ |
198 | ␉␉value = XMLGetProperty(config->dictionary, key);␊ |
199 | ␉␉if (value != 0) {␊ |
200 | ␉␉␉if (value->type != kTagTypeString) {␊ |
201 | ␉␉␉␉error("Non-string tag '%s' found in config file\n",␊ |
202 | ␉␉␉␉␉ key);␊ |
203 | ␉␉␉␉return false;␊ |
204 | ␉␉␉}␊ |
205 | ␉␉␉*val = value->string;␊ |
206 | ␉␉␉*size = strlen(value->string);␊ |
207 | ␉␉␉return true;␊ |
208 | ␉␉}␊ |
209 | ␉} else {␊ |
210 | ␉␊ |
211 | ␉␉// Legacy plist-style table␊ |
212 | ␊ |
213 | ␉}␊ |
214 | ␊ |
215 | ␉return false;␊ |
216 | }␊ |
217 | ␊ |
218 | #if UNUSED␊ |
219 | ␊ |
220 | /*␊ |
221 | * Returns a new malloc'ed string if one is found␊ |
222 | * in the string table matching 'key'. Also translates␊ |
223 | * \n escapes in the string.␊ |
224 | */␊ |
225 | char *newStringForStringTableKey(␊ |
226 | ␉char *table,␊ |
227 | ␉char *key,␊ |
228 | ␉config_file_t *config␊ |
229 | )␊ |
230 | {␊ |
231 | const char *val;␊ |
232 | char *newstr, *p;␊ |
233 | int size;␊ |
234 | ␊ |
235 | if (getValueForConfigTableKey(config, key, &val, &size)) {␊ |
236 | ␉newstr = (char *)malloc(size+1);␊ |
237 | ␉for (p = newstr; size; size--, p++, val++) {␊ |
238 | ␉ if ((*p = *val) == '\\') {␊ |
239 | ␉␉switch (*++val) {␊ |
240 | ␉␉case 'r':␊ |
241 | ␉␉ *p = '\r';␊ |
242 | ␉␉ break;␊ |
243 | ␉␉case 'n':␊ |
244 | ␉␉ *p = '\n';␊ |
245 | ␉␉ break;␊ |
246 | ␉␉case 't':␊ |
247 | ␉␉ *p = '\t';␊ |
248 | ␉␉ break;␊ |
249 | ␉␉default:␊ |
250 | ␉␉ *p = *val;␊ |
251 | ␉␉ break;␊ |
252 | ␉␉}␊ |
253 | ␉␉size--;␊ |
254 | ␉ }␊ |
255 | ␉}␊ |
256 | ␉*p = '\0';␊ |
257 | ␉return newstr;␊ |
258 | } else {␊ |
259 | ␉return 0;␊ |
260 | }␊ |
261 | }␊ |
262 | ␊ |
263 | #endif␊ |
264 | ␊ |
265 | char *␊ |
266 | newStringForKey(char *key, config_file_t *config)␊ |
267 | {␊ |
268 | const char *val;␊ |
269 | char *newstr;␊ |
270 | int size;␊ |
271 | ␊ |
272 | if (getValueForKey(key, &val, &size, config) && size) {␊ |
273 | ␉newstr = (char *)malloc(size + 1);␊ |
274 | ␉strlcpy(newstr, val, size + 1);␊ |
275 | ␉return newstr;␊ |
276 | } else {␊ |
277 | ␉return 0;␊ |
278 | }␊ |
279 | }␊ |
280 | ␊ |
281 | /* parse a command line␊ |
282 | * in the form: [<argument> ...] [<option>=<value> ...]␊ |
283 | * both <option> and <value> must be either composed of␊ |
284 | * non-whitespace characters, or enclosed in quotes.␊ |
285 | */␊ |
286 | ␊ |
287 | static const char *getToken(const char *line, const char **begin, int *len)␊ |
288 | {␊ |
289 | if (*line == '\"') {␊ |
290 | ␉*begin = ++line;␊ |
291 | ␉while (*line && *line != '\"')␊ |
292 | ␉ line++;␊ |
293 | ␉*len = line++ - *begin;␊ |
294 | } else {␊ |
295 | ␉*begin = line;␊ |
296 | ␉while (*line && !isspace(*line) && *line != '=')␊ |
297 | ␉ line++;␊ |
298 | ␉*len = line - *begin;␊ |
299 | }␊ |
300 | return line;␊ |
301 | }␊ |
302 | ␊ |
303 | bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)␊ |
304 | {␊ |
305 | const char *key, *value;␊ |
306 | int key_len, value_len;␊ |
307 | bool retval = false;␊ |
308 | ␊ |
309 | while (*line) {␊ |
310 | ␉/* look for keyword or argument */␊ |
311 | ␉while (isspace(*line)) line++;␊ |
312 | ␊ |
313 | ␉/* now look for '=' or whitespace */␊ |
314 | ␉line = getToken(line, &key, &key_len);␊ |
315 | ␉/* line now points to '=' or space */␊ |
316 | ␉if (*line && !isspace(*line)) {␊ |
317 | ␉ line = getToken(++line, &value, &value_len);␊ |
318 | ␉} else {␊ |
319 | ␉ value = line;␊ |
320 | ␉ value_len = 0;␊ |
321 | ␉}␊ |
322 | ␉if ((strlen(match) == key_len)␊ |
323 | ␉ && strncmp(match, key, key_len) == 0) {␊ |
324 | ␉ *matchval = value;␊ |
325 | ␉ *len = value_len;␊ |
326 | ␉ retval = true;␊ |
327 | /* Continue to look for this key; last one wins. */␊ |
328 | ␉}␊ |
329 | }␊ |
330 | return retval;␊ |
331 | }␊ |
332 | ␊ |
333 | /* Return NULL if no option has been successfully retrieved, or the string otherwise */␊ |
334 | const char * getStringForKey(const char * key, config_file_t *config)␊ |
335 | {␊ |
336 | static const char* value =0;␊ |
337 | int len=0;␊ |
338 | if(!getValueForKey(key, &value, &len, config)) value = 0;␊ |
339 | return value;␊ |
340 | }␊ |
341 | ␊ |
342 | ␊ |
343 | /* Returns TRUE if a value was found, FALSE otherwise.␊ |
344 | * The boolean value of the key is stored in 'val'.␊ |
345 | */␊ |
346 | ␊ |
347 | bool getBoolForKey( const char *key, bool *result_val, config_file_t *config )␊ |
348 | {␊ |
349 | const char *key_val;␊ |
350 | int size;␊ |
351 | ␊ |
352 | if (getValueForKey(key, &key_val, &size, config)) {␊ |
353 | if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {␊ |
354 | *result_val = true;␊ |
355 | } else {␊ |
356 | *result_val = false;␊ |
357 | }␊ |
358 | return true;␊ |
359 | }␊ |
360 | return false;␊ |
361 | }␊ |
362 | ␊ |
363 | bool getIntForKey( const char *key, int *value, config_file_t *config )␊ |
364 | {␊ |
365 | const char *val;␊ |
366 | int size, sum;␊ |
367 | bool negative = false;␊ |
368 | ␊ |
369 | if (getValueForKey(key, &val, &size, config))␊ |
370 | ␉{␊ |
371 | ␉␉if ( size )␊ |
372 | ␉␉{␊ |
373 | ␉␉␉if (*val == '-')␊ |
374 | ␉␉␉{␊ |
375 | ␉␉␉␉negative = true;␊ |
376 | ␉␉␉␉val++;␊ |
377 | ␉␉␉␉size--;␊ |
378 | ␉␉␉}␊ |
379 | ␉␉␉␊ |
380 | ␉␉␉for (sum = 0; size > 0; size--)␊ |
381 | ␉␉␉{␊ |
382 | ␉␉␉␉if (*val < '0' || *val > '9')␊ |
383 | ␉␉␉␉␉return false;␊ |
384 | ␉␉␉␉␊ |
385 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
386 | ␉␉␉}␊ |
387 | ␉␉␉␊ |
388 | ␉␉␉if (negative)␊ |
389 | ␉␉␉␉sum = -sum;␊ |
390 | ␉␉␉␊ |
391 | ␉␉␉*value = sum;␊ |
392 | ␉␉␉return true;␊ |
393 | ␉␉}␊ |
394 | ␉}␊ |
395 | return false;␊ |
396 | }␊ |
397 | ␊ |
398 | /*␊ |
399 | *␊ |
400 | */␊ |
401 | ␊ |
402 | bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )␊ |
403 | {␊ |
404 | ␉const char *val;␊ |
405 | ␉␊ |
406 | int size = 0;␊ |
407 | ␉int sum = 0;␊ |
408 | ␊ |
409 | ␉bool negative = false;␊ |
410 | ␉bool percentage = false;␊ |
411 | ␉␊ |
412 | if (getValueForKey(key, &val, &size, config))␊ |
413 | ␉{␊ |
414 | ␉␉if ( size )␊ |
415 | ␉␉{␊ |
416 | ␉␉␉if (*val == '-')␊ |
417 | ␉␉␉{␊ |
418 | ␉␉␉␉negative = true;␊ |
419 | ␉␉␉␉val++;␊ |
420 | ␉␉␉␉size--;␊ |
421 | ␉␉␉}␊ |
422 | ␉␉␉␊ |
423 | ␉␉␉if (val[size-1] == '%')␊ |
424 | ␉␉␉{␊ |
425 | ␉␉␉␉percentage = true;␊ |
426 | ␉␉␉␉size--;␊ |
427 | ␉␉␉}␊ |
428 | ␉␉␉␊ |
429 | ␉␉␉// convert string to integer␊ |
430 | ␉␉␉for (sum = 0; size > 0; size--)␊ |
431 | ␉␉␉{␊ |
432 | ␉␉␉␉if (*val < '0' || *val > '9')␊ |
433 | ␉␉␉␉␉return false;␊ |
434 | ␉␉␉␉␊ |
435 | ␉␉␉␉sum = (sum * 10) + (*val++ - '0');␊ |
436 | ␉␉␉}␊ |
437 | ␉␉␉␊ |
438 | ␉␉␉if (percentage)␊ |
439 | ␉␉␉␉sum = ( dimension_max * sum ) / 100;␊ |
440 | ␉␉␉␊ |
441 | ␉␉␉// calculate offset from opposite origin␊ |
442 | ␉␉␉if (negative)␊ |
443 | ␉␉␉␉sum = ( ( dimension_max - object_size ) - sum );␊ |
444 | ␉␉␉␊ |
445 | ␉␉} else {␊ |
446 | ␉␉␉␊ |
447 | ␉␉␉// null value calculate center␊ |
448 | ␉␉␉sum = ( dimension_max - object_size ) / 2;␊ |
449 | ␉␉␉␊ |
450 | ␉␉}␊ |
451 | ␉␉␊ |
452 | ␉␉*value = (uint16_t) sum;␊ |
453 | ␉␉return true;␊ |
454 | ␉}␊ |
455 | ␉␊ |
456 | ␉// key not found␊ |
457 | return false;␊ |
458 | }␊ |
459 | ␊ |
460 | /*␊ |
461 | *␉get color value from plist format #RRGGBB␊ |
462 | */␊ |
463 | ␊ |
464 | bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )␊ |
465 | {␊ |
466 | const char *val;␊ |
467 | int size;␊ |
468 | ␊ |
469 | if (getValueForKey(key, &val, &size, config))␊ |
470 | ␉{␊ |
471 | ␉␉if (*val == '#')␊ |
472 | ␉␉{␊ |
473 | val++;␊ |
474 | ␉␉␉*value = strtol(val, NULL, 16);␊ |
475 | ␉␉␉return true;␊ |
476 | }␊ |
477 | }␊ |
478 | return false;␊ |
479 | }␊ |
480 | ␊ |
481 | bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )␊ |
482 | {␊ |
483 | return getValueForConfigTableKey(config, key, val, size);␊ |
484 | }␊ |
485 | ␊ |
486 | ␊ |
487 | #if UNUSED␊ |
488 | void␊ |
489 | printSystemConfig(char *p1)␊ |
490 | {␊ |
491 | char *p2 = p1, tmp;␊ |
492 | ␊ |
493 | while (*p1 != '\0') {␊ |
494 | ␉while (*p2 != '\0' && *p2 != '\n') p2++;␊ |
495 | ␉tmp = *p2;␊ |
496 | ␉*p2 = '\0';␊ |
497 | ␉printf("%s\n", p1);␊ |
498 | ␉*p2 = tmp;␊ |
499 | ␉if (tmp == '\0') break;␊ |
500 | ␉p1 = ++p2;␊ |
501 | }␊ |
502 | }␊ |
503 | #endif␊ |
504 | ␊ |
505 | //==========================================================================␊ |
506 | // ParseXMLFile␊ |
507 | // Modifies the input buffer.␊ |
508 | // Expects to see one dictionary in the XML file.␊ |
509 | // Puts the first dictionary it finds in the␊ |
510 | // tag pointer and returns 0, or returns -1 if not found␊ |
511 | // (and does not modify dict pointer).␊ |
512 | // Prints an error message if there is a parsing error.␊ |
513 | //␊ |
514 | int ParseXMLFile( char * buffer, TagPtr * dict )␊ |
515 | {␊ |
516 | long length, pos;␊ |
517 | TagPtr tag;␊ |
518 | pos = 0;␊ |
519 | char *configBuffer;␊ |
520 | ␊ |
521 | configBuffer = malloc(strlen(buffer)+1);␊ |
522 | strcpy(configBuffer, buffer);␊ |
523 | ␊ |
524 | while (1)␊ |
525 | {␊ |
526 | length = XMLParseNextTag(configBuffer + pos, &tag);␊ |
527 | if (length == -1) break;␊ |
528 | ␊ |
529 | pos += length;␊ |
530 | ␊ |
531 | if (tag == 0) continue;␊ |
532 | if (tag->type == kTagTypeDict) break;␊ |
533 | ␊ |
534 | XMLFreeTag(tag);␊ |
535 | }␊ |
536 | free(configBuffer);␊ |
537 | if (length < 0) {␊ |
538 | error ("Error parsing plist file\n");␊ |
539 | return -1;␊ |
540 | }␊ |
541 | *dict = tag;␊ |
542 | return 0;␊ |
543 | }␊ |
544 | ␊ |
545 | char * newString(const char * oldString)␊ |
546 | {␊ |
547 | if ( oldString )␊ |
548 | return strcpy(malloc(strlen(oldString)+1), oldString);␊ |
549 | else␊ |
550 | return NULL;␊ |
551 | }␊ |
552 | ␊ |
553 | /*␊ |
554 | * Extracts the next argument from the command line, double quotes are allowed here.␊ |
555 | */␊ |
556 | char * getNextArg(char ** argPtr, char * val)␊ |
557 | {␊ |
558 | char * ptr = *argPtr;␊ |
559 | const char * strStart;␊ |
560 | int len = 0;␊ |
561 | bool isQuoted = false;␊ |
562 | ␊ |
563 | *val = '\0';␊ |
564 | ␊ |
565 | // Scan for the next non-whitespace character.␊ |
566 | while ( *ptr && (*ptr == ' ' || *ptr == '=') )␊ |
567 | {␊ |
568 | ptr++;␊ |
569 | }␊ |
570 | ␊ |
571 | strStart = ptr;␊ |
572 | ␊ |
573 | // Skip the leading double quote character.␊ |
574 | if (*ptr == '\"')␊ |
575 | {␊ |
576 | isQuoted = true;␊ |
577 | ptr++;␊ |
578 | strStart++;␊ |
579 | }␊ |
580 | ␊ |
581 | // Scan for the argument terminator character.␊ |
582 | // This can be either a NULL character - in case we reach the end of the string,␊ |
583 | // a double quote in case of quoted argument,␊ |
584 | // or a whitespace character (' ' or '=') for non-quoted argument.␊ |
585 | while (*ptr && !( (isQuoted && (*ptr == '\"')) ||␊ |
586 | (!isQuoted && (*ptr == ' ' || *ptr == '=')) )␊ |
587 | )␊ |
588 | {␊ |
589 | ptr++;␊ |
590 | }␊ |
591 | ␊ |
592 | len = ptr - strStart;␊ |
593 | ␊ |
594 | // Skip the closing double quote character and adjust␊ |
595 | // the starting pointer for the next getNextArg call.␊ |
596 | if (*ptr && isQuoted && *ptr == '\"')␊ |
597 | ptr++;␊ |
598 | ␊ |
599 | // Copy the extracted argument to val.␊ |
600 | strncat(val, strStart, len);␊ |
601 | ␊ |
602 | // Set command line pointer.␊ |
603 | *argPtr = ptr;␊ |
604 | ␊ |
605 | return ptr;␊ |
606 | }␊ |
607 |