/** * Parse the option usage flags string. Any parsing problems yield * a zero (no flags set) result. This function is internal to * set_usage_flags(). * * @param[in] fnt Flag Name Table - maps a name to a mask * @param[in] txt the text to process. If NULL, then * getenv("AUTOOPTS_USAGE") is used. * @returns a bit mask indicating which \a fnt entries were found. */ static unsigned int parse_usage_flags(ao_flag_names_t const * fnt, char const * txt) { unsigned int res = 0; /* * The text may be passed in. If not, use the environment variable. */ if (txt == NULL) { txt = getenv("AUTOOPTS_USAGE"); if (txt == NULL) return 0; } txt = SPN_WHITESPACE_CHARS(txt); if (*txt == NUL) return 0; /* * search the string for table entries. We must understand everything * we see in the string, or we give up on it. */ for (;;) { int ix = 0; for (;;) { if (strneqvcmp(txt, fnt[ix].fnm_name, (int)fnt[ix].fnm_len) == 0) break; if (++ix >= AOUF_COUNT) return 0; } /* * Make sure we have a full match. Look for whitespace, * a comma, or a NUL byte. */ if (! IS_END_LIST_ENTRY_CHAR(txt[fnt[ix].fnm_len])) return 0; res |= 1U << ix; txt = SPN_WHITESPACE_CHARS(txt + fnt[ix].fnm_len); switch (*txt) { case NUL: return res; case ',': txt = SPN_WHITESPACE_CHARS(txt + 1); /* Something must follow the comma */ default: continue; } } }
LOCAL void set_usage_flags(tOptions * opts, char const * flg_txt) { typedef struct { size_t fnm_len; uint32_t fnm_mask; char const * fnm_name; } ao_flag_names_t; # define _aof_(_n, _f) AOUF_ ## _n ## _ID, typedef enum { AOFLAG_TABLE AOUF_COUNT } ao_flag_id_t; # undef _aof_ # define _aof_(_n, _f) AOUF_ ## _n = (1 << AOUF_ ## _n ## _ID), typedef enum { AOFLAG_TABLE } ao_flags_t; # undef _aof_ # define _aof_(_n, _f) { sizeof(#_n)-1, _f, #_n }, static ao_flag_names_t const fn_table[AOUF_COUNT] = { AOFLAG_TABLE }; # undef _aof_ ao_flags_t flg = 0; if (flg_txt == NULL) { flg_txt = getenv("AUTOOPTS_USAGE"); if (flg_txt == NULL) return; } while (IS_WHITESPACE_CHAR(*flg_txt)) flg_txt++; if (*flg_txt == NUL) return; for (;;) { int ix = 0; ao_flag_names_t const * fnt = fn_table; for (;;) { if (strneqvcmp(flg_txt, fnt->fnm_name, fnt->fnm_len) == 0) break; if (++ix >= AOUF_COUNT) return; fnt++; } /* * Make sure we have a full match. Look for whitespace, * a comma, or a NUL byte. */ if (! IS_END_LIST_ENTRY_CHAR(flg_txt[fnt->fnm_len])) return; flg |= 1 << ix; flg_txt += fnt->fnm_len; while (IS_WHITESPACE_CHAR(*flg_txt)) flg_txt++; if (*flg_txt == NUL) break; if (*flg_txt == ',') { /* * skip the comma and following white space */ while (IS_WHITESPACE_CHAR(*++flg_txt)) ; if (*flg_txt == NUL) break; } } { ao_flag_names_t const * fnm = fn_table; while (flg != 0) { if ((flg & 1) != 0) { if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0) opts->fOptSet &= fnm->fnm_mask; else opts->fOptSet |= fnm->fnm_mask; } flg >>= 1; fnm++; } } }