1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * See getopt(3C) and SUS/XPG getopt() for function definition and 34 * requirements. 35 * 36 * This actual implementation is a bit looser than the specification 37 * as it allows any character other than ':' and '(' to be used as 38 * a short option character - The specification only guarantees the 39 * alnum characters ([a-z][A-Z][0-9]). 40 */ 41 42 #pragma weak _getopt = getopt 43 44 #include "lint.h" 45 #include "_libc_gettext.h" 46 47 #include <unistd.h> 48 #include <string.h> 49 #include <stdio.h> 50 51 /* 52 * Generalized error processing macro. The parameter i is a pointer to 53 * the failed option string. If it is NULL, the character in c is converted 54 * to a string and displayed instead. s is the error text. 55 * 56 * This could be / should be a static function if it is used more, but 57 * that would require moving the 'optstring[0]' test outside of the 58 * function. 59 */ 60 #define ERR(s, c, i) if (opterr && optstring[0] != ':') { \ 61 char errbuf[256]; \ 62 char cbuf[2]; \ 63 cbuf[0] = c; \ 64 cbuf[1] = '\0'; \ 65 (void) snprintf(errbuf, sizeof (errbuf), s, argv[0], \ 66 (i ? argv[i]+2 : cbuf)); \ 67 (void) write(2, errbuf, strlen(errbuf)); } 68 69 /* 70 * _sp is required to keep state between successive calls to getopt() while 71 * extracting aggregated short-options (ie: -abcd). Hence, getopt() is not 72 * thread safe or reentrant, but it really doesn't matter. 73 * 74 * So, why isn't this "static" you ask? Because the historical Bourne 75 * shell has actually latched on to this little piece of private data. 76 */ 77 int _sp = 1; 78 79 /* 80 * Determine if the specified character (c) is present in the string 81 * (optstring) as a regular, single character option. If the option is found, 82 * return a pointer into optstring pointing at the short-option character, 83 * otherwise return null. The characters ':' and '(' are not allowed. 84 */ 85 static char * 86 parseshort(const char *optstring, const char c) 87 { 88 char *cp = (char *)optstring; 89 90 if (c == ':' || c == '(') 91 return (NULL); 92 do { 93 if (*cp == c) 94 return (cp); 95 while (*cp == '(') 96 while (*cp != '\0' && *cp != ')') 97 cp++; 98 } while (*cp++ != '\0'); 99 return (NULL); 100 } 101 102 /* 103 * Determine if the specified string (opt) is present in the string 104 * (optstring) as a long-option contained within parenthesis. If the 105 * long-option specifies option-argument, return a pointer to it in 106 * longoptarg. Otherwise set longoptarg to null. If the option is found, 107 * return a pointer into optstring pointing at the short-option character 108 * associated with this long-option; otherwise return null. 109 * 110 * optstring The entire optstring passed to getopt() by the caller 111 * 112 * opt The long option read from the command line 113 * 114 * longoptarg The argument to the option is returned in this parameter, 115 * if an option exists. Possible return values in longoptarg 116 * are: 117 * NULL No argument was found 118 * empty string ("") Argument was explicitly left empty 119 * by the user (e.g., --option= ) 120 * valid string Argument found on the command line 121 * 122 * returns Pointer to equivalent short-option in optstring, null 123 * if option not found in optstring. 124 * 125 * ASSUMES: No parameters are NULL 126 * 127 */ 128 static char * 129 parselong(const char *optstring, const char *opt, char **longoptarg) 130 { 131 char *cp; /* ptr into optstring, beginning of one option spec. */ 132 char *ip; /* ptr into optstring, traverses every char */ 133 char *op; /* pointer into opt */ 134 int match; /* nonzero if opt is matching part of optstring */ 135 136 cp = ip = (char *)optstring; 137 do { 138 if (*ip != '(' && *++ip == '\0') 139 break; 140 if (*ip == ':' && *++ip == '\0') 141 break; 142 while (*ip == '(') { 143 if (*++ip == '\0') 144 break; 145 op = (char *)opt; 146 match = 1; 147 while (*ip != ')' && *ip != '\0' && *op != '\0') 148 match = (*ip++ == *op++ && match); 149 if (match && *ip == ')' && 150 (*op == '\0' || *op == '=')) { 151 if ((*op) == '=') { 152 /* may be an empty string - OK */ 153 (*longoptarg) = op + 1; 154 } else { 155 (*longoptarg) = NULL; 156 } 157 return (cp); 158 } 159 if (*ip == ')' && *++ip == '\0') 160 break; 161 } 162 cp = ip; 163 /* 164 * Handle double-colon in optstring ("a::(longa)") 165 * The old getopt() accepts it and treats it as a 166 * required argument. 167 */ 168 while ((cp > optstring) && ((*cp) == ':')) { 169 --cp; 170 } 171 } while (*cp != '\0'); 172 return (NULL); 173 } /* parselong() */ 174 175 /* 176 * External function entry point. 177 */ 178 int 179 getopt(int argc, char *const *argv, const char *optstring) 180 { 181 char c; 182 char *cp; 183 int longopt; 184 char *longoptarg; 185 186 /* 187 * Has the end of the options been encountered? The following 188 * implements the SUS requirements: 189 * 190 * If, when getopt() is called: 191 * argv[optind] is a null pointer 192 * *argv[optind] is not the character '-' 193 * argv[optind] points to the string "-" 194 * getopt() returns -1 without changing optind. If 195 * argv[optind] points to the string "--" 196 * getopt() returns -1 after incrementing optind. 197 */ 198 if (_sp == 1) { 199 if (optind >= argc || argv[optind][0] != '-' || 200 argv[optind] == NULL || argv[optind][1] == '\0') 201 return (EOF); 202 else if (strcmp(argv[optind], "--") == NULL) { 203 optind++; 204 return (EOF); 205 } 206 } 207 208 /* 209 * Getting this far indicates that an option has been encountered. 210 * Note that the syntax of optstring applies special meanings to 211 * the characters ':' and '(', so they are not permissible as 212 * option letters. A special meaning is also applied to the ')' 213 * character, but its meaning can be determined from context. 214 * Note that the specification only requires that the alnum 215 * characters be accepted. 216 * 217 * If the second character of the argument is a '-' this must be 218 * a long-option, otherwise it must be a short option. Scan for 219 * the option in optstring by the appropriate algorithm. Either 220 * scan will return a pointer to the short-option character in 221 * optstring if the option is found and NULL otherwise. 222 * 223 * For an unrecognized long-option, optopt will equal 0, but 224 * since long-options can't aggregate the failing option can 225 * be identified by argv[optind-1]. 226 */ 227 optopt = c = (unsigned char)argv[optind][_sp]; 228 optarg = NULL; 229 longopt = (_sp == 1 && c == '-'); 230 if (!(longopt ? 231 ((cp = parselong(optstring, argv[optind]+2, &longoptarg)) != NULL) : 232 ((cp = parseshort(optstring, c)) != NULL))) { 233 ERR(_libc_gettext("%s: illegal option -- %s\n"), 234 c, (longopt ? optind : 0)); 235 /* 236 * Note: When the long option is unrecognized, optopt 237 * will be '-' here, which matches the specification. 238 */ 239 if (argv[optind][++_sp] == '\0' || longopt) { 240 optind++; 241 _sp = 1; 242 } 243 return ('?'); 244 } 245 optopt = c = *cp; 246 247 /* 248 * A valid option has been identified. If it should have an 249 * option-argument, process that now. SUS defines the setting 250 * of optarg as follows: 251 * 252 * 1. If the option was the last character in the string pointed to 253 * by an element of argv, then optarg contains the next element 254 * of argv, and optind is incremented by 2. If the resulting 255 * value of optind is not less than argc, this indicates a 256 * missing option-argument, and getopt() returns an error 257 * indication. 258 * 259 * 2. Otherwise, optarg points to the string following the option 260 * character in that element of argv, and optind is incremented 261 * by 1. 262 * 263 * The second clause allows -abcd (where b requires an option-argument) 264 * to be interpreted as "-a -b cd". 265 * 266 * Note that the option-argument can legally be an empty string, 267 * such as: 268 * command --option= operand 269 * which explicitly sets the value of --option to nil 270 */ 271 if (*(cp + 1) == ':') { 272 /* The option takes an argument */ 273 if (!longopt && argv[optind][_sp+1] != '\0') { 274 optarg = &argv[optind++][_sp+1]; 275 } else if (longopt && longoptarg) { 276 /* 277 * The option argument was explicitly set to 278 * the empty string on the command line (--option=) 279 */ 280 optind++; 281 optarg = longoptarg; 282 } else if (++optind >= argc) { 283 ERR(_libc_gettext("%s: option requires an argument" \ 284 " -- %s\n"), c, (longopt ? optind - 1 : 0)); 285 _sp = 1; 286 optarg = NULL; 287 return (optstring[0] == ':' ? ':' : '?'); 288 } else 289 optarg = argv[optind++]; 290 _sp = 1; 291 } else { 292 /* The option does NOT take an argument */ 293 if (longopt && (longoptarg != NULL)) { 294 /* User supplied an arg to an option that takes none */ 295 ERR(_libc_gettext( 296 "%s: option doesn't take an argument -- %s\n"), 297 0, (longopt ? optind : 0)); 298 optarg = longoptarg = NULL; 299 c = '?'; 300 } 301 302 if (longopt || argv[optind][++_sp] == '\0') { 303 _sp = 1; 304 optind++; 305 } 306 optarg = NULL; 307 } 308 return (c); 309 } /* getopt() */