1/* $NetBSD: getopt_long.c,v 1.1.1.1 2021/04/07 02:43:15 christos Exp $ */ 2 3/* 4 * Copyright (c) 1987, 1993, 1994, 1996 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the names of the copyright holders nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 20 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <assert.h> 32#include <errno.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include "getopt.h" 37 38extern int opterr; /* if error message should be printed */ 39extern int optind; /* index into parent argv vector */ 40extern int optopt; /* character checked for validity */ 41extern int optreset; /* reset getopt */ 42extern char *optarg; /* argument associated with option */ 43 44#define __P(x) x 45#define _DIAGASSERT(x) assert(x) 46 47static char * __progname __P((char *)); 48int getopt_internal __P((int, char * const *, const char *)); 49 50static char * 51__progname(nargv0) 52 char * nargv0; 53{ 54 char * tmp; 55 56 _DIAGASSERT(nargv0 != NULL); 57 58 tmp = strrchr(nargv0, '/'); 59 if (tmp) 60 tmp++; 61 else 62 tmp = nargv0; 63 return(tmp); 64} 65 66#define BADCH (int)'?' 67#define BADARG (int)':' 68#define EMSG "" 69 70/* 71 * getopt -- 72 * Parse argc/argv argument vector. 73 */ 74int 75getopt_internal(nargc, nargv, ostr) 76 int nargc; 77 char * const *nargv; 78 const char *ostr; 79{ 80 static char *place = EMSG; /* option letter processing */ 81 char *oli; /* option letter list index */ 82 83 _DIAGASSERT(nargv != NULL); 84 _DIAGASSERT(ostr != NULL); 85 86 if (optreset || !*place) { /* update scanning pointer */ 87 optreset = 0; 88 if (optind >= nargc || *(place = nargv[optind]) != '-') { 89 place = EMSG; 90 return (-1); 91 } 92 if (place[1] && *++place == '-') { /* found "--" */ 93 /* ++optind; */ 94 place = EMSG; 95 return (-2); 96 } 97 } /* option letter okay? */ 98 if ((optopt = (int)*place++) == (int)':' || 99 !(oli = strchr(ostr, optopt))) { 100 /* 101 * if the user didn't specify '-' as an option, 102 * assume it means -1. 103 */ 104 if (optopt == (int)'-') 105 return (-1); 106 if (!*place) 107 ++optind; 108 if (opterr && *ostr != ':') 109 (void)fprintf(stderr, 110 "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); 111 return (BADCH); 112 } 113 if (*++oli != ':') { /* don't need argument */ 114 optarg = NULL; 115 if (!*place) 116 ++optind; 117 } else { /* need an argument */ 118 if (*place) /* no white space */ 119 optarg = place; 120 else if (nargc <= ++optind) { /* no arg */ 121 place = EMSG; 122 if ((opterr) && (*ostr != ':')) 123 (void)fprintf(stderr, 124 "%s: option requires an argument -- %c\n", 125 __progname(nargv[0]), optopt); 126 return (BADARG); 127 } else /* white space */ 128 optarg = nargv[optind]; 129 place = EMSG; 130 ++optind; 131 } 132 return (optopt); /* dump back option letter */ 133} 134 135#if 0 136/* 137 * getopt -- 138 * Parse argc/argv argument vector. 139 */ 140int 141getopt2(nargc, nargv, ostr) 142 int nargc; 143 char * const *nargv; 144 const char *ostr; 145{ 146 int retval; 147 148 if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { 149 retval = -1; 150 ++optind; 151 } 152 return(retval); 153} 154#endif 155 156/* 157 * getopt_long -- 158 * Parse argc/argv argument vector. 159 */ 160int 161getopt_long(nargc, nargv, options, long_options, index) 162 int nargc; 163 char ** nargv; 164 const char * options; 165 const struct option * long_options; 166 int * index; 167{ 168 int retval; 169 170 _DIAGASSERT(nargv != NULL); 171 _DIAGASSERT(options != NULL); 172 _DIAGASSERT(long_options != NULL); 173 /* index may be NULL */ 174 175 if ((retval = getopt_internal(nargc, nargv, options)) == -2) { 176 char *current_argv = nargv[optind++] + 2, *has_equal; 177 int i, match = -1; 178 size_t current_argv_len; 179 180 if (*current_argv == '\0') { 181 return(-1); 182 } 183 if ((has_equal = strchr(current_argv, '=')) != NULL) { 184 current_argv_len = has_equal - current_argv; 185 has_equal++; 186 } else 187 current_argv_len = strlen(current_argv); 188 189 for (i = 0; long_options[i].name; i++) { 190 if (strncmp(current_argv, long_options[i].name, current_argv_len)) 191 continue; 192 193 if (strlen(long_options[i].name) == current_argv_len) { 194 match = i; 195 break; 196 } 197 if (match == -1) 198 match = i; 199 } 200 if (match != -1) { 201 if (long_options[match].has_arg == required_argument || 202 long_options[match].has_arg == optional_argument) { 203 if (has_equal) 204 optarg = has_equal; 205 else 206 optarg = nargv[optind++]; 207 } 208 if ((long_options[match].has_arg == required_argument) 209 && (optarg == NULL)) { 210 /* 211 * Missing argument, leading : 212 * indicates no error should be generated 213 */ 214 if ((opterr) && (*options != ':')) 215 (void)fprintf(stderr, 216 "%s: option requires an argument -- %s\n", 217 __progname(nargv[0]), current_argv); 218 return (BADARG); 219 } 220 } else { /* No matching argument */ 221 if ((opterr) && (*options != ':')) 222 (void)fprintf(stderr, 223 "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); 224 return (BADCH); 225 } 226 if (long_options[match].flag) { 227 *long_options[match].flag = long_options[match].val; 228 retval = 0; 229 } else 230 retval = long_options[match].val; 231 if (index) 232 *index = match; 233 } 234 return(retval); 235} 236