⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libconf.c

📁 this ebook is for GSM if any one has interest in it you can take it
💻 C
字号:
/* * TODO: * 	- token has childs although validate entrys say no childs * 	  -> need to error * */#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <sys/types.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include "libconf.h"enum {	TOKEN_STRING,	TOKEN_QSTRING,	TOKEN_COLON,	TOKEN_OBRACKET,	TOKEN_CBRACKET,	TOKEN_NEWLINE,	TOKEN_EOF,	TOKEN_QSTRING_EOL,	TOKEN_QSTRING_EOF,	TOKEN_QSTRING_BROKEN};static void dumpconfig(struct lc_centry *c) {	printf("token %p\n", c);	printf("\tprev %p next %p\n", c->prev, c->next);	printf("\tchild %p parent %p\n", c->child, c->parent);	printf("\ttoken %s value %s\n", c->token, c->value);	if(c->child)		dumpconfig(c->child);	if(c->next)		dumpconfig(c->next);}static int gettoken(char *c, off_t len, char *tb, off_t *off) {	off_t	o=*off,		ts;	char	*tbp=NULL;	while(o<len) {		switch(c[o]) {			/* Spaces */			case(' '):			case('\t'):				o++;				break;			/* Comment - Skip until end of line */			case('#'):				while(o<len && c[o] != '\n')					o++;				if (o>=len)	/* EOF ? */					return TOKEN_EOF;				break;			/* Quoted string */			case('"'):				o++;				ts=o;				if (tbp)					return TOKEN_QSTRING_BROKEN;				tbp=tb;				/* Seek closing quote				 * FIXME What about quoted chars ?				 */				while(o<len) {					switch(c[o]) {						case('\n'):							return TOKEN_QSTRING_EOL;						case('"'):							*off=++o;							*tbp++=0x0;							return TOKEN_QSTRING;						default:							*tbp++=c[o++];							break;					}				}				return TOKEN_QSTRING_EOF;			/* Newline */			case('\n'):				*off=++o;				return TOKEN_NEWLINE;			case(';'):				*off=++o;				return TOKEN_COLON;			case('}'):				*off=++o;				return TOKEN_CBRACKET;			case('{'):				*off=++o;				return TOKEN_OBRACKET;			/* non Quoted Token */			default:				tbp=tb;				while(o<len) {					switch(c[o]) {						/* Single char tokens */						case(';'):						case('}'):						case('{'):						case('\n'):						case(' '):						case('\t'):						case('#'):							*off=o;							*tbp++=0x0;							return TOKEN_STRING;						default:							*tbp++=c[o++];							break;					}				}						}	}	return TOKEN_EOF;}struct lc_centry *libconf_parse(char *c, off_t len) {	off_t			off=0;	char			tb[256];	int			te, line=1;	struct lc_centry	*config=NULL,				*cce=NULL,				*lce=NULL;	cce=calloc(1, sizeof(struct lc_centry));	config=cce;	while(1) {		te=gettoken(c, len, tb, &off);		switch(te) {			case(TOKEN_NEWLINE):				line++;				break;			case(TOKEN_OBRACKET):				lce=cce;				cce=calloc(1, sizeof(struct lc_centry));				cce->parent=lce;				lce->child=cce;				break;			case(TOKEN_CBRACKET):				if (!cce->parent) {					fprintf(stderr, "To many closing brackets in line %d\n", line);					return NULL;				}				/* Empty {} ? */				if (!cce->token && !cce->value && cce->parent) {					/* Remove empty child ce */					cce=cce->parent;					free(cce->child);					cce->child=NULL;					/* Get next token - hopefully ; */					break;				}				/* Did we close last token/value pair ? */				if (!cce->closed) {					fprintf(stderr, "Token not finished e.g. missing ; in line %d\n", line);					return NULL;				}				cce=cce->parent;				break;			case(TOKEN_COLON):				/* Close token */				cce->closed=1;				break;			case(TOKEN_STRING):				/* Last token was closed - we need a new one */				if (cce->closed) {					lce=cce;					cce=calloc(1, sizeof(struct lc_centry));					cce->prev=lce;					lce->next=cce;					cce->parent=lce->parent;				}				if (!cce->token) {					cce->token=strdup(tb);					cce->tline=line;				} else if (!cce->value) {					cce->value=strdup(tb);					cce->vline=line;				} else {					fprintf(stderr, "Double value for token in line %d\n", line);					return NULL;				}				break;			case(TOKEN_QSTRING):				if (!cce || !cce->token) {					fprintf(stderr, "Quoted token in line %d\n", line);					return NULL;				} else if (!cce->value) {					cce->value=strdup(tb);					cce->vline=line;				} else {					fprintf(stderr, "Double value for token in line %d\n", line);					return NULL;				} 				break;			case(TOKEN_EOF):				return config;			default:				fprintf(stderr, "failed reading config %d\n", te);				return NULL;		}	}	/* Unreachable */	return NULL;}static int libconf_validate_value(struct lc_centry *ce, 		struct lc_ventry *ve) {	if (!ve->name) {		fprintf(stderr, "Unknown config option %s in line %d\n", ce->token, ce->tline);		return 0;	}	/* We dont have a value but we would need one */	if (ve->type != LCV_NONE && (!ce->value && !(ve->opt & LCO_OPTIONAL))) {		fprintf(stderr, "Config value for option %s in line %d is missing\n", ve->name, ce->tline);		return 0;	}	if (ce->value) {		switch(ve->type) {			case(LCV_NONE):				fprintf(stderr, "Config option %s does not allow value in line %d\n",						ve->name, ce->vline);				return 0;			case(LCV_STRING):				ce->cbvalue.string=ce->value;				break;			case(LCV_BOOL): {				if ((strcasecmp("true", ce->value) == 0) ||					(strcasecmp("yes", ce->value) == 0) ||					(strcasecmp("on", ce->value) == 0) ||					(strcasecmp("1", ce->value) == 0)) {					ce->cbvalue.num=1;				} else if((strcasecmp("false", ce->value) == 0) ||					(strcasecmp("no", ce->value) == 0 ) ||					(strcasecmp("off", ce->value) == 0 ) ||					(strcasecmp("0", ce->value) == 0)) {					ce->cbvalue.num=0;				} else {					fprintf(stderr, "Value %s for boolean option %s is invalid in line %d\n",							ce->value, ve->name, ce->vline);					return 0;				}				break;			}			case(LCV_NUM): {				char 		*endptr;				unsigned long	num;				num=strtol(ce->value, &endptr, 0);				if (*endptr != 0x0) {					fprintf(stderr, "Value %s for option %s is not a number in line %d\n", 							ce->value, ve->name, ce->vline);					return 0;				}				ce->cbvalue.num=num;				break;			}			case(LCV_HEX): {				char 		*endptr;				unsigned long	num;				num=strtol(ce->value, &endptr, 16);				if (*endptr != 0x0) {					fprintf(stderr, "Value %s for option %s is not a hex number in line %d\n", 							ce->value, ve->name, ce->vline);					return 0;				}				ce->cbvalue.num=num;				break;			}			case(LCV_IPADDR):			case(LCV_IPV6ADDR):			case(LCV_IPV4ADDR): {				struct addrinfo *ai;				int		rc;				rc=getaddrinfo(ce->value, NULL, NULL, &ai);				if (rc) {					fprintf(stderr, "Value %s for option %s is not an ip address in line %d\n", 							ce->value, ve->name, ce->vline);					return 0;				}				if (ve->type == LCV_IPV6ADDR &&					ai->ai_family != PF_INET6) {					fprintf(stderr, "Value %s for option %s is not an ip version 6 address in line %d\n", 							ce->value, ve->name, ce->vline);					freeaddrinfo(ai);					return 0;				}				if (ve->type == LCV_IPV4ADDR &&					ai->ai_family != PF_INET) {					fprintf(stderr, "Value %s for option %s is not an ip version 4 address in line %d\n", 							ce->value, ve->name, ce->vline);					freeaddrinfo(ai);					return 0;				}				ce->cbvalue.string=ce->value;				freeaddrinfo(ai);				break;			}		}	}	return 1;}static struct lc_ventry *libconf_find_token(struct lc_centry *ce, 		struct lc_ventry *ventry) {	struct	lc_ventry	*ve;	for(ve=ventry;ve->name;ve++) {		/* Do we know this config entry ? */		if (strcasecmp(ce->token, ve->name) == 0)			break;	}	return (ve->name) ? ve : NULL;}/* * Recurse through parsed config entrys and check tokens  * Fill in ventry pointer into centrys * */static int libconf_validate_token(struct lc_centry *centry, 		struct lc_ventry *ventry) {	struct lc_ventry 	*ve;	struct lc_centry 	*ce;	/* Loop on config option entrys */	for(ce=centry;ce;ce=ce->next) {		/* Find token */		ve=libconf_find_token(ce, ventry);		if (!ve) {			fprintf(stderr, "Unknown config option %s in line %d\n",					ce->token, ce->tline);			return 0;		}		/* Fill ventry in centry */		ce->ventry=ve;		/* Recurse into children */		if (ce->child) {			if(!ve->child) {				fprintf(stderr, "Config option %s does not allow suboptions in line %d\n", ve->name, ce->tline);				return 0;			}			/* Recurse into childs */			if (!libconf_validate_token(ce->child, ve->child))				return 0;		}		centry->noce++;	}	return 1;}/* Recurse through centrys and validate values */static int libconf_validate_values(struct lc_centry *centry) {	struct lc_centry	*ce;	for(ce=centry;ce;ce=ce->next) {		if (!libconf_validate_value(ce, ce->ventry))			return 0;		if (ce->child)			if (!libconf_validate_values(ce->child))				return 0;	}	return 1;}static int libconf_validate_valueopt(struct lc_centry *centry, 		struct lc_ventry *ventry) {	struct lc_centry	*ce;	struct lc_ventry	*ve;	char			**tuval;	/* First confentry the *child points to has a noce field */	tuval=calloc(centry->noce+1, sizeof(char *));	for(ve=ventry;ve->name;ve++) {		int	optcount=0, 			optline=0, 			valcount=0,			i;		for(ce=centry;ce;ce=ce->next) {			/* Check prefilled ventry ptr */			if (ce->ventry != ve)				continue;			optcount++;			optline=ce->tline;			/* Check values */			if ((ve->opt & LCO_UNIQ) && (ce->value)) {				/* Check stored value pointers for uniqueness */				for(i=0;i<valcount;i++) {					if (strcasecmp(ce->value, tuval[i]) == 0) {						fprintf(stderr, "Value %s for option %s in line %d is not unique\n",								ce->value, ve->name, ce->vline);						return 0;					}				}				/* Store pointer for later uniqueness check */				tuval[valcount++]=ce->value;			}		}		if (ve->max && optcount > ve->max) {			fprintf(stderr, "Option %s is only allowed %d times in line %d\n",					ve->name, ve->max, optline);			return 0;		}		if (ve->min && optcount < ve->min) {			/* FIXME - line is not really nice */			fprintf(stderr, "Option %s is needed %d times\n",					ve->name, ve->min);			return 0;		}	}	free(tuval);	for(ce=centry;ce;ce=ce->next) {		if (ce->child)			if (!libconf_validate_valueopt(ce->child, 						ce->ventry->child))				return 0;	}	return 1;}/* * Run through the parsed and validated tree and  * call applications callback functions * */static int libconf_validate_callback(struct lc_centry *centry) {	struct lc_centry *ce;	for(ce=centry;ce;ce=ce->next) {		if (ce->ventry->cback)			if (!ce->ventry->cback(ce, &ce->cbvalue)) 				return 0;		if (ce->child)			if (!libconf_validate_callback(ce->child))				return 0;		/* Does application want a late callback ? */			if (ce->ventry->opt & LCO_LATECB)			if (!ce->ventry->cback(ce, NULL)) 				return 0;	}	return 1;}int libconf_validate(struct lc_centry *ce, struct lc_ventry *ve) {	/* Recurse through config entrys - check tokens	 * and fill ventry pointer */	if (!libconf_validate_token(ce, ve))		return 0;	/* Recurse through config entrys - check values for syntax */	if (!libconf_validate_values(ce))		return 0;	/* Recurse through config and ventry and check for value options 	 * e.g. uniqueness, min and max count	 */	if (!libconf_validate_valueopt(ce, ve))		return 0;	/* Recurse through config and call user callbacks */	if (!libconf_validate_callback(ce))		return 0;	return 1;}/* Free all libconf related structures */void libconf_free(struct lc_centry *ce) {	struct lc_centry *cce=ce, *next;	while(cce) {		/* Recurse into children */		if (cce->child)			libconf_free(cce->child);		/* Save next pointer */		next=cce->next;		/* Free current centry */		if (cce->token)			free(cce->token);		if (cce->value)			free(cce->value);		free(cce);		cce=next;	}	return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -