/* * shortOptionFind * * Find the short option descriptor for the current option */ LOCAL tSuccess shortOptionFind(tOptions* pOpts, uint_t optValue, tOptState* pOptState) { tOptDesc* pRes = pOpts->pOptDesc; int ct = pOpts->optCt; /* * Search the option list */ do { if (optValue != pRes->optValue) continue; if (SKIP_OPT(pRes)) { if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) && (pRes->pz_Name != NULL)) { fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); if (pRes->pzText != NULL) fprintf(stderr, " -- %s", pRes->pzText); fputc('\n', stderr); (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); /* NOTREACHED */ } goto short_opt_error; } pOptState->pOD = pRes; pOptState->optType = TOPT_SHORT; return SUCCESS; } while (pRes++, --ct > 0); /* * IF the character value is a digit * AND there is a special number option ("-n") * THEN the result is the "option" itself and the * option is the specially marked "number" option. */ if ( IS_DEC_DIGIT_CHAR(optValue) && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { pOptState->pOD = \ pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; (pOpts->pzCurOpt)--; pOptState->optType = TOPT_SHORT; return SUCCESS; } short_opt_error: /* * IF we are to stop on errors (the default, actually) * THEN call the usage procedure. */ if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue); (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); } return FAILURE; }
/** * Alters the current line number and/or file name. You may wish to * use this directive if you extract definition source from other files. * @command{getdefs} uses this mechanism so AutoGen will report the correct * file and approximate line number of any errors found in extracted * definitions. */ char * doDir_line(directive_enum_t id, char const * dir, char * scan_next) { (void)id; /* * The sequence must be: #line <number> "file-name-string" * * Start by scanning up to and extracting the line number. */ dir = SPN_WHITESPACE_CHARS(dir); if (! IS_DEC_DIGIT_CHAR(*dir)) return scan_next; cctx->scx_line = (int)strtol(dir, (char **)&dir, 0); /* * Now extract the quoted file name string. * We dup the string so it won't disappear on us. */ dir = SPN_WHITESPACE_CHARS(dir); if (*(dir++) != '"') return scan_next; { char * pz = strchr(dir, '"'); if (pz == NULL) return scan_next; *pz = NUL; } AGDUPSTR(cctx->scx_fname, dir, "#line"); return scan_next; }
/*=directive line * * text: * * Alters the current line number and/or file name. You may wish to * use this directive if you extract definition source from other files. * @command{getdefs} uses this mechanism so AutoGen will report the correct * file and approximate line number of any errors found in extracted * definitions. =*/ static char* doDir_line(char* pzArg, char* pzScan) { /* * The sequence must be: #line <number> "file-name-string" * * Start by scanning up to and extracting the line number. */ while (IS_WHITESPACE_CHAR(*pzArg)) pzArg++; if (! IS_DEC_DIGIT_CHAR(*pzArg)) return pzScan; pCurCtx->lineNo = strtol(pzArg, &pzArg, 0); /* * Now extract the quoted file name string. * We dup the string so it won't disappear on us. */ while (IS_WHITESPACE_CHAR(*pzArg)) pzArg++; if (*(pzArg++) != '"') return pzScan; { char* pz = strchr(pzArg, '"'); if (pz == NULL) return pzScan; *pz = NUL; } AGDUPSTR(pCurCtx->pzCtxFname, pzArg, "#line file name"); return pzScan; }
/** * Associate a name with a boolean value * * @param[in,out] pp argument list to add to * @param[in] name the name of the "suboption" * @param[in] nm_len the length of the name * @param[in] val the boolean value for the suboption * @param[in] d_len the length of the value * * @returns the new value structure */ static tOptionValue * add_bool(void ** pp, char const * name, size_t nm_len, char const * val, size_t d_len) { size_t sz = nm_len + sizeof(tOptionValue) + 1; tOptionValue * new_val = AGALOC(sz, "bool val"); /* * Scan over whitespace is constrained by "d_len" */ while (IS_WHITESPACE_CHAR(*val) && (d_len > 0)) { d_len--; val++; } if (d_len == 0) new_val->v.boolVal = 0; else if (IS_DEC_DIGIT_CHAR(*val)) new_val->v.boolVal = (unsigned)atoi(val); else new_val->v.boolVal = ! IS_FALSE_TYPE_CHAR(*val); new_val->valType = OPARG_TYPE_BOOLEAN; new_val->pzName = (char *)(new_val + 1); memcpy(new_val->pzName, name, nm_len); new_val->pzName[ nm_len ] = NUL; addArgListEntry(pp, new_val); return new_val; }
/* addBoolValue * * Associate a name with either a string or no value. */ static tOptionValue* addBoolValue( void** pp, char const* pzName, size_t nameLen, char const* pzValue, size_t dataLen ) { tOptionValue* pNV; size_t sz = nameLen + sizeof(*pNV) + 1; pNV = AGALOC( sz, "option name/bool value pair" ); if (pNV == NULL) return NULL; while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) { dataLen--; pzValue++; } if (dataLen == 0) pNV->v.boolVal = 0; else if (IS_DEC_DIGIT_CHAR(*pzValue)) pNV->v.boolVal = atoi(pzValue); else pNV->v.boolVal = ! IS_FALSE_TYPE_CHAR(*pzValue); pNV->valType = OPARG_TYPE_BOOLEAN; pNV->pzName = (char*)(pNV + 1); memcpy( pNV->pzName, pzName, nameLen ); pNV->pzName[ nameLen ] = NUL; addArgListEntry( pp, pNV ); return pNV; }
/** * Figure out where to insert an entry in a list of twins. */ LOCAL tDefEntry* findPlace(char* name, char const * pzIndex) { tDefEntry* pE = getEntry(); pE->pzDefName = name; if (pzIndex == NULL) pE->index = NO_INDEX; else if (IS_DEC_DIGIT_CHAR(*pzIndex) || (*pzIndex == '-')) pE->index = strtol(pzIndex, NULL, 0); else { pzIndex = getDefine(pzIndex, AG_TRUE); if (pzIndex != NULL) pE->index = strtol(pzIndex, NULL, 0); else pE->index = NO_INDEX; } strtransform(pE->pzDefName, pE->pzDefName); pE->valType = VALTYP_UNKNOWN; pE->pzSrcFile = (char*)pCurCtx->pzCtxFname; pE->srcLineNum = pCurCtx->lineNo; return (pCurrentEntry = insertDef(pE)); }
/*=gfunc version_compare * * what: compare two version numbers * general_use: * * exparg: op, comparison operator * exparg: v1, first version * exparg: v2, compared-to version * * doc: Converts v1 and v2 strings into 64 bit values and returns the * result of running 'op' on those values. It assumes that the version * is a 1 to 4 part dot-separated series of numbers. Suffixes like, * "5pre4" or "5-pre4" will be interpreted as two numbers. The first * number ("5" in this case) will be decremented and the number after * the "pre" will be added to 0xC000. (Unless your platform is unable * to support 64 bit integer arithmetic. Then it will be added to 0xC0.) * Consequently, these yield true: * @example * (version-compare > "5.8.5" "5.8.5-pre4") * (version-compare > "5.8.5-pre10" "5.8.5-pre4") * @end example =*/ static ver_type_t str2int_ver(char* pz) { char* pzStr = pz; ver_type_t val = 0; int ix = 4; while (--ix >= 0) { unsigned int v; val <<= VER_UNIT_SHIFT; while (IS_WHITESPACE_CHAR(*pz)) pz++; next_number: if (! IS_DEC_DIGIT_CHAR(*pz)) break; v = (unsigned int)strtoul(pz, &pz, 0) & ((1 << VER_UNIT_SHIFT) - 1); if (pz == NULL) break; val += v; if (*pz == '-') pz++; switch (*pz) { case 'p': if ((pz[1] == 'r') && (pz[2] == 'e')) { pz += 3; val = (val << 2) - 1; val <<= (VER_UNIT_SHIFT - 2); if (--ix < 0) goto leave_str2int_ver; goto next_number; } /* FALLTHROUGH */ default: goto leave_str2int_ver; case '.': if (! IS_DEC_DIGIT_CHAR(*(++pz))) goto leave_str2int_ver; break; } } leave_str2int_ver: ; while (--ix >= 0) val <<= VER_UNIT_SHIFT; if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) fprintf(pfTrace, "0x%016llX <<== '%s'\n", (long long)val, pzStr); return val; }
/** * Convert a name or number into a binary number. * "~0" and "-1" will be converted to the largest value in the enumeration. * * @param name the keyword name (number) to convert * @param pOpts the program's option descriptor * @param pOD the option descriptor for this option * @param paz_names the list of keywords for this option * @param name_ct the count of keywords */ static uintptr_t find_name(char const * name, tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, unsigned int name_ct) { /* * Return the matching index as a pointer sized integer. * The result gets stashed in a char * pointer. */ uintptr_t res = name_ct; size_t len = strlen((char *)name); uintptr_t idx; if (IS_DEC_DIGIT_CHAR(*name)) { char * pz = VOIDP(name); unsigned long val = strtoul(pz, &pz, 0); if ((*pz == NUL) && (val < name_ct)) return (uintptr_t)val; pz_enum_err_fmt = znum_too_large; option_usage_fp = stderr; enum_err(pOpts, pOD, paz_names, (int)name_ct); return name_ct; } if (IS_INVERSION_CHAR(*name) && (name[2] == NUL)) { if ( ((name[0] == '~') && (name[1] == '0')) || ((name[0] == '-') && (name[1] == '1'))) return (uintptr_t)(name_ct - 1); goto oops; } /* * Look for an exact match, but remember any partial matches. * Multiple partial matches means we have an ambiguous match. */ for (idx = 0; idx < name_ct; idx++) { if (strncmp((char *)paz_names[idx], (char *)name, len) == 0) { if (paz_names[idx][len] == NUL) return idx; /* full match */ if (res == name_ct) res = idx; /* save partial match */ else res = (uintptr_t)~0; /* may yet find full match */ } } if (res < name_ct) return res; /* partial match */ oops: pz_enum_err_fmt = (res == name_ct) ? zNoKey : zambiguous_key; option_usage_fp = stderr; enum_err(pOpts, pOD, paz_names, (int)name_ct); return name_ct; }
static uintptr_t findName( tCC* pzName, tOptions* pOpts, tOptDesc* pOD, tCC* const * paz_names, unsigned int name_ct ) { /* * Return the matching index as a pointer sized integer. * The result gets stashed in a char* pointer. */ uintptr_t res = name_ct; size_t len = strlen( (char*)pzName ); uintptr_t idx; if (IS_DEC_DIGIT_CHAR(*pzName)) { char * pz = (char *)(void *)pzName; unsigned long val = strtoul(pz, &pz, 0); if ((*pz == NUL) && (val < name_ct)) return (uintptr_t)val; enumError(pOpts, pOD, paz_names, (int)name_ct); return name_ct; } /* * Look for an exact match, but remember any partial matches. * Multiple partial matches means we have an ambiguous match. */ for (idx = 0; idx < name_ct; idx++) { if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) { if (paz_names[idx][len] == NUL) return idx; /* full match */ res = (res != name_ct) ? ~0 : idx; /* save partial match */ } } if (res < name_ct) return res; /* partial match */ pz_enum_err_fmt = (res == name_ct) ? zNoKey : zAmbigKey; option_usage_fp = stderr; enumError(pOpts, pOD, paz_names, (int)name_ct); return name_ct; }
/* * eval_true - should a string be interpreted as TRUE? * * It is always true unless: * * 1. it is the empty string * 2. it starts with a digit and the number evaluates to zero * 3. it starts with either "#f" or "#F" * 4. For its length or its first five characters (whichever is less) * it matches the string "false" */ static ag_bool eval_true(void) { ag_bool needFree; ag_bool res = AG_TRUE; char const * pz = evalExpression(&needFree); if (IS_DEC_DIGIT_CHAR(*pz)) res = (atoi(pz) == 0) ? AG_FALSE : AG_TRUE; else switch (*pz) { case NUL: res = AG_FALSE; break; case '#': if ((pz[1] == 'f') || (pz[1] == 'F')) res = AG_FALSE; break; case 'f': case 'F': { int len = strlen(pz); if (len > 5) len = 5; if (strneqvcmp(EVAL_TRUE_FALSE_STR, pz, len) == 0) res = AG_FALSE; break; } } if (needFree) AGFREE(pz); return res; }
/** * parse XML encodings */ static int parse_xml_encoding(char ** ppz) { # define XMLTABLE \ _xmlNm_(amp, '&') \ _xmlNm_(lt, '<') \ _xmlNm_(gt, '>') \ _xmlNm_(ff, '\f') \ _xmlNm_(ht, '\t') \ _xmlNm_(cr, '\r') \ _xmlNm_(vt, '\v') \ _xmlNm_(bel, '\a') \ _xmlNm_(nl, NL) \ _xmlNm_(space, ' ') \ _xmlNm_(quot, '"') \ _xmlNm_(apos, '\'') static struct { char const * const nm_str; unsigned short nm_len; short nm_val; } const xml_names[] = { # define _xmlNm_(_n, _v) { #_n ";", sizeof(#_n), _v }, XMLTABLE # undef _xmlNm_ # undef XMLTABLE }; static int const nm_ct = sizeof(xml_names) / sizeof(xml_names[0]); int base = 10; char * pz = *ppz; if (*pz == '#') { pz++; goto parse_number; } if (IS_DEC_DIGIT_CHAR(*pz)) { unsigned long v; parse_number: switch (*pz) { case 'x': case 'X': /* * Some forms specify hex with: &#xNN; */ base = 16; pz++; break; case '0': /* *  is hex and  is decimal. Cool. * Ya gotta love it. */ if (pz[1] == '0') base = 16; break; } v = strtoul(pz, &pz, base); if ((*pz != ';') || (v > 0x7F)) return NUL; *ppz = pz + 1; return (int)v; } { int ix = 0; do { if (strncmp(pz, xml_names[ix].nm_str, xml_names[ix].nm_len) == 0) { *ppz = pz + xml_names[ix].nm_len; return xml_names[ix].nm_val; } } while (++ix < nm_ct); } return NUL; }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * It may be a number, a name, a keyword or garbage. * Figure out which. */ static char* assembleName(char * pzScan, te_dp_event * pRetVal) { /* * Check for a number. * Scan it in and advance "pzScan". */ if ( IS_DEC_DIGIT_CHAR(*pzScan) || ( (*pzScan == '-') && IS_DEC_DIGIT_CHAR(pzScan[1]) ) ) { pz_token = pzScan; (void)strtol(pzScan, &pzScan, 0); *pRetVal = DP_EV_NUMBER; return pzScan; } if (! IS_UNQUOTABLE_CHAR(*pzScan)) AG_ABEND(aprf("%s Error: Invalid input char '%c' in %s on line %d\n", pzProg, *pzScan, pCurCtx->pzCtxFname, pCurCtx->lineNo)); { unsigned char* pz = (unsigned char*)pzScan; while (IS_VALUE_NAME_CHAR(*pz)) pz++; if (IS_UNQUOTABLE_CHAR(*pz)) { *pRetVal = DP_EV_OTHER_NAME; while (IS_UNQUOTABLE_CHAR(*++pz)) ; } else *pRetVal = DP_EV_VAR_NAME; /* * Return a NAME token, maybe. * If the name is actually a keyword, * we will return that token code instead. */ pz_token = pzScan; pzScan = (char*)pz; } /* * Now scan the keyword table. */ if (*pRetVal == DP_EV_VAR_NAME) { char sv_ch = *pzScan; /* preserve the following character */ int kw_ix = 0; *pzScan = NUL; /* NUL terminate the name */ do { if (streqvcmp(apzKeywords[ kw_ix ], (char*)pz_token) == 0) { /* * Return the keyword token code instead of DP_EV_NAME */ *pRetVal = aKeywordTkn[ kw_ix ]; break; } } while (++kw_ix < KEYWORD_CT); *pzScan = sv_ch; /* restore the following character */ } return pzScan; }
static tDefEntry * find_by_index(tDefEntry * pE, char * pzScan) { int idx; /* * '[]' means the first entry of whatever index number */ if (*pzScan == ']') return pE; /* * '[$]' means the last entry of whatever index number */ if (*pzScan == '$') { pzScan = SPN_WHITESPACE_CHARS(pzScan + 1); if (*pzScan != ']') return NULL; if (pE->pEndTwin != NULL) return pE->pEndTwin; return pE; } /* * '[nn]' means the specified index number */ if (IS_DEC_DIGIT_CHAR(*pzScan)) { char* pz; idx = strtol(pzScan, &pz, 0); /* * Skip over any trailing space and make sure we have a closer */ pz = SPN_WHITESPACE_CHARS(pz); if (*pz != ']') return NULL; } else { /* * '[XX]' means get the index from our definitions */ char* pzDef = pzScan; char const* pzVal; if (! IS_VAR_FIRST_CHAR(*pzScan)) return NULL; pzScan = SPN_VALUE_NAME_CHARS(pzScan); /* * Temporarily remove the character under *pzScan and * find the corresponding defined value. */ { char svch = *pzScan; *pzScan = NUL; pzVal = getDefine(pzDef, AG_TRUE); *pzScan = svch; } /* * Skip over any trailing space and make sure we have a closer */ pzScan = SPN_WHITESPACE_CHARS(pzScan); if (*pzScan != ']') return NULL; /* * make sure we found a defined value */ if ((pzVal == NULL) || (*pzVal == NUL)) return NULL; idx = strtol(pzVal, &pzDef, 0); /* * Make sure we got a legal number */ if (*pzDef != NUL) return NULL; } /* * Search for the entry with the specified index. */ do { if (pE->index > idx) return NULL; if (pE->index == idx) break; pE = pE->pTwin; } while (pE != NULL); return pE; }
/** * Run the FSM. Will return CGI_ST_DONE or CGI_ST_INVALID */ te_cgi_state cgi_run_fsm( char const * pzSrc, int inlen, char * pzOut, int outlen ) { te_cgi_state cgi_state = CGI_ST_INIT; te_cgi_event trans_evt; te_cgi_state nxtSt; te_cgi_trans trans; char const * saved_pzSrc = pzSrc; int saved_inlen = inlen; char * saved_pzOut = pzOut; int saved_outlen = outlen; (void)saved_pzSrc; (void)saved_inlen; (void)saved_pzOut; (void)saved_outlen; while (cgi_state < CGI_ST_INVALID) { /* START == FIND TRANSITION == DO NOT CHANGE THIS COMMENT */ char curCh; if (--inlen < 0) { trans_evt = CGI_EV_END; curCh = NUL; } else { if (outlen < 4) { static char const exhaustion[] = "output space exhausted\n"; if (saved_outlen > (int)sizeof(exhaustion)) memcpy(saved_pzOut, exhaustion, sizeof(exhaustion)); return CGI_ST_INVALID; } curCh = *(pzSrc++); if (IS_ALPHABETIC_CHAR( curCh )) trans_evt = CGI_EV_ALPHA; else if (IS_DEC_DIGIT_CHAR( curCh )) trans_evt = CGI_EV_NAME_CHAR; else switch (curCh) { case '_': trans_evt = CGI_EV_NAME_CHAR; break; case '=': trans_evt = CGI_EV_EQUAL; break; case '+': trans_evt = CGI_EV_SPACE; curCh = ' '; break; case '%': trans_evt = CGI_EV_ESCAPE; break; case '&': trans_evt = CGI_EV_SEPARATOR; break; default: trans_evt = CGI_EV_OTHER; break; } } /* END == FIND TRANSITION == DO NOT CHANGE THIS COMMENT */ #ifndef __COVERITY__ if (trans_evt >= CGI_EV_INVALID) { nxtSt = CGI_ST_INVALID; trans = CGI_TR_INVALID; } else #endif /* __COVERITY__ */ { const t_cgi_transition * ttbl = cgi_trans_table[ cgi_state ] + trans_evt; nxtSt = ttbl->next_state; trans = ttbl->transition; } switch (trans) { case CGI_TR_INVALID: /* START == INVALID == DO NOT CHANGE THIS COMMENT */ exit( cgi_invalid_transition( cgi_state, trans_evt )); /* END == INVALID == DO NOT CHANGE THIS COMMENT */ break; case CGI_TR_NAME_EQUAL: /* START == NAME_EQUAL == DO NOT CHANGE THIS COMMENT */ strcpy( pzOut, "='" ); outlen -= 2; pzOut += 2; /* END == NAME_EQUAL == DO NOT CHANGE THIS COMMENT */ break; case CGI_TR_SEPARATE: /* START == SEPARATE == DO NOT CHANGE THIS COMMENT */ strcpy( pzOut, "';\n" ); outlen -= 2; pzOut += 3; /* END == SEPARATE == DO NOT CHANGE THIS COMMENT */ break; case CGI_TR_STASH: /* START == STASH == DO NOT CHANGE THIS COMMENT */ *(pzOut++) = curCh; outlen--; /* END == STASH == DO NOT CHANGE THIS COMMENT */ break; case CGI_TR_VALUE_ESCAPE: /* START == VALUE_ESCAPE == DO NOT CHANGE THIS COMMENT */ { char z[4]; if (inlen < 2) exit( cgi_invalid_transition( cgi_state, trans_evt )); z[0] = *(pzSrc++); z[1] = *(pzSrc++); z[2] = NUL; inlen -= 2; /* * We must backslash quote certain characters that are %-quoted * in the input string: */ switch (*(pzOut++) = (char)strtol( z, NULL, 16 )) { case '\'': case '\\': case '#': pzOut[0] = pzOut[-1]; pzOut[-1] = '\\'; pzOut++; } } /* END == VALUE_ESCAPE == DO NOT CHANGE THIS COMMENT */ break; default: /* START == BROKEN MACHINE == DO NOT CHANGE THIS COMMENT */ exit( cgi_invalid_transition( cgi_state, trans_evt )); /* END == BROKEN MACHINE == DO NOT CHANGE THIS COMMENT */ } cgi_state = nxtSt; } return cgi_state; }