1 /* $NetBSD: egetopt.c,v 1.11 2026/06/28 10:47:54 rillig Exp $ */ 2 3 /*- 4 * Copyright (c) 1991 Keith Muller. 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Keith Muller of the University of California, San Diego. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 /* From: "@(#)egetopt.c 8.1 (Berkeley) 6/6/93" */ 38 __RCSID("$NetBSD: egetopt.c,v 1.11 2026/06/28 10:47:54 rillig Exp $"); 39 40 #include <ctype.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #include "extern.h" 46 47 /* 48 * egetopt: get option letter from argument vector (an extended 49 * version of getopt). 50 * 51 * Non standard additions to the ostr specs are: 52 * 1) '?': immediate value following arg is optional (no white space 53 * between the arg and the value) 54 * 2) '#': +/- followed by a number (with an optional sign but 55 * no white space between the arg and the number). The - may be 56 * combined with other options, but the + cannot. 57 */ 58 59 int eopterr = 1; /* if error message should be printed */ 60 int eoptind = 1; /* index into parent argv vector */ 61 int eoptopt; /* character checked for validity */ 62 char *eoptarg; /* argument associated with option */ 63 64 static char EMSG[1] = { '\0' }; 65 66 int 67 egetopt(int nargc, char * const *nargv, const char *ostr) 68 { 69 static char *place = EMSG; /* option letter processing */ 70 const char *oli; /* option letter list index */ 71 static int delim; /* which option delimiter */ 72 char *p; 73 static char savec = '\0'; 74 75 if (savec != '\0') { 76 *place = savec; 77 savec = '\0'; 78 } 79 80 if (!*place) { 81 /* 82 * update scanning pointer 83 */ 84 if (eoptind >= nargc || 85 (*(place = nargv[eoptind]) != '-' && *place != '+')) { 86 place = EMSG; 87 return -1; 88 } 89 90 delim = *place; 91 if (place[1] && *++place == '-' && !place[1]) { 92 /* 93 * found "--" 94 */ 95 ++eoptind; 96 place = EMSG; 97 return -1; 98 } 99 } 100 101 /* 102 * check option letter 103 */ 104 if ((eoptopt = (unsigned char)*place++) == ':' || eoptopt == '?' || 105 !(oli = strchr(ostr, eoptopt))) { 106 /* 107 * if the user didn't specify '-' as an option, 108 * assume it means -1 when by itself. 109 */ 110 if (eoptopt == '-' && !*place) 111 return -1; 112 if (strchr(ostr, '#') && (isdigit(eoptopt) || 113 ((eoptopt == '-' || eoptopt == '+') && 114 isdigit((unsigned char)*place)))) { 115 /* 116 * # option: +/- with a number is ok 117 */ 118 for (p = place; *p != '\0'; ++p) { 119 if (!isdigit((unsigned char)*p)) 120 break; 121 } 122 eoptarg = place - 1; 123 124 if (*p == '\0') { 125 place = EMSG; 126 ++eoptind; 127 } else { 128 place = p; 129 savec = *p; 130 *place = '\0'; 131 } 132 return delim; 133 } 134 135 if (!*place) 136 ++eoptind; 137 if (eopterr) { 138 if (!(p = strrchr(*nargv, '/'))) 139 p = *nargv; 140 else 141 ++p; 142 (void)fprintf(stderr, "%s: illegal option -- %c\n", 143 p, eoptopt); 144 } 145 return '?'; 146 } 147 if (delim == '+') { 148 /* 149 * '+' is only allowed with numbers 150 */ 151 if (!*place) 152 ++eoptind; 153 if (eopterr) { 154 if (!(p = strrchr(*nargv, '/'))) 155 p = *nargv; 156 else 157 ++p; 158 (void)fprintf(stderr, 159 "%s: illegal '+' delimiter with option -- %c\n", 160 p, eoptopt); 161 } 162 return '?'; 163 } 164 ++oli; 165 if (*oli != ':' && *oli != '?') { 166 /* 167 * don't need argument 168 */ 169 eoptarg = NULL; 170 if (!*place) 171 ++eoptind; 172 return eoptopt; 173 } 174 175 if (*place) { 176 /* 177 * no white space 178 */ 179 eoptarg = place; 180 } else if (*oli == '?') { 181 /* 182 * no arg, but NOT required 183 */ 184 eoptarg = NULL; 185 } else if (nargc <= ++eoptind) { 186 /* 187 * no arg, but IS required 188 */ 189 place = EMSG; 190 if (eopterr) { 191 if (!(p = strrchr(*nargv, '/'))) 192 p = *nargv; 193 else 194 ++p; 195 (void)fprintf(stderr, 196 "%s: option requires an argument -- %c\n", p, 197 eoptopt); 198 } 199 return '?'; 200 } else { 201 /* 202 * arg has white space 203 */ 204 eoptarg = nargv[eoptind]; 205 } 206 place = EMSG; 207 ++eoptind; 208 return eoptopt; 209 } 210