VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/getopt.cpp@ 23868

Last change on this file since 23868 was 23868, checked in by vboxsync, 16 years ago

RTGetOpt: Added RTGetOptFetchValue to fetch an additional value for an argument

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.6 KB
Line 
1/* $Id: getopt.cpp 23868 2009-10-19 14:22:42Z vboxsync $ */
2/** @file
3 * IPRT - Command Line Parsing
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/net.h> /* must come before getopt.h */
35#include <iprt/getopt.h>
36#include "internal/iprt.h"
37
38#include <iprt/err.h>
39#include <iprt/string.h>
40#include <iprt/assert.h>
41#include <iprt/ctype.h>
42#include <iprt/uuid.h>
43
44
45
46RTDECL(int) RTGetOptInit(PRTGETOPTSTATE pState, int argc, char **argv,
47 PCRTGETOPTDEF paOptions, size_t cOptions,
48 int iFirst, uint32_t fFlags)
49{
50 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
51
52 pState->argv = argv;
53 pState->argc = argc;
54 pState->paOptions = paOptions;
55 pState->cOptions = cOptions;
56 pState->iNext = iFirst;
57 pState->pszNextShort = NULL;
58 pState->pDef = NULL;
59
60 /* validate the options. */
61 for (size_t i = 0; i < cOptions; i++)
62 {
63 Assert(!(paOptions[i].fFlags & ~RTGETOPT_VALID_MASK));
64 Assert(paOptions[i].iShort > 0);
65 Assert(paOptions[i].iShort != VINF_GETOPT_NOT_OPTION);
66 Assert(paOptions[i].iShort != '-');
67 }
68
69 /** @todo Add an flag for sorting the arguments so that all the options comes
70 * first. */
71 return VINF_SUCCESS;
72}
73RT_EXPORT_SYMBOL(RTGetOptInit);
74
75
76/**
77 * Converts an stringified IPv4 address into the RTNETADDRIPV4 representation.
78 *
79 * @todo This should be move to some generic part of the runtime.
80 *
81 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on
82 * failure.
83 *
84 * @param pszValue The value to convert.
85 * @param pAddr Where to store the result.
86 */
87static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr)
88{
89 char *pszNext;
90 int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 10, &pAddr->au8[0]);
91 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
92 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
93 if (*pszNext++ != '.')
94 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
95
96 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
97 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
98 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
99 if (*pszNext++ != '.')
100 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
101
102 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
103 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
104 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
105 if (*pszNext++ != '.')
106 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
107
108 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
109 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
110 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
111 pszNext = RTStrStripL(pszNext);
112 if (*pszNext)
113 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
114
115 return VINF_SUCCESS;
116}
117
118
119/**
120 * Converts an stringified Ethernet MAC address into the RTMAC representation.
121 *
122 * @todo This should be move to some generic part of the runtime.
123 *
124 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on
125 * failure.
126 *
127 * @param pszValue The value to convert.
128 * @param pAddr Where to store the result.
129 */
130static int rtgetoptConvertMacAddr(const char *pszValue, PRTMAC pAddr)
131{
132 /*
133 * Not quite sure if I should accept stuff like "08::27:::1" here...
134 * The code is accepting "::" patterns now, except for for the first
135 * and last parts.
136 */
137
138 /* first */
139 char *pszNext;
140 int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]);
141 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
142 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
143 if (*pszNext++ != ':')
144 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
145
146 /* middle */
147 for (unsigned i = 1; i < 5; i++)
148 {
149 if (*pszNext == ':')
150 pAddr->au8[i] = 0;
151 else
152 {
153 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]);
154 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
155 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
156 if (*pszNext != ':')
157 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
158 }
159 pszNext++;
160 }
161
162 /* last */
163 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]);
164 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
165 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
166 pszNext = RTStrStripL(pszNext);
167 if (*pszNext)
168 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
169
170 return VINF_SUCCESS;
171}
172
173
174/**
175 * Searches for a long option.
176 *
177 * @returns Pointer to a matching option.
178 * @param pszOption The alleged long option.
179 * @param paOptions Option array.
180 * @param cOptions Number of items in the array.
181 */
182static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions)
183{
184 PCRTGETOPTDEF pOpt = paOptions;
185 while (cOptions-- > 0)
186 {
187 if (pOpt->pszLong)
188 {
189 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
190 {
191 /*
192 * A value is required with the argument. We're trying to be very
193 * understanding here and will permit any of the following:
194 * --long12:value, --long12=value, --long12 value,
195 * --long:value, --long=value, --long value,
196 * --long: value, --long= value
197 *
198 * If the option is index, then all trailing chars must be
199 * digits. For error reporting reasons we also match where
200 * there is no index.
201 */
202 size_t cchLong = strlen(pOpt->pszLong);
203 if (!strncmp(pszOption, pOpt->pszLong, cchLong))
204 {
205 if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
206 while (RT_C_IS_DIGIT(pszOption[cchLong]))
207 cchLong++;
208 if ( pszOption[cchLong] == '\0'
209 || pszOption[cchLong] == ':'
210 || pszOption[cchLong] == '=')
211 return pOpt;
212 }
213 }
214 else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
215 {
216 /*
217 * The option takes an index but no value.
218 * As above, we also match where there is no index.
219 */
220 size_t cchLong = strlen(pOpt->pszLong);
221 if (!strncmp(pszOption, pOpt->pszLong, cchLong))
222 {
223 while (RT_C_IS_DIGIT(pszOption[cchLong]))
224 cchLong++;
225 if (pszOption[cchLong] == '\0')
226 return pOpt;
227 }
228 }
229 else if (!strcmp(pszOption, pOpt->pszLong))
230 return pOpt;
231 }
232 pOpt++;
233 }
234 return NULL;
235}
236
237
238/**
239 * Searches for a matching short option.
240 *
241 * @returns Pointer to a matching option.
242 * @param chOption The option char.
243 * @param paOptions Option array.
244 * @param cOptions Number of items in the array.
245 */
246static PCRTGETOPTDEF rtGetOptSearchShort(int chOption, PCRTGETOPTDEF paOptions, size_t cOptions)
247{
248 PCRTGETOPTDEF pOpt = paOptions;
249 while (cOptions-- > 0)
250 {
251 if (pOpt->iShort == chOption)
252 return pOpt;
253 pOpt++;
254 }
255 return NULL;
256}
257
258
259/**
260 * Value string -> Value union.
261 *
262 * @returns IPRT status code.
263 * @param fFlags The value flags.
264 * @param pszValue The value string.
265 * @param pValueUnion Where to return the processed value.
266 */
267static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion)
268{
269 /*
270 * Transform into a option value as requested.
271 * If decimal conversion fails, we'll check for "0x<xdigit>" and
272 * try a 16 based conversion. We will not interpret any of the
273 * generic ints as octals.
274 */
275 switch (fFlags & ( RTGETOPT_REQ_MASK
276 | RTGETOPT_FLAG_HEX
277 | RTGETOPT_FLAG_DEC
278 | RTGETOPT_FLAG_OCT))
279 {
280 case RTGETOPT_REQ_STRING:
281 pValueUnion->psz = pszValue;
282 break;
283
284#define MY_INT_CASE(req,type,memb,convfn) \
285 case req: \
286 { \
287 type Value; \
288 if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \
289 && ( pszValue[0] != '0' \
290 || (pszValue[1] != 'x' && pszValue[1] != 'X') \
291 || !RT_C_IS_XDIGIT(pszValue[2]) \
292 || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
293 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
294 pValueUnion->memb = Value; \
295 break; \
296 }
297#define MY_BASE_INT_CASE(req,type,memb,convfn,base) \
298 case req: \
299 { \
300 type Value; \
301 if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
302 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
303 pValueUnion->memb = Value; \
304 break; \
305 }
306
307 MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i, RTStrToInt8Full)
308 MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i, RTStrToInt16Full)
309 MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i, RTStrToInt32Full)
310 MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i, RTStrToInt64Full)
311 MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u, RTStrToUInt8Full)
312 MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u, RTStrToUInt16Full)
313 MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u, RTStrToUInt32Full)
314 MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u, RTStrToUInt64Full)
315
316 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i, RTStrToInt8Full, 16)
317 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i, RTStrToInt16Full, 16)
318 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i, RTStrToInt32Full, 16)
319 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i, RTStrToInt64Full, 16)
320 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u, RTStrToUInt8Full, 16)
321 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u, RTStrToUInt16Full, 16)
322 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u, RTStrToUInt32Full, 16)
323 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u, RTStrToUInt64Full, 16)
324
325 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i, RTStrToInt8Full, 10)
326 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i, RTStrToInt16Full, 10)
327 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i, RTStrToInt32Full, 10)
328 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i, RTStrToInt64Full, 10)
329 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u, RTStrToUInt8Full, 10)
330 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u, RTStrToUInt16Full, 10)
331 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u, RTStrToUInt32Full, 10)
332 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u, RTStrToUInt64Full, 10)
333
334 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i, RTStrToInt8Full, 8)
335 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i, RTStrToInt16Full, 8)
336 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i, RTStrToInt32Full, 8)
337 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i, RTStrToInt64Full, 8)
338 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u, RTStrToUInt8Full, 8)
339 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u, RTStrToUInt16Full, 8)
340 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u, RTStrToUInt32Full, 8)
341 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u, RTStrToUInt64Full, 8)
342
343#undef MY_INT_CASE
344#undef MY_BASE_INT_CASE
345
346 case RTGETOPT_REQ_IPV4ADDR:
347 {
348 RTNETADDRIPV4 Addr;
349 if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS)
350 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
351 pValueUnion->IPv4Addr = Addr;
352 break;
353 }
354#if 0 /** @todo CIDR */
355#endif
356
357 case RTGETOPT_REQ_MACADDR:
358 {
359 RTMAC Addr;
360 if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS)
361 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
362 pValueUnion->MacAddr = Addr;
363 break;
364 }
365
366 case RTGETOPT_REQ_UUID:
367 {
368 RTUUID Uuid;
369 if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS)
370 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
371 pValueUnion->Uuid = Uuid;
372 break;
373 }
374
375 default:
376 AssertMsgFailed(("f=%#x\n", fFlags));
377 return VERR_INTERNAL_ERROR;
378 }
379
380 return VINF_SUCCESS;
381}
382
383
384RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion)
385{
386 /*
387 * Reset the variables kept in state.
388 */
389 pState->pDef = NULL;
390 pState->uIndex = UINT64_MAX;
391
392 /*
393 * Make sure the union is completely cleared out, whatever happens below.
394 */
395 pValueUnion->u64 = 0;
396 pValueUnion->pDef = NULL;
397
398 /** @todo Handle '--' (end of options).*/
399 /** @todo Add a flag to RTGetOptInit for handling the various help options in
400 * a common way. (-?,-h,-help,--help,++) */
401 /** @todo Add a flag to RTGetOptInit for handling the standard version options
402 * in a common way. (-V,--version) */
403
404 /*
405 * The next option.
406 */
407 bool fShort;
408 int iThis;
409 const char *pszArgThis;
410 PCRTGETOPTDEF pOpt;
411
412 if (pState->pszNextShort)
413 {
414 /*
415 * We've got short options left over from the previous call.
416 */
417 pOpt = rtGetOptSearchShort(*pState->pszNextShort, pState->paOptions, pState->cOptions);
418 if (!pOpt)
419 {
420 pValueUnion->psz = pState->pszNextShort;
421 return VERR_GETOPT_UNKNOWN_OPTION;
422 }
423 pState->pszNextShort++;
424 pszArgThis = pState->pszNextShort - 2;
425 iThis = pState->iNext;
426 fShort = true;
427 }
428 else
429 {
430 /*
431 * Pop off the next argument.
432 */
433 if (pState->iNext >= pState->argc)
434 return 0;
435 iThis = pState->iNext++;
436 pszArgThis = pState->argv[iThis];
437
438 /*
439 * Do a long option search first and then a short option one.
440 * This way we can make sure single dash long options doesn't
441 * get mixed up with short ones.
442 */
443 pOpt = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions);
444 if ( !pOpt
445 && pszArgThis[0] == '-'
446 && pszArgThis[1] != '-'
447 && pszArgThis[1] != '\0')
448 {
449 pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions);
450 fShort = pOpt != NULL;
451 }
452 else
453 fShort = false;
454 }
455
456 if (pOpt)
457 {
458 pValueUnion->pDef = pOpt; /* in case of no value or error. */
459
460 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
461 {
462 /*
463 * Find the argument value.
464 *
465 * A value is required with the argument. We're trying to be very
466 * understanding here and will permit any of the following:
467 * -svalue, -s:value, -s=value,
468 * -s value, -s: value, -s= value
469 * (Ditto for long options.)
470 */
471 const char *pszValue;
472 if (fShort)
473 {
474 if ( pszArgThis[2] == '\0'
475 || ( pszArgThis[3] == '\0'
476 && ( pszArgThis[2] == ':'
477 || pszArgThis[2] == '=')) )
478 {
479 if (iThis + 1 >= pState->argc)
480 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
481 pszValue = pState->argv[iThis + 1];
482 pState->iNext++;
483 }
484 else /* same argument. */
485 pszValue = &pszArgThis[2 + (pszArgThis[2] == ':' || pszArgThis[2] == '=')];
486 if (pState->pszNextShort)
487 {
488 pState->pszNextShort = NULL;
489 pState->iNext++;
490 }
491 }
492 else
493 {
494 size_t cchLong = strlen(pOpt->pszLong);
495 if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
496 {
497
498 if (pszArgThis[cchLong] == '\0')
499 return VERR_GETOPT_INDEX_MISSING;
500
501 uint64_t uIndex;
502 char *pszRet = NULL;
503 int rc = RTStrToUInt64Ex(&pszArgThis[cchLong], &pszRet, 10, &uIndex);
504 if (rc == VWRN_TRAILING_CHARS)
505 {
506 if ( pszRet[0] != ':'
507 && pszRet[0] != '=')
508 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
509 pState->uIndex = uIndex;
510 pszValue = pszRet + 1;
511 }
512 else if (rc == VINF_SUCCESS)
513 {
514 if (iThis + 1 >= pState->argc)
515 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
516 pState->uIndex = uIndex;
517 pszValue = pState->argv[iThis + 1];
518 pState->iNext++;
519 }
520 else
521 AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */
522 }
523 else
524 {
525 if ( pszArgThis[cchLong] == '\0'
526 || pszArgThis[cchLong + 1] == '\0')
527 {
528 if (iThis + 1 >= pState->argc)
529 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
530 pszValue = pState->argv[iThis + 1];
531 pState->iNext++;
532 }
533 else /* same argument. */
534 pszValue = &pszArgThis[cchLong + 1];
535 }
536 }
537
538 /*
539 * Set up the ValueUnion.
540 */
541 int rc = rtGetOptProcessValue(pOpt->fFlags, pszValue, pValueUnion);
542 if (RT_FAILURE(rc))
543 return rc;
544 }
545 else if (fShort)
546 {
547 /*
548 * Deal with "compressed" short option lists, correcting the next
549 * state variables for the start and end cases.
550 */
551 if (pszArgThis[2])
552 {
553 if (!pState->pszNextShort)
554 {
555 /* start */
556 pState->pszNextShort = &pszArgThis[2];
557 pState->iNext--;
558 }
559 }
560 else if (pState->pszNextShort)
561 {
562 /* end */
563 pState->pszNextShort = NULL;
564 pState->iNext++;
565 }
566 }
567 else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
568 {
569 size_t cchLong = strlen(pOpt->pszLong);
570 if (pszArgThis[cchLong] == '\0')
571 return VERR_GETOPT_INDEX_MISSING;
572
573 uint64_t uIndex;
574 char *pszRet = NULL;
575 if (RTStrToUInt64Full(&pszArgThis[cchLong], 10, &uIndex) == VINF_SUCCESS)
576 pState->uIndex = uIndex;
577 else
578 AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */
579 }
580
581 pState->pDef = pOpt;
582 return pOpt->iShort;
583 }
584
585 /*
586 * Not a known option argument. If it starts with a switch char (-) we'll
587 * fail with unkown option, and if it doesn't we'll return it as a non-option.
588 */
589
590 if (*pszArgThis == '-')
591 {
592 pValueUnion->psz = pszArgThis;
593 return VERR_GETOPT_UNKNOWN_OPTION;
594 }
595
596 pValueUnion->psz = pszArgThis;
597 return VINF_GETOPT_NOT_OPTION;
598}
599RT_EXPORT_SYMBOL(RTGetOpt);
600
601
602RTDECL(int) RTGetOptFetchValue(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion, uint32_t fFlags)
603{
604 /*
605 * Validate input.
606 */
607 PCRTGETOPTDEF pOpt = pState->pDef;
608 AssertReturn(pOpt, VERR_GETOPT_UNKNOWN_OPTION);
609 AssertReturn(!(fFlags & ~RTGETOPT_VALID_MASK), VERR_INVALID_PARAMETER);
610 AssertReturn((fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING, VERR_INVALID_PARAMETER);
611
612 /*
613 * Make sure the union is completely cleared out, whatever happens below.
614 */
615 pValueUnion->u64 = 0;
616 pValueUnion->pDef = NULL;
617
618 /*
619 * Pop off the next argument and convert it into a value union.
620 */
621 if (pState->iNext >= pState->argc)
622 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
623 int iThis = pState->iNext++;
624 const char *pszValue = pState->argv[iThis];
625 pValueUnion->pDef = pOpt; /* in case of no value or error. */
626
627 return rtGetOptProcessValue(fFlags, pszValue, pValueUnion);
628}
629RT_EXPORT_SYMBOL(RTGetOptFetchValue);
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette