readconf.c
来自「与Casio BOSS进行串口通讯的程序」· C语言 代码 · 共 992 行 · 第 1/2 页
C
992 行
cf_err_str = "invalid rhs - no data after colon"; state = R_ERROR; break; } /* figure out if it's a MULTI_STRING or not, since we have to parse it differently if it is */ if ((configp = lookup_tag(config_tab, config_size, tag_buf)) == NULL) { if (cf_forgiving) { return (0); /* error gets caught later */ } cf_err_str = "unknown tag"; state = R_ERROR; break; } is_ms = (configp->kind == CF_MULTI_STRING); outp = full_line_buf; if (is_ms) add_ms(outp); state = R_RHS; /* else --> R_RHS */ break; case R_RHS: /* reading right-hand-side now */ if (outp - full_line_buf >= CF_MAX_LINE_LEN) { cf_err_str = "invalid rhs - line too long"; state = R_ERROR; break; } if (cf_iseol(*inp)) { /* EOL --> R_DONE */ *outp = '\0'; state = R_DONE; break; } if (*inp == '\"') { /* '"' --> R_DQUOTE */ inp++; state = R_DQUOTE; break; } if (*inp == '\\') { /* '\' --> R_BACK */ inp++; state = R_BACK; break; } if (is_ms) { /* see if we want to break here */ if (strchr(configp->delim, *inp) != NULL) { *outp++ = '\0'; inp++; state = R_RHS_MS; break; } } *outp++ = *inp++; /* else --> loop */ break; case R_RHS_MS: /* skipping over delimiter(s) */ if (strchr(configp->delim, *inp) == NULL) { /* !DELIM --> RHS */ if (add_ms(outp) < 0) { /* another one coming! */ state = R_ERROR; break; } state = R_RHS; break; } inp++; /* else --> loop */ break; case R_DQUOTE: /* inside double quotes */ if (outp - full_line_buf >= CF_MAX_LINE_LEN) { cf_err_str = "invalid rhs - line too long"; state = R_ERROR; break; } if (cf_iseol(*inp)) { /* EOL --> R_ERROR */ cf_err_str = "reached EOL inside double quotes"; state = R_ERROR; break; } if (*inp == '\"') { /* '"' --> R_RHS */ inp++; state = R_RHS; break; } if (*inp == '\\') { /* '\' --> R_DQ_BACK */ inp++; state = R_DQ_BACK; break; } *outp++ = *inp++; /* else --> loop */ break; case R_BACK: /* escape the next character */ if (outp - full_line_buf >= CF_MAX_LINE_LEN) { cf_err_str = "invalid rhs - line too long"; state = R_ERROR; break; } if (cf_iseol(*inp)) { /* EOL --> read next */ if ((val = read_line(fp))) { if (val > 0) cf_err_str = "can't escape EOF!"; state = R_ERROR; break; } inp = line_buf; state = R_RHS; break; } switch (*inp) { case 'n': *outp++ = '\n'; break; case 't': *outp++ = '\t'; break; default: *outp++ = *inp; break; } inp++; state = R_RHS; break; case R_DQ_BACK: /* escape next, inside double quotes */ if (outp - full_line_buf >= CF_MAX_LINE_LEN) { cf_err_str = "invalid rhs - line too long"; state = R_ERROR; break; } if (cf_iseol(*inp)) { /* EOL --> read next */ if ((val = read_line(fp))) { if (val > 0) cf_err_str = "can't escape EOF!"; state = R_ERROR; } inp = line_buf; state = R_DQUOTE; break; } switch (*inp) { case 'n': *outp++ = '\n'; break; case 't': *outp++ = '\t'; break; default: *outp++ = *inp; break; } inp++; state = R_DQUOTE; break; case R_DONE: /* we're all done! */ /* shouldn't actually get here, caught by while() */ break; case R_ERROR: /* error! */ if (cf_debug) printf("--- full_line_buf R_ERROR\n"); return (-1); default: cf_err_str = "damaged state in read_full_line()"; return (-1); } } /* * Now trim off trailing white space. In the case of a MULTI_STRING, * this could cause us to completely trim off the final string. This * is fine... usually. */ cp = outp-1; while (cf_isspace(*cp)) *cp-- = '\0'; if (is_ms) convert_ms(); if (cf_debug) { if (is_ms) printf("PARSED: '%s':(multi-line str)\n", tag_buf); else printf("PARSED: '%s':'%s'\n", tag_buf, full_line_buf); } return (0);}/* * Evaluate an argument of the appropriate kind, storing the value in * configp->reference or calling the function (*configp->reference)(). * * Returns 0 on a successful evaluation, -1 on error. */static inteval_boolean(const CONFIG *configp){ if (strcasecmp(full_line_buf, "true") == 0 || strcasecmp(full_line_buf, "on") == 0) { *((int *) configp->reference) = TRUE; return (0); } else if (strcasecmp(full_line_buf, "false") == 0 || strcasecmp(full_line_buf, "off") == 0) { *((int *) configp->reference) = FALSE; return (0); } else { cf_err_str = "invalid value for a boolean"; return (-1); }}static inteval_int(const CONFIG *configp){ *((int *) configp->reference) = strtol(full_line_buf, NULL, 0); return (0);}static inteval_double(const CONFIG *configp){ /* Can use atof() here. Note this will fail if strtod() not prototyped. */ *((double *) configp->reference) = (double)strtod(full_line_buf, NULL); return (0);}static inteval_string(const CONFIG *configp){ char *cp; int len; len = strlen(full_line_buf); if (!configp->size) { /* need to allocate space */ if (cf_check_alloc) { if (*((char **) configp->reference) != NULL) { cf_err_str = "tried to store dynamic string in non-NULL var"; return (-1); } } if ((cp = (char *)malloc(len+1)) == NULL) { cf_err_str = "malloc() failed"; return (-1); } if (cf_debug) printf("MALLOC 0x%.8lx\n", (long)cp); strcpy(cp, full_line_buf); *((char **) configp->reference) = cp; } else { /* reference is a fixed-size buffer */ if (configp->size < (len+1)) { cf_err_str = "string longer than allocated space"; return (-1); } strcpy((char *) configp->reference, full_line_buf); } return (0);}static inteval_multi_string(const CONFIG *configp){ int res; res = (*((CF_INTFUNCPTR) configp->reference))(ms_argc, ms_argv); free(ms_argv); /* free vector of pointers into full_line_buf */ ms_argc = 0; if (res < 0) cf_err_str = "error parsing string data"; return (res);}static inteval_multi_line(const CONFIG *configp, FILE *fp){ int res, len; len = strlen(configp->delim); while (1) { res = read_line(fp); if (res < 0) return (-1); /*if (res > 0) break;*/ /* EOF reached; allow it */ if (res > 0) return (-1); /* EOF reached; error */ /* match as a prefix; don't require a '\n' after it in line_buf */ if (strncasecmp(configp->delim, line_buf, len) == 0) break; res = (*((CF_INTFUNCPTR) configp->reference))(line_buf); if (res < 0) { cf_err_str = "error parsing multi-line data"; return (-1); } } return (0);}/* * Report a problem to the user. * * This exists because of a specific application in something I was working * on (multiple independently updated programs sharing a config file, some * of which didn't have a stdout/stderr), so it's not used consistently. */static voidreport_problem(char *whine, int cline){ /*syslog(LOG_ALERT|LOG_USER, "WARNING: config line %d: %s", cline, whine);*/ fprintf(stderr, "WARNING: config line %d: %s\n", cline, whine);}/* * =========================================================================== * Public routines. * =========================================================================== *//* * Main entry point. * * Returns 0 on success, -1 on failure. Appropriate diagnostic messages * will be sent to stderr on failure. * * (Takes argv0 as an argument to generate nice error messages.) */intread_config(const char *argv0, const CONFIG *config_tab, int config_size, FILE *fp){ const CONFIG *configp; int err, res; /* sanity check on config table */ if (config_tab[0].kind > CF_MULTI_LINE || config_size < 0 || config_size > 1024) { cf_err_str = "config table corrupt"; goto error; } if (argv0 == NULL) argv0 = default_argv0; line = 0; while (1) { /* read a full config line into full_line_buf, tag in tag_buf */ res = get_full_line(config_tab, config_size, fp); if (res > 0) break; /* EOF reached */ if (res < 0) goto error; /* error */ /* find the matching entry in config[] */ if ((configp = lookup_tag(config_tab, config_size, tag_buf)) == NULL) { cf_err_str = "unknown tag"; if (cf_forgiving) { report_problem(cf_err_str, line); continue; } else { goto error; } } /* empty right-hand-side only allowed on MULTI_LINE tag */ if (configp->kind != CF_MULTI_LINE && full_line_buf[0] == '\0') { /* (...but full_line_buf is irrelevant for MULTI_STRING) */ if (!(configp->kind == CF_MULTI_STRING && ms_argc)) { cf_err_str = "missing rhs"; goto error; } } /* do something appropriate with the tag we got */ switch (configp->kind) { case CF_BOOLEAN: res = eval_boolean(configp); break; case CF_INT: res = eval_int(configp); break; case CF_DOUBLE: res = eval_double(configp); break; case CF_STRING: res = eval_string(configp); break; case CF_MULTI_STRING: res = eval_multi_string(configp); break; case CF_MULTI_LINE: res = eval_multi_line(configp, fp); break; default: cf_err_str = "bogus config kind?"; res = -1; } if (res < 0) goto error; } if (cf_verbose) printf("--- configuration successfully read\n"); return (0);error: err = errno; fflush(stdout); errno = err; if (cf_err_str != NULL) { fprintf(stderr, "%s: ", argv0); if (line) fprintf(stderr, "line %d: ", line); fprintf(stderr, "%s\n", cf_err_str); } else { perror(argv0); } cf_err_str = NULL; if (cf_verbose) printf("--- aborting config file read\n"); return (-1);}/* * Alternate entry point; takes a filename as an argument instead of a * FILE*. File will be opened before calling read_config(), and closed * before returning. */intread_config_file(const char *argv0, const CONFIG *config_tab, int config_count, const char *filename){ FILE *fp; int err, res; if (argv0 == NULL) argv0 = default_argv0; if ((fp = fopen(filename, "r")) == NULL) { err = errno; fprintf(stderr, "%s: unable to read %s: ", argv0, filename); errno = err; /* fprintf() could change errno */ perror(NULL); return (-1); } if (cf_verbose) printf("--- reading configuration from '%s'\n", filename); res = read_config(argv0, config_tab, config_count, fp); fclose(fp); return (res);}/* * Run down the config_tab, calling any dispose routines found. * * Entries with type=CF_STRING and size!=0 that are non-NULL and don't * have a dispose routine will be free()d. If cf_check_alloc is false * this could end up calling free() on static storage, but that isn't fatal. * * To reload the config file, you should call this routine and then * call read_config() or read_config_file(). */intdispose_config(const char *argv0, const CONFIG *config_tab, int config_count){ const CONFIG *configp; if (argv0 == NULL) argv0 = default_argv0; for (configp = config_tab; config_count--; configp++) { if (configp->dispose != NULL) { if (cf_debug) printf("DISPOSE 0x%.8lx\n", (long)configp->dispose); (*configp->dispose)(); } else { /* no dispose routine; see if we want to call free() on the "reference" field */ if (configp->kind == CF_STRING && !configp->size && *((char **)configp->reference) != NULL) { char *cp = *((char **) configp->reference); if (cf_debug) printf("FREE 0x%.8lx\n", (long)cp); free(cp); *((char **)configp->reference) = NULL; } } } return (0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?