coan 4.2.4
|
00001 00002 /*************************************************************************** 00003 * Copyright (C) 2004 - 2006 Symbian Software Ltd. * 00004 * All rights reserved. * 00005 * Copyright (C) 2007-2011 Mike Kinghan, imk@strudl.org * 00006 * All rights reserved. * 00007 * * 00008 * Contributed originally by Mike Kinghan, imk@strudl.org * 00009 * * 00010 * Redistribution and use in source and binary forms, with or without * 00011 * modification, are permitted provided that the following conditions * 00012 * are met: * 00013 * * 00014 * Redistributions of source code must retain the above copyright * 00015 * notice, this list of conditions and the following disclaimer. * 00016 * * 00017 * Redistributions in binary form must reproduce the above copyright * 00018 * notice, this list of conditions and the following disclaimer in the * 00019 * documentation and/or other materials provided with the distribution. * 00020 * * 00021 * Neither the name of Symbian Software Ltd. nor the names of its * 00022 * contributors may be used to endorse or promote products derived from * 00023 * this software without specific prior written permission. * 00024 * * 00025 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 00026 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 00027 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 00028 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 00029 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 00030 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 00031 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 00032 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 00033 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,* 00034 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * 00035 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * 00036 * DAMAGE. * 00037 * * 00038 **************************************************************************/ 00039 00040 #include "get_options.h" 00041 #include <assert.h> 00042 #include <string.h> 00043 00049 /* API */ 00050 00051 int optind; 00052 int optopt; 00053 char *optarg; 00054 00055 cmd_option_t const * 00056 get_command_option(int argc, char *argv[], cmd_option_t const * commands) 00057 { 00058 if (argc > 1) { 00059 cmd_option_t const * command = commands; 00060 assert(commands); 00061 for ( ; command->name; ++command) { 00062 if (!strcmp(argv[1],command->name)) { 00063 return command; 00064 } 00065 } 00066 } 00067 return NULL; 00068 } 00069 00070 bool 00071 opts_are_compatible( int opt_excluder, int opt_excluded, 00072 struct exclusion_list const *exclusions, bool indexed) 00073 { 00074 struct exclusion_list const * which; 00075 bool verdict = true; 00076 assert(exclusions); 00077 if (indexed) { 00078 which = exclusions + opt_excluder; 00079 } else { 00080 which = exclusions; 00081 for ( ; which->excluder; ++which) { 00082 if (which->excluder == opt_excluder) { 00083 break; 00084 } 00085 } 00086 } 00087 if (which->excluder) { 00088 int const *excluded = which->excluded; 00089 if (excluded) { 00090 for ( ; *excluded; ++excluded ) { 00091 if (opt_excluded == *excluded) { 00092 verdict = false; 00093 } 00094 } 00095 } 00096 } 00097 return verdict; 00098 } 00099 00100 int 00101 getopt_long(int argc, char * argv[], const char *optstr, 00102 const struct option *longopts, int *longind) 00103 { 00104 char *opt; 00105 optarg = NULL; 00106 if (longind) { 00107 *longind = -1; 00108 } 00109 if (optind < 0) { 00110 return -1; 00111 } 00112 if (optind == 0) { /* Initial or re-initialising call*/ 00113 ++optind; /* Skip argv[0]*/ 00114 } 00115 if (optind >= argc) { 00116 return -1; 00117 } 00118 opt = argv[optind]; 00119 if (*opt == '-') { /* argv[optind] is an option*/ 00120 ++optind; 00121 if (*++opt == ':') { 00122 optopt = ':'; 00123 return '?'; 00124 } 00125 if (*opt != '-') { /* Short option*/ 00126 char *where = strchr(optstr,*opt); 00127 if (!where) { 00128 optopt = *opt; 00129 return '?'; 00130 } 00131 if (where[1] != ':') { /* No argument*/ 00132 if (opt[1]) { 00133 optopt = *opt; 00134 return '?'; 00135 } 00136 optarg = NULL; 00137 return *opt; 00138 } else if (where[2] != ':') { /* Optional argument*/ 00139 if (opt[1] != 0) { /* arg abuts opt*/ 00140 optarg = opt + 1; 00141 return *opt; 00142 } else if (optind >= argc || *argv[optind] == '-') { 00143 /* No arg*/ 00144 optarg = NULL; 00145 return *opt; 00146 } else { /* Arg is next argv*/ 00147 optarg = argv[optind++]; 00148 return *opt; 00149 } 00150 } else { /* Required argument*/ 00151 if (opt[1] != 0) { /* arg abuts opt*/ 00152 optarg = opt + 1; 00153 return *opt; 00154 } else if (optind >= argc || *argv[optind] == '-') { 00155 /* Required arg missing*/ 00156 optopt = *opt; 00157 return '?'; 00158 } else { /* arg is next argv*/ 00159 optarg = argv[optind++]; 00160 return *opt; 00161 } 00162 } 00163 } else { /* Long option*/ 00164 int i, match = -1; 00165 size_t optlen; 00166 /* Test for `opt=arg' and get length of opt*/ 00167 char *eq = strchr(++opt,'='); 00168 if (eq) { 00169 optarg = eq + 1; 00170 optlen = eq - opt; 00171 } else { 00172 optlen = strlen(opt); 00173 } 00174 /* Test for exactly one match of the option*/ 00175 for (i = 0; longopts[i].name != NULL; ++i) { 00176 if (!strncmp(opt,longopts[i].name,optlen)) { 00177 if (match != -1) { 00178 match = -1; 00179 break; 00180 } 00181 match = i; 00182 } 00183 } 00184 if (longind != NULL) { 00185 *longind = match; 00186 } 00187 if (match == -1) { /* Not found*/ 00188 return '?'; 00189 } 00190 switch(longopts[match].has_arg) { 00191 case no_argument: 00192 if (optarg) { /* Illegal arg*/ 00193 return '?'; 00194 } 00195 break; 00196 case required_argument: 00197 if (optarg) { /* Arg after `='*/ 00198 break; 00199 } 00200 if (optind >= argc || *argv[optind] == '-') { 00201 /* Required arg missing*/ 00202 return '?'; 00203 } 00204 /* Arg is next argv*/ 00205 optarg = argv[optind++]; 00206 break; 00207 case optional_argument: 00208 if (optarg) { /* Arg after `='*/ 00209 break; 00210 } 00211 if (optarg || optind >= argc || *argv[optind] == '-') { 00212 /* No argument*/ 00213 break; 00214 } 00215 optarg = argv[optind++]; 00216 break; 00217 default: 00218 assert(false); 00219 } 00220 /* Store or return value as required*/ 00221 if (longopts[match].flag != NULL) { 00222 *(longopts[match].flag) = longopts[i].val; 00223 return 0; 00224 } else { 00225 return longopts[match].val; 00226 } 00227 } 00228 } else { 00229 /* argv[optind] is a non-option. 00230 We want to shuffle it to the end*/ 00231 bool done = true; /* Posit no more options to the right*/ 00232 int i; 00233 for (i = optind; done && i < argc; ++i) { 00234 /* Now see if this is true*/ 00235 done = *argv[i] != '-'; 00236 } 00237 if (done) { /* There are no more options to the right*/ 00238 optarg = argv[optind]; /* optind at start of non-options*/ 00239 return -1; /* All done*/ 00240 } else { /* There are more options to the right*/ 00241 /* Swap the current non-opt to the end of argv*/ 00242 char *temp = argv[optind]; 00243 memmove(argv + optind,argv + optind + 1, 00244 (argc - optind - 1) * sizeof(char *)); 00245 argv[argc - 1] = temp; 00246 /* Try for another option*/ 00247 return getopt_long(argc,argv,optstr,longopts,longind); 00248 } 00249 } 00250 } 00251 00252 const char * 00253 get_long_opt_name(struct option const * longopts, int opt) 00254 { 00255 struct option const * longopt = longopts; 00256 for ( ; longopt->name; ++longopt) { 00257 if (longopt->val == opt) { 00258 return longopt->name; 00259 } 00260 } 00261 return NULL; 00262 } 00263 00264 00265 /* EOF*/