1/* $NetBSD: autoopts.c,v 1.7 2020/05/25 20:47:34 christos Exp $ */ 2 3 4/** 5 * \file autoopts.c 6 * 7 * This file contains all of the routines that must be linked into 8 * an executable to use the generated option processing. The optional 9 * routines are in separately compiled modules so that they will not 10 * necessarily be linked in. 11 * 12 * @addtogroup autoopts 13 * @{ 14 */ 15/* 16 * This file is part of AutoOpts, a companion to AutoGen. 17 * AutoOpts is free software. 18 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 19 * 20 * AutoOpts is available under any one of two licenses. The license 21 * in use must be one of these two and the choice is under the control 22 * of the user of the license. 23 * 24 * The GNU Lesser General Public License, version 3 or later 25 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 26 * 27 * The Modified Berkeley Software Distribution License 28 * See the file "COPYING.mbsd" 29 * 30 * These files have the following sha256 sums: 31 * 32 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 33 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 34 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 35 */ 36 37/** 38 * The number of tab characters to skip when printing continuation lines. 39 */ 40static unsigned int tab_skip_ct = 0; 41 42#ifndef HAVE_PATHFIND 43# define pathfind(_p, _n, _m) option_pathfind(_p, _n, _m) 44# include "compat/pathfind.c" 45#endif 46 47#ifndef HAVE_SNPRINTF 48# define vsnprintf option_vsnprintf 49# define snprintf option_snprintf 50# include "compat/snprintf.c" 51#endif 52 53#ifndef HAVE_STRDUP 54# define strdup(_s) option_strdup(_s) 55# include "compat/strdup.c" 56#endif 57 58#ifndef HAVE_STRCHR 59# define strrchr(_s, _c) option_strrchr(_s, _c) 60# define strchr(_s, _c) option_strchr(_s, _c) 61# include "compat/strchr.c" 62#endif 63 64LOCAL void * 65ao_malloc(size_t sz) 66{ 67 void * res = malloc(sz); 68 if (res == NULL) { 69 fprintf(stderr, zalloc_fail, (int)sz); 70 option_exits(EXIT_FAILURE); 71 } 72 return res; 73} 74#undef malloc 75#define malloc(_s) ao_malloc(_s) 76 77LOCAL void * 78ao_realloc(void *p, size_t sz) 79{ 80 void * res = (p == NULL) ? malloc(sz) : realloc(p, sz); 81 if (res == NULL) { 82 fprintf(stderr, zrealloc_fail, (int)sz, p); 83 option_exits(EXIT_FAILURE); 84 } 85 return res; 86} 87#undef realloc 88#define realloc(_p,_s) ao_realloc(_p,_s) 89 90LOCAL char * 91ao_strdup(char const *str) 92{ 93 char * res = strdup(str); 94 if (res == NULL) { 95 fprintf(stderr, zalloc_fail, (int)strlen(str)); 96 option_exits(EXIT_FAILURE); 97 } 98 return res; 99} 100#undef strdup 101#define strdup(_p) ao_strdup(_p) 102 103/** 104 * handle an option. 105 * 106 * This routine handles equivalencing, sets the option state flags and 107 * invokes the handler procedure, if any. 108 */ 109LOCAL tSuccess 110handle_opt(tOptions * opts, tOptState * o_st) 111{ 112 /* 113 * Save a copy of the option procedure pointer. 114 * If this is an equivalence class option, we still want this proc. 115 */ 116 tOptDesc * od = o_st->pOD; 117 tOptProc * opt_proc = od->pOptProc; 118 if (od->fOptState & OPTST_ALLOC_ARG) 119 AGFREE(od->optArg.argString); 120 121 od->optArg.argString = o_st->pzOptArg; 122 123 /* 124 * IF we are presetting options, then we will ignore any un-presettable 125 * options. They are the ones either marked as such. 126 */ 127 if ( ((opts->fOptSet & OPTPROC_PRESETTING) != 0) 128 && ((od->fOptState & OPTST_NO_INIT) != 0) 129 ) 130 return PROBLEM; 131 132 /* 133 * IF this is an equivalence class option, 134 * THEN 135 * Save the option value that got us to this option 136 * entry. (It may not be od->optChar[0], if this is an 137 * equivalence entry.) 138 * set the pointer to the equivalence class base 139 */ 140 if (od->optEquivIndex != NO_EQUIVALENT) { 141 tOptDesc * eqv_od = opts->pOptDesc + od->optEquivIndex; 142 143 /* 144 * IF the current option state has not been defined (set on the 145 * command line), THEN we will allow continued resetting of 146 * the value. Once "defined", then it must not change. 147 */ 148 if ((od->fOptState & OPTST_DEFINED) != 0) { 149 /* 150 * The equivalenced-to option has been found on the command 151 * line before. Make sure new occurrences are the same type. 152 * 153 * IF this option has been previously equivalenced and 154 * it was not the same equivalenced-to option, 155 * THEN we have a usage problem. 156 */ 157 if (eqv_od->optActualIndex != od->optIndex) { 158 fprintf(stderr, zmultiway_bug, eqv_od->pz_Name, od->pz_Name, 159 (opts->pOptDesc + eqv_od->optActualIndex)->pz_Name); 160 return FAILURE; 161 } 162 } else { 163 /* 164 * Set the equivalenced-to actual option index to no-equivalent 165 * so that we set all the entries below. This option may either 166 * never have been selected before, or else it was selected by 167 * some sort of "presetting" mechanism. 168 */ 169 eqv_od->optActualIndex = NO_EQUIVALENT; 170 } 171 172 if (eqv_od->optActualIndex != od->optIndex) { 173 /* 174 * First time through, copy over the state 175 * and add in the equivalence flag 176 */ 177 eqv_od->optActualValue = od->optValue; 178 eqv_od->optActualIndex = od->optIndex; 179 o_st->flags |= OPTST_EQUIVALENCE; 180 } 181 182 /* 183 * Copy the most recent option argument. set membership state 184 * is kept in 'eqv_od->optCookie'. Do not overwrite. 185 */ 186 eqv_od->optArg.argString = od->optArg.argString; 187 od = eqv_od; 188 189 } else { 190 od->optActualValue = od->optValue; 191 od->optActualIndex = od->optIndex; 192 } 193 194 od->fOptState &= OPTST_PERSISTENT_MASK; 195 od->fOptState |= (o_st->flags & ~OPTST_PERSISTENT_MASK); 196 197 /* 198 * Keep track of count only for DEFINED (command line) options. 199 * IF we have too many, build up an error message and bail. 200 */ 201 if ( (od->fOptState & OPTST_DEFINED) 202 && (++od->optOccCt > od->optMaxCt) ) 203 return too_many_occurrences(opts, od); 204 /* 205 * If provided a procedure to call, call it 206 */ 207 if (opt_proc != NULL) 208 (*opt_proc)(opts, od); 209 210 return SUCCESS; 211} 212 213/** 214 * Find the option descriptor and option argument (if any) for the 215 * next command line argument. DO NOT modify the descriptor. Put 216 * all the state in the state argument so that the option can be skipped 217 * without consequence (side effect). 218 * 219 * @param opts the program option descriptor 220 * @param o_st the state of the next found option 221 */ 222LOCAL tSuccess 223next_opt(tOptions * opts, tOptState * o_st) 224{ 225 { 226 tSuccess res = find_opt(opts, o_st); 227 if (! SUCCESSFUL(res)) 228 return res; 229 } 230 231 if ( ((o_st->flags & OPTST_DEFINED) != 0) 232 && ((o_st->pOD->fOptState & OPTST_NO_COMMAND) != 0)) { 233 fprintf(stderr, zNotCmdOpt, o_st->pOD->pz_Name); 234 return FAILURE; 235 } 236 237 return get_opt_arg(opts, o_st); 238} 239 240/** 241 * Process all the options from our current position onward. (This allows 242 * interspersed options and arguments for the few non-standard programs that 243 * require it.) Thus, do not rewind option indexes because some programs 244 * choose to re-invoke after a non-option. 245 * 246 * @param[in,out] opts program options descriptor 247 * @returns SUCCESS or FAILURE 248 */ 249LOCAL tSuccess 250regular_opts(tOptions * opts) 251{ 252 /* assert: opts->fOptSet & OPTPROC_IMMEDIATE == 0 */ 253 for (;;) { 254 tOptState opt_st = OPTSTATE_INITIALIZER(DEFINED); 255 256 switch (next_opt(opts, &opt_st)) { 257 case FAILURE: goto failed_option; 258 case PROBLEM: return SUCCESS; /* no more args */ 259 case SUCCESS: break; 260 } 261 262 /* 263 * IF this is an immediate action option, 264 * THEN skip it (unless we are supposed to do it a second time). 265 */ 266 if (! DO_NORMALLY(opt_st.flags)) { 267 if (! DO_SECOND_TIME(opt_st.flags)) 268 continue; 269 opt_st.pOD->optOccCt--; /* don't count this repetition */ 270 } 271 272 if (! SUCCESSFUL(handle_opt(opts, &opt_st))) 273 break; 274 } failed_option:; 275 276 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) 277 (*opts->pUsageProc)(opts, EXIT_FAILURE); 278 279 return FAILURE; 280} 281 282/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 283 * 284 * THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE 285 */ 286/*=--subblock=arg=arg_type,arg_name,arg_desc =*/ 287/*=* 288 * library: opts 289 * header: your-opts.h 290 * 291 * lib_description: 292 * 293 * These are the routines that libopts users may call directly from their 294 * code. There are several other routines that can be called by code 295 * generated by the libopts option templates, but they are not to be 296 * called from any other user code. The @file{options.h} header is 297 * fairly clear about this, too. 298=*/ 299 300/*=export_func optionProcess 301 * 302 * what: this is the main option processing routine 303 * 304 * arg: + tOptions * + opts + program options descriptor + 305 * arg: + int + a_ct + program arg count + 306 * arg: + char ** + a_v + program arg vector + 307 * 308 * ret_type: int 309 * ret_desc: the count of the arguments processed 310 * 311 * doc: 312 * 313 * This is the main entry point for processing options. It is intended 314 * that this procedure be called once at the beginning of the execution of 315 * a program. Depending on options selected earlier, it is sometimes 316 * necessary to stop and restart option processing, or to select completely 317 * different sets of options. This can be done easily, but you generally 318 * do not want to do this. 319 * 320 * The number of arguments processed always includes the program name. 321 * If one of the arguments is "--", then it is counted and the processing 322 * stops. If an error was encountered and errors are to be tolerated, then 323 * the returned value is the index of the argument causing the error. 324 * A hyphen by itself ("-") will also cause processing to stop and will 325 * @emph{not} be counted among the processed arguments. A hyphen by itself 326 * is treated as an operand. Encountering an operand stops option 327 * processing. 328 * 329 * err: Errors will cause diagnostics to be printed. @code{exit(3)} may 330 * or may not be called. It depends upon whether or not the options 331 * were generated with the "allow-errors" attribute, or if the 332 * ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked. 333=*/ 334int 335optionProcess(tOptions * opts, int a_ct, char ** a_v) 336{ 337 if (! SUCCESSFUL(validate_struct(opts, a_v[0]))) 338 ao_bug(zbad_data_msg); 339 340 /* 341 * Establish the real program name, the program full path, 342 * and do all the presetting the first time thru only. 343 */ 344 if (! ao_initialize(opts, a_ct, a_v)) 345 return 0; 346 347 /* 348 * IF we are (re)starting, 349 * THEN reset option location 350 */ 351 if (opts->curOptIdx <= 0) { 352 opts->curOptIdx = 1; 353 opts->pzCurOpt = NULL; 354 } 355 356 if (! SUCCESSFUL(regular_opts(opts))) 357 return (int)opts->origArgCt; 358 359 /* 360 * IF there were no errors 361 * AND we have RC/INI files 362 * AND there is a request to save the files 363 * THEN do that now before testing for conflicts. 364 * (conflicts are ignored in preset options) 365 */ 366 switch (opts->specOptIdx.save_opts) { 367 case 0: 368 case NO_EQUIVALENT: 369 break; 370 default: 371 { 372 tOptDesc * od = opts->pOptDesc + opts->specOptIdx.save_opts; 373 374 if (SELECTED_OPT(od)) { 375 optionSaveFile(opts); 376 option_exits(EXIT_SUCCESS); 377 } 378 } 379 } 380 381 /* 382 * IF we are checking for errors, 383 * THEN look for too few occurrences of required options 384 */ 385 if (((opts->fOptSet & OPTPROC_ERRSTOP) != 0) 386 && (! is_consistent(opts))) 387 (*opts->pUsageProc)(opts, EXIT_FAILURE); 388 389 return (int)opts->curOptIdx; 390} 391 392/** @} 393 * 394 * Local Variables: 395 * mode: C 396 * c-file-style: "stroustrup" 397 * indent-tabs-mode: nil 398 * End: 399 * end of autoopts/autoopts.c */ 400