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