00001 /*! \file option.c 00002 This file implements the options' reader. 00003 */ 00004 00005 #include <strings.h> 00006 #include <sys/types.h> 00007 #include <regex.h> 00008 #include "option.h" 00009 00010 /*! \brief Pointer used to set the argument of the options that do not require arguments (ex: --help). 00011 */ 00012 00013 static char self_option[] = ""; 00014 00015 /*! \brief Returns a pointer to the <I>Option</I> data structure that represents a given option. 00016 \param opt Pointer to a <I>Option_set</I> data structure that defines all options. 00017 \param flag Pointer to a zero terminated string of characters that represents the option's flag to 00018 locate. 00019 \return If the option represented by the string pointed by <I>flag</I> is found, then the function returns 00020 a non NULL pointer to the <I>Option</I> data structure that defines the option. Otherwize (the 00021 option was not found), the function returns the value NULL. 00022 */ 00023 00024 static Option* find_option (Option_set *opt, char *flag) 00025 { 00026 Option *opt_found; 00027 int i; 00028 00029 opt_found = opt->opt; 00030 for (i=0; i<opt->count; i++) 00031 { 00032 if (strcmp(opt_found->flag, flag) == 0) { return opt_found; } 00033 opt_found++; 00034 } 00035 00036 return NULL; 00037 } 00038 00039 /*! \brief Returns a pointer to the argument associated with a given option. 00040 \param opt Pointer to a <I>Option_set</I> data structure that defines all options. 00041 \param flag Pointer to a zero terminated string of characters that represents the option's flag that you 00042 want to get the argument. 00043 \param arg If the option is valid (defined in the list of options), then the content of <I>arg</I> pointes 00044 to the argument associated with the option. If the content of <I>arg</I> is equal to NULL, this 00045 means that the option is not activated in the command line. 00046 \return If the option is found (that is: the option is defined in the <I>Option_set</I> data structure 00047 pointed by <I>opt</I>), the function returns the value 0. In this case: 00048 <UL> 00049 <LI>if <I>arg</I> is NULL, it means that the option was not activated. 00050 <LI>if <I>arg</I> is not NULL, it means that the option was activated. 00051 <UL> 00052 <LI>If the option requires one argument, then <I>arg</I> pointes to a zero terminated 00053 string of characters that represents the argument. 00054 <LI>If the option does not require any argument, then you don't care about the string 00055 of characters pointed by <I>arg</I> (this string exists, but it does not mean 00056 anything). 00057 </UL> 00058 </UL> 00059 If the option can not be found (the option is not defined in the <I>Option_set</I> data structure 00060 pointed by <I>opt</I>), the function returns the value 1. Please note that a return value of 1 means 00061 that you've made an programming error (in your code, you are testing for options that you did not 00062 define earlier). 00063 */ 00064 00065 int get_argument (Option_set *opt, char *flag, char **arg) 00066 { 00067 Option *opt_found; 00068 00069 *arg = NULL; 00070 opt_found = find_option (opt, flag); 00071 00072 if (opt_found == NULL) { return 1; } 00073 *arg = *(opt_found->pointer); 00074 00075 return 0; 00076 } 00077 00078 /*! \example test_options.c 00079 This file shows how to use all the function of the library libmy_option. 00080 */ 00081 00082 /*! \brief This function returns a value that represents the number of arguments (0 or 1 argument) required by 00083 for a given option. 00084 \param opt Pointer to a <I>Option_set</I> data structure that contains the definitions of all options. 00085 \param flag Pointer to a zero terminated string of characters that represents the option's flag to test. 00086 \return The function may return one of the following values: 00087 <UL> 00088 <LI>-1: An error occured. The option's flag pointed by <I>flag</I> does not represent any 00089 pre-defined options. This is a programming error. You are trying to test an option that 00090 you did not define previously. 00091 <LI>0: The option does not require any argument. 00092 <LI>1: The option requires one argument. 00093 </UL> 00094 */ 00095 00096 int is_argument_required (Option_set *opt, char *flag) 00097 { 00098 Option *opt_found; 00099 00100 opt_found = find_option (opt, flag); 00101 if (opt_found == NULL) { return -1; } 00102 00103 if (opt_found->arg != 0) { return 1; } 00104 00105 return 0; 00106 } 00107 00108 /*! \example test_options.c 00109 This file shows how to use all the function of the library libmy_option. 00110 */ 00111 00112 /*! \brief Initialize the array of option definitions. 00113 \param opt Pointer to a <I>Option_set</I> data structure that contains the definitions of all options. 00114 \return Upon successful completion the function returns the value 0. Otherwise it returns the value 1. 00115 \warning Please note that an option's flag should verify the following rules: 00116 <UL> 00117 <LI>At least 2 characters. 00118 <LI>Begin with a '-'. 00119 <LI>No spaces. 00120 <LI>Not all '-'. 00121 </UL> 00122 */ 00123 00124 int init_options (Option_set *opt) 00125 { 00126 int i, j, s; 00127 Option *o; 00128 char *pt; 00129 00130 /* ------------------------------------------------------------- */ 00131 /* Initialize options' array */ 00132 /* ------------------------------------------------------------- */ 00133 00134 opt->last_index = -1; 00135 for (i=0; i<opt->count; i++) { *((opt->opt + i)->pointer) = NULL; } 00136 00137 /* ------------------------------------------------------------- */ 00138 /* Check the syntax of all option's tags */ 00139 /* - At least 2 characters. */ 00140 /* - Begin with a '-'. */ 00141 /* - No spaces. */ 00142 /* - Not all '-'. */ 00143 /* */ 00144 /* Note: the algo is not fast, but who cares. Command line is */ 00145 /* not very long and we parse it only once. At least, this */ 00146 /* algo is pretty simple. */ 00147 /* ------------------------------------------------------------- */ 00148 00149 for (i=0; i<opt->count; i++) 00150 { 00151 o = opt->opt + i; 00152 pt = o->flag; 00153 s = strlen(pt); 00154 00155 if ((s < 2) || (*pt != '-')) { return 1; } 00156 for (j=0; j<s; j++) { if (*(pt+j) == ' ') { return 1; } } 00157 for (j=0; j<s; j++) { if (*(pt+j) != '-') { break; } } 00158 if (j == s) { return 1; } 00159 } 00160 00161 return 0; 00162 } 00163 00164 /*! \example test_options.c 00165 This file shows how to use all the function of the library libmy_option. 00166 */ 00167 00168 /*! \brief Parse the command line and set up the option's data structure. 00169 \param argv Array of sero terminated strings of characters that represents the command line. Please 00170 note that the first element of the array (indice 0) should point to the name of the process. 00171 \param argc Number of elements in the array <I>argv</I>. 00172 \param opt Pointer to the <I>Option_set</I> data structure that contains the option's definitions. 00173 \param err Pointer to a pointer that will be used to store the address of a zero terminated string of 00174 characters. If an error occured, this string contains a literal description of the error. 00175 \param flag Pointer to a pointer that will be used to store the address of a zero terminated string of 00176 characters. If an error occured, this string contains the option that generated the error. 00177 \param arg Pointer to a pointer that will be used to store the address of a zero terminated string of 00178 characters. If an error occured, this string contains the argument that caused the error. 00179 \return Upon successful completion, the function returns the value 0. Otherwise the function returns the 00180 value 1. 00181 \warning A valid command line should look something like:<P> 00182 <process name> [-flag1 [arg1]] [-flag2 [arg2]] [...] <required arg 1> ... 00183 */ 00184 00185 int parse_command_line (char *argv[], int argc, Option_set *opt, char **err, char **flag, char **arg) 00186 { 00187 int i, oflag, rv; 00188 static char err1[] = "Success"; 00189 static char err2[] = ""; 00190 static char err3[] = "Unknown option"; 00191 static char err4[] = "Missing option's argument"; 00192 static char err5[] = "Duplicated option"; 00193 static char err6[] = "Argument too long"; 00194 static char err7[] = "Invalid regular expression"; 00195 static char err8[] = "Invalid argument (syntax error)"; 00196 static char last_opt[] = ""; 00197 regex_t reg; 00198 regmatch_t pmatch[1]; 00199 Option *ofound; 00200 char *last_option; 00201 00202 /* ------------------------------------------------------------- */ 00203 /* Initialize variables */ 00204 /* ------------------------------------------------------------- */ 00205 00206 *err = err1; 00207 *flag = err2; 00208 *arg = self_option; 00209 last_option = last_opt; 00210 oflag = 0; 00211 opt->last_index = 0; 00212 00213 /* ------------------------------------------------------------- */ 00214 /* Parse command line now */ 00215 /* ------------------------------------------------------------- */ 00216 00217 for (i=1; i<argc; i++) 00218 { 00219 if ((*(argv[i]) != '-') && (oflag == 0)) { return 0; } 00220 00221 /* ----------------------------------------------------------- */ 00222 /* Is it an option ? */ 00223 /* ----------------------------------------------------------- */ 00224 00225 if (*(argv[i]) == '-') 00226 { 00227 if (oflag == 1) 00228 { 00229 /* ------------------------------------------------------- */ 00230 /* We get an option's flag, but we expected an argument */ 00231 /* ------------------------------------------------------- */ 00232 00233 *err = err4; 00234 *flag = last_option; 00235 return 1; 00236 } 00237 00238 ofound = find_option (opt, argv[i]); 00239 if (ofound == NULL) 00240 { 00241 /* ------------------------------------------------------- */ 00242 /* This option is bot defined */ 00243 /* ------------------------------------------------------- */ 00244 00245 *err = err3; 00246 *flag = argv[i]; 00247 return 1; 00248 } 00249 00250 if (*(ofound->pointer) != NULL) 00251 { 00252 /* ------------------------------------------------------- */ 00253 /* This option is already activated */ 00254 /* ------------------------------------------------------- */ 00255 00256 *err = err5; 00257 *flag = argv[i]; 00258 return 1; 00259 } 00260 00261 /* --------------------------------------------------------- */ 00262 /* Option found. Is it a "self option" ? */ 00263 /* --------------------------------------------------------- */ 00264 00265 if (ofound->arg == 0) { oflag = 0; *(ofound->pointer) = self_option; } 00266 else { oflag = 1; } 00267 00268 last_option = argv[i]; 00269 } 00270 00271 /* ----------------------------------------------------------- */ 00272 /* Is it an argument ? */ 00273 /* ----------------------------------------------------------- */ 00274 00275 if (*(argv[i]) != '-') 00276 { 00277 if (oflag == 0) { return 0; } 00278 00279 /* --------------------------------------------------------- */ 00280 /* Testing the size of the argument */ 00281 /* --------------------------------------------------------- */ 00282 00283 if (strlen(argv[i]) > ofound->max_size) 00284 { 00285 *err = err6; 00286 *arg = argv[i]; 00287 *flag = last_option; 00288 return 1; 00289 } 00290 00291 /* --------------------------------------------------------- */ 00292 /* Check argumment against regular expression */ 00293 /* --------------------------------------------------------- */ 00294 00295 rv = regcomp (®, ofound->reg_exp, REG_EXTENDED); 00296 if (rv != 0) 00297 { 00298 *err = err7; 00299 *flag = last_option; 00300 *arg = argv[i]; 00301 return 1; 00302 } 00303 00304 rv = regexec (®, argv[i], 1, pmatch, 0); 00305 if (rv != 0) 00306 { 00307 *err = err8; 00308 *flag = last_option; 00309 *arg = argv[i]; 00310 regfree (®); 00311 return 1; 00312 } 00313 00314 regfree (®); 00315 00316 *(ofound->pointer) = argv[i]; 00317 oflag = 0; 00318 } 00319 00320 opt->last_index = i; 00321 } 00322 00323 if (oflag == 1) 00324 { 00325 *err = err4; 00326 *flag = last_option; 00327 return 1; 00328 } 00329 00330 return 0; 00331 } 00332 00333 /*! \example test_options.c 00334 This file shows how to use all the function of the library libmy_option. 00335 */ 00336 00337 00338