getopt.c (2979B)
1 /* 2 * getopt() - command option parsing 3 * 4 * Gunnar Ritter, Freiburg i. Br., Germany, March 2002. 5 */ 6 7 /* Sccsid @(#)getopt.c 1.6 (gritter) 12/16/07 */ 8 9 #include <sys/types.h> 10 #include <alloca.h> 11 #include <string.h> 12 #include "msgselect.h" 13 14 /* 15 * One should not think that re-implementing this is necessary, but 16 * 17 * - Some libcs print weird messages. 18 * 19 * - GNU libc getopt() is totally brain-damaged, as it requires special 20 * care _not_ to reorder parameters and can't be told to work correctly 21 * with ':' as first optstring character at all. 22 */ 23 24 char *optarg = 0; 25 int optind = 1; 26 int opterr = 1; 27 int optopt = 0; 28 extern char *pfmt_label__; 29 30 static void 31 error(const char *s, int c) 32 { 33 /* 34 * Avoid including <unistd.h>, in case its getopt() declaration 35 * conflicts. 36 */ 37 extern ssize_t write(int, const void *, size_t); 38 const char *msg = 0; 39 char *buf, *bp; 40 41 if (pfmt_label__) 42 s = pfmt_label__; 43 switch (c) { 44 case '?': 45 msg = ": " msgselect("I","i") "llegal option -- "; 46 break; 47 case ':': 48 msg = ": " msgselect("O","o") "ption requires an argument -- "; 49 break; 50 } 51 bp = buf = alloca(strlen(s) + strlen(msg) + 2); 52 while (*s) 53 *bp++ = *s++; 54 while (*msg) 55 *bp++ = *msg++; 56 *bp++ = optopt; 57 *bp++ = '\n'; 58 write(2, buf, bp - buf); 59 } 60 61 int 62 getopt(int argc, char *const argv[], const char *optstring) 63 { 64 int colon; 65 static const char *lastp; 66 const char *curp; 67 68 if (optstring[0] == ':') { 69 colon = 1; 70 optstring++; 71 } else 72 colon = 0; 73 if (lastp) { 74 curp = lastp; 75 lastp = 0; 76 } else { 77 if (optind >= argc || argv[optind] == 0 || 78 argv[optind][0] != '-' || 79 argv[optind][1] == '\0') 80 return -1; 81 if (argv[optind][1] == '-' && argv[optind][2] == '\0') { 82 optind++; 83 return -1; 84 } 85 curp = &argv[optind][1]; 86 } 87 optopt = curp[0] & 0377; 88 while (optstring[0]) { 89 if (optstring[0] == ':') { 90 optstring++; 91 continue; 92 } 93 if ((optstring[0] & 0377) == optopt) { 94 if (optstring[1] == ':') { 95 if (curp[1] != '\0') { 96 optarg = (char *)&curp[1]; 97 optind++; 98 } else { 99 if ((optind += 2) > argc) { 100 if (!colon && opterr) 101 error(argv[0], ':'); 102 return colon ? ':' : '?'; 103 } 104 optarg = argv[optind - 1]; 105 } 106 } else { 107 if (curp[1] != '\0') 108 lastp = &curp[1]; 109 else 110 optind++; 111 optarg = 0; 112 } 113 return optopt; 114 } 115 optstring++; 116 } 117 if (!colon && opterr) 118 error(argv[0], '?'); 119 if (curp[1] != '\0') 120 lastp = &curp[1]; 121 else 122 optind++; 123 optarg = 0; 124 return '?'; 125 } 126 127 #ifdef __APPLE__ 128 /* 129 * Starting with Mac OS 10.5 Leopard, <unistd.h> turns getopt() 130 * into getopt$UNIX2003() by default. Consequently, this function 131 * is called instead of the one defined above. However, optind is 132 * still taken from this file, so in effect, options are not 133 * properly handled. Defining an own getopt$UNIX2003() function 134 * works around this issue. 135 */ 136 int 137 getopt$UNIX2003(int argc, char *const argv[], const char *optstring) 138 { 139 return getopt(argc, argv, optstring); 140 } 141 #endif /* __APPLE__ */