/*** analog 4.13 http://www.analog.cx/ ***/ /*** This program is copyright (c) Stephen R. E. Turner 1995 - 2000 except as *** stated otherwise. Distribution, usage and modification of this program is *** subject to the conditions of the Licence which you should have received *** with it. This program comes with no warranty, expressed or implied. ***/ /*** init2.c; subsiduary functions for parsing config files */ /* See also init.c */ #include "anlghea3.h" /*** All config commands have the following structure: void config.....(void *opt, char *cmd, char *arg1, char *arg2, int rc) opt is the variable to be changed, "cmd arg1 arg2" is the config command issued, rc is the number of arguments retrieved from the config line (0..3), or -1 if the config command was issued by the program internally, or -2 if it was issued by the program in parsing command line (the last don't go through confline(), so cmd is command line option). -3 is occasionally used for special cases. ***/ /* First some warnings of things that can go wrong in config commands. NB rc = -1 announced to be because anlghead.h got messed up. But it could be an internal error caused by a bug. */ void shortwarn(char *cmd, char *arg1, int rc) { char *s = "Not enough arguments for configuration command: ignoring it"; if (rc == -1) error("Default given for %s in anlghead.h too short"); else if (arg1 == NULL) warn('C', TRUE, "%s:\n%s", s, cmd); else warn('C', TRUE, "%s:\n%s %s", s, cmd, delimit(arg1)); } void longwarn(char *cmd, char *arg1, char *arg2, int rc) { char *s = "Too many arguments for configuration command: " "ignoring end of line starting"; if (rc == -1) warn('C', TRUE, "Default given for %s in anlghead.h too long: " "ignoring end of it", cmd); else if (arg2 == NULL) warn('C', TRUE, "%s:\n%s %s", s, cmd, delimit(arg1)); else warn('C', TRUE, "%s:\n%s %s %s", s, cmd, delimit(arg1), delimit(arg2)); } void badwarn(char *cmd, choice domess, char *arg1, char *arg2, int rc) { char *s = "Bad argument in configuration command: ignoring it"; if (rc == -2) warn('C', TRUE, "Bad argument in command line argument %s: ignoring it", cmd); else if (rc == -1) error("Incorrect default given for %s in anlghead.h", cmd); else if (arg2 == NULL) warn('C', domess, "%s:\n%s %s", s, cmd, delimit(arg1)); else warn('C', domess, "%s:\n%s %s %s", s, cmd, delimit(arg1), delimit(arg2)); } void unknownwarn(char *cmd, char *arg1, char *arg2) { char *s = "Unknown configuration command: ignoring it"; if (arg1 == NULL) warn('C', TRUE, "%s:\n%s", s, cmd); else if (arg2 == NULL) warn('C', TRUE, "%s:\n%s %s", s, cmd, delimit(arg1)); else warn('C', TRUE, "%s:\n%s %s %s", s, cmd, delimit(arg1), delimit(arg2)); } void configcall(void *opt, char *cmd, char *arg1, char *arg2, int rc) { if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); /* calling function will then call config() */ } void configcols(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *cols = (choice *)opt; /* see also configallcols() */ logical warn1 = FALSE, warn2 = FALSE, warn3; char *c; int i = 0, j; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } for (c = arg1; *c != '\0' && i < COL_NUMBER - 1; c++, i++) { if (*c == 'R') cols[i] = COL_REQS; else if (*c == 'P') cols[i] = COL_PAGES; else if (*c == 'B') cols[i] = COL_BYTES; else if (*c == 'r') cols[i] = COL_PREQS; else if (*c == 'p') cols[i] = COL_PPAGES; else if (*c == 'b') cols[i] = COL_PBYTES; else if (*c == 'd') cols[i] = COL_DATE; else if (*c == 'D') cols[i] = COL_TIME; else if (*c == 'N') cols[i] = COL_INDEX; else { i--; if (!warn1) { warn('C', TRUE, "Ignoring unknown columns in\n%s %s", cmd, arg1); warn1 = TRUE; } } if (cols[i] == COL_DATE && strchr(arg1, 'D') != NULL) { i--; /* cancel i++ in for loop, so overwriting this column */ if (!warn2) { warn('C', TRUE, "Ignoring repeated columns in configuration command\n%s %s", cmd, arg1); warn2 = TRUE; } } else { for (j = 0, warn3 = FALSE; j < i && !warn3; j++) { if (cols[j] == cols[i]) { /* shortest code, not least work */ warn3 = TRUE; i--; /* see above */ if (!warn2) { warn('C', TRUE, "Ignoring repeated columns in configuration command\n%s %s", cmd, arg1); warn2 = TRUE; } } } } } if (*c != '\0' /* can this happen? */ || rc > 1) longwarn(cmd, arg1, arg2, rc); cols[i] = COL_NUMBER; } void configallcols(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *cols = (choice *)opt; int j; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); for (j = 0; j < DATEREP_NUMBER; j++) /* possibility of dup. warns */ configcols((void *)&(cols[j * COL_NUMBER]), cmd, arg1, NULL, -3); } /* now a set of similar configs that use symbolic words */ void configsortby(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *sortby = (choice *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "REQUESTS")) *sortby = REQUESTS; else if (strcaseeq(arg1, "PAGES")) *sortby = PAGES; else if (strcaseeq(arg1, "BYTES")) *sortby = BYTES; else if (strcaseeq(arg1, "DATE")) *sortby = DATESORT; else if (strcaseeq(arg1, "ALPHABETICAL")) *sortby = ALPHABETICAL; else if (strcaseeq(arg1, "RANDOM")) *sortby = RANDOM; else badwarn(cmd, TRUE, arg1, arg2, rc); } void configdebug(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char **args = (char **)opt; char *c; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ON") || strcaseeq(arg1, "TRUE")) configstr(args, NULL, "CDEFLMRSUV", NULL, -1); /* kludge: include all of both sets: same string in settings.c */ else if (strcaseeq(arg1, "OFF") || strcaseeq(arg1, "FALSE")) configstr(args, NULL, "", NULL, -1); else if (arg1[0] == '-') { while ((c = strpbrk(*args, arg1 + 1)) != NULL) memmove((void *)c, (void *)(c + 1), strlen(c)); } else if (arg1[0] == '+') { /* c.f. configstr() */ *args = (char *)xrealloc((void *)(*args), strlen(arg1) + strlen(*args)); memcpy((void *)strchr(*args, '\0'), (void *)(arg1 + 1), strlen(arg1)); } else { if (arg1[0] == '+') arg1++; configstr(args, NULL, arg1, NULL, -1); } } void configonoff(void *opt, char *cmd, char *arg1, char *arg2, int rc) { logical *q = (logical *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ON") || strcaseeq(arg1, "TRUE")) *q = TRUE; else if (strcaseeq(arg1, "OFF") || strcaseeq(arg1, "FALSE")) *q = FALSE; else badwarn(cmd, TRUE, arg1, arg2, rc); } void configall(void *opt, char *cmd, char *arg1, char *arg2, int rc) { logical *q = (logical *)opt; int i; logical result; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ON") || strcaseeq(arg1, "TRUE")) result = TRUE; else if (strcaseeq(arg1, "OFF") || strcaseeq(arg1, "FALSE")) result = FALSE; else { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for (i = 0; i < REP_NUMBER; i++) { if (i != REP_GENSUM) q[i] = result; } } void configallback(void *opt, char *cmd, char *arg1, char *arg2, int rc) { logical *q = (logical *)opt; /* same as configall(), but only DATEREPs */ int i; logical result; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ON") || strcaseeq(arg1, "TRUE")) result = TRUE; else if (strcaseeq(arg1, "OFF") || strcaseeq(arg1, "FALSE")) result = FALSE; else { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for (i = 0; i < DATEREP_NUMBER; i++) q[i] = result; } void configgotos(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *q = (choice *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ON") || strcaseeq(arg1, "TRUE")) *q = TRUE; else if (strcaseeq(arg1, "OFF") || strcaseeq(arg1, "FALSE")) *q = FALSE; else if (strcaseeq(arg1, "FEW")) *q = FEW; else badwarn(cmd, TRUE, arg1, arg2, rc); } void configcase(void *opt, char *cmd, char *arg1, char *arg2, int rc) { logical *q = (logical *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "INSENSITIVE")) *q = TRUE; else if (strcaseeq(arg1, "SENSITIVE")) *q = FALSE; else badwarn(cmd, TRUE, arg1, arg2, rc); } void configweekday(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *d = (choice *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "SUNDAY")) *d = SUNDAY; else if (strcaseeq(arg1, "MONDAY")) *d = MONDAY; else if (strcaseeq(arg1, "TUESDAY")) *d = TUESDAY; else if (strcaseeq(arg1, "WEDNESDAY")) *d = WEDNESDAY; else if (strcaseeq(arg1, "THURSDAY")) *d = THURSDAY; else if (strcaseeq(arg1, "FRIDAY")) *d = FRIDAY; else if (strcaseeq(arg1, "SATURDAY")) *d = SATURDAY; else badwarn(cmd, TRUE, arg1, arg2, rc); } void configoutstyle(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *s = (choice *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "HTML")) *s = HTML; else if (strcaseeq(arg1, "PLAIN")) *s = PLAIN; else if (strcaseeq(arg1, "ASCII")) *s = ASCII; else if (strcaseeq(arg1, "COMPUTER") || strcaseeq(arg1, "PREFORMATTED")) *s = COMPUTER; else if (strcaseeq(arg1, "CACHE") || strcaseeq(arg1, "NONE")) *s = OUT_NONE; else badwarn(cmd, TRUE, arg1, arg2, rc); } #ifndef NODNS void configdns(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *s = (choice *)opt; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "NONE")) *s = DNS_NONE; else if (strcaseeq(arg1, "READ")) *s = DNS_READ; else if (strcaseeq(arg1, "LOOKUP")) *s = DNS_LOOKUP; else if (strcaseeq(arg1, "WRITE")) *s = DNS_WRITE; else badwarn(cmd, TRUE, arg1, arg2, rc); } #endif void configlang(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Lang *lang = (Lang *)opt; logical v3lang = FALSE; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "ARMENIAN")) lang->code = ARMENIAN; else if (strcaseeq(arg1, "BOSNIAN")) lang->code = BOSNIAN; else if (strcaseeq(arg1, "BULGARIAN")) lang->code = BULGARIAN; else if (strcaseeq(arg1, "CATALAN")) lang->code = CATALAN; else if (strcaseeq(arg1, "SIMP-CHINESE") || strcaseeq(arg1, "CHINESE")) lang->code = SIMP_CHINESE; else if (strcaseeq(arg1, "TRAD-CHINESE")) lang->code = TRAD_CHINESE; else if (strcaseeq(arg1, "CROATIAN")) lang->code = CROATIAN; else if (strcaseeq(arg1, "CZECH")) lang->code = CZECH; else if (strcaseeq(arg1, "DANISH")) lang->code = DANISH; else if (strcaseeq(arg1, "FLEMISH") || strcaseeq(arg1, "DUTCH")) lang->code = DUTCH; else if (strcaseeq(arg1, "ENGLISH")) lang->code = ENGLISH; else if (strcaseeq(arg1, "US-ENGLISH")) lang->code = US_ENGLISH; else if (strcaseeq(arg1, "FINNISH")) lang->code = FINNISH; else if (strcaseeq(arg1, "FRENCH")) lang->code = FRENCH; else if (strcaseeq(arg1, "GERMAN")) lang->code = GERMAN; else if (strcaseeq(arg1, "GREEK")) lang->code = GREEK; else if (strcaseeq(arg1, "HUNGARIAN")) lang->code = HUNGARIAN; else if (strcaseeq(arg1, "ICELANDIC")) lang->code = ICELANDIC; else if (strcaseeq(arg1, "ITALIAN")) lang->code = ITALIAN; else if (strcaseeq(arg1, "JAPANESE")) lang->code = JAPANESE; else if (strcaseeq(arg1, "KOREAN")) lang->code = KOREAN; else if (strcaseeq(arg1, "LATVIAN")) /* lang->code = LATVIAN */ v3lang = TRUE; else if (strcaseeq(arg1, "LITHUANIAN")) /* lang->code = LITHUANIAN */ v3lang = TRUE; else if (strcaseeq(arg1, "NORWEGIAN")) lang->code = NORWEGIAN; else if (strcaseeq(arg1, "NYNORSK")) lang->code = NYNORSK; else if (strcaseeq(arg1, "POLISH")) lang->code = POLISH; else if (strcaseeq(arg1, "PORTUGUESE") || strcaseeq(arg1, "PORTUGESE")) lang->code = PORTUGUESE; else if (strcaseeq(arg1, "BR-PORTUGUESE") || strcaseeq(arg1, "BR-PORTUGESE")) lang->code = BR_PORTUGUESE; else if (strcaseeq(arg1, "ROMANIAN")) lang->code = ROMANIAN; else if (strcaseeq(arg1, "RUSSIAN")) lang->code = RUSSIAN; else if (strcaseeq(arg1, "SERBIAN") || strcaseeq(arg1, "SERBOCROATIAN") || strcaseeq(arg1, "SERBOCROAT")) lang->code = SERBIAN; else if (strcaseeq(arg1, "SLOVAK")) lang->code = SLOVAK; else if (strcaseeq(arg1, "SLOVENE") || strcaseeq(arg1, "SLOVENIAN")) lang->code = SLOVENE; else if (strcaseeq(arg1, "SPANISH")) lang->code = SPANISH; else if (strcaseeq(arg1, "SWEDISH")) lang->code = SWEDISH; else if (strcaseeq(arg1, "TURKISH")) lang->code = TURKISH; else if (strcaseeq(arg1, "UKRAINIAN") || strcaseeq(arg1, "UKRANIAN")) lang->code = UKRAINIAN; else { badwarn(cmd, TRUE, arg1, arg2, rc); return; } if (v3lang) { badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (language not yet translated for version 4)"); return; } lang->file = NULL; /* if successful */ } void selectlang(char *country, Outchoices *op) { /* Select langfile and domains file with country code. If outstyle is HTML or ASCII, look first for special files for those styles. */ extern char *workspace; FILE *f; if (op->outstyle == HTML || op->outstyle == ASCII) { sprintf(workspace, "%s%s%c%s", LANGDIR, country, (op->outstyle == HTML)?'h':'a', EXTSEP"lng"); } if ((op -> outstyle != HTML && op->outstyle != ASCII) || (f = FOPENR(workspace)) == NULL) sprintf(workspace, "%s%s%s", LANGDIR, country, EXTSEP"lng"); else fclose(f); configstr(&(op->lang.file), NULL, workspace, NULL, -1); if (op->domainsfile == NULL) { if (op->outstyle == HTML || op->outstyle == ASCII) { sprintf(workspace, "%s%s%c%s", LANGDIR, country, (op->outstyle == HTML)?'h':'a', "dom"EXTSEP"tab"); } if ((op->outstyle == HTML || op->outstyle == ASCII) && (f = FOPENR(workspace)) != NULL) { fclose(f); configstr(&(op->domainsfile), NULL, workspace, NULL, -1); } else { sprintf(workspace, "%s%s%s", LANGDIR, country, "dom"EXTSEP"tab"); if ((f = FOPENR(workspace)) != NULL) { fclose(f); configstr(&(op->domainsfile), NULL, workspace, NULL, -1); } /* otherwise will get set to ukdom.tab on return to finalinit() */ } } } void configlogfmt(void *opt, char *cmd, char *arg1, char *arg2, int rc) { extern Memman *xmemman; Inputformatlist **logfmt = (Inputformatlist **)opt; Inputformatlist *fp; Inputformat *form; choice count[INPUT_NUMBER]; choice rc2; int i; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "DEFAULT")) { (*logfmt)->used = TRUE; configlogfmt(opt, NULL, "%x0", NULL, -1); (*logfmt)->used = TRUE; } else if (strcaseeq(arg1, "AUTO")) { (*logfmt)->used = TRUE; configlogfmt(opt, NULL, "%x1", NULL, -1); (*logfmt)->used = TRUE; } else if (strcaseeq(arg1, "COMMON")) { configlogfmt(opt, NULL, LOG_COMMON1, NULL, -1); configlogfmt(opt, NULL, LOG_COMMON2, NULL, -1); configlogfmt(opt, NULL, LOG_COMMON3, NULL, -1); } else if (strcaseeq(arg1, "MS-COMMON")) { configlogfmt(opt, NULL, LOG_MS_COMMON1, NULL, -1); configlogfmt(opt, NULL, LOG_COMMON2, NULL, -1); configlogfmt(opt, NULL, LOG_COMMON3, NULL, -1); } else if (strcaseeq(arg1, "COMBINED")) { configlogfmt(opt, NULL, LOG_COMBINED1, NULL, -1); configlogfmt(opt, NULL, LOG_COMBINED2, NULL, -1); configlogfmt(opt, NULL, LOG_COMBINED3, NULL, -1); } else if (strcaseeq(arg1, "MICROSOFT-NA")) { configlogfmt(opt, NULL, LOG_MS_NA1, NULL, -1); configlogfmt(opt, NULL, LOG_MS_NA2, NULL, -1); } else if (strcaseeq(arg1, "MICROSOFT-INT")) { configlogfmt(opt, NULL, LOG_MS_INT1, NULL, -1); configlogfmt(opt, NULL, LOG_MS_INT2, NULL, -1); } else if (strcaseeq(arg1, "WEBSITE-NA")) configlogfmt(opt, NULL, LOG_WEBSITE_NA, NULL, -1); else if (strcaseeq(arg1, "WEBSITE-INT")) configlogfmt(opt, NULL, LOG_WEBSITE_INT, NULL, -1); else if (strcaseeq(arg1, "WEBSTAR")) { configlogfmt(opt, NULL, LOG_WEBSTAR1, NULL, -1); configlogfmt(opt, NULL, LOG_WEBSTAR2, NULL, -1); } else if (strcaseeq(arg1, "EXTENDED")) { configlogfmt(opt, NULL, LOG_EXTENDED1, NULL, -1); configlogfmt(opt, NULL, LOG_EXTENDED2, NULL, -1); } else if (strcaseeq(arg1, "MS-EXTENDED")) { configlogfmt(opt, NULL, LOG_MS_EXTENDED1, NULL, -1); configlogfmt(opt, NULL, LOG_EXTENDED2, NULL, -1); } else if (strcaseeq(arg1, "WEBSTAR-EXTENDED")) { configlogfmt(opt, NULL, LOG_WEBSTAR_EXTENDED1, NULL, -1); configlogfmt(opt, NULL, LOG_EXTENDED2, NULL, -1); } else if (strcaseeq(arg1, "NETSCAPE")) configlogfmt(opt, NULL, LOG_NETSCAPE, NULL, -1); else if (strcaseeq(arg1, "BROWSER")) configlogfmt(opt, NULL, LOG_BROWSER, NULL, -1); else if (strcaseeq(arg1, "REFERRER") || strcaseeq(arg1, "REFERER")) { configlogfmt(opt, NULL, LOG_REFERRER1, NULL, -1); configlogfmt(opt, NULL, LOG_REFERRER2, NULL, -1); } else if ((rc2 = strtoinfmt(&form, arg1, count)) != FMT_OK) { if (rc == -3) warn('C', FALSE, "Ignoring corrupt format line in logfile"); else badwarn(cmd, FALSE, arg1, arg2, rc); if (rc2 == FMT_DUP) warn('C', CONTINUATION, " (reason: one item occurs twice in format)"); else if (rc2 == FMT_PARTTIME) warn('C', CONTINUATION, " (reason: time without date or vice versa)"); else if (rc2 == FMT_BADPC) warn('C', CONTINUATION, " (reason: an unknown item code is present)"); else if (rc2 == FMT_NOPC) warn('C', CONTINUATION, " (reason: no item codes are present)"); else if (rc2 == FMT_BADCHAR) warn('C', CONTINUATION, " (reason: an unknown escape sequence is present)"); else if (rc2 == FMT_NOTERM) warn('C', CONTINUATION, " (reason: an unterminated string is present)"); else if (rc2 == FMT_BADBUILTIN) warn('C', CONTINUATION, " (reason: non-existent built-in format)"); else if (rc2 == FMT_QBUTNOR) warn('C', CONTINUATION, " (reason: query string without filename)"); /* despite finishing "else if", that should be all the rc2's */ return; } else { if ((*logfmt)->used) { fp = (Inputformatlist *)submalloc(xmemman, sizeof(Inputformatlist)); *logfmt = fp; (*logfmt)->used = FALSE; } else { for (fp = *logfmt; fp->next != NULL; TO_NEXT(fp)) ; fp->next = (Inputformatlist *)submalloc(xmemman, sizeof(Inputformatlist)); TO_NEXT(fp); } fp->form = form; for (i = 0; i < INPUT_NUMBER; i++) fp->count[i] = count[i]; fp->next = NULL; } } void configapachelogfmt(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *p; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if ((p = apachelogfmt(arg1)) == NULL) warn('C', TRUE, "Sorry, can't parse \"%%...{format}t\" in %s: ignoring whole line", cmd); else if (STREQ(cmd, "APACHELOGFORMAT")) configlogfmt(opt, "APACHELOGFORMAT -> LOGFORMAT", p, NULL, 1); else configlogfmt(opt, "APACHEDAFAULTLOGFORMAT -> DEFAULTLOGFORMAT", p, NULL, 1); } void configrepord(void *opt, char *cmd, char *arg1, char *arg2, int rc) { extern char repcodes[]; char *s1 = "REPORTORDER"; char *s2 = "REPORTORDER in anlghead.h"; char *s = (rc == -1)?s2:s1; choice *order = (choice *)opt; logical used[REP_NUMBER]; int i, j, k; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } for (i = 0; i < REP_NUMBER; i++) used[i] = 0; for (i = 0, k = 0; k < REP_NUMBER && arg1[i] != '\0'; i++) { if (ISALNUM(arg1[i])) { /* else ignore */ for (j = 0; repcodes[j] != arg1[i] && repcodes[j] != '\0'; j++) ; if (repcodes[j] == '\0') warn('C', TRUE, "Spurious character %c in %s: ignoring it", arg1[i], s); else if (used[j] == 0) { order[k++] = j; used[j] = 1; } else if (used[j] == 1) { warn('C', TRUE, "Character %c used more than once in %s: " "ignoring later occurrences", arg1[i], s); used[j] = 2; } } } if (rc > 1 || arg1[i] != '\0') longwarn(cmd, arg1, arg2, rc); if (k < REP_NUMBER) { for (i = 0; i < REP_NUMBER && k < REP_NUMBER; i++) { if (used[i] == 0) { /* k should stay < R_N automatically, but... */ warn('C', TRUE, "Character %c not used in %s: adding it at end", repcodes[i], s); order[k++] = i; } } } order[k] = -1; } void configstr(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char **s = (char **)opt; size_t len; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); len = strlen(arg1); *s = (char *)xrealloc((void *)(*s), len + 1); strcpy(*s, arg1); } void configstrlist(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Strlist **list = (Strlist **)opt; Strlist *lp = NULL; char *t; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc == -1) /* have to be careful because can't strtok a const string */ t = arg1; else if ((t = strtok(arg1, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (*list != NULL) { for (lp = *list; lp->next != NULL; TO_NEXT(lp)) ; /* find end of list */ } for ( ; t != NULL; t = ((rc == -1)?NULL:strtok((char *)NULL, ","))) { if (*list == NULL) { lp = (Strlist *)xmalloc(sizeof(Strlist)); *list = lp; } else { lp->next = (Strlist *)xmalloc(sizeof(Strlist)); TO_NEXT(lp); } DEFAULTSTR(lp->name, t); lp->next = NULL; } return; } void configerrfile(void *opt, char *cmd, char *arg1, char *arg2, int rc) { /* NB Don't use freopen(), coz fatal errors sent to both errfile & stderr. */ FILE **err = (FILE **)opt; FILE *tmp; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "stderr")) { if (*err != stderr) { debug('F', "Opening stderr as new ERRFILE"); warn('E', TRUE, "Redirecting future diagnostic messages to stderr"); fclose(*err); *err = stderr; } } else if ((tmp = FOPENW(arg1)) == NULL) warn('F', TRUE, "Failed to open ERRFILE %s: ignoring it", arg1); else { debug('F', "Opening %s as new ERRFILE", arg1); warn('E', TRUE, "Redirecting future diagnostic messages to %s", arg1); if (*err != stderr) fclose(*err); *err = tmp; setvbuf(*err, NULL, ERRBUFMODE, BUFSIZ); } } #ifndef NODIRENT #ifndef VMSDIRENT #ifndef WIN32DIRENT /* i.e. if POSIX dirent */ void configwildlogs(void *opt, char *arg1, char *arg2, int rc) { struct dirent *filep; struct stat buf; DIR *dirp; char *dirname, *filename, *c; size_t dirlen, len = 0; logical matched = FALSE; if ((c = strrchr(arg1, DIRSEP)) == NULL) { filename = arg1; dirname = (char *)xmalloc(3); #ifdef MAC dirname[0] = '\0'; #else sprintf(dirname, ".%c", DIRSEP); #endif } else { filename = c + 1; dirname = (char *)xmalloc((size_t)(c - arg1) + 2); memcpy((void *)dirname, (void *)arg1, (size_t)(c - arg1) + 1); dirname[(c - arg1) + 1] = '\0'; } if ((dirp = opendir(dirname)) == NULL) { if (strchr(dirname, '*') != NULL || strchr(dirname, '?') != NULL) warn('F', TRUE, "Cannot open directory %s: ignoring logfiles %s\n" "(wildcards not allowed in directory name)", dirname, arg1); else warn('F', TRUE, "Cannot open directory %s: ignoring logfiles %s", dirname, arg1); return; } dirlen = strlen(dirname); while ((filep = readdir(dirp)) != NULL) { if (MATCHES(filep->d_name, filename)) { if (strlen(filep->d_name) > len) { len = strlen(filep->d_name); /* d_namlen is not portable */ dirname = (char *)xrealloc((void *)dirname, dirlen + len + 1); } memcpy((void *)(dirname + dirlen), (void *)(filep->d_name), len + 1); stat(dirname, &buf); /* dirname now contains complete filename */ if (S_ISREG(buf.st_mode)) { configlogfile(opt, "LOGFILE", dirname, arg2, rc); matched = TRUE; } } } closedir(dirp); if (!matched) warn('F', TRUE, "Cannot find logfile %s: ignoring it", arg1); free((void *)dirname); } #else /* WIN32DIRENT */ void configwildlogs(void *opt, char *arg1, char *arg2, int rc) { struct _stat buf; char *dirname, *c; struct _finddata_t file; long code; int rc2; size_t dirlen, len = 0; logical matched = FALSE; if ((code = _findfirst(arg1, &file)) != (long)(-1)) { if ((c = strrchr(arg1, DIRSEP)) == NULL) { dirname = (char *)xmalloc(1); dirname[0] = '\0'; } else { dirname = (char *)xmalloc((size_t)(c - arg1) + 2); memcpy((void *)dirname, (void *)arg1, (size_t)(c - arg1) + 1); dirname[(c - arg1) + 1] = '\0'; } dirlen = strlen(dirname); for (rc2 = 0; rc2 == 0; rc2 = _findnext(code, &file)) { if (strlen(file.name) > len) { len = strlen(file.name); dirname = (char *)xrealloc((void *)dirname, dirlen + len + 1); } memcpy((void *)(dirname + dirlen), (void *)(file.name), len + 1); _stat(dirname, &buf); /* dirname now contains complete filename */ if (_S_IFREG & buf.st_mode) { /* bitwise & */ configlogfile(opt, "LOGFILE", dirname, arg2, rc); matched = TRUE; } } _findclose(code); free((void *)dirname); } if (!matched) warn('F', TRUE, "Cannot find logfile %s: ignoring it", arg1); } #endif #else /* VMSDIRENT */ /* This function is due to Dave Jones */ void configwildlogs(void *opt, char *arg1, char *arg2, int rc) { static char fspec[VMS_FSPEC_MAX], related[VMS_FSPEC_MAX]; static char result[VMS_FSPEC_MAX]; static $DESCRIPTOR(fspec_dx,fspec); static $DESCRIPTOR(related_dx,""); static $DESCRIPTOR(default_dx,".log"); static $DESCRIPTOR(result_dx,result); char *space, *ques; long int context; int status, stsval, length, LIB$FIND_FILE(), LIB$FIND_FILE_END(); logical matched; length = strlen (arg1); if ( length >= VMS_FSPEC_MAX ) length = VMS_FSPEC_MAX - 1; strncpy ( fspec, arg1, length ); fspec[length] = '\0'; while ( ques = strchr(fspec,'?') ) *ques = '%'; fspec_dx.dsc$w_length = length; for ( matched = FALSE, context = 0; 1&(status=LIB$FIND_FILE ( &fspec_dx, &result_dx, &context, &default_dx, &related_dx, &stsval, (long *) 0 )); matched = TRUE) { space = strchr ( result, ' ' ); if ( !space ) space = &result[VMS_FSPEC_MAX-1]; *space = '\0'; configlogfile ( opt, "LOGFILE", result, arg2, rc ); /* Save last result to use as default for next lookup */ strcpy ( related, result ); related_dx.dsc$w_length = strlen(result); related_dx.dsc$a_pointer = related; } if ( context ) LIB$FIND_FILE_END ( &context ); if (!matched) warn('F', TRUE, "Cannot find logfile %s: ignoring it", arg1); } #endif #endif void configlogfile(void *opt, char *cmd, char *arg1, char *arg2, int rc) { extern Inputformatlist *logformat; extern logical newloglist; extern int tz; Filelist **logfile = (Filelist **)opt; Filelist *lf; char *s, *t; int i; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 2) longwarn(cmd, arg1, arg2, rc); if (strchr(arg1, ',') != NULL) { s = (char *)xmalloc(strlen(arg1) + 1); strcpy(s, arg1); /* can't strtok arg1 directly in case it's const */ if ((t = strtok(s, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); free((void *)s); return; } for ( ; t != NULL; t = strtok((char *)NULL, ",")) configlogfile(opt, "LOGFILE", t, arg2, rc); free((void *)s); return; } #ifndef NODIRENT else if (strchr(arg1, '*') || strchr(arg1, '?')) { configwildlogs(opt, arg1, arg2, rc); return; } #endif else if (strcaseeq(arg1, "NONE")) { configlogfmt((void *)&logformat, "LOGFORMAT", "DEFAULT", NULL, -1); *logfile = NULL; return; } else if (*logfile == NULL || newloglist == TRUE) { *logfile = (Filelist *)xmalloc(sizeof(Filelist)); lf = *logfile; newloglist = FALSE; } else { for (lf = *logfile; lf->next != NULL; TO_NEXT(lf)) ; lf->next = (Filelist *)xmalloc(sizeof(Filelist)); TO_NEXT(lf); } DEFAULTSTR(lf->name, arg1); lf->format = logformat; lf->from = LAST_TIME; lf->to = FIRST_TIME; for (i = 0; i < LOGDATA_NUMBER; i++) lf->data[i] = 0; lf->bytes = 0; lf->bytes7 = 0; lf->tz = tz; if (rc >= 2) { DEFAULTSTR(lf->prefix, arg2); lf->prefixlen = strlen(lf->prefix); if (strstr(arg2, "%v") == NULL) lf->pvpos = UNSET; else lf->pvpos = strstr(arg2, "%v") - arg2; } else lf->prefix = NULL; lf->ispipe = FALSE; lf->next = NULL; logformat->used = TRUE; } void configcachefile(void *opt, char *cmd, char *arg1, char *arg2, int rc) { /* a wrapper to configlogfile(), but we have to catch a few cases first */ Filelist **cachefile = (Filelist **)opt; extern Inputformatlist *logformat; extern logical newloglist; logical lfu, nll; if (rc > 1) { longwarn(cmd, arg1, arg2, rc); rc = 1; } if (strcaseeq(arg1, "NONE")) { *cachefile = NULL; return; } lfu = logformat->used; nll = newloglist; newloglist = FALSE; configlogfile(opt, cmd, arg1, arg2, rc); logformat->used = lfu; newloglist = nll; } void configchar(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *c = (char *)opt; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strcaseeq(arg1, "none")) *c = '\0'; else { if (arg1[1] != '\0') longwarn(cmd, arg1, arg2, rc); *c = arg1[0]; } } void configbarstyle(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *g = (char *)opt; char h; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1 || arg1[1] != '\0') longwarn(cmd, arg1, arg2, rc); h = TOLOWER(arg1[0]); if (h != 'a' && h != 'b' && h != 'c' && h != 'd' && h != 'e' && h != 'f' && h != 'g' && h != 'h') badwarn(cmd, TRUE, arg1, arg2, rc); else *g = h; } void configgraph(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *g = (char *)opt; /* see also configallgraph() below */ if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1 || arg1[1] != '\0') longwarn(cmd, arg1, arg2, rc); if (arg1[0] != 'R' && arg1[0] != 'P' && arg1[0] != 'B' && arg1[0] != 'r' && arg1[0] != 'p' && arg1[0] != 'b') badwarn(cmd, TRUE, arg1, arg2, rc); else *g = arg1[0]; } void configallgraph(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *g = (char *)opt; /* same as configgraph() */ int i; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1 || arg1[1] != '\0') longwarn(cmd, arg1, arg2, rc); if (arg1[0] != 'R' && arg1[0] != 'P' && arg1[0] != 'B' && arg1[0] != 'r' && arg1[0] != 'p' && arg1[0] != 'b') badwarn(cmd, TRUE, arg1, arg2, rc); else { for (i = 0; i < DATEREP_NUMBER; i++) g[i] = arg1[0]; } } void configfloor(void *opt, char *cmd, char *arg1, char *arg2, int rc) { /* This function parses the following formats for floor -100(r|p|b|d) // top 100 1000(r|p|b) // at least 1000 9.5(k|M|G|T)b // ditto 0.5%(r|p|B) // at least 0.5% of total 0.5:(r|p|B) // at least 0.5% of largest 970701d // last access since -00-0201d // same with a relative date Upper case letters for r|p|b|d are also acceptable. */ extern time_t starttime; Floor *floor = (Floor *)opt; char **b, *c, d; choice floorby; char qual = '\0'; double mn; timecode_t t; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); c = arg1 + strlen(arg1) - 1; d = TOUPPER(*c); if (d == 'R') floorby = REQUESTS; else if (d == 'P') floorby = PAGES; else if (d == 'B') floorby = BYTES; else if (d == 'D') floorby = DATESORT; else { badwarn(cmd, TRUE, arg1, arg2, rc); return; } if (floorby != DATESORT) { b = (char **)xmalloc(sizeof(char *)); mn = strtod(arg1, b); if (*b == arg1) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } else if (*b == c - 1) { if (mn < 0) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } else if (**b == '%' || **b == ':' || (floorby == BYTES && (**b == 'k' || **b == 'M' || **b == 'G' || **b == 'T'))) qual = **b; else { badwarn(cmd, TRUE, arg1, arg2, rc); return; } } free((void *)b); } else { /* floorby == DATESORT */ if (arg1[0] == '-' && arg1[1] != '0' && ISDIGIT(arg1[1])) mn = atof(arg1); else if (parsedate(starttime, arg1, &t, TRUE, FALSE) == ERR) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } else mn = (double)t; } floor->min = mn; floor->qual = qual; floor->floorby = floorby; } void configtree(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Tree **treex = (Tree **)opt; Hashindex item; Hashentry own; char *name, *nameend, *t; int i; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strchr(arg1, ',') != NULL) { if ((t = strtok(arg1, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for ( ; t != NULL; t = strtok((char *)NULL, ",")) configtree(opt, cmd, t, NULL, -1); return; } for (i = 0; i < DATA_NUMBER; i++) own.data[i] = 0; /* set up dummy item */ own.bytes = 0; item.own = &own; item.name = arg1; name = NULL; (*treex)->cutfn(&name, &nameend, item.name, TRUE); (void)treefind(name, nameend, &((*treex)->tree), &item, (*treex)->cutfn, TRUE, TRUE, FALSE, (*treex)->space); } void configulong(void *opt, char *cmd, char *arg1, char *arg2, int rc) { unsigned int *x = (unsigned int *)opt; char **c; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (!ISDIGIT(arg1[0])) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } c = (char **)xmalloc(sizeof(char *)); *x = strtoul(arg1, c, 10); if (rc > 1 || **c != '\0') longwarn(cmd, arg1, arg2, rc); free((void *)c); } void configuint(void *opt, char *cmd, char *arg1, char *arg2, int rc) { unsigned int *x = (unsigned int *)opt; char **c; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (!ISDIGIT(arg1[0])) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } c = (char **)xmalloc(sizeof(char *)); *x = (unsigned int)strtoul(arg1, c, 10); if (rc > 1 || **c != '\0') longwarn(cmd, arg1, arg2, rc); free((void *)c); } void configoffset(void *opt, char *cmd, char *arg1, char *arg2, int rc) { /* configint with extra checks */ int *x = (int *)opt; char **c; int y; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (arg1[0] == '+') { if (!ISDIGIT(arg1[1])) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } arg1++; } else if (!ISDIGIT(arg1[0]) && !(arg1[0] == '-' && ISDIGIT(arg1[1]))) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } c = (char **)xmalloc(sizeof(char *)); y = (int)strtol(arg1, c, 10); if (rc > 1 || **c != '\0') longwarn(cmd, arg1, arg2, rc); if (y > 40320 || y < -40320) warn('C', TRUE, "Ignoring offset of more than 28 days in configuration " "command\n%s %s", cmd, arg1); else { *x = y; if (*x % 30 != 0) warn('D', TRUE, "Offset not a multiple of 30 in configuration command\n%s %s", cmd, arg1); else if (*x > 1500 || *x < -1500) warn('D', TRUE, "Offset more than 25 hours in configuration command\n%s %s", cmd, arg1); } free((void *)c); } void configlowmem(void *opt, char *cmd, char *arg1, char *arg2, int rc) { choice *x = (choice *)opt; if (rc == 0 || IS_EMPTY_STRING(arg1)) { shortwarn(cmd, arg1, rc); return; } if (!(arg1[0] >= '0' && arg1[0] <= '3')) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } if (rc > 1 || arg1[1] != '\0') longwarn(cmd, arg1, arg2, rc); *x = (choice)(arg1[0] - '0'); } int aliastocount(char *s) { int n = (strchr(s, '*') != NULL); while ((s = strchr(s, '$')) != NULL) { s++; if ((*s < '1' || *s > '9') && *s != '$') return(ERR); else if (*s == '$') s++; else n = MAX(n, (*s - '0')); } return(n); } AliasTo *configaliasto(char *s, logical is_regex) { /* already checked parseable in aliastocount() */ /* Can prob be optimised somewhat, but with loss of any remaining clarity. */ AliasTo *ans, *atp; char *t, next; ans = (AliasTo *)xmalloc(sizeof(AliasTo)); atp = ans; while (TRUE) { t = strpbrk(s, "*$"); while (t != NULL && *t == '$' && *(t + 1) == '$') /* ignore "$$" */ t = strpbrk(t + 2, "*$"); if (t == NULL) t = strchr(s, '\0'); atp->string = (char *)xmalloc(t - s + 1); memcpy(atp->string, s, t - s); atp->string[t - s] = '\0'; for (s = atp->string; (s = strstr(s, "$$")) != NULL; s++) memmove(s + 1, s + 2, strlen(s + 1)); /* "$$"->"$" (reuse s) */ if (*t == '\0') atp->after = -1; else { if (*t == '*') next = '1'; else /* *t == '$' */ next = *(++t); atp->after = 2 * ((int)next - (int)(is_regex?'0':'1')); /* internal index of *'s is from 0; of regex brackets is from 1 */ } if (*t == '\0' || *(t + 1) == '\0') { atp->next = NULL; return(ans); } else { atp->next = (AliasTo *)xmalloc(sizeof(AliasTo)); TO_NEXT(atp); } s = t + 1; /* set s to rest of original string */ } } void configalias(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Alias **alias = (Alias **)opt; Alias *ap; unsigned int leftstars; int maxrightstar; char starchar; logical is_regex = FALSE; pcre *pattern = NULL; char *errstr; int erroffset; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc == 1) { if (strcaseeq(arg1, "none")) *alias = NULL; else shortwarn(cmd, arg1, rc); return; } if (rc > 2) longwarn(cmd, arg1, arg2, rc); if (headcasematch(arg1, "REGEXP:") || headcasematch(arg1, "REGEXPI:")) { if ((pattern = pcre_compile(arg1 + 7 + (arg1[6] != ':'), PCRE_DOTALL | ((arg1[6] == ':')?0:PCRE_CASELESS), (const char **)(&errstr), &erroffset, NULL)) == NULL) { badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (%s in regular expression)", errstr); return; } starchar = '('; pcre_fullinfo(pattern, NULL, PCRE_INFO_CAPTURECOUNT, (void *)&leftstars); is_regex = TRUE; } else { starchar = '*'; leftstars = chrdistn(arg1, starchar); } if (leftstars >= 2 && strchr(arg2, '*') != NULL) { badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (Can't have * on RHS with two %c's on LHS: use $1, $2 etc.)", starchar); return; } if ((maxrightstar = aliastocount(arg2)) == ERR) { badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (Can't parse $ substitutions on RHS)"); return; } if (maxrightstar > (int)leftstars) { badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (More substitutions on RHS than %c's on LHS)", starchar); return; } /* add new one to front for speed; swap round in reversealias() later */ ap = (Alias *)xmalloc(sizeof(Alias)); DEFAULTSTR(ap->from, arg1); /* save string even for regex: might l.c. */ ap->to = configaliasto(arg2, is_regex); ap->isregex = is_regex; if (is_regex) ap->pattern = pattern; ap->next = *alias; *alias = ap; } void configstrpair(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Strpair **pair = (Strpair **)opt; Strpair *ap; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc == 1) { if (strcaseeq(arg1, "none")) *pair = NULL; else shortwarn(cmd, arg1, rc); return; } if (chrn(arg1, '*') >= 2 && strchr(arg2, '*') != NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } if (rc > 2) longwarn(cmd, arg1, arg2, rc); if (*pair == NULL) { ap = (Strpair *)xmalloc(sizeof(Strpair)); *pair = ap; } else { for (ap = *pair; ap->next != NULL; TO_NEXT(ap)) ; /* find end of list */ ap->next = (Strpair *)xmalloc(sizeof(Strpair)); TO_NEXT(ap); } DEFAULTSTR(ap->name, arg1); DEFAULTSTR(ap->data, arg2); ap->next = NULL; } void configstrpairlist(void *opt, char *cmd, char *arg1, char *arg2, int rc) { char *t; if ((t = strtok(arg1, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for ( ; t != NULL; t = strtok((char *)NULL, ",")) configstrpair(opt, cmd, t, arg2, rc); return; } void configstrpair2list(void *opt, char *cmd, char *arg1, char *arg2, int rc) { /* comma-separated list in arg2 instead of arg1 */ char *t; if ((t = strtok(arg2, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for ( ; t != NULL; t = strtok((char *)NULL, ",")) configstrpair(opt, cmd, arg1, t, rc); return; } void configdomlevel(void *opt, char *cmd, char *arg1, char *arg2, int rc) { Strpair ***levels = (Strpair ***)opt; unsigned int c; c = 26 * ((int)(*arg1 - 'a')); if (*arg1 != '\0') c += (int)(*(arg1 + 1) - 'a'); if (c >= DOMLEVEL_NUMBER) /* this shouldn't happen */ c = DOMLEVEL_NUMBER - 1; configstrpair((void *)(&((*levels)[c])), cmd, arg1, arg2, rc); } void configinex(void *opt, char *cmd, char *arg1, char *arg2, int rc, logical in) { Include **include = (Include **)opt; Include *ip; char *errstr; int erroffset; char *t; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strchr(arg1, ',') != NULL) { if ((t = strtok(arg1, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for ( ; t != NULL; t = strtok((char *)NULL, ",")) configinex(opt, cmd, t, NULL, -1, in); return; } /* NB Put new include on front of list (so will test it earlier) */ ip = *include; *include = (Include *)xmalloc(sizeof(Include)); DEFAULTSTR((*include)->name, arg1); (*include)->next = ip; /* save name even for regex: might l.c. */ if (headcasematch(arg1, "REGEXP:") || headcasematch(arg1, "REGEXPI:")) { if (((*include)->pattern = pcre_compile(arg1 + 7 + (arg1[6] != ':'), PCRE_DOTALL | ((arg1[6] == ':')?0:PCRE_CASELESS), (const char **)(&errstr), &erroffset, NULL)) == NULL) { *include = ip; badwarn(cmd, FALSE, arg1, arg2, rc); warn('C', CONTINUATION, " (%s in regular expression)", errstr); return; } (*include)->type = in?(REGEX_INC):(REGEX_EXC); } else { if (strcaseeq((*include)->name, "pages")) strcpy((*include)->name, "pages"); (*include)->type = in?(NORMAL_INC):(NORMAL_EXC); } } void configinc(void *opt, char *cmd, char *arg1, char *arg2, int rc) { configinex(opt, cmd, arg1, arg2, rc, TRUE); } void configexc(void *opt, char *cmd, char *arg1, char *arg2, int rc) { configinex(opt, cmd, arg1, arg2, rc, FALSE); } /* same, omitting initial dot */ void configincd(void *opt, char *cmd, char *arg1, char *arg2, int rc) { if (arg1 != NULL && arg1[0] == '.') configinex(opt, cmd, arg1 + 1, arg2, rc, TRUE); else configinex(opt, cmd, arg1, arg2, rc, TRUE); } void configexcd(void *opt, char *cmd, char *arg1, char *arg2, int rc) { if (arg1 != NULL && arg1[0] == '.') configinex(opt, cmd, arg1 + 1, arg2, rc, FALSE); else configinex(opt, cmd, arg1, arg2, rc, FALSE); } /* same, omitting trailing slash */ void configincs(void *opt, char *cmd, char *arg1, char *arg2, int rc) { if (arg1 != NULL && !IS_EMPTY_STRING(arg1) && arg1[strlen(arg1) - 1] == '/') arg1[strlen(arg1) - 1] = '\0'; configinex(opt, cmd, arg1, arg2, rc, TRUE); } void configexcs(void *opt, char *cmd, char *arg1, char *arg2, int rc) { if (arg1 != NULL && !IS_EMPTY_STRING(arg1) && arg1[strlen(arg1) - 1] == '/') arg1[strlen(arg1) - 1] = '\0'; configinex(opt, cmd, arg1, arg2, rc, FALSE); } /* for status codes */ void configscinex(void *opt, char *cmd, char *arg1, char *arg2, int rc, logical in) { choice *code2type = (choice *)opt; unsigned int bottom, top, i; char *c, *d; logical f = FALSE; if (rc == 0) { shortwarn(cmd, arg1, rc); return; } if (rc > 1) longwarn(cmd, arg1, arg2, rc); if (strchr(arg1, ',') != NULL) { if ((c = strtok(arg1, ",")) == NULL) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } for ( ; c != NULL; c = strtok((char *)NULL, ",")) configscinex(opt, cmd, c, NULL, 1, in); return; } if (STREQ(arg1, "*")) { bottom = MIN_SC; top = SC_NUMBER - 1; } else { if (*arg1 == '-') { bottom = MIN_SC; c = arg1 + 1; if (!ISDIGIT(*c)) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } } else { bottom = (unsigned int)strtoul(arg1, &c, 10); if (*c == '-') { c++; f = TRUE; } if (bottom < MIN_SC || bottom >= SC_NUMBER || (*c != '\0' && !ISDIGIT(*c))) { badwarn(cmd, TRUE, arg1, arg2, rc); return; } } if (*c == '\0') { if (f) top = SC_NUMBER - 1; else top = bottom; } else { top = (unsigned int)strtoul(c, &d, 10); if (top < bottom || top >= SC_NUMBER || *d != '\0') { badwarn(cmd, TRUE, arg1, arg2, rc); return; } } } if (code2type[0] == UNSET) code2type[0] = in?SUCCESS:UNWANTED; /* mark first in/ex: see finalinit() */ for (i = bottom; i <= top; i++) code2type[i] = in?SUCCESS:UNWANTED; /* SUCCESS set more carefully there */ } void configscinc(void *opt, char *cmd, char *arg1, char *arg2, int rc) { configscinex(opt, cmd, arg1, arg2, rc, TRUE); } void configscexc(void *opt, char *cmd, char *arg1, char *arg2, int rc) { configscinex(opt, cmd, arg1, arg2, rc, FALSE); }