getopt.c (6585B)
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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany 28 * 29 * Sccsid @(#)getopt.c 1.10 (gritter) 12/16/07 30 */ 31 /* from OpenSolaris "getopt.c 1.23 05/06/08 SMI" */ 32 33 /* Copyright (c) 1988 AT&T */ 34 /* All Rights Reserved */ 35 36 37 /* 38 * See getopt(3C) and SUS/XPG getopt() for function definition and 39 * requirements. 40 * 41 * This actual implementation is a bit looser than the specification 42 * as it allows any character other than ':' to be used as an option 43 * character - The specification only guarantees the alnum characters 44 * ([a-z][A-Z][0-9]). 45 */ 46 47 #include <sys/types.h> 48 #include <string.h> 49 #include <stdio.h> 50 51 extern ssize_t write(int, const void *, size_t); 52 53 char *optarg = NULL; 54 int optind = 1; 55 int opterr = 1; 56 int optopt = 0; 57 58 #define ERR(s, c) err(s, c, optstring, argv[0]) 59 static void 60 err(const char *s, int c, const char *optstring, const char *argv0) 61 { 62 char errbuf[256], *ep = errbuf; 63 const char *cp; 64 65 if (opterr && optstring[0] != ':') { 66 for (cp = argv0; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++) 67 *ep = *cp; 68 for (cp = ": "; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++) 69 *ep = *cp; 70 for (cp = s; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++) 71 *ep = *cp; 72 for (cp = " -- "; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++) 73 *ep = *cp; 74 if (ep<&errbuf[sizeof errbuf]) 75 *ep++ = c; 76 if (ep<&errbuf[sizeof errbuf]) 77 *ep++ = '\n'; 78 write(2, errbuf, ep - errbuf); 79 } 80 } 81 82 /* 83 * getopt_sp is required to keep state between successive calls to getopt() 84 * while extracting aggregated options (ie: -abcd). Hence, getopt() is not 85 * thread safe or reentrant, but it really doesn't matter. 86 * 87 * So, why isn't this "static" you ask? Because the historical Bourne 88 * shell has actually latched on to this little piece of private data. 89 */ 90 int getopt_sp = 1; 91 92 /* 93 * Determine if the specified character (c) is present in the string 94 * (optstring) as a regular, single character option. If the option is found, 95 * return a pointer into optstring pointing at the option character, 96 * otherwise return null. The character ':' is not allowed. 97 */ 98 static char * 99 parse(const char *optstring, const char c) 100 { 101 char *cp = (char *)optstring; 102 103 if (c == ':') 104 return (NULL); 105 do { 106 if (*cp == c) 107 return (cp); 108 } while (*cp++ != '\0'); 109 return (NULL); 110 } 111 112 /* 113 * External function entry point. 114 */ 115 int 116 getopt(int argc, char *const *argv, const char *optstring) 117 { 118 char c; 119 char *cp; 120 121 /* 122 * Has the end of the options been encountered? The following 123 * implements the SUS requirements: 124 * 125 * If, when getopt() is called: 126 * argv[optind] is a null pointer 127 * *argv[optind] is not the character '-' 128 * argv[optind] points to the string "-" 129 * getopt() returns -1 without changing optind. If 130 * argv[optind] points to the string "--" 131 * getopt() returns -1 after incrementing optind. 132 */ 133 if (getopt_sp == 1) { 134 if (optind >= argc || argv[optind][0] != '-' || 135 argv[optind] == NULL || argv[optind][1] == '\0') 136 return (EOF); 137 else if (strcmp(argv[optind], "--") == 0) { 138 optind++; 139 return (EOF); 140 } 141 } 142 143 /* 144 * Getting this far indicates that an option has been encountered. 145 * Note that the syntax of optstring applies special meanings to 146 * the characters ':' and '(', so they are not permissible as 147 * option letters. A special meaning is also applied to the ')' 148 * character, but its meaning can be determined from context. 149 * Note that the specification only requires that the alnum 150 * characters be accepted. 151 */ 152 optopt = c = (unsigned char)argv[optind][getopt_sp]; 153 optarg = NULL; 154 if ((cp = parse(optstring, c)) == NULL) { 155 /* LINTED: variable format specifier */ 156 ERR("illegal option", c); 157 if (argv[optind][++getopt_sp] == '\0') { 158 optind++; 159 getopt_sp = 1; 160 } 161 return ('?'); 162 } 163 optopt = c = *cp; 164 165 /* 166 * A valid option has been identified. If it should have an 167 * option-argument, process that now. SUS defines the setting 168 * of optarg as follows: 169 * 170 * 1. If the option was the last character in the string pointed to 171 * by an element of argv, then optarg contains the next element 172 * of argv, and optind is incremented by 2. If the resulting 173 * value of optind is not less than argc, this indicates a 174 * missing option-argument, and getopt() returns an error 175 * indication. 176 * 177 * 2. Otherwise, optarg points to the string following the option 178 * character in that element of argv, and optind is incremented 179 * by 1. 180 * 181 * The second clause allows -abcd (where b requires an option-argument) 182 * to be interpreted as "-a -b cd". 183 */ 184 if (*(cp + 1) == ':') { 185 /* The option takes an argument */ 186 if (argv[optind][getopt_sp+1] != '\0') { 187 optarg = &argv[optind++][getopt_sp+1]; 188 } else if (++optind >= argc) { 189 /* LINTED: variable format specifier */ 190 ERR("option requires an argument", c); 191 getopt_sp = 1; 192 optarg = NULL; 193 return (optstring[0] == ':' ? ':' : '?'); 194 } else 195 optarg = argv[optind++]; 196 getopt_sp = 1; 197 } else { 198 /* The option does NOT take an argument */ 199 if (argv[optind][++getopt_sp] == '\0') { 200 getopt_sp = 1; 201 optind++; 202 } 203 optarg = NULL; 204 } 205 return (c); 206 } /* getopt() */ 207 208 #ifdef __APPLE__ 209 /* 210 * Starting with Mac OS 10.5 Leopard, <unistd.h> turns getopt() 211 * into getopt$UNIX2003() by default. Consequently, this function 212 * is called instead of the one defined above. However, optind is 213 * still taken from this file, so in effect, options are not 214 * properly handled. Defining an own getopt$UNIX2003() function 215 * works around this issue. 216 */ 217 int 218 getopt$UNIX2003(int argc, char *const argv[], const char *optstring) 219 { 220 return getopt(argc, argv, optstring); 221 } 222 #endif /* __APPLE__ */