1 /* $NetBSD: getopt.c,v 1.1 2009/03/22 22:33:13 joerg Exp $*/ 2 /* Modified by David Anderson to work with GNU/Linux and freebsd. 3 Added {} for clarity. 4 Switched to standard dwarfdump formatting. 5 Treatment of : modified so that :: gets dwoptarg NULL 6 if space follows the letter 7 (the dwoptarg is set to null). 8 renamed to make it clear this is a private version. 9 Oct 17 2017: Created dwgetopt_long(). See dwgetopt.h 10 */ 11 /* 12 * Copyright (c) 1987, 1993, 1994 13 * The Regents of the University of California. All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 3. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 /* This does not presently handle the option string 41 leading + or leading - features. Such are not used 42 by by libdwarfdump. Nor does it understand the 43 GNU Env var POSIXLY_CORRECT . 44 It does know of the leading ":" in the option string. 45 See BADCH below. 46 */ 47 48 #include <stdio.h> 49 #ifdef HAVE_STDLIB_H 50 #include <stdlib.h> 51 #endif /* HAVE_STDLIB_H */ 52 #include <string.h> /* For strchr */ 53 #include "dwgetopt.h" 54 55 #define STRIP_OFF_CONSTNESS(a) ((void *)(size_t)(const void *)(a)) 56 57 int dwopterr = 1, /* if error message should be printed */ 58 dwoptind = 1, /* index into parent argv vector */ 59 dwoptopt, /* character checked for validity */ 60 dwoptreset; /* reset getopt */ 61 char *dwoptarg; /* argument associated with option */ 62 63 #define BADCH (int)'?' 64 #define BADARG (int)':' 65 #define EMSG "" 66 67 #define TRUE 1 68 #define FALSE 0 69 70 #if 0 /* FOR DEBUGGING ONLY */ 71 /* Use for testing dwgetopt only. 72 Not a standard function. */ 73 void 74 dwgetoptresetfortestingonly(void) 75 { 76 dwopterr = 1; 77 dwoptind = 1; 78 dwoptopt = 0; 79 dwoptreset = 0; 80 dwoptarg = 0; 81 } 82 #endif /* FOR DEBUGGING ONLY */ 83 84 85 static const char *place = EMSG;/* option letter processing */ 86 87 88 /* Post Condition: 89 if return FALSE then *argerr is set false. */ 90 static int 91 dwoptnamematches( 92 const struct dwoption *dwlopt, 93 const char *iplace, 94 const char **argloc, 95 int *argerr) 96 { 97 98 const char *eq = 0; 99 size_t namelen = 0; 100 size_t arglen = 0; 101 int d = 0; 102 103 for(eq = iplace; *eq; ++eq) { 104 if (*eq != '=') { 105 continue; 106 } 107 /* Found =, arg should follow */ 108 namelen = (eq - iplace); 109 if (namelen != (unsigned)strlen(dwlopt->name)) { 110 return FALSE; 111 } 112 eq++; 113 arglen = strlen(eq); 114 break; 115 } 116 if (namelen) { 117 d = strncmp(iplace,dwlopt->name,namelen); 118 if (d) { 119 return FALSE; 120 } 121 if (dwlopt->has_arg == 0) { 122 *argerr = TRUE; 123 return TRUE; 124 } 125 if (arglen) { 126 /* Discarding const, avoiding warning. 127 Data is in user space, so this is ok. */ 128 dwoptarg = (char *)eq; 129 *argloc = (const char *)eq; 130 } else { 131 /* Has arg = but arg is empty. */ 132 dwoptarg = 0; 133 } 134 return TRUE; 135 } else { 136 d = strcmp(iplace,dwlopt->name); 137 if (d) { 138 return FALSE; 139 } 140 if (dwlopt->has_arg == 1) { 141 *argerr = TRUE; 142 return TRUE; 143 } 144 dwoptarg = 0; 145 return TRUE; 146 } 147 } 148 149 150 151 /* dwgetopt_long 152 A reimplemenation of a portion of 153 the getopt(3) GNU/Linux getopt_long(). 154 See dwgetopt.h for more details. 155 */ 156 int dwgetopt_long(int nargc, char *const nargv[], 157 const char *ostr, 158 const struct dwoption* longopts, 159 int *longindex) 160 { 161 char *lplace = 0; 162 if (dwoptreset) { 163 /* Not really supported. */ 164 place = EMSG; 165 return (-1); 166 } 167 if (*place) { 168 int v = dwgetopt(nargc,nargv,ostr); 169 return v; 170 } 171 /* Use local lplace in case we need to call getopt() 172 just below. */ 173 lplace = nargv[dwoptind]; 174 if (dwoptind >= nargc || *lplace++ != '-') { 175 /* Argument is absent or is not an option */ 176 place = EMSG; 177 return (-1); 178 } 179 if (*lplace != '-') { 180 /* Notice place not disturbed. */ 181 int v = dwgetopt(nargc,nargv,ostr); 182 return v; 183 } 184 /* Starts with two dashes. 185 Now we set the global place */ 186 place = lplace+1; 187 if (!*place) { 188 /* "--" => end of options */ 189 ++dwoptind; 190 place = EMSG; 191 return (-1); 192 } 193 194 /* We think this is a longopt. */ 195 { 196 int lo_num = 0; 197 198 for(;;lo_num++) { 199 const struct dwoption *dwlopt = longopts +lo_num; 200 const char * argloc = 0; 201 int argerr = 0; 202 int resmatch = 0; 203 204 if (!dwlopt->name) { 205 dwoptind++; 206 (void)fprintf(stderr, 207 "%s: invalid long option '--%s'\n", 208 nargv[0]?nargv[0]:"", 209 place); 210 /* Leave longindex unchanged. */ 211 place = EMSG; 212 return (BADCH); 213 } 214 resmatch= dwoptnamematches(dwlopt,place, 215 &argloc,&argerr); 216 if (resmatch) { 217 dwoptarg = 0; 218 if (argloc) { 219 /* Must drop const here. Ugh. */ 220 dwoptarg = (char *)argloc; 221 } 222 } 223 if (argerr) { 224 /* resmatch == TRUE 225 226 arg option missing if required, present 227 but not allowed. 228 GNU Behavior not well documented. 229 Had to experiment. 230 231 if argument-not-allowed, and we have one, 232 do ??? 233 234 If argument-required, 235 then here GNU 236 would take the next argv as the argument. 237 we are not currently doing that. */ 238 /**longindex = lo_num; */ 239 if (dwlopt->has_arg) { 240 /* Missing required arg, this does not 241 match GNU getopt_long behavior 242 of taking next argv as the arg value. 243 and thus making getopt_long succeed. */ 244 (void)fprintf(stderr, 245 "%s: missing required long option argument '--%s'\n", 246 nargv[0]?nargv[0]:"", 247 place); 248 } else { 249 /* has arg but should not */ 250 (void)fprintf(stderr, 251 "%s: option '--%s' does not allow an argument\n", 252 nargv[0]?nargv[0]:"", 253 dwlopt->name); 254 } 255 dwoptind++; 256 place = EMSG; 257 return (BADCH); 258 } 259 if (resmatch) { 260 *longindex = lo_num; 261 place = EMSG; 262 dwoptind++; 263 return dwlopt->val; 264 } 265 } 266 /* Can never get here */ 267 place = EMSG; 268 dwoptind++; 269 return (-1); 270 } 271 } 272 273 /* 274 * getopt -- 275 * Parse argc/argv argument vector. 276 * a: means 277 * -afoo 278 * -a foo 279 * and 'foo' is returned in dwoptarg 280 * b:: means 281 * -b 282 * and dwoptarg is null 283 * -bother 284 * and dwoptarg is 'other' 285 */ 286 int 287 dwgetopt(int nargc, char * const nargv[], const char *ostr) 288 { 289 char *oli; /* option letter list index */ 290 291 if (dwoptreset || *place == 0) { /* update scanning pointer */ 292 dwoptreset = 0; 293 place = nargv[dwoptind]; 294 295 if (dwoptind >= nargc || *place++ != '-') { 296 /* Argument is absent or is not an option */ 297 place = EMSG; 298 return (-1); 299 } 300 dwoptopt = *place++; 301 if (dwoptopt == '-' && *place == 0) { 302 /* "--" => end of options */ 303 ++dwoptind; 304 place = EMSG; 305 return (-1); 306 } 307 if (dwoptopt == 0) { 308 /* Solitary '-', treat as a '-' option 309 if the program (eg su) is looking for it. */ 310 place = EMSG; 311 if (strchr(ostr, '-') == NULL) { 312 return -1; 313 } 314 dwoptopt = '-'; 315 } 316 } else { 317 dwoptopt = *place++; 318 } 319 /* See if option letter is one the caller wanted... */ 320 if (dwoptopt == ':' || (oli = strchr(ostr, dwoptopt)) == NULL) { 321 if (*place == 0) { 322 ++dwoptind; 323 } 324 if (dwopterr && *ostr != ':') { 325 (void)fprintf(stderr, 326 "%s: invalid option -- '%c'\n", 327 nargv[0]?nargv[0]:"", 328 dwoptopt); 329 } 330 return (BADCH); 331 } 332 333 /* Does this option need an argument? */ 334 if (oli[1] != ':') { 335 /* don't need argument */ 336 dwoptarg = NULL; 337 if (*place == 0) { 338 ++dwoptind; 339 } 340 } else { 341 int reqnextarg = 1; 342 if (oli[1] && (oli[2] == ':')) { 343 /* Pair of :: means special treatment of dwoptarg */ 344 reqnextarg = 0; 345 } 346 /* Option-argument is either the rest of this argument or the 347 entire next argument. */ 348 if (*place ) { 349 /* Whether : or :: */ 350 dwoptarg = STRIP_OFF_CONSTNESS(place); 351 } else if (reqnextarg) { 352 /* ! *place */ 353 if (nargc > (++dwoptind)) { 354 dwoptarg = nargv[dwoptind]; 355 } else { 356 place=EMSG; 357 /* Next arg required, but is missing */ 358 if (*ostr == ':') { 359 /* Leading : in ostr calls for BADARG return. */ 360 return (BADARG); 361 } 362 if (dwopterr) { 363 (void)fprintf(stderr, 364 "%s: option requires an argument. -- '%c'\n", 365 nargv[0]?nargv[0]:"", 366 dwoptopt); 367 } 368 return (BADCH); 369 } 370 } else { 371 /* ! *place */ 372 /* The key part of :: treatment. */ 373 dwoptarg = NULL; 374 } 375 place = EMSG; 376 ++dwoptind; 377 } 378 return (dwoptopt); /* return option letter */ 379 } 380