VirtualBox

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

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

RTGetOpt comment.

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