VirtualBox

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

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

RTGetOpt: Fixed 'tstHeadless -startvm vm' breakage from earlier today.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/* $Id: getopt.cpp 17100 2009-02-24 21:37:20Z 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/getopt.h>
35#include <iprt/err.h>
36#include <iprt/string.h>
37#include <iprt/assert.h>
38#include <iprt/ctype.h>
39
40
41
42RTDECL(int) RTGetOptInit(PRTGETOPTSTATE pState, int argc, char **argv,
43 PCRTGETOPTDEF paOptions, size_t cOptions,
44 int iFirst, uint32_t fFlags)
45{
46 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
47
48 pState->argv = argv;
49 pState->argc = argc;
50 pState->paOptions = paOptions;
51 pState->cOptions = cOptions;
52 pState->iNext = iFirst;
53
54 /* validate the options. */
55 for (size_t i = 0; i < cOptions; i++)
56 {
57 Assert(!(paOptions[i].fFlags & ~RTGETOPT_VALID_MASK));
58 Assert(paOptions[i].iShort > 0);
59 Assert(paOptions[i].iShort != VINF_GETOPT_NOT_OPTION);
60 Assert(paOptions[i].iShort != '-');
61 }
62
63 return VINF_SUCCESS;
64}
65
66
67/**
68 * Searches for a long option.
69 *
70 * @returns Pointer to a matching option.
71 * @param pszOption The alleged long option.
72 * @param paOptions Option array.
73 * @param cOptions Number of items in the array.
74 */
75static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions)
76{
77 PCRTGETOPTDEF pOpt = paOptions;
78 while (cOptions-- > 0)
79 {
80 if (pOpt->pszLong)
81 {
82 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
83 {
84 /*
85 * A value is required with the argument. We're trying to be very
86 * understanding here and will permit any of the following:
87 * -svalue, -s:value, -s=value,
88 * -s value, -s: value, -s= value
89 * (Ditto for long options.)
90 */
91 size_t cchLong = strlen(pOpt->pszLong);
92 if ( !strncmp(pszOption, pOpt->pszLong, cchLong)
93 && ( pszOption[cchLong] == '\0'
94 || pszOption[cchLong] == ':'
95 || pszOption[cchLong] == '='))
96 return pOpt;
97 }
98 else if (!strcmp(pszOption, pOpt->pszLong))
99 return pOpt;
100 }
101 pOpt++;
102 }
103 return NULL;
104}
105
106
107/**
108 * Searches for a matching short option.
109 *
110 * @returns Pointer to a matching option.
111 * @param chOption The option char.
112 * @param paOptions Option array.
113 * @param cOptions Number of items in the array.
114 */
115static PCRTGETOPTDEF rtGetOptSearchShort(int chOption, PCRTGETOPTDEF paOptions, size_t cOptions)
116{
117 PCRTGETOPTDEF pOpt = paOptions;
118 while (cOptions-- > 0)
119 {
120 if (pOpt->iShort == chOption)
121 return pOpt;
122 pOpt++;
123 }
124 return NULL;
125}
126
127
128RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion)
129{
130 pValueUnion->u64 = 0;
131 pValueUnion->pDef = NULL;
132
133 if (pState->iNext >= pState->argc)
134 return 0;
135
136 /** @todo Handle '--' and possibly implement an RTGetOptInit that lets us
137 * optionally sort the stuff and set other policeis sorts the result. */
138 /** @todo Implement short form short option like in:
139 * ls -latr .
140 * tar -xzvf foobar.tar.gz
141 */
142
143 /*
144 * Pop off the next argument.
145 */
146 int iThis = pState->iNext++;
147 const char *pszArgThis = pState->argv[iThis];
148
149 /*
150 * Do a long option search first and the a short option one.
151 * This way we can make sure single dash long options doesn't
152 * get mixed up with short ones.
153 */
154 bool fShort = false;
155 PCRTGETOPTDEF pOpt = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions);
156 if ( !pOpt
157 && pszArgThis[0] == '-'
158 && pszArgThis[1] != '-'
159 && pszArgThis[1] != '\0')
160 {
161 pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions);
162 fShort = pOpt != NULL;
163 }
164 if (pOpt)
165 {
166 pValueUnion->pDef = pOpt; /* in case of no value or error. */
167
168 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
169 {
170 /*
171 * Find the argument value.
172 *
173 * A value is required with the argument. We're trying to be very
174 * understanding here and will permit any of the following:
175 * -svalue, -s:value, -s=value,
176 * -s value, -s: value, -s= value
177 * (Ditto for long options.)
178 */
179 const char *pszValue;
180 if (fShort)
181 {
182 if ( pszArgThis[2] == '\0'
183 || ( pszArgThis[3] == '\0'
184 && ( pszArgThis[2] == ':'
185 || pszArgThis[2] == '=')) )
186 {
187 if (iThis + 1 >= pState->argc)
188 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
189 pszValue = pState->argv[iThis + 1];
190 pState->iNext++;
191 }
192 else /* same argument. */
193 pszValue = &pszArgThis[2 + (pszArgThis[2] == ':' || pszArgThis[2] == '=')];
194 }
195 else
196 {
197 size_t cchLong = strlen(pOpt->pszLong);
198 if ( pszArgThis[cchLong] == '\0'
199 || pszArgThis[cchLong + 1] == '\0')
200 {
201 if (iThis + 1 >= pState->argc)
202 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
203 pszValue = pState->argv[iThis + 1];
204 pState->iNext++;
205 }
206 else /* same argument. */
207 pszValue = &pszArgThis[cchLong + 1];
208 }
209
210 /*
211 * Transform into a option value as requested.
212 * If decimal conversion fails, we'll check for "0x<xdigit>" and
213 * try a 16 based conversion. We will not interpret any of the
214 * generic ints as octals.
215 */
216 switch (pOpt->fFlags & (RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_OCT | RTGETOPT_FLAG_DEC))
217 {
218 case RTGETOPT_REQ_STRING:
219 pValueUnion->psz = pszValue;
220 break;
221
222#define MY_INT_CASE(req,type,memb,convfn) \
223 case req: \
224 { \
225 type Value; \
226 if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \
227 && ( pszValue[0] != '0' \
228 || (pszValue[1] != 'x' && pszValue[1] != 'X') \
229 || !RT_C_IS_XDIGIT(pszValue[2]) \
230 || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
231 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
232 pValueUnion->memb = Value; \
233 break; \
234 }
235#define MY_BASE_INT_CASE(req,type,memb,convfn,base) \
236 case req: \
237 { \
238 type Value; \
239 if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
240 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
241 pValueUnion->memb = Value; \
242 break; \
243 }
244
245 MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i, RTStrToInt8Full)
246 MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i, RTStrToInt16Full)
247 MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i, RTStrToInt32Full)
248 MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i, RTStrToInt64Full)
249 MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u, RTStrToUInt8Full)
250 MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u, RTStrToUInt16Full)
251 MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u, RTStrToUInt32Full)
252 MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u, RTStrToUInt64Full)
253
254 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i, RTStrToInt8Full, 16)
255 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i, RTStrToInt16Full, 16)
256 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i, RTStrToInt32Full, 16)
257 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i, RTStrToInt64Full, 16)
258 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u, RTStrToUInt8Full, 16)
259 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u, RTStrToUInt16Full, 16)
260 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u, RTStrToUInt32Full, 16)
261 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u, RTStrToUInt64Full, 16)
262
263 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i, RTStrToInt8Full, 10)
264 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i, RTStrToInt16Full, 10)
265 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i, RTStrToInt32Full, 10)
266 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i, RTStrToInt64Full, 10)
267 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u, RTStrToUInt8Full, 10)
268 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u, RTStrToUInt16Full, 10)
269 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u, RTStrToUInt32Full, 10)
270 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u, RTStrToUInt64Full, 10)
271
272 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i, RTStrToInt8Full, 8)
273 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i, RTStrToInt16Full, 8)
274 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i, RTStrToInt32Full, 8)
275 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i, RTStrToInt64Full, 8)
276 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u, RTStrToUInt8Full, 8)
277 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u, RTStrToUInt16Full, 8)
278 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u, RTStrToUInt32Full, 8)
279 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u, RTStrToUInt64Full, 8)
280#undef MY_INT_CASE
281#undef MY_BASE_INT_CASE
282
283 default:
284 AssertMsgFailed(("i=%d f=%#x\n", pOpt - &pState->paOptions[0], pOpt->fFlags));
285 return VERR_INTERNAL_ERROR;
286 }
287 }
288 return pOpt->iShort;
289 }
290
291 /*
292 * Not a known option argument. If it starts with a switch char (-) we'll
293 * fail with unkown option, and if it doesn't we'll return it as a non-option.
294 */
295
296 if (*pszArgThis == '-')
297 return VERR_GETOPT_UNKNOWN_OPTION;
298
299 pValueUnion->psz = pszArgThis;
300 return VINF_GETOPT_NOT_OPTION;
301}
302
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