00001 00002 // pgetopt.C: portable and simplified version of getopt() in UNIX, system V 00003 //............................................................................. 00004 // version 1: Nov 1989 Piet Hut email: piet@iassns.bitnet 00005 // Institute for Advanced Study, Princeton, NJ, USA 00006 // version 2: Dec 1992 Piet Hut -- adopted to the new C++-based starlab 00007 // version 3: Aug 1999 Steve McMillan 00008 // allow up to 16 arguments per option 00009 // allow single optional arguments 00010 //............................................................................. 00011 // non-local function: 00012 // pgetopt 00013 //............................................................................. 00014 // 00015 // Command line argument passing is done in System V UNIX style. However, 00016 // instead of the function getopt() , we use a private, portable version 00017 // pgetopt(), given here. The reason for providing our own function is that 00018 // there are non-system V UNIX versions, such as some Berkeley UNICES, which 00019 // do not provide getopt(). By always using our own pgetopt() we guarantee 00020 // uniform behavior, independent of the UNIX version used. 00021 // 00022 // Restrictions: the length of an option is one character, and the argument 00023 // has to follow the corresponding option, but separated by 00024 // a space (or tab). 00025 // Options have to start with a minus sign, but more than one 00026 // option can be combined after the same minus sign. 00027 // 00028 // Examples: The following command lines all give the same effect: 00029 // mumble -a -b 10 -c 00030 // mumble -c -a -b 10 00031 // mumble -b 10 -ca 00032 // mumble -acb 10 00033 // but the following versions are illegal, and will give error messages: 00034 // mumble -a -b10 -c 00035 // mumble -ab10c 00036 // mumble -a -c -b 00037 //............................................................................. 00038 00039 #include "stdinc.h" 00040 00041 #ifndef TOOLBOX 00042 00043 #define VERSION_OPTION_A "-version" 00044 #define VERSION_OPTION_B "--version" 00045 00046 char *poptarg; // global variable 00047 00048 // New version (Steve, 8/99): allow up to 16 numeric arguments to be 00049 // associated with an option. Store the pointers in the global array 00050 // poparr[N_POP_ARG]. Retain poptarg for compatibility, but note that 00051 // poparr[0] is the same thing. 00052 00053 #define N_POP_ARG 16 00054 00055 char *poparr[N_POP_ARG]; // global array 00056 00057 //----------------------------------------------------------------------------- 00058 // pgetopt -- each call to pgetopt() returns the next option encountered 00059 // on the command line, starting from the beginning. If the 00060 // option occurs in the optstr string as well, the option 00061 // itself is returned (as the int value of the character; 00062 // options are limited to one char). Otherwise, the character '?' 00063 // is returned. If the end of the string is reached, the value 00064 // -1 is returned. If an option is followed by the character ':' 00065 // in optstr , then a command line argument is expected, 00066 // separated by spaces. If such an argument if found, the pointer 00067 // poptarg is pointed at that string, so that the calling 00068 // function can access the argument. If such an argument is not 00069 // found, an error message is given. 00070 // 00071 // .............................................................. 00072 // 00073 // See above note for extension to this scheme, as of 8/99. 00074 // Also added optional arguments, indicated by "." in optstr. 00075 // 00076 // Optional arguments *may not* start with "-", as that character 00077 // is used to identify the start of the next option string... 00078 // 00079 // .............................................................. 00080 // 00081 // This function is quite unforgiving of errors in the format 00082 // of the command line. In typical use, there is no check in 00083 // the calling program that poptarg (etc.) are properly set, or 00084 // that the number of arguments is correct. No default values 00085 // are set, and errors generally cause the program to stop 00086 // -- caveat emptor! 00087 // 00088 // NOTE: The option "-version" or "--version" to any Starlab 00089 // program is legal, and will result in the program 00090 // printing the current version number on cerr and 00091 // terminating. 00092 // 00093 //---------------------------------------------------------------------------- 00094 00095 int pgetopt(int argc, char ** argv, char * optstr) 00096 { 00097 static int argv_counter = 1; // argument counter 00098 // skip argv[0], the command name 00099 static int argv_offset = 0; // character counter within argument 00100 // (multiple switches per argument 00101 // are allowed) 00102 00103 if (argv_counter >= argc) 00104 return -1; // signal that we've run out of options 00105 00106 if (argv_offset == 0) { 00107 if (argv[argv_counter][argv_offset] != '-') { 00108 cerr << "pgetopt: warning: command line argument \"" 00109 << argv[argv_counter] 00110 << "\" does not begin with \"-\"\n"; 00111 00112 // exit(1); // too severe... 00113 00114 argv_counter++; 00115 return '?'; 00116 00117 } else 00118 argv_offset++; 00119 } 00120 00121 // We have a legal switch. First check to see if all we want to 00122 // know is the STARLAB version number. 00123 00124 if (streq(argv[argv_counter], VERSION_OPTION_A) 00125 || streq(argv[argv_counter], VERSION_OPTION_B)) { 00126 cerr << "Starlab version " << STARLAB_VERSION << endl; 00127 exit(0); 00128 } 00129 00130 char option_char = argv[argv_counter][argv_offset]; 00131 00132 // Locate the next character in the argument list in optstr. 00133 00134 int optstr_counter = 0; 00135 while (optstr[optstr_counter] != option_char) { 00136 00137 if (optstr[optstr_counter] == '\0') { 00138 00139 // Prepare for the next call to pgetopt. 00140 00141 if (argv[argv_counter][++argv_offset] == '\0') { 00142 argv_counter++; 00143 argv_offset = 0; 00144 } 00145 return '?'; // couldn't find the specified 00146 // command-line option in optstr 00147 00148 } else 00149 00150 optstr_counter++; 00151 } 00152 00153 // Current command-line option is option_char, and it exists in 00154 // optstr, at position optstr_counter. 00155 00156 poptarg = poparr[0] = NULL; // default: no/optional argument 00157 00158 // Look for arguments, and set up pointers to them. 00159 00160 char opt; 00161 int narg = 0; 00162 00163 while ((opt = optstr[++optstr_counter]) == ':' || opt == '.') { 00164 00165 // Options must always be immediately followed by their arguments. 00166 00167 if (narg == 0) { 00168 if (argv[argv_counter][argv_offset + 1] != '\0') { 00169 cerr << "pgetopt: option \"-" << option_char 00170 << "\" not followed by a space"; 00171 if (opt == ':') cerr << " and argument"; 00172 cerr << endl; 00173 exit(1); 00174 } 00175 } else if (narg >= N_POP_ARG) { 00176 00177 // Shouldn't happen... 00178 00179 cerr << "pgetopt: too many arguments requested for option \"-" 00180 << option_char << "\"" << endl; 00181 exit(1); 00182 } 00183 00184 // Move to the next argument and check that it exists. 00185 00186 if (++argv_counter >= argc && opt == ':') { 00187 cerr << "pgetopt: option \"-" << option_char 00188 << "\" requires space-separated argument(s)\n"; 00189 exit(1); 00190 } 00191 00192 // Check for a single optional argument. 00193 00194 if (opt == '.' 00195 && (argv_counter >= argc || argv[argv_counter][0] == '-')) { 00196 argv_counter--; 00197 break; 00198 } 00199 00200 // Comptibility: 00201 00202 if (narg == 0) poptarg = argv[argv_counter]; 00203 00204 poparr[narg++] = argv[argv_counter]; 00205 00206 } 00207 00208 // Prepare for the next call to pgetopt. 00209 00210 if (poptarg || argv[argv_counter][++argv_offset] == '\0') { 00211 00212 argv_counter++; 00213 argv_offset = 0; 00214 00215 } 00216 00217 return option_char; 00218 } 00219 00220 00221 #else 00222 00223 void main(char argc, char ** argv) 00224 { 00225 extern char *poptarg; 00226 extern char *poparr[]; // new (8/99) 00227 int c; 00228 char* param_string = "ab:c::d:::e::::fg.h"; 00229 00230 while ((c = pgetopt(argc, argv, param_string)) != -1) { 00231 switch (c) { 00232 00233 case 'a': cerr << "option a: no arguments" 00234 << endl; 00235 break; 00236 00237 case 'b': cerr << "option b: argument: " 00238 << poptarg << " = " << poparr[0] 00239 << endl; 00240 break; 00241 00242 case 'c': cerr << "option c: arguments: " 00243 << poparr[0] << " " << poparr[1] 00244 << endl; 00245 break; 00246 00247 case 'd': cerr << "option d: arguments: " 00248 << poparr[0] << " " << poparr[1] << " " 00249 << poparr[2] 00250 << endl; 00251 break; 00252 00253 case 'e': cerr << "option e: arguments: " 00254 << poparr[0] << " " << poparr[1] << " " 00255 << poparr[2] << " " << poparr[3] 00256 << endl; 00257 break; 00258 00259 case 'f': cerr << "option f: no arguments" 00260 << endl; 00261 break; 00262 00263 case 'g': if (poptarg) 00264 cerr << "option g: optional argument: " 00265 << poptarg << " = " << poparr[0] 00266 << endl; 00267 else 00268 cerr << "option g: no optional argument" 00269 << endl; 00270 break; 00271 00272 case 'h': cerr << "option h: no arguments" 00273 << endl; 00274 break; 00275 00276 } 00277 } 00278 } 00279 00280 #endif