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 + -
显示快捷键?