diff options
| author | katherine <ageha@airen-no-jikken.icu> | 2019-07-10 20:24:08 -0700 | 
|---|---|---|
| committer | katherine <ageha@airen-no-jikken.icu> | 2019-07-10 20:24:08 -0700 | 
| commit | 06cb82a8ccc3587dff728321dff5416b18090483 (patch) | |
| tree | 95dc02df244856b5ede95a3a1a44ea756e850203 | |
| parent | 34271c906a2de43a68d2fa764d31e6f5b2c3299f (diff) | |
| download | confconf-06cb82a8ccc3587dff728321dff5416b18090483.tar.gz | |
implement deftype get
| -rw-r--r-- | src/analyse.c | 273 | ||||
| -rw-r--r-- | src/analyse.h | 22 | ||||
| -rw-r--r-- | src/gen-consts.h | 691 | ||||
| -rw-r--r-- | src/gen.c | 788 | ||||
| -rw-r--r-- | src/gen.h | 2 | ||||
| -rw-r--r-- | src/main.c | 33 | ||||
| -rw-r--r-- | src/opt.c | 42 | ||||
| -rw-r--r-- | src/parse.c | 395 | ||||
| -rw-r--r-- | src/parse.h | 11 | ||||
| -rw-r--r-- | src/tok.c | 4 | 
10 files changed, 1428 insertions, 833 deletions
| diff --git a/src/analyse.c b/src/analyse.c index 416b10a..e5d1cb9 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -1,149 +1,244 @@ -#include "err.h"  #include "analyse.h" +#include "err.h" +  #include <assert.h>  #include <string.h> -struct analyse_result_s analyse(struct parse_result_s pr) +static void sub_trie_insert(struct analyse_trie_s *t, +	const char *s, char *sv) +{ +	const char *si = s; +	struct analyse_trie_s *parent = NULL; +	unsigned i; + +	/* walk down the trie, creating nodes when necessary */ +	for (; *si != '\0'; si++) { +		for (i = 0; i < t->branch_count && *si != t->branch_chars[i]; i++); +		if (t->branch_count == 0 +			|| i == t->branch_count +		) { +			t->branch_count++; +			t->branch_chars[t->branch_count - 1] = *si; +			TRYALLOC(t->branches[t->branch_count - 1], 1); +			parent = t; +			t = t->branches[t->branch_count - 1]; +			t->parent = parent; +			t->branch_count = 0; +			t->sval = NULL; +		} else { +			t = t->branches[i]; +		} +	} + +	TRYALLOC(t->sval, strlen(sv) + 1); +	strcpy(t->sval, sv); +} + +/* tries used to generate static jump-based token matching */ +static inline void sub_build_tries(struct parse_result_s *pr, +	struct analyse_result_s *ar)  { -	struct analyse_result_s ar = { -		.uses_hash = false, -		.uses_array = false, -	};  	struct parse_deftype_s *dcur, *dtmp;  	struct parse_var_s *vcur, *vtmp; -	struct analyse_tree_s *cur; -	unsigned i; +	unsigned i, j; +	/* dtype sval == TOK_MAX_LEN +	 * dtype member == TOK_MAX_LEN +	 * suffix == TOK_MAX_LEN +	 * 32 == padding for "CONFCONF_TYPE_" + "_" + "_" + "\0" */ +	char sbuf[TOK_MAX_LEN * 3 + 32]; + +	/* variable trie */ +	ar->var_trie.branch_count = 0; +	ar->var_trie.sval = NULL; +	ar->var_trie.parent = NULL; + +	if (pr->vars != NULL) { +		HASH_ITER(hh, pr->vars, vcur, vtmp) { +			sprintf(sbuf, "%s", vcur->name); +			sub_trie_insert(&(ar->var_trie), vcur->name, sbuf); +		} +	} + +	ar->deftype_mem_tries = NULL; +	if (pr->deftypes != NULL) { +		TRYALLOC( +			ar->deftype_mem_tries, +			HASH_COUNT(pr->deftypes) +		); -	/*************** -	 * BUILD TREES * -	 ***************/ +		ar->deftype_mem_trie_count = HASH_COUNT(pr->deftypes); -	ar.deftype_tree.branch_count = 0; -	ar.deftype_tree.is_terminal = false; +		i = 0; +		HASH_ITER(hh, pr->deftypes, dcur, dtmp) { +			ar->deftype_mem_tries[i].branch_count = 0; +			ar->deftype_mem_tries[i].sval = NULL; +			ar->deftype_mem_tries[i].parent = NULL; -	if (pr.deftypes != NULL) { -		HASH_ITER(hh, pr.deftypes, dcur, dtmp) { -			if (!dcur->is_used) +			if (!dcur->is_used) { +				i++;  				continue; +			} + +			/* union types */ +			if (dcur->type == PARSE_DEFTYPE_UNION) { +				for (j = 0; j < dcur->member_list_len; j++) { +					sprintf(sbuf, "%u", j); -			cur = &(ar.deftype_tree); - -			/* walk down the tree, creating nodes when necessary */ -			for (i = 0; dcur->name[i] != '\0'; i++) { -				if (cur->branch_count == 0 -						|| cur->branch_chars[cur->branch_count - 1] -						!= dcur->name[i] -				) { -					cur->branch_count++; -					cur->branch_chars[cur->branch_count - 1] = dcur->name[i]; -					TRYALLOC(cur->branches[cur->branch_count - 1], 1); -					cur = cur->branches[cur->branch_count - 1]; -					cur->branch_count = 0; -					cur->is_terminal = false; -				} else { -					cur = cur->branches[cur->branch_count - 1]; +					sub_trie_insert( +						&(ar->deftype_mem_tries[i]), +						dcur->member_name_list[j], +						sbuf +					);  				}  			} -			cur->is_terminal = true; -			strcpy(cur->name, dcur->name); -		} -	} - -	ar.var_tree.branch_count = 0; -	ar.var_tree.is_terminal = false; - -	if (pr.vars != NULL) { -		HASH_ITER(hh, pr.vars, vcur, vtmp) { -			cur = &(ar.var_tree); - -			/* walk down the tree, creating nodes when necessary */ -			for (i = 0; vcur->name[i] != '\0'; i++) { -				if (cur->branch_count == 0 -						|| cur->branch_chars[cur->branch_count - 1] -						!= vcur->name[i] -				) { -					cur->branch_count++; -					cur->branch_chars[cur->branch_count - 1] = vcur->name[i]; -					TRYALLOC(cur->branches[cur->branch_count - 1], 1); -					cur = cur->branches[cur->branch_count - 1]; -					cur->branch_count = 0; -					cur->is_terminal = false; -				} else { -					cur = cur->branches[cur->branch_count - 1]; +			/* enum mems */ +			if (dcur->type == PARSE_DEFTYPE_ENUM) { +				for (j = 0; j < dcur->member_list_len; j++) { +					sprintf(sbuf, +						"CONFCONF_TYPE_%s_%s_%s", +						dcur->name, +						dcur->member_name_list[j], +						pr->suffix +					); +					sub_trie_insert( +						&(ar->deftype_mem_tries[i]), +						dcur->member_name_list[j], +						sbuf +					);  				}  			} -			cur->is_terminal = true; -			strcpy(cur->name, vcur->name); +			i++;  		}  	} +} - -	/************************ -	 * CALCULATE USED TYPES * -	 ************************/ +static inline void sub_calculate_used_types(struct parse_result_s *pr, +	struct analyse_result_s *ar) +{ +	struct parse_deftype_s *dcur, *dtmp; +	struct parse_var_s *vcur, *vtmp; +	unsigned i;  	for (i = PARSE_TYPE_BOOL; i < PARSE_TYPE_HASH_DEFTYPE; i++) -		ar.uses_type[i] = false; +		ar->uses_type[i] = false; -	HASH_ITER(hh, pr.deftypes, dcur, dtmp) { +	HASH_ITER(hh, pr->deftypes, dcur, dtmp) {  		if (!dcur->is_used)  			continue; +		if (dcur->type == PARSE_DEFTYPE_ENUM) +			continue; +  		for (i = 0; i < dcur->member_list_len; i++) {  			if (dcur->member_type_list[i] >= PARSE_TYPE_HASH_BOOL) { -				ar.uses_hash = true; -				ar.uses_type[dcur->member_type_list[i] +				ar->uses_hash = true; +				ar->uses_type[dcur->member_type_list[i]  					- PARSE_TYPE_HASH_BOOL] = true;  			} else if (dcur->member_type_list[i] >= PARSE_TYPE_ARRAY_BOOL) { -				ar.uses_array = true; -				ar.uses_type[dcur->member_type_list[i] +				ar->uses_array = true; +				ar->uses_type[dcur->member_type_list[i]  					- PARSE_TYPE_ARRAY_BOOL] = true;  			} -			ar.uses_type[dcur->member_type_list[i]] = true; +			ar->uses_type[dcur->member_type_list[i]] = true;  		}  	} -	HASH_ITER(hh, pr.vars, vcur, vtmp) { +	HASH_ITER(hh, pr->vars, vcur, vtmp) {  		if (vcur->type >= PARSE_TYPE_HASH_BOOL) { -			ar.uses_hash = true; -			ar.uses_type[vcur->type - PARSE_TYPE_HASH_BOOL] = true; +			ar->uses_hash = true; +			ar->uses_type[vcur->type - PARSE_TYPE_HASH_BOOL] = true;  		} else if (vcur->type >= PARSE_TYPE_ARRAY_BOOL) { -			ar.uses_array = true; -			ar.uses_type[vcur->type - PARSE_TYPE_ARRAY_BOOL] = true; +			ar->uses_array = true; +			ar->uses_type[vcur->type - PARSE_TYPE_ARRAY_BOOL] = true;  		}  		if (vcur->type == PARSE_TYPE_DEFTYPE -				|| vcur->type == PARSE_TYPE_ARRAY_DEFTYPE  -				|| vcur->type == PARSE_TYPE_HASH_DEFTYPE +			|| vcur->type == PARSE_TYPE_ARRAY_DEFTYPE +			|| vcur->type == PARSE_TYPE_HASH_DEFTYPE  		) {  			continue;  		} -		ar.uses_type[vcur->type] = true; +		ar->uses_type[vcur->type] = true;  	} +} + +struct analyse_result_s* analyse(struct parse_result_s *pr) +{ +	struct analyse_result_s *ar; + +	assert(pr != NULL); + +	TRYALLOC(ar, 1); +	ar->uses_hash = false; +	ar->uses_array = false; + +	sub_build_tries(pr, ar); + +	sub_calculate_used_types(pr, ar);  	return ar;  } -static void sub_recurse_free(struct analyse_tree_s *t) +static void sub_wipe_trie(struct analyse_trie_s *t)  { -	unsigned i; +	struct analyse_trie_s *cur = t, *prev = NULL; -	for (i = 0; i < t->branch_count; i++) { -		sub_recurse_free(t->branches[i]); -		free(t->branches[i]); -	} +	assert(t != NULL); + +	t->parent = NULL; +	t->idx = 0; + +	/* do nothing for an empty trie */ +	if (t->branch_count == 0) +		return; + +	do { +		/* drop into a branch to its tail */ +		if (cur->idx != cur->branch_count) { +			prev = cur; +			cur = cur->branches[cur->idx]; +			cur->idx = 0; +			prev->idx++; +			continue; +		} + +		/* break at the head node */ +		if (cur->parent == NULL) +			break; + +		/* at a tail. jump up to its parent */ +		prev = cur; +		cur = cur->parent; + +		/* prev guaranteed to have no more children here */ +		if (prev->sval != NULL) +			free(prev->sval); + +		free(prev); +	} while (true);  } -void analyse_result_wipe(struct analyse_result_s *r) +void analyse_result_free(struct analyse_result_s *ar)  { -	assert(r != NULL); +	unsigned i; + +	assert(ar != NULL); + +	sub_wipe_trie(&(ar->var_trie)); + +	if (ar->deftype_mem_tries != NULL) { +		for (i = 0; i < ar->deftype_mem_trie_count; i++) { +			sub_wipe_trie(&(ar->deftype_mem_tries[i])); +		} + +		free(ar->deftype_mem_tries); +	} -	sub_recurse_free(&(r->deftype_tree)); -	sub_recurse_free(&(r->var_tree)); +	free(ar);  } diff --git a/src/analyse.h b/src/analyse.h index 539e003..2e1556e 100644 --- a/src/analyse.h +++ b/src/analyse.h @@ -4,29 +4,35 @@  #include "tok.h"  #include "parse.h" +#include "../reqs/uthash/include/uthash.h" +  #include <stdbool.h>  /* 26 letters * 2 for case + 1 for '_' */  #define ANALYSE_MAX_BRANCH (26 * 2 + 1) -struct analyse_tree_s { -	bool is_terminal; -	char name[TOK_MAX_LEN]; +struct analyse_trie_s { +	/* NULL for non-terminals */ +	char *sval;  	unsigned branch_count;  	char branch_chars[ANALYSE_MAX_BRANCH]; -	struct analyse_tree_s *branches[ANALYSE_MAX_BRANCH]; +	struct analyse_trie_s *branches[ANALYSE_MAX_BRANCH]; +	/* these two used for traversal */ +	struct analyse_trie_s *parent; +	unsigned idx;  };  struct analyse_result_s {  	bool uses_type[PARSE_TYPE_HASH_DEFTYPE];  	bool uses_array;  	bool uses_hash; -	struct analyse_tree_s deftype_tree; -	struct analyse_tree_s var_tree; +	struct analyse_trie_s var_trie; +	unsigned deftype_mem_trie_count; +	struct analyse_trie_s *deftype_mem_tries;  }; -struct analyse_result_s analyse(struct parse_result_s pr); +struct analyse_result_s* analyse(struct parse_result_s *pr); -void analyse_result_wipe(struct analyse_result_s *r); +void analyse_result_free(struct analyse_result_s *ar);  #endif diff --git a/src/gen-consts.h b/src/gen-consts.h index 72c1a46..90c2d9c 100644 --- a/src/gen-consts.h +++ b/src/gen-consts.h @@ -28,39 +28,32 @@ static const char sheadp1[] =  "	size_t line;\n"  "	size_t col;\n"  "	size_t byte;\n" -"	union {\n" -"		bool b;\n" -"		char *s;\n" -"		int i;\n" -"		long int il;\n" -"		long long int ill;\n" -"		unsigned u;\n" -"		long unsigned ul;\n" -"		long long unsigned ull;\n" -"		float f;\n" -"		double d;\n" -"		long double dl;\n" -"	} val;\n" +"	size_t sbuf_len;\n" +"	size_t sbuf_mlen;\n" +"	char *sbuf;\n" +"	void *vp;\n"  "};\n"  "\n" -"static int confconf_priv_gcp_file(void *fp)\n" +"static int\n" +"confconf_priv_gcp_file(void *fp)\n"  "{\n"  "	return getc((FILE *)fp);\n"  "}\n"  "\n" -"static int confconf_priv_ugcp_file(int c, void *fp)\n" +"static int\n" +"confconf_priv_ugcp_file(int c, void *fp)\n"  "{\n"  "	return ungetc(c, (FILE *)fp);\n"  "}\n"  "\n" -"static void confconf_priv_eat_space(struct confconf_priv_state *st)\n" +"static void\n" +"confconf_priv_eat_space(struct confconf_priv_state *st)\n"  "{\n"  "	int c;\n"  "\n"  "	while (true) {\n"  "		c = (*(st->gcp))(st->fp);\n"  "\n" -"		/* comment */\n"  "		if (c == '#') {\n"  "			st->col++;\n"  "			st->byte++;\n" @@ -82,11 +75,12 @@ static const char sheadp1[] =  "			}\n"  "		}\n"  "\n" -"		/* space */\n"  "		if (c == ' ' || c == '\\f' || c == '\\n'\n" -"				|| c == '\\r' || c == '\\t' || c == '\\v') {\n" +"			|| c == '\\r' || c == '\\t' || c == '\\v'\n" +"		) {\n"  "			while (c == ' ' || c == '\\f' || c == '\\n'\n" -"					|| c == '\\r' || c == '\\t' || c == '\\v') {\n" +"				|| c == '\\r' || c == '\\t' || c == '\\v'\n" +"			) {\n"  "				if (c == '\\n') {\n"  "					st->col = 1;\n"  "					st->line++;\n" @@ -111,153 +105,153 @@ static const char sheadp1[] =  "	}\n"  "}\n"  "\n" +"static bool\n" +"confconf_priv_push_char(struct confconf_priv_state *st, char c)\n" +"{\n" +"	char *stmp;\n" +"\n" +"	if (st->sbuf_len == st->sbuf_mlen\n" +"		|| st->sbuf_len + 1 == st->sbuf_mlen\n" +"	) {\n" +"		st->sbuf_mlen += CONFCONF_ALLOCWIDTH;\n" +"		stmp = realloc(st->sbuf, st->sbuf_mlen * sizeof(char));\n" +"		\n" +"		if (stmp == NULL) {\n" +"			if (st->sbuf != NULL)\n" +"				free(st->sbuf);\n" +"			st->sbuf = NULL;\n" +"			return false;\n" +"		}\n" +"\n" +"		st->sbuf = stmp;\n" +"	}\n" +"\n" +"	st->sbuf[st->sbuf_len] = c;\n" +"	st->sbuf_len++;\n" +"	st->sbuf[st->sbuf_len] = '\\0';\n" +"\n" +"	return true;\n" +"}\n" +"\n"  ;  static const char sheadp2[] = -"static enum confconf_result_type confconf_priv_get_tok(\n" -"		struct confconf_priv_state *st)\n" +"struct confconf_priv_pos {\n" +"	size_t line;\n" +"	size_t col;\n" +"	size_t byte;\n" +"};\n" +"\n" +"static struct confconf_priv_pos\n" +"confconf_priv_pos_get(struct confconf_priv_state *st)\n" +"{\n" +"	struct confconf_priv_pos pos = {\n" +"		.line = st->line,\n" +"		.col = st->col,\n" +"		.byte = st->byte,\n" +"	};\n" +"\n" +"	return pos;\n" +"}\n" +"static void\n" +"confconf_priv_pos_set(struct confconf_priv_state *st,\n" +"	struct confconf_priv_pos pos)\n" +"{\n" +"	st->line = pos.line;\n" +"	st->col = pos.col;\n" +"	st->byte = pos.byte;\n" +"}\n" +"\n" +"static enum confconf_result_type\n" +"confconf_priv_get_tok(struct confconf_priv_state *st)\n"  "{\n" -"	size_t len = 0, mlen = CONFCONF_ALLOCWIDTH;\n" -"	char *stmp;\n"  "	int c;\n"  "\n" -"	st->val.s = NULL;\n" +"	st->sbuf_len = 0;\n"  "\n"  "	c = (*(st->gcp))(st->fp);\n"  "\n"  "	if (c == EOF)\n"  "		return CONFCONF_ERR_UNEXPECTED_EOF;\n"  "\n" -"	st->val.s = realloc(st->val.s, mlen);\n" -"	if (st->val.s == NULL)\n" -"		return CONFCONF_ERR_MEMORY;\n" -"	st->val.s[0] = '\\0';\n" -"\n"  "	while (c != ' ' && c != '\\f' && c != '\\n'\n" -"			&& c != '\\r' && c != '\\t' && c != '\\v'\n" -"			&& c != ']' && c != '}'\n" -"			&& c != '[' && c != '{'\n" -"			&& c != ',' && c != ':'\n" -"			&& c != EOF) {\n" -"		if (len == mlen) {\n" -"			mlen += CONFCONF_ALLOCWIDTH;\n" -"\n" -"			if (mlen < len) {\n" -"				if (st->val.s != NULL) {\n" -"					free(st->val.s);\n" -"					st->val.s = NULL;\n" -"				}\n" -"				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"\n" -"			stmp = realloc(st->val.s, mlen);\n" -"			if (stmp == NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" -"				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"			st->val.s = stmp;\n" -"		}\n" +"		&& c != '\\r' && c != '\\t' && c != '\\v'\n" +"		&& c != ']' && c != '}'\n" +"		&& c != '[' && c != '{'\n" +"		&& c != ',' && c != ':'\n" +"		&& c != '\\'' && c != '\"'\n" +"		&& c != '=' && c != EOF\n" +"	) {\n" +"		if ( !confconf_priv_push_char(st, (char)c) )\n" +"			return CONFCONF_ERR_MEMORY;\n"  "\n" -"		st->val.s[len] = c;\n" -"		len++;\n"  "		c = (*(st->gcp))(st->fp);\n"  "	}\n"  "\n" -"	if (st->val.s[0] == '\\0') {\n" -"		st->val.s[0] = c;\n" -"		len++;\n" -"		if (len == mlen) {\n" -"			mlen += CONFCONF_ALLOCWIDTH;\n" -"\n" -"			if (mlen < len) {\n" -"				if (st->val.s != NULL) {\n" -"					free(st->val.s);\n" -"					st->val.s = NULL;\n" -"				}\n" +"	if (st->sbuf_len == 0) {\n" +"		if (c == ' ' || c == '\\f' || c == '\\n'\n" +"			|| c == '\\r' || c == '\\t' || c == '\\v'\n" +"		) {\n" +"			(*(st->ugcp))(c, st->fp);\n" +"			if ( !confconf_priv_push_char(st, '\\0') )\n"  "				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"\n" -"			stmp = realloc(st->val.s, mlen);\n" -"			if (stmp == NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" +"		} else {\n" +"			if ( !confconf_priv_push_char(st, (char)c) )\n"  "				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"			st->val.s = stmp;\n" -"		}\n" -"		st->val.s[1] = '\\0';\n" -"		return CONFCONF_SUCCESS;\n" -"	}\n" -"\n" -"	if (len == mlen) {\n" -"		mlen += CONFCONF_ALLOCWIDTH;\n" -"\n" -"		if (mlen < len) {\n" -"			if (st->val.s != NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" -"			}\n" -"			return CONFCONF_ERR_MEMORY;\n" +"			st->sbuf_len = 1;\n"  "		}\n" -"\n" -"		stmp = realloc(st->val.s, mlen);\n" -"		if (stmp == NULL) {\n" -"			free(st->val.s);\n" -"			st->val.s = NULL;\n" -"			return CONFCONF_ERR_MEMORY;\n" -"		}\n" -"		st->val.s = stmp;\n" +"	} else {\n" +"		(*(st->ugcp))(c, st->fp);\n"  "	}\n"  "\n" -"	(*(st->ugcp))(c, st->fp);\n" -"\n" -"	st->val.s[len] = '\\0';\n" -"\n" -"	st->col += len;\n" -"	st->byte += len;\n" +"	st->col += st->sbuf_len;\n" +"	st->byte += st->sbuf_len;\n"  "\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" -"static enum confconf_result_type confconf_priv_get_id(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_id(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n"  "	char *off;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n" -"	for (off = st->val.s; *off != '\\0'; off++) {\n" +"	for (off = st->sbuf; *off != '\\0'; off++) {\n"  "		if (*off >= '0' && *off <= '9')\n"  "			continue;\n" +"\n"  "		if (\n" -"				*off == 'a' || *off == 'b' || *off == 'c' ||\n" -"				*off == 'd' || *off == 'e' || *off == 'f' ||\n" -"				*off == 'g' || *off == 'h' || *off == 'i' ||\n" -"				*off == 'j' || *off == 'k' || *off == 'l' ||\n" -"				*off == 'm' || *off == 'n' || *off == 'o' ||\n" -"				*off == 'p' || *off == 'q' || *off == 'r' ||\n" -"				*off == 's' || *off == 't' || *off == 'u' ||\n" -"				*off == 'v' || *off == 'w' || *off == 'x' ||\n" -"				*off == 'y' || *off == 'z' ||\n" -"				*off == 'A' || *off == 'B' || *off == 'C' ||\n" -"				*off == 'D' || *off == 'E' || *off == 'F' ||\n" -"				*off == 'G' || *off == 'H' || *off == 'I' ||\n" -"				*off == 'J' || *off == 'K' || *off == 'L' ||\n" -"				*off == 'M' || *off == 'N' || *off == 'O' ||\n" -"				*off == 'P' || *off == 'Q' || *off == 'R' ||\n" -"				*off == 'S' || *off == 'T' || *off == 'U' ||\n" -"				*off == 'V' || *off == 'W' || *off == 'X' ||\n" -"				*off == 'Y' || *off == 'Z' ||\n" -"				*off == '-' || *off == '_'\n" +"			*off == 'a' || *off == 'b' || *off == 'c' ||\n" +"			*off == 'd' || *off == 'e' || *off == 'f' ||\n" +"			*off == 'g' || *off == 'h' || *off == 'i' ||\n" +"			*off == 'j' || *off == 'k' || *off == 'l' ||\n" +"			*off == 'm' || *off == 'n' || *off == 'o' ||\n" +"			*off == 'p' || *off == 'q' || *off == 'r' ||\n" +"			*off == 's' || *off == 't' || *off == 'u' ||\n" +"			*off == 'v' || *off == 'w' || *off == 'x' ||\n" +"			*off == 'y' || *off == 'z' ||\n" +"			*off == 'A' || *off == 'B' || *off == 'C' ||\n" +"			*off == 'D' || *off == 'E' || *off == 'F' ||\n" +"			*off == 'G' || *off == 'H' || *off == 'I' ||\n" +"			*off == 'J' || *off == 'K' || *off == 'L' ||\n" +"			*off == 'M' || *off == 'N' || *off == 'O' ||\n" +"			*off == 'P' || *off == 'Q' || *off == 'R' ||\n" +"			*off == 'S' || *off == 'T' || *off == 'U' ||\n" +"			*off == 'V' || *off == 'W' || *off == 'X' ||\n" +"			*off == 'Y' || *off == 'Z' ||\n" +"			*off == '-' || *off == '_'\n"  "		) {\n" -"		   continue;\n" +"			continue;\n"  "		}\n" -"				\n" +"\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "	}\n"  "\n" @@ -272,100 +266,103 @@ static const char sbool[] =  "#ifndef CONFCONF_BOOL_H\n"  "#define CONFCONF_BOOL_H\n"  "\n" -"static enum confconf_result_type confconf_priv_get_bool(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_bool(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" +"	bool *b = st->vp;\n"  "	char *off;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n" -"	off = st->val.s;\n" +"	off = st->sbuf;\n"  "\n"  "	if (*off == 't' || *off == 'T') {\n"  "		if (\n" -"				(*(++off) == 'r' || *off == 'R') &&\n" -"				(*(++off) == 'u' || *off == 'U') &&\n" -"				(*(++off) == 'e' || *off == 'E') &&\n" -"				(*(++off) == '\\0')\n" +"			(*(++off) == 'r' || *off == 'R') &&\n" +"			(*(++off) == 'u' || *off == 'U') &&\n" +"			(*(++off) == 'e' || *off == 'E') &&\n" +"			(*(++off) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = true;\n" +"			*b = true;\n"  "			return CONFCONF_SUCCESS;\n"  "		} else {\n" +"			confconf_priv_pos_set(st, pos);\n"  "			return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "		}\n"  "	}\n"  "\n"  "	if (*off == 'y' || *off == 'Y') {\n"  "		if (\n" -"				(*(++off) == 'e' || *off == 'E') &&\n" -"				(*(++off) == 's' || *off == 'S') &&\n" -"				(*(++off) == '\\0')\n" +"			(*(++off) == 'e' || *off == 'E') &&\n" +"			(*(++off) == 's' || *off == 'S') &&\n" +"			(*(++off) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = true;\n" +"			*b = true;\n"  "			return CONFCONF_SUCCESS;\n"  "		} else {\n" +"			confconf_priv_pos_set(st, pos);\n"  "			return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "		}\n"  "	}\n"  "\n"  "	if (*off == 'n' || *off == 'N') {\n"  "		if (\n" -"				(*(++off) == 'o' || *off == 'O') &&\n" -"				(*(++off) == '\\0')\n" +"			(*(++off) == 'o' || *off == 'O') &&\n" +"			(*(++off) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = false;\n" +"			*b = false;\n"  "			return CONFCONF_SUCCESS;\n"  "		} else {\n" +"			confconf_priv_pos_set(st, pos);\n"  "			return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "		}\n"  "	}\n"  "\n"  "	if (*off == 'f' || *off == 'F') {\n"  "		if (\n" -"				(*(++off) == 'a' || *off == 'A') &&\n" -"				(*(++off) == 'l' || *off == 'L') &&\n" -"				(*(++off) == 's' || *off == 'S') &&\n" -"				(*(++off) == 'e' || *off == 'E') &&\n" -"				(*(++off) == '\\0')\n" +"			(*(++off) == 'a' || *off == 'A') &&\n" +"			(*(++off) == 'l' || *off == 'L') &&\n" +"			(*(++off) == 's' || *off == 'S') &&\n" +"			(*(++off) == 'e' || *off == 'E') &&\n" +"			(*(++off) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = false;\n" +"			*b = false;\n"  "			return CONFCONF_SUCCESS;\n"  "		} else {\n" +"			confconf_priv_pos_set(st, pos);\n"  "			return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "		}\n"  "	}\n"  "\n"  "	if (*off == 'o' || *off == 'O') {\n"  "		if (\n" -"				(*(off+1) == 'n' || *(off+1) == 'N') &&\n" -"				(*(off+2) == '\\0')\n" +"			(*(off+1) == 'n' || *(off+1) == 'N') &&\n" +"			(*(off+2) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = true;\n" +"			*b = true;\n"  "			return CONFCONF_SUCCESS;\n"  "		}\n"  "\n"  "		if (\n" -"				(*(++off) == 'f' || *off == 'F') &&\n" -"				(*(++off) == 'f' || *off == 'F') &&\n" -"				(*(++off) == '\\0')\n" +"			(*(++off) == 'f' || *off == 'F') &&\n" +"			(*(++off) == 'f' || *off == 'F') &&\n" +"			(*(++off) == '\\0')\n"  "		) {\n" -"			free(st->val.s);\n" -"			st->val.b = false;\n" +"			*b = false;\n"  "			return CONFCONF_SUCCESS;\n"  "		} else {\n" +"			confconf_priv_pos_set(st, pos);\n"  "			return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "		}\n"  "	}\n"  "\n" +"	confconf_priv_pos_set(st, pos);\n"  "	return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "}\n"  "\n" @@ -377,32 +374,63 @@ static const char sstring[] =  "#ifndef CONFCONF_STRING_H\n"  "#define CONFCONF_STRING_H\n"  "\n" -"static enum confconf_result_type confconf_priv_get_str(\n" -"		struct confconf_priv_state *st)\n" +"#include <string.h>\n" +"\n" +"static char*\n" +"confconf_priv_dup_sbuf(struct confconf_priv_state *st)\n" +"{\n" +"	char *s;\n" +"\n" +"	s = malloc((st->sbuf_len + 1) * sizeof(char));\n" +"\n" +"	if (s == NULL)\n" +"		return NULL;\n" +"\n" +"	if (st->sbuf_len == 0)\n" +"		s[0] = '\\0';\n" +"	else\n" +"		strcpy(s, st->sbuf);\n" +"\n" +"	return s;\n" +"}\n" +"\n" +"static enum confconf_result_type\n" +"confconf_priv_get_str(struct confconf_priv_state *st)\n"  "{\n" -"	size_t len = 0, mlen = 0;\n" -"	char *stmp;\n"  "	int c, endc;\n"  "	bool escape = false;\n" -"\n" -"	st->val.s = NULL;\n" +"	enum confconf_result_type r;\n" +"	struct confconf_priv_pos pos;\n"  "\n"  "	c = (*(st->gcp))(st->fp);\n" +"\n"  "	if (c == EOF)\n"  "		return CONFCONF_ERR_UNEXPECTED_EOF;\n"  "\n"  "	if (c != '\\'' && c != '\\\"') {\n"  "		(*(st->ugcp))(c, st->fp);\n" +"		pos = confconf_priv_pos_get(st);\n" +"		r = confconf_priv_get_tok(st);\n" +"\n" +"		if (r != CONFCONF_SUCCESS)\n" +"			return r;\n" +"\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n"  "	}\n"  "\n"  "	endc = c;\n" -"\n"  "	st->col++;\n"  "	st->byte++;\n"  "\n" +"	st->sbuf_len = 0;\n" +"\n"  "	while (true) {\n"  "		c = (*(st->gcp))(st->fp);\n" +"\n" +"		if (c == EOF)\n" +"			return CONFCONF_ERR_UNEXPECTED_EOF;\n" +"\n"  "		st->col++;\n"  "		st->byte++;\n"  "\n" @@ -421,59 +449,10 @@ static const char sstring[] =  "			st->line++;\n"  "		}\n"  "\n" -"		if (c == EOF) {\n" -"			if (st->val.s != NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" -"			}\n" -"			return CONFCONF_ERR_UNEXPECTED_EOF;\n" -"		}\n" -"\n" -"		if (len == mlen) {\n" -"			mlen += CONFCONF_ALLOCWIDTH;\n" -"\n" -"			if (mlen < len) {\n" -"				if (st->val.s != NULL) {\n" -"					free(st->val.s);\n" -"					st->val.s = NULL;\n" -"				}\n" -"				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"\n" -"			stmp = realloc(st->val.s, mlen);\n" -"			if (stmp == NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" -"				return CONFCONF_ERR_MEMORY;\n" -"			}\n" -"			st->val.s = stmp;\n" -"		}\n" -"\n" -"		st->val.s[len] = c;\n" -"		len++;\n" -"	}\n" -"\n" -"	if (len == mlen) {\n" -"		mlen += CONFCONF_ALLOCWIDTH;\n" -"\n" -"		if (mlen < len) {\n" -"			if (st->val.s != NULL) {\n" -"				free(st->val.s);\n" -"				st->val.s = NULL;\n" -"			}\n" +"		if ( !confconf_priv_push_char(st, (char)c) )\n"  "			return CONFCONF_ERR_MEMORY;\n" -"		}\n" -"\n" -"		stmp = realloc(st->val.s, mlen);\n" -"		if (stmp == NULL) {\n" -"			free(st->val.s);\n" -"			st->val.s = NULL;\n" -"			return CONFCONF_ERR_MEMORY;\n" -"		}\n" -"		st->val.s = stmp;\n"  "	}\n"  "\n" -"	st->val.s[len] = '\\0';\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -488,32 +467,40 @@ static const char sint[] =  "#include <errno.h>\n"  "#include <limits.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_int(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_int(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long int i;\n" +"	int *i = st->vp;\n" +"	long int local_i;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	i = strtol(st->val.s, &check, 0);\n" +"	local_i = strtol(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	if (i > INT_MAX || i < INT_MIN)\n" +"	if (local_i > INT_MAX || local_i < INT_MIN) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.i = (int)i;\n" +"	*i = (int)local_i;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -527,29 +514,33 @@ static const char sintl[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_intl(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_intl(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long int il;\n" +"	long int *il = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	il = strtol(st->val.s, &check, 0);\n" +"	*il = strtol(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.il = il;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -563,29 +554,33 @@ static const char sintll[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_intll(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_intll(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long long int ill;\n" +"	long long int *ill = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	ill = strtoll(st->val.s, &check, 0);\n" +"	*ill = strtoll(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.ill = ill;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -600,32 +595,40 @@ static const char suint[] =  "#include <errno.h>\n"  "#include <limits.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_uint(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_uint(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long unsigned u;\n" +"	unsigned *u = st->vp;\n" +"	long unsigned u_local;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	u = strtoul(st->val.s, &check, 0);\n" +"	u_local = strtoul(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	if (u > UINT_MAX)\n" +"	if (u_local > UINT_MAX) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.u = (unsigned)u;\n" +"	*u = (unsigned)u_local;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -639,29 +642,33 @@ static const char suintl[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_uintl(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_uintl(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long unsigned ul;\n" +"	long unsigned *ul = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	ul = strtoul(st->val.s, &check, 0);\n" +"	*ul = strtoul(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.ul = ul;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -675,29 +682,33 @@ static const char suintll[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_uintll(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_uintll(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	long long unsigned ull;\n" +"	long long unsigned *ull = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	ull = strtoull(st->val.s, &check, 0);\n" +"	*ull = strtoull(st->sbuf, &check, 0);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.ull = ull;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -711,29 +722,33 @@ static const char sfloat[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_float(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_float(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	double f;\n" +"	float *f = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	f = strtof(st->val.s, &check);\n" +"	*f = strtof(st->sbuf, &check);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.f = f;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -747,29 +762,33 @@ static const char sdouble[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_double(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_double(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	double d;\n" +"	double *d = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	d = strtod(st->val.s, &check);\n" +"	*d = strtod(st->sbuf, &check);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.d = d;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n" @@ -783,116 +802,36 @@ static const char sdoublel[] =  "\n"  "#include <errno.h>\n"  "\n" -"static enum confconf_result_type confconf_priv_get_doublel(\n" -"		struct confconf_priv_state *st)\n" +"static enum confconf_result_type\n" +"confconf_priv_get_doublel(struct confconf_priv_state *st)\n"  "{\n"  "	enum confconf_result_type r;\n" -"	double dl;\n" +"	long double *dl = st->vp;\n"  "	char *check;\n" +"	struct confconf_priv_pos pos;\n"  "\n" +"	pos = confconf_priv_pos_get(st);\n"  "	r = confconf_priv_get_tok(st);\n"  "\n"  "	if (r != CONFCONF_SUCCESS)\n"  "		return r;\n"  "\n"  "	errno = EILSEQ;\n" -"	dl = strtold(st->val.s, &check);\n" +"	*dl = strtold(st->sbuf, &check);\n"  "\n" -"	if (errno == ERANGE)\n" +"	if (errno == ERANGE) {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_RANGE;\n" +"	}\n"  "\n" -"	if (*check != '\\0')\n" +"	if (*check != '\\0') {\n" +"		confconf_priv_pos_set(st, pos);\n"  "		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +"	}\n"  "\n" -"	free(st->val.s);\n" -"	st->val.dl = dl;\n"  "	return CONFCONF_SUCCESS;\n"  "}\n"  "\n"  "#endif\n"  "\n"  ; - -static const char shash[] = -"#ifndef CONFCONF_HASH_H\n" -"#define CONFCONF_HASH_H\n" -"\n" -"#include %s\n" -"\n" -"#define CONFCONF_PRIV_GET_HASH_main(h, htmp, fun, mem) \\\n" -"	do { \\\n" -"		int c; \\\n" -"		char *hash_swp; \\\n" -"		(h) = NULL; \\\n" -"		c = (*(st.gcp))(st.fp); \\\n" -"		if (c != '[') { \\\n" -"			if (c == EOF) { \\\n" -"				r = CONFCONF_ERR_UNEXPECTED_EOF; \\\n" -"				st.val.s = NULL; \\\n" -"				break; \\\n" -"			} \\\n" -"			(*(st.ugcp))(c, st.fp); \\\n" -"			confconf_priv_get_tok(&st); \\\n" -"			r = CONFCONF_ERR_UNEXPECTED_TOKEN; \\\n" -"		} \\\n" -"		st.col++; \\\n" -"		st.byte++; \\\n" -"		while (1) { \\\n" -"			confconf_priv_eat_space(&st); \\\n" -"			r = confconf_priv_get_id(&st); \\\n" -"			if (r != CONFCONF_SUCCESS) \\\n" -"				break; \\\n" -"			HASH_FIND_STR((h), st.val.s, (htmp)); \\\n" -"			if ((htmp) != NULL) { \\\n" -"				r = CONFCONF_ERR_HASH_DUPLICATE_KEY; \\\n" -"				break; \\\n" -"			} \\\n" -"			hash_swp = st.val.s; \\\n" -"			confconf_priv_eat_space(&st); \\\n" -"			c = (*(st.gcp))(st.fp); \\\n" -"			if (c == ':') { \\\n" -"				st.col++; \\\n" -"				st.byte++; \\\n" -"				confconf_priv_eat_space(&st); \\\n" -"			} else { \\\n" -"				(*(st.ugcp))(c, st.fp); \\\n" -"				free(hash_swp); \\\n" -"				r = confconf_priv_get_tok(&st); \\\n" -"				if (r == CONFCONF_SUCCESS) \\\n" -"					r = CONFCONF_ERR_UNEXPECTED_TOKEN; \\\n" -"				break; \\\n" -"			} \\\n" -"			r = confconf_priv_get_ ## fun (&st); \\\n" -"			if (r != CONFCONF_SUCCESS) { \\\n" -"				free(hash_swp); \\\n" -"				break; \\\n" -"			} \\\n" -"			(htmp) = malloc(sizeof(*(htmp))); \\\n" -"			if ((htmp) == NULL) { \\\n" -"				free(hash_swp); \\\n" -"				r = CONFCONF_ERR_MEMORY; \\\n" -"				break; \\\n" -"			} \\\n" -"			(htmp)->key = hash_swp; \\\n" -"			(htmp)->val.mem = st.val.mem; \\\n" -"			HASH_ADD_STR((h), key, (htmp)); \\\n" -"			confconf_priv_eat_space(&st); \\\n" -"			c = (*(st.gcp))(st.fp); \\\n" -"			if (c == ',') { \\\n" -"				st.col++; \\\n" -"				st.byte++; \\\n" -"				confconf_priv_eat_space(&st); \\\n" -"			} else if (c == ']') { \\\n" -"				st.col++; \\\n" -"				st.byte++; \\\n" -"				r = CONFCONF_SUCCESS; \\\n" -"				break; \\\n" -"			} else { \\\n" -"				(*(st.ugcp))(c, st.fp); \\\n" -"			} \\\n" -"		} \\\n" -"	} while (0)\n" -"\n" -"#endif\n" -"\n" -; @@ -4,197 +4,695 @@  #include "parse.h"  #include "opt.h" +#include "../reqs/uthash/include/uthash.h" +  #include <time.h>  #include <assert.h>  #include "gen-consts.h" -void gen(FILE *f, struct parse_result_s pr, struct analyse_result_s ar) +static inline void sub_head(FILE *f, struct analyse_result_s *ar)  { -	time_t t; -	struct tm *ti; - -	struct parse_deftype_s *dcur, *dtmp; -	struct parse_var_s *vcur, *vtmp; - -	unsigned i; - -	time(&t); -	ti = localtime(&t); - -	/******** -	 * HEAD * -	 ********/ - -	fprintf(f, "/* generated by %s on %04d-%02d-%02d */\n",  -			VERSION, ti->tm_year + 1900, ti->tm_mon + 1, ti->tm_mday); -  	fprintf(f, sheadp1);  	fprintf(f, sheadp2); -	if (ar.uses_type[PARSE_TYPE_BOOL]) +	if (ar->uses_type[PARSE_TYPE_BOOL])  		fprintf(f, sbool); -	if (ar.uses_type[PARSE_TYPE_STRING]) +	if (ar->uses_type[PARSE_TYPE_STRING])  		fprintf(f, sstring); -	if (ar.uses_type[PARSE_TYPE_INT]) +	if (ar->uses_type[PARSE_TYPE_INT])  		fprintf(f, sint); -	if (ar.uses_type[PARSE_TYPE_INTL]) +	if (ar->uses_type[PARSE_TYPE_INTL])  		fprintf(f, sintl); -	if (ar.uses_type[PARSE_TYPE_INTLL]) +	if (ar->uses_type[PARSE_TYPE_INTLL])  		fprintf(f, sintll); -	if (ar.uses_type[PARSE_TYPE_UINT]) +	if (ar->uses_type[PARSE_TYPE_UINT])  		fprintf(f, suint); -	if (ar.uses_type[PARSE_TYPE_UINTL]) +	if (ar->uses_type[PARSE_TYPE_UINTL])  		fprintf(f, suintl); -	if (ar.uses_type[PARSE_TYPE_UINTLL]) +	if (ar->uses_type[PARSE_TYPE_UINTLL])  		fprintf(f, suintll); -	if (ar.uses_type[PARSE_TYPE_FLOAT]) +	if (ar->uses_type[PARSE_TYPE_FLOAT])  		fprintf(f, sfloat); -	if (ar.uses_type[PARSE_TYPE_DOUBLE]) +	if (ar->uses_type[PARSE_TYPE_DOUBLE])  		fprintf(f, sdouble); -	if (ar.uses_type[PARSE_TYPE_DOUBLEL]) +	if (ar->uses_type[PARSE_TYPE_DOUBLEL])  		fprintf(f, sdoublel); +} -	/* if (ar.uses_array) */ -	/* 	fprintf(f, sarray); */ -	if (ar.uses_hash) -		fprintf(f, shash, (opt_header_str() ? opt_header_str() : pr.header)); +static inline void sub_deftypes_type(FILE *f, struct parse_result_s *pr, +	struct parse_deftype_s *dcur) +{ +	unsigned i; -	/******** -	 * BODY * -	 ********/ +	/* enum for indicating which union elem is used */ +	if (dcur->type == PARSE_DEFTYPE_UNION) { +		fprintf(f, +			"enum confconf_utype_%s_%s {\n", +			dcur->name, +			(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +		); + +		for (i = 0; i < dcur->member_list_len; i++) { +			fprintf(f, +				"	CONFCONF_UTYPE_%s_%s_%s,\n", +				dcur->name, +				dcur->member_name_list[i], +				(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +			); +		} + +		fprintf(f, "};\n\n"); +	}  	fprintf(f, -			"#ifndef CONFCONF_BODY_%s_H\n" -			"#define CONFCONF_BODY_%s_H\n\n", -			(opt_suffix_str() ? opt_suffix_str() : pr.suffix), -			(opt_suffix_str() ? opt_suffix_str() : pr.suffix) +		"%s confconf_type_%s_%s {\n", +		(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" : "struct"), +		dcur->name, +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix)  	); -	/* deftypes */ -	HASH_ITER(hh, pr.deftypes, dcur, dtmp) { -		if (!dcur->is_used) -			continue; +	if (dcur->type == PARSE_DEFTYPE_UNION) { +		fprintf(f, +			"	enum confconf_utype_%s_%s type;\n" +			"	union {\n", +			dcur->name, +			(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +		); +	} -		fprintf(f, "%s confconf_type_%s_%s {\n", -				(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" :  -					 (dcur->type == PARSE_DEFTYPE_UNION ? -					  "union" : "struct") -				), +	for (i = 0; i < dcur->member_list_len; i++) { +		if (dcur->type == PARSE_DEFTYPE_UNION) { +			fprintf(f, "	"); +		} + +		if (dcur->type == PARSE_DEFTYPE_ENUM) { +			fprintf(f, +				"	CONFCONF_TYPE_%s_%s_%s,\n",  				dcur->name, -				(opt_suffix_str() ? opt_suffix_str() : pr.suffix) -		); +				dcur->member_name_list[i], +				(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +			); +			continue; +		} + +		switch (dcur->member_type_list[i]) { +		case PARSE_TYPE_BOOL: +			fprintf(f, "	bool "); +			break; +		case PARSE_TYPE_STRING: +			fprintf(f, "	char *"); +			break; +		case PARSE_TYPE_ID: +			fprintf(f, "	char *"); +			break; +		case PARSE_TYPE_INT: +			fprintf(f, "	int "); +			break; +		case PARSE_TYPE_INTL: +			fprintf(f, "	long int "); +			break; +		case PARSE_TYPE_INTLL: +			fprintf(f, "	long long int "); +			break; +		case PARSE_TYPE_UINT: +			fprintf(f, "	unsigned "); +			break; +		case PARSE_TYPE_UINTL: +			fprintf(f, "	long unsigned "); +			break; +		case PARSE_TYPE_UINTLL: +			fprintf(f, "	long long unsigned "); +			break; +		case PARSE_TYPE_FLOAT: +			fprintf(f, "	float "); +			break; +		case PARSE_TYPE_DOUBLE: +			fprintf(f, "	double "); +			break; +		case PARSE_TYPE_DOUBLEL: +			fprintf(f, "	long double "); +			break; +		default: +			assert(0); +		} +		fprintf(f, "%s;\n", dcur->member_name_list[i]); +	} +	if (dcur->type == PARSE_DEFTYPE_UNION) { +		fprintf(f, "	} val;\n"); +	} + +	fprintf(f, "};\n\n"); +} + +static inline void sub_deftypes_get_struct(FILE *f, +	struct parse_deftype_s *dcur) +{ +	unsigned i; + +	fprintf(f, "	int c;\n"); + +	/* add stmp for alloc-swap and set all string elements to NULL */ +	if (dcur->contains_heap) { +		fprintf(f, "	char *stmp;\n");  		for (i = 0; i < dcur->member_list_len; i++) { -			if (dcur->type == PARSE_DEFTYPE_ENUM) { -				fprintf(f, "	CONFCONF_TYPE_%s_%s_%s,\n", -						dcur->name, -						dcur->member_name_list[i], -						(opt_suffix_str() ? opt_suffix_str() : pr.suffix) +			if (dcur->member_type_list[i] == PARSE_TYPE_STRING) { +				fprintf(f, +					"\n" +					"	t->%s = NULL;\n", +					dcur->member_name_list[i]  				); -				continue;  			} +		} +	} -			switch (dcur->member_type_list[i]) { -			case PARSE_TYPE_BOOL: -				fprintf(f, "	bool "); -				break; -			case PARSE_TYPE_STRING: -				fprintf(f, "	char *"); -				break; -			case PARSE_TYPE_ID: -				fprintf(f, "	char *"); -				break; -			case PARSE_TYPE_INT: -				fprintf(f, "	int "); -				break; -			case PARSE_TYPE_INTL: -				fprintf(f, "	long int "); -				break; -			case PARSE_TYPE_INTLL: -				fprintf(f, "	long long int "); -				break; -			case PARSE_TYPE_UINT: -				fprintf(f, "	unsigned "); -				break; -			case PARSE_TYPE_UINTL: -				fprintf(f, "	long unsigned "); -				break; -			case PARSE_TYPE_UINTLL: -				fprintf(f, "	long long unsigned "); -				break; -			case PARSE_TYPE_FLOAT: -				fprintf(f, "	float "); -				break; -			case PARSE_TYPE_DOUBLE: -				fprintf(f, "	double "); -				break; -			case PARSE_TYPE_DOUBLEL: -				fprintf(f, "	long double "); -				break; -			default: -				assert(0); -			} +	fprintf(f, +		"\n" +		"	c = (*(st->gcp))(st->fp);\n" +		"\n" +		"	if (c == EOF)\n" +		"		return CONFCONF_ERR_UNEXPECTED_EOF;\n" +		"\n" +		"	if (c != '{') {\n" +		"		(*(st->ugcp))(c, st->fp);\n" +		"		pos = confconf_priv_pos_get(st);\n" +		"		r = confconf_priv_get_tok(st);\n" +		"		if (r != CONFCONF_SUCCESS)\n" +		"			return r;\n" +		"		confconf_priv_pos_set(st, pos);\n" +		"		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +		"	}\n" +		"\n" +		"	st->col++;\n" +		"	st->byte++;\n" +		"\n" +		"	confconf_priv_eat_space(st);\n" +	); -			fprintf(f, "%s;\n", dcur->member_name_list[i]); +	for (i = 0; i < dcur->member_list_len; i++) { +		if (i != 0) { +			fprintf(f, +				"\n" +				"	confconf_priv_eat_space(st);\n" +				"\n" +				"	c = (*(st->gcp))(st->fp);\n" +				"	if (c == ',') {\n" +				"		st->col++;\n" +				"		st->byte++;\n" +				"		confconf_priv_eat_space(st);\n" +				"	} else {\n" +				"		(*(st->ugcp))(c, st->fp);\n" +				"	}\n" +			);  		} -		fprintf(f, "};\n\n"); -	} +		fprintf(f, "\n"); + +		if (dcur->member_type_list[i] != PARSE_TYPE_STRING) { +			fprintf(f, +				"	st->vp = &(t->%s);\n", +				dcur->member_name_list[i] +			); +		} + +		switch (dcur->member_type_list[i]) { +		case PARSE_TYPE_BOOL: +			fprintf(f, "	r = confconf_priv_get_bool(st);\n"); +			break; +		case PARSE_TYPE_STRING: +			fprintf(f, "	r = confconf_priv_get_str(st);\n"); +			break; +		case PARSE_TYPE_ID: +			fprintf(f, "	r = confconf_priv_get_id(st);\n"); +			break; +		case PARSE_TYPE_INT: +			fprintf(f, "	r = confconf_priv_get_int(st);\n"); +			break; +		case PARSE_TYPE_INTL: +			fprintf(f, "	r = confconf_priv_get_intl(st);\n"); +			break; +		case PARSE_TYPE_INTLL: +			fprintf(f, "	r = confconf_priv_get_intll(st);\n"); +			break; +		case PARSE_TYPE_UINT: +			fprintf(f, "	r = confconf_priv_get_uint(st);\n"); +			break; +		case PARSE_TYPE_UINTL: +			fprintf(f, "	r = confconf_priv_get_uintl(st);\n"); +			break; +		case PARSE_TYPE_UINTLL: +			fprintf(f, "	r = confconf_priv_get_uintll(st);\n"); +			break; +		case PARSE_TYPE_FLOAT: +			fprintf(f, "	r = confconf_priv_get_float(st);\n"); +			break; +		case PARSE_TYPE_DOUBLE: +			fprintf(f, "	r = confconf_priv_get_double(st);\n"); +			break; +		case PARSE_TYPE_DOUBLEL: +			fprintf(f, "	r = confconf_priv_get_doublel(st);\n"); +			break; +		default: +			assert(0); +		} -	/* hash type */ -	if (ar.uses_hash) {  		fprintf(f, -				"#include %s\n\n" -				"struct confconf_hash_%s {\n" -				"	char *key;\n" -				"	union {\n" -				"%s%s%s%s%s%s%s%s%s%s%s", -				(opt_header_str() ? opt_header_str() : pr.header), -				(opt_suffix_str() ? opt_suffix_str() : pr.suffix), -				(ar.uses_type[PARSE_TYPE_HASH_BOOL] -				 ? "		bool b;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_STRING] -				 ? "		char *s;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_INT] -				 ? "		int i;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_INTL] -				 ? "		long int il;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_INTLL] -				 ? "		long long int ill;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_UINT] -				 ? "		unsigned u;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_UINTL] -				 ? "		long unsigned ul;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_UINTLL] -				 ? "		long long unsigned ull;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_FLOAT] -				 ? "		float f;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_DOUBLE] -				 ? "		double d;\n" : ""), -				(ar.uses_type[PARSE_TYPE_HASH_DOUBLEL] -				 ? "		long double dl;\n" : "") +			"	if (r != CONFCONF_SUCCESS)\n" +			"		%s;\n", +			(dcur->contains_heap ? "goto err" : "return r")  		); -		HASH_ITER(hh, pr.deftypes, dcur, dtmp) { -			if (dcur->is_used && dcur->is_in_hash) { -				fprintf(f, "		%s confconf_type_%s_%s type_%s;\n", -						(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" :  -							 (dcur->type == PARSE_DEFTYPE_UNION ? -							  "union" : "struct") -						), -						dcur->name, -						(opt_suffix_str() ? opt_suffix_str() : pr.suffix), -						dcur->name + +		if (dcur->member_type_list[i] == PARSE_TYPE_STRING) { +			fprintf(f, +				"\n" +				"	stmp = confconf_priv_dup_sbuf(st);\n" +				"	if (stmp == NULL)\n" +				"		goto err;\n" +				"	t->%s = stmp;\n", +				dcur->member_name_list[i] +			); +		} +	} + +	fprintf(f, +		"\n" +		"	c = (*(st->gcp))(st->fp);\n" +		"\n" +		"	if (c == EOF)\n" +		"		return CONFCONF_ERR_UNEXPECTED_EOF;\n" +		"\n" +		"	if (c != '}') {\n" +		"		(*(st->ugcp))(c, st->fp);\n" +		"		pos = confconf_priv_pos_get(st);\n" +		"		r = confconf_priv_get_tok(st);\n" +		"		if (r != CONFCONF_SUCCESS)\n" +		"			%s;\n" +		"		confconf_priv_pos_set(st, pos);\n" +		"		return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +		"		%s;\n" +		"	}\n" +		"\n" +		"	return CONFCONF_SUCCESS;\n", +		(dcur->contains_heap ? "goto err" : "return r"), +		(dcur->contains_heap ? "goto err" : "return r") +	); + +	if (dcur->contains_heap) { +		fprintf(f, "\nerr:\n"); +		for (i = 0; i < dcur->member_list_len; i++) { +			if (dcur->member_type_list[i] == PARSE_TYPE_STRING +				|| dcur->member_type_list[i] == PARSE_TYPE_ID +			) { +				fprintf(f, +					"	if (t->%s != NULL)\n" +					"		free(t->%s);\n" +					"\n", +					dcur->member_name_list[i], +					dcur->member_name_list[i]  				);  			}  		} +		fprintf(f, "	return r;\n"); +	} +} + +/* emit a switch statement dfa to char-by-char recognise a string */ +static void sub_print_switch(FILE *f, struct analyse_trie_s *cur, +	unsigned depth, const char *dest, const char *stmt) +{ +	unsigned i; + +	cur->idx = 0; +	do { +		/* skip leaves */ +		if (cur->branch_count == 0) { +			for (i = 0; i < depth; i++) +				fprintf(f, "\t"); +			fprintf(f, "if (*stmp == '\\0') {\n"); +			for (i = 0; i < depth + 1; i++) +				fprintf(f, "\t"); +			fprintf(f, "%s = %s;\n", dest, cur->sval); +			for (i = 0; i < depth + 1; i++) +				fprintf(f, "\t"); +			fprintf(f, "%s;\n", stmt); +			for (i = 0; i < depth; i++) +				fprintf(f, "\t"); +			fprintf(f, "}\n"); +			for (i = 0; i < depth; i++) +				fprintf(f, "\t"); +			fprintf(f, "break;\n"); +			depth--; +		} else { +			if (cur->idx == 0) { +				for (i = 0; i < depth; i++) +					fprintf(f, "\t"); +				fprintf(f, "switch ( *(stmp++) ) {\n"); +			} + +			if (cur->idx == cur->branch_count) { +				for (i = 0; i < depth; i++) +					fprintf(f, "\t"); +				fprintf(f, "}\n"); +				/* skip break for final '}' */ +				if (cur->parent != NULL || cur->idx != cur->branch_count) { +					for (i = 0; i < depth; i++) +						fprintf(f, "\t"); +					fprintf(f, "break;\n"); +				} +				depth--; +			} else { +				/* match prefix terminals */ +				if (cur->idx == 0 && cur->sval != NULL) { +					for (i = 0; i < depth; i++) +						fprintf(f, "\t"); +					fprintf(f, "case '\\0':\n"); +					for (i = 0; i < depth + 1; i++) +						fprintf(f, "\t"); +					fprintf(f, "%s = %s;\n", dest, cur->sval); +					for (i = 0; i < depth + 1; i++) +						fprintf(f, "\t"); +					fprintf(f, "%s;\n", stmt); +					for (i = 0; i < depth + 1; i++) +						fprintf(f, "\t"); +					fprintf(f, "break;\n"); +				} +				for (i = 0; i < depth; i++) +					fprintf(f, "\t"); +				fprintf(f, "case '%c':\n", cur->branch_chars[cur->idx]); +				depth++; +			} +		} + +		/* next node in the trie, iterating depth-first */ +		if (cur->idx == cur->branch_count) { +			cur = cur->parent; +		} else { +			cur->idx++; +			cur = cur->branches[cur->idx - 1]; +			cur->idx = 0; +		} +	} while (cur != NULL); + +} + +static inline void sub_deftypes_get_union(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar, struct parse_deftype_s *dcur, unsigned idx) +{ +	struct analyse_trie_s *t = &(ar->deftype_mem_tries[idx]); +	unsigned i; + +	fprintf(f, +		"	char *stmp;\n" +		"	unsigned mem;\n" +		"\n" +		"	confconf_priv_eat_space(st);\n" +		"\n" +		"	pos = confconf_priv_pos_get(st);\n" +		"	r = confconf_priv_get_tok(st);\n" +		"	if (r != CONFCONF_SUCCESS)\n" +		"		return r;\n" +		"	stmp = st->sbuf;\n" +		"\n" +	); + +	sub_print_switch(f, t, 1, "mem", "goto match"); + +	fprintf(f, +		"\n" +		"	confconf_priv_pos_set(st, pos);\n" +		"	return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +		"\n" +		"match:\n" +		"	pos = confconf_priv_pos_get(st);\n" +		"\n" +		"	switch (mem) {\n" +	); + +	for (i = 0; i < dcur->member_list_len; i++) {  		fprintf(f, -				"	} val;\n" -				"	UT_hash_handle hh;\n" -				"};\n\n" +			"	case %u:\n" +			"		st->vp = &(t->val.%s);\n" +			"		r = confconf_priv_get_%s(st);\n" +			"		t->type = CONFCONF_UTYPE_%s_%s_%s;\n" +			"		break;\n", +			i, +			dcur->member_name_list[i], +			parse_typestrs[dcur->member_type_list[i]], +			dcur->name, +			dcur->member_name_list[i], +			(opt_suffix_str() ? opt_suffix_str() : pr->suffix)  		); +	} + +	fprintf(f, +		"	}\n" +		"\n" +		"	if (r != CONFCONF_SUCCESS)\n" +		"		return r;\n" +		"\n" +		"	return CONFCONF_SUCCESS;\n" +	); +} + +static inline void sub_deftypes_get_enum(FILE *f, struct analyse_result_s *ar, +	struct parse_deftype_s *dcur, unsigned idx) +{ +	struct analyse_trie_s *t = &(ar->deftype_mem_tries[idx]); + +	fprintf(f, +		"	char *stmp;\n" +		"\n" +		"	confconf_priv_eat_space(st);\n" +		"\n" +		"	pos = confconf_priv_pos_get(st);\n" +		"	r = confconf_priv_get_tok(st);\n" +		"	if (r != CONFCONF_SUCCESS)\n" +		"		return r;\n" +		"	stmp = st->sbuf;\n" +		"\n" +	); + +	sub_print_switch(f, t, 1, "*t", "return CONFCONF_SUCCESS"); + +	fprintf(f, +		"\n" +		"	confconf_priv_pos_set(st, pos);\n" +		"	return CONFCONF_ERR_UNEXPECTED_TOKEN;\n" +	); +} + +static inline void sub_deftypes_get(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar, struct parse_deftype_s *dcur, unsigned idx) +{ +	fprintf(f, +		"static enum confconf_result_type\n" +		"confconf_priv_get_%s_%s(struct confconf_priv_state *st)\n" +		"{\n" +		"	enum confconf_result_type r;\n" +		"	%s confconf_type_%s_%s *t = st->vp;\n" +		"	struct confconf_priv_pos pos;\n", +		dcur->name, +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix), +		(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" : "struct"), +		dcur->name, +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +	); + +	switch (dcur->type) { +	case PARSE_DEFTYPE_STRUCT: +		sub_deftypes_get_struct(f, dcur); +		break; + +	case PARSE_DEFTYPE_UNION: +		sub_deftypes_get_union(f, pr, ar, dcur, idx); +		break; + +	case PARSE_DEFTYPE_ENUM: +		sub_deftypes_get_enum(f, ar, dcur, idx); +		break; + +	default: +		assert(0); +	} + +	fprintf(f, "}\n\n"); +} + +static inline void sub_deftypes(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar) +{ +	struct parse_deftype_s *dcur, *dtmp; +	unsigned i = 0; + +	HASH_ITER(hh, pr->deftypes, dcur, dtmp) { + +		if (!dcur->is_used) { +			i++; +			continue; +		} + +		/* print the type definition */ +		sub_deftypes_type(f, pr, dcur); +		/* print it's get function */ +		sub_deftypes_get(f, pr, ar, dcur, i); +		i++; +	} + +} + +static inline void sub_arraytype(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar) +{ +	struct parse_deftype_s *dcur, *dtmp; + +	fprintf(f, +		"struct confconf_array_%s {\n" +		"	size_t len;\n" +		"	union {\n" +		"%s%s%s%s%s%s%s%s%s%s%s", +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix), +		(ar->uses_type[PARSE_TYPE_ARRAY_BOOL] +			? "		bool b;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_STRING] +			? "		char *s;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_INT] +			? "		int i;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_INTL] +			? "		long int il;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_INTLL] +			? "		long long int ill;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_UINT] +			? "		unsigned u;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_UINTL] +			? "		long unsigned ul;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_UINTLL] +			? "		long long unsigned ull;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_FLOAT] +			? "		float f;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_DOUBLE] +			? "		double d;\n" : ""), +		(ar->uses_type[PARSE_TYPE_ARRAY_DOUBLEL] +			? "		long double dl;\n" : "") +	); + +	HASH_ITER(hh, pr->deftypes, dcur, dtmp) { +		if (dcur->is_used && dcur->is_in_array) { +			fprintf(f, +				"		%s confconf_type_%s_%s type_%s;\n", +				(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" : +					(dcur->type == PARSE_DEFTYPE_UNION ? "union" : "struct") +				), +				dcur->name, pr->suffix, dcur->name +			); +		} +	} + +	fprintf(f, +		"	} *arr;\n" +		"};\n\n" +	); +} + +static inline void sub_hashtype(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar) +{ +	struct parse_deftype_s *dcur, *dtmp; + +	fprintf(f, +		"#include %s\n\n" +		"struct confconf_hash_%s {\n" +		"	char *key;\n" +		"	union {\n" +		"%s%s%s%s%s%s%s%s%s%s%s", +		(opt_header_str() ? opt_header_str() : pr->header), +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix), +		(ar->uses_type[PARSE_TYPE_HASH_BOOL] +			? "		bool b;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_STRING] +			? "		char *s;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_INT] +			? "		int i;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_INTL] +			? "		long int il;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_INTLL] +			? "		long long int ill;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_UINT] +			? "		unsigned u;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_UINTL] +			? "		long unsigned ul;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_UINTLL] +			? "		long long unsigned ull;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_FLOAT] +			? "		float f;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_DOUBLE] +			? "		double d;\n" : ""), +		(ar->uses_type[PARSE_TYPE_HASH_DOUBLEL] +			? "		long double dl;\n" : "") +	); +	HASH_ITER(hh, pr->deftypes, dcur, dtmp) { +		if (dcur->is_used && dcur->is_in_hash) { +			fprintf(f, +				"		%s confconf_type_%s_%s type_%s;\n", +				(dcur->type == PARSE_DEFTYPE_ENUM ? "enum" : +					(dcur->type == PARSE_DEFTYPE_UNION ? "union" : "struct") +				), +				dcur->name, +				(opt_suffix_str() ? opt_suffix_str() : pr->suffix), +				dcur->name +			); +		}  	} +	fprintf(f, +		"	} val;\n" +		"	UT_hash_handle hh;\n" +		"};\n\n" +	); +} + +static inline void sub_body(FILE *f, struct parse_result_s *pr, +	struct analyse_result_s *ar) +{ +	struct parse_var_s *vcur, *vtmp; + +} + +void gen(FILE *f, struct parse_result_s *pr, struct analyse_result_s *ar) +{ +	time_t t; +	struct tm *ti; + +	assert(pr != NULL); +	assert(ar != NULL); + +	time(&t); +	ti = localtime(&t); + +	fprintf(f, "/* generated by %s on %04d-%02d-%02d */\n\n", +		VERSION, ti->tm_year + 1900, ti->tm_mon + 1, ti->tm_mday); + +	/* conditionally include static subroutines from gen-consts.h */ +	sub_head(f, ar); + +	fprintf(f, +		"#ifndef CONFCONF_BODY_%s_H\n" +		"#define CONFCONF_BODY_%s_H\n\n", +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix), +		(opt_suffix_str() ? opt_suffix_str() : pr->suffix) +	); + +	/* define struct/enum/unions and their get functions */ +	sub_deftypes(f, pr, ar); + +	if (ar->uses_array) +		sub_arraytype(f, pr, ar); + +	if (ar->uses_hash) +		sub_hashtype(f, pr, ar); + +	sub_body(f, pr, ar); +  	fprintf(f, "#endif\n");  } @@ -4,6 +4,6 @@  #include "parse.h"  #include "analyse.h" -void gen(FILE *f, struct parse_result_s pr, struct analyse_result_s ar); +void gen(FILE *f, struct parse_result_s *pr, struct analyse_result_s *ar);  #endif @@ -4,33 +4,15 @@  #include "analyse.h"  #include "gen.h" -/* static void print_tree(struct analyse_tree_s *t) */ -/* { */ -/* 	unsigned i; */ -/* 	if (t->is_terminal) */ -/* 		printf("!"); */ -/*  */ -/* 	if (t->branch_count > 1) */ -/* 		printf("("); */ -/*  */ -/* 	for (i = 0; i < t->branch_count; i++) { */ -/* 		printf("%c", t->branch_chars[i]); */ -/* 		print_tree(t->branches[i]); */ -/* 		if (t->branch_count > 1 && i < t->branch_count - 1) */ -/* 			printf("|"); */ -/* 	} */ -/*  */ -/* 	if (t->branch_count > 1) */ -/* 		printf(")"); */ -/* } */ +#include <stdio.h>  int main(int argc, char **argv)  {  	FILE *fo = stdout;  	FILE *fi = stdin;  	const char *finame = "stdin"; -	struct parse_result_s pr; -	struct analyse_result_s ar; +	struct parse_result_s *pr; +	struct analyse_result_s *ar;  	opt_parse(argc, argv); @@ -52,18 +34,13 @@ int main(int argc, char **argv)  	ar = analyse(pr); -	/* print_tree(&ar.deftype_tree); */ -	/* puts(""); */ -	/* print_tree(&ar.var_tree); */ -	/* puts(""); */ -  	gen(fo, pr, ar);  	if (fo != stdout)  		fclose(fo); -	parse_result_wipe(&pr); -	analyse_result_wipe(&ar); +	parse_result_free(pr); +	analyse_result_free(ar);  	return 0;  } @@ -43,9 +43,9 @@ void opt_parse(int argc, char **argv)  	/* help */  	if (options[0].was_seen) {  		simple_opt_print_usage(stdout, 80, argv[0], -				"[-i input.confconf] [-o output.h]", -				"confconf is a config file parser generator for C", -				options); +			"[-i input.confconf] [-o output.h]", +			"confconf is a config file parser generator for C", +			options);  		exit(EXIT_SUCCESS);  	} @@ -61,7 +61,7 @@ void opt_parse(int argc, char **argv)  		if (cend != '"' && cend != '<') {  			fprintf(stderr, "%s: err: badly-formatted uthash header `%s`\n", -					argv[0], options[4].val.v_string); +				argv[0], options[4].val.v_string);  			exit(EXIT_FAILURE);  		} @@ -69,33 +69,33 @@ void opt_parse(int argc, char **argv)  			cend = '>';  		for (i = 1, c = options[4].val.v_string[1]; -				c && c != cend && c != '\n'; -				c = options[4].val.v_string[++i] +			c && c != cend && c != '\n'; +			c = options[4].val.v_string[++i]  		);  		if (c != cend -				|| options[4].val.v_string[i+1] != '\0' -				|| strlen(options[4].val.v_string) > TOK_MAX_LEN -				|| options[4].val.v_string[2] == '\0' +			|| options[4].val.v_string[i+1] != '\0' +			|| strlen(options[4].val.v_string) > TOK_MAX_LEN +			|| options[4].val.v_string[2] == '\0'  		) {  			fprintf(stderr, "%s: err: badly-formatted uthash header `%s`\n", -					argv[0], options[4].val.v_string); +				argv[0], options[4].val.v_string);  			exit(EXIT_FAILURE);  		}  	}  	/* check suffix */  	if (options[5].was_seen) { -		if (options[5].val.v_string[i] == '\0') { +		if (options[5].val.v_string[0] == '\0') {  			fprintf(stderr, "%s: err: badly-formatted name suffix ``\n", -					argv[0]); +				argv[0]);  			exit(EXIT_FAILURE);  		}  		for (i = 0; options[5].val.v_string[i] != '\0'; i++) {  			if (!isalnum(options[5].val.v_string[i]) ) {  				fprintf(stderr, "%s: err: badly-formatted name suffix `%s`\n", -						argv[0], options[5].val.v_string); +					argv[0], options[5].val.v_string);  				exit(EXIT_FAILURE);  			}  		} @@ -106,27 +106,27 @@ void opt_parse(int argc, char **argv)  const char* opt_infile_str(void)  {  	return (options[2].was_seen -			? options[2].val.v_string -			: NULL); +		? options[2].val.v_string +		: NULL);  }  const char* opt_outfile_str(void)  {  	return (options[3].was_seen -			? options[3].val.v_string -			: NULL); +		? options[3].val.v_string +		: NULL);  }  const char* opt_header_str(void)  {  	return (options[4].was_seen -			? options[4].val.v_string -			: NULL); +		? options[4].val.v_string +		: NULL);  }  const char* opt_suffix_str(void)  {  	return (options[5].was_seen -			? options[5].val.v_string -			: NULL); +		? options[5].val.v_string +		: NULL);  } diff --git a/src/parse.c b/src/parse.c index 9e0a29b..05524a8 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,4 +1,5 @@  #include "parse.h" +  #include "err.h"  #include <assert.h> @@ -14,7 +15,7 @@ static const char *curfname;  #define ERR_AT(l, c, ...) \  	do { \  		fprintf(stderr, "\x1B[1m%s:%zu:%zu:\x1B[0m ", \ -				curfname, (l), (c)); \ +			curfname, (l), (c)); \  		ERR(__VA_ARGS__); \  	} while (0) @@ -29,23 +30,111 @@ static const char *curfname;  	do { \  		if ((t).type == TOK_END) { \  			ERR_AT((t).line, (t).col, "unexpected end of file (expected %s)", \ -					(m) ); \ +				(m) ); \  		} \  	} while (0)  #define WARN_AT(l, c, ...) \  	do { \  		fprintf(stderr, "\x1B[1m%s:%zu:%zu:\x1B[0m ", \ -				curfname, (l), (c)); \ +			curfname, (l), (c)); \  		WARN(__VA_ARGS__); \  	} while (0) -static struct parse_result_s r; +static struct parse_result_s prs; + +const char *parse_typestrs[] = { +	[PARSE_TYPE_BOOL]    = "bool", +	[PARSE_TYPE_STRING]  = "string", +	[PARSE_TYPE_ID]      = "id", +	[PARSE_TYPE_INT]     = "int", +	[PARSE_TYPE_INTL]    = "intl", +	[PARSE_TYPE_INTLL]   = "intll", +	[PARSE_TYPE_UINT]    = "uint", +	[PARSE_TYPE_UINTL]   = "uintl", +	[PARSE_TYPE_UINTLL]  = "uintll", +	[PARSE_TYPE_FLOAT]   = "float", +	[PARSE_TYPE_DOUBLE]  = "double", +	[PARSE_TYPE_DOUBLEL] = "doublel" +}; + +int parse_typestr_to_type(const char *s) +{ +	if (*s == 'b'  +		&& *(++s) == 'o' && *(++s) == 'o' +		&& *(++s) == 'l' && *(++s) == '\0' +	) { +		return PARSE_TYPE_BOOL; +	} else if (*s == 's' +		&& *(++s) == 't' && *(++s) == 'r' +		&& *(++s) == 'i' && *(++s) == 'n' +		&& *(++s) == 'g' && *(++s) == '\0' +	) { +		return PARSE_TYPE_STRING; +	} else if (*s == 'i') { +		s++; +		if (*s == 'd' && *(++s) == '\0') { +			return PARSE_TYPE_ID; +		} else if (*s == 'n' && *(++s) == 't') { +			s++; +			if (*s == '\0') { +				return PARSE_TYPE_INT; +			} else if (*s == 'l') { +				s++; +				if (*s == '\0') { +					return PARSE_TYPE_INTL; +				} else if (*s == 'l' && *(++s) == '\0') { +					return PARSE_TYPE_INTLL; +				} else { +					return -1; +				} +			} +		} +	} else if (*s == 'u' +		&& *(++s) == 'i' && *(++s) == 'n' +		&& *(++s) == 't' +	) { +		s++; +		if (*s == '\0') { +			return PARSE_TYPE_UINT; +		} else if (*s == 'l') { +			s++; +			if (*s == '\0') { +				return PARSE_TYPE_UINTL; +			} else if (*s == 'l' && *(++s) == '\0') { +				return PARSE_TYPE_UINTLL; +			} else { +				return -1; +			} +		} +	} else if (*s == 'f' +		&& *(++s) == 'l' && *(++s) == 'o' +		&& *(++s) == 'a' && *(++s) == 't' +		&& *(++s) == '\0' +	) { +		return PARSE_TYPE_FLOAT; +	} else if (*s == 'd' +		&& *(++s) == 'o' && *(++s) == 'u' +		&& *(++s) == 'b' && *(++s) == 'l' +		&& *(++s) == 'e' +	) { +		s++; +		if (*s == '\0') { +			return PARSE_TYPE_DOUBLE; +		} else if (*s == 'l' && *(++s) == '\0') { +			return PARSE_TYPE_DOUBLEL; +		} else { +			return -1; +		} +	} + +	return -1; +} -static enum parse_type_e sub_parse_type(void) +static int sub_parse_type(void)  {  	struct tok_s t = tok_get(); -	enum parse_type_e type = PARSE_TYPE_BOOL; +	enum parse_type_e type = PARSE_TYPE_BOOL, tswp;  	size_t l, c;  	l = t.line; @@ -71,41 +160,10 @@ static enum parse_type_e sub_parse_type(void)  			ERR_AT(l, c, "invalid type `%s`", t.val);  	} -	if (!strcmp(t.val, "bool")) -		return type; - -	if (!strcmp(t.val, "string")) -		return type + PARSE_TYPE_STRING; - -	if (!strcmp(t.val, "id")) -		return type + PARSE_TYPE_ID; - -	if (!strcmp(t.val, "int")) -		return type + PARSE_TYPE_INT; - -	if (!strcmp(t.val, "intl")) -		return type + PARSE_TYPE_INTL; - -	if (!strcmp(t.val, "intll")) -		return type + PARSE_TYPE_INTLL; +	tswp = parse_typestr_to_type(t.val); -	if (!strcmp(t.val, "uint")) -		return type + PARSE_TYPE_UINT; - -	if (!strcmp(t.val, "uintl")) -		return type + PARSE_TYPE_UINTL; - -	if (!strcmp(t.val, "uintll")) -		return type + PARSE_TYPE_UINTLL; - -	if (!strcmp(t.val, "float")) -		return type + PARSE_TYPE_FLOAT; - -	if (!strcmp(t.val, "double")) -		return type + PARSE_TYPE_DOUBLE; - -	if (!strcmp(t.val, "doublel")) -		return type + PARSE_TYPE_DOUBLEL; +	if (tswp != -1) +		return type + tswp;  	tok_unget(t); @@ -113,7 +171,7 @@ static enum parse_type_e sub_parse_type(void)  }  static void sub_parse_deftype(size_t line, size_t col, -		enum parse_deftype_e dtype) +	enum parse_deftype_e dtype)  {  	struct tok_s t;  	enum parse_type_e type; @@ -125,68 +183,62 @@ static void sub_parse_deftype(size_t line, size_t col,  		.type = dtype,  		.is_in_array = false,  		.is_in_hash = false, +		.contains_heap = false,  		.member_list_len = 0,  	};  	unsigned i, j; +	/* name */ +  	t = tok_get();  	ERR_END(t, -			(dt.type == PARSE_DEFTYPE_UNION ? "union name" : -				(dt.type == PARSE_DEFTYPE_STRUCT ? -				 "struct name" : "enum name" -				) +		(dt.type == PARSE_DEFTYPE_UNION ? "union name" : +			(dt.type == PARSE_DEFTYPE_STRUCT ? +			 "struct name" : "enum name"  			) +		)  	);  	ERR_LONG(t);  	if (t.type != TOK_ID) { -			ERR_AT(t.line, t.col, "unexpected token `%s` (expected %s name)", -					t.val, -					(dt.type == PARSE_DEFTYPE_UNION ? "union" -						: (dt.type == PARSE_DEFTYPE_STRUCT ? "struct" : "enum") -					) -			); +		ERR_AT(t.line, t.col, "unexpected token `%s` (expected %s name)", +			t.val, +			(dt.type == PARSE_DEFTYPE_UNION ? "union" +				: (dt.type == PARSE_DEFTYPE_STRUCT ? "struct" : "enum") +			) +		);  	} -	if ( -			dt.type != PARSE_DEFTYPE_ENUM && ( -			!strcmp(t.val, "hash") || !strcmp(t.val, "array") || -			!strcmp(t.val, "bool") || -			!strcmp(t.val, "string") || !strcmp(t.val, "id") || -			!strcmp(t.val, "int") || !strcmp(t.val, "intl") || -			!strcmp(t.val, "intll") || -			!strcmp(t.val, "uint") || !strcmp(t.val, "uintl") || -			!strcmp(t.val, "uintll") || -			!strcmp(t.val, "float") || !strcmp(t.val, "double") || -			!strcmp(t.val, "doublell") -			) -	) { +	if (parse_typestr_to_type(t.val) != -1) {  		ERR_AT(dt.line, dt.col, -				"defined type conflicts with builtin type `%s`", t.val); +			"defined type conflicts with builtin type `%s`", t.val);  	} -	HASH_FIND_STR(r.deftypes, t.val, dtp); +	HASH_FIND_STR(prs.deftypes, t.val, dtp);  	if (dtp != NULL) {  		ERR_AT(dt.line, dt.col, -				"type `%s` redefined (previous definition was at line %zu)", -				t.val, dtp->line); +			"type `%s` redefined (previous definition was at line %zu)", +			t.val, dtp->line);  	}  	strcpy(dt.name, t.val); +	/* { */ +  	t = tok_get();  	ERR_END(t, "`{`");  	if (t.type != TOK_LBRACE)  		ERR_AT(t.line, t.col, "unexpected token `%s` (expected `{`)", t.val); +	/* body */ +  	while (true) {  		if (dt.member_list_len == PARSE_DEFTYPE_MAX_LEN) {  			ERR_AT(dt.line, dt.col, "%s %s has too many %s", -					(dt.type == PARSE_DEFTYPE_ENUM ? "enum" :  -						 (dt.type == PARSE_DEFTYPE_UNION ? -						  "union" : "struct") -					), -					dt.name, -					(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members") +				(dt.type == PARSE_DEFTYPE_ENUM ? "enum" : +					(dt.type == PARSE_DEFTYPE_UNION ? "union" : "struct") +				), +				dt.name, +				(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members")  			);  		} @@ -194,12 +246,11 @@ static void sub_parse_deftype(size_t line, size_t col,  		if (t.type == TOK_RBRACE) {  			if (dt.member_list_len < 2) {  				ERR_AT(dt.line, dt.col, "%s `%s` must specify at fewest two %s", -						(dt.type == PARSE_DEFTYPE_ENUM ? "enum" :  -							 (dt.type == PARSE_DEFTYPE_UNION ? -							  "union" : "struct") -						), -						dt.name, -						(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members") +					(dt.type == PARSE_DEFTYPE_ENUM ? "enum" : +						(dt.type == PARSE_DEFTYPE_UNION ? "union" : "struct") +					), +					dt.name, +					(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members")  				);  			} @@ -209,51 +260,55 @@ static void sub_parse_deftype(size_t line, size_t col,  		if (dt.type != PARSE_DEFTYPE_ENUM) {  			tok_unget(t); -			ERR_END(t, "type or `}`"); +			ERR_END(t,  +				(dt.member_list_len < 2 ? "type" : "type or `}`") +			);  			type = sub_parse_type();  			if (type >= PARSE_TYPE_ARRAY_BOOL) {  				ERR_AT(t.line, t.col, -						"defined types may not contain arrays or hashes"); +					"defined types may not contain arrays or hashes");  			} -			/*  */  			if (type == PARSE_TYPE_DEFTYPE) {  				t = tok_get();  				ERR_AT(t.line, t.col, -						"defined types may not contain other defined types"); +					"defined types may not contain other defined types");  			} +			if (type == PARSE_TYPE_STRING || type == PARSE_TYPE_ID) +				dt.contains_heap = true; +  			t = tok_get();  		} -		ERR_END(t, (dt.type == PARSE_DEFTYPE_ENUM ? "id or `}`" -					: "member name")); +		ERR_END(t, +			(dt.type == PARSE_DEFTYPE_ENUM +				? (dt.member_list_len > 1 ? "id or `}`" : "id") +				: "member name" +			) +		);  		ERR_LONG(t);  		if (t.type != TOK_ID) {  			if (t.type == TOK_RBRACE || t.type == TOK_COMMA) {  				ERR_AT(t.line, t.col, "missing %s in %s `%s'", -						(dt.type == PARSE_DEFTYPE_ENUM ? "id" : "member name"), -						(dt.type == PARSE_DEFTYPE_ENUM ? "enum" :  -						 (dt.type == PARSE_DEFTYPE_UNION ? -						  "union" : "struct" -						 ) -						), -						dt.name +					(dt.type == PARSE_DEFTYPE_ENUM ? "id" : "member name"), +					(dt.type == PARSE_DEFTYPE_ENUM ? "enum" : +						(dt.type == PARSE_DEFTYPE_UNION ? "union" : "struct") +					), +					dt.name  				);  			}  			ERR_AT(t.line, t.col, "bad %s `%s` in %s %s", -						(dt.type == PARSE_DEFTYPE_ENUM ? "id" : "member name"), -						t.val, -						(dt.type == PARSE_DEFTYPE_ENUM ? "enum" :  -						 (dt.type == PARSE_DEFTYPE_UNION ? -						  "union" : "struct" -						 ) -						), -						dt.name +				(dt.type == PARSE_DEFTYPE_ENUM ? "id" : "member name"), +				t.val, +				(dt.type == PARSE_DEFTYPE_ENUM ? "enum" : +					(dt.type == PARSE_DEFTYPE_UNION ? "union" : "struct") +				), +				dt.name  			);  		} @@ -270,24 +325,32 @@ static void sub_parse_deftype(size_t line, size_t col,  		for (j = i + 1; j < dt.member_list_len; j++) {  			if (!strcmp(dt.member_name_list[i], dt.member_name_list[j]) ) {  				ERR_AT(dt.line, dt.col, -						"%s `%s` contains multiple %s named `%s`", -						(dt.type == PARSE_DEFTYPE_ENUM ? "enum" :  -						 (dt.type == PARSE_DEFTYPE_UNION ? -						  "union" : "struct") -						), -						dt.name, -						(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members"), -						dt.member_name_list[i] +					"%s `%s` contains multiple %s named `%s`", +					(dt.type == PARSE_DEFTYPE_ENUM ? "enum" : +						(dt.type == PARSE_DEFTYPE_UNION ? "union" : "struct") +					), +					dt.name, +					(dt.type == PARSE_DEFTYPE_ENUM ? "ids" : "members"), +					dt.member_name_list[i]  				);  			} +			if (dt.type == PARSE_DEFTYPE_UNION +				&& dt.member_type_list[i] == dt.member_type_list[j] +			) { +				ERR_AT(dt.line, dt.col, +					"union `%s` contains multiple members of type %s", +					dt.name, +					parse_typestrs[dt.member_type_list[i]] +				); +			}  		}  	}  	TRYALLOC(dtp, 1);  	memcpy(dtp, &dt, sizeof(*dtp)); -	HASH_ADD_STR(r.deftypes, name, dtp); +	HASH_ADD_STR(prs.deftypes, name, dtp);  }  static bool sub_parse_op(void) @@ -306,10 +369,10 @@ static bool sub_parse_op(void)  		return true;  	case TOK_OP_NAMING_SUFFIX: -		if (r.suffix_seen) { +		if (prs.suffix_seen) {  			WARN_AT(t.line, t.col, -					"naming suffix redefined (previous value was `%s`)", -					r.suffix); +				"naming suffix redefined (previous value was `%s`)", +				prs.suffix);  		}  		t = tok_get(); @@ -318,17 +381,17 @@ static bool sub_parse_op(void)  		if (t.type != TOK_ID)  			ERR_AT(t.line, t.col, "invalid naming suffix `%s`", t.val); -		strcpy(r.suffix, t.val); +		strcpy(prs.suffix, t.val); -		r.suffix_seen = true; +		prs.suffix_seen = true;  		return true;  	case TOK_OP_UTHASH_HEADER: -		if (r.header_seen) { +		if (prs.header_seen) {  			WARN_AT(t.line, t.col, -					"uthash header redefined (previous value was %s)", -					r.header); +				"uthash header redefined (previous value was %s)", +				prs.header);  		}  		t = tok_get(); @@ -337,9 +400,9 @@ static bool sub_parse_op(void)  		if (t.type != TOK_HEADER)  			ERR_AT(t.line, t.col, "invalid uthash header `%s`", t.val); -		strcpy(r.header, t.val); +		strcpy(prs.header, t.val); -		r.header_seen = true; +		prs.header_seen = true;  		return true; @@ -376,14 +439,14 @@ static bool sub_parse_rule(void)  	ERR_LONG(t);  	if (t.type != TOK_ID) {  		ERR_AT(t.line, t.col, -				"unexpected token `%s`, (expected variable name)", t.val); +			"unexpected token `%s`, (expected variable name)", t.val);  	} -	HASH_FIND_STR(r.vars, t.val, vp); +	HASH_FIND_STR(prs.vars, t.val, vp);  	if (vp != NULL) {  		ERR_AT(v.line, v.col, -				"`%s` redefined (previous definition was at line %zu)", -				t.val, vp->line); +			"`%s` redefined (previous definition was at line %zu)", +			t.val, vp->line);  	}  	strcpy(v.name, t.val); @@ -396,8 +459,8 @@ static bool sub_parse_rule(void)  	v.type = sub_parse_type();  	if (v.type == PARSE_TYPE_DEFTYPE -			|| v.type == PARSE_TYPE_ARRAY_DEFTYPE -			|| v.type == PARSE_TYPE_HASH_DEFTYPE +		|| v.type == PARSE_TYPE_ARRAY_DEFTYPE +		|| v.type == PARSE_TYPE_HASH_DEFTYPE  	) {  		t = tok_get();  		strcpy(v.deftype_name, t.val); @@ -405,13 +468,13 @@ static bool sub_parse_rule(void)  	TRYALLOC(vp, 1);  	memcpy(vp, &v, sizeof(*vp)); -	HASH_ADD_STR(r.vars, name, vp); +	HASH_ADD_STR(prs.vars, name, vp);  	return true;  }  static int sub_sort_deftypes(struct parse_deftype_s *d1, -		struct parse_deftype_s *d2) +	struct parse_deftype_s *d2)  {  	return strcmp(d1->name, d2->name);  } @@ -421,7 +484,7 @@ static int sub_sort_vars(struct parse_var_s *v1, struct parse_var_s *v2)  	return strcmp(v1->name, v2->name);  } -struct parse_result_s parse(FILE *f, const char *fname) +struct parse_result_s* parse(FILE *f, const char *fname)  {  	size_t i, j;  	struct tok_s t; @@ -429,10 +492,17 @@ struct parse_result_s parse(FILE *f, const char *fname)  	struct parse_var_s *vcur, *vtmp;  	struct parse_deftype_s *dcur, *dtmp; -	r.suffix_seen = false; -	r.header_seen = false; -	r.deftypes = NULL; -	r.vars = NULL; +	struct parse_result_s *pr; + +	assert(f != NULL); +	assert(fname != NULL); + +	TRYALLOC(pr, 1); + +	prs.suffix_seen = false; +	prs.header_seen = false; +	prs.deftypes = NULL; +	prs.vars = NULL;  	curfname = fname;  	tok_reset(f); @@ -448,22 +518,22 @@ struct parse_result_s parse(FILE *f, const char *fname)  	}  	/* err >0 rules */ -	if (r.vars == NULL) { +	if (prs.vars == NULL) {  		fprintf(stderr, "\x1B[1m%s:\x1B[0m ", fname);  		ERR("config must specify at fewest one variable rule");  	}  	/* err undefined type */ -	HASH_ITER(hh, r.vars, vcur, vtmp) { +	HASH_ITER(hh, prs.vars, vcur, vtmp) {  		switch (vcur->type) {  		case PARSE_TYPE_DEFTYPE:  		case PARSE_TYPE_ARRAY_DEFTYPE:  		case PARSE_TYPE_HASH_DEFTYPE: -			HASH_FIND_STR(r.deftypes, vcur->deftype_name, dcur); +			HASH_FIND_STR(prs.deftypes, vcur->deftype_name, dcur);  			if (dcur == NULL) {  				ERR_AT(vcur->line, vcur->col, -						"rule for variable `%s` references undefined type `%s`", -						vcur->name, vcur->deftype_name); +					"rule for variable `%s` references undefined type `%s`", +					vcur->name, vcur->deftype_name);  			}  			dcur->is_used = true;  			if (vcur->type == PARSE_TYPE_ARRAY_DEFTYPE) @@ -477,31 +547,31 @@ struct parse_result_s parse(FILE *f, const char *fname)  	}  	/* warn type use */ -	HASH_ITER(hh, r.deftypes, dcur, dtmp) { +	HASH_ITER(hh, prs.deftypes, dcur, dtmp) {  		if (!dcur->is_used) {  			WARN_AT(dcur->line, dcur->col, -					"type `%s` defined but not used", -					dcur->name); +				"type `%s` defined but not used", +				dcur->name);  		}  	}  	/* warn hash header */ -	HASH_ITER(hh, r.vars, vcur, vtmp) { -		if (vcur->type >= PARSE_TYPE_HASH_BOOL && !r.header_seen) { +	HASH_ITER(hh, prs.vars, vcur, vtmp) { +		if (vcur->type >= PARSE_TYPE_HASH_BOOL && !prs.header_seen) {  			fprintf(stderr, "\x1B[1m%s:\x1B[0m ", fname);  			WARN("no uthash location header specified. using `<uthash.h>`"); -			strcpy(r.header, "<uthash.h>"); +			strcpy(prs.header, "<uthash.h>");  			break;  		}  	}  	/* warn/err suffix */ -	if (!r.suffix_seen) { +	if (!prs.suffix_seen) {  		j = 0;  		for (i = strlen(fname); i > 0 && fname[i] != '/' -				&& fname[i] != '\\'; i--); +			&& fname[i] != '\\'; i--);  		j = i + (fname[i] == '/' || fname[i] == '\\'); @@ -510,45 +580,48 @@ struct parse_result_s parse(FILE *f, const char *fname)  				fprintf(stderr, "\x1B[1m%s:\x1B[0m ", fname);  				ERR("no function suffix specified, and could not generate one");  			} -			r.suffix[i - j] = fname[i]; +			prs.suffix[i - j] = fname[i];  		} -		r.suffix[i - j] = '\0'; +		prs.suffix[i - j] = '\0'; -		if (r.suffix[0] == '\0') { +		if (prs.suffix[0] == '\0') {  			fprintf(stderr, "\x1B[1m%s:\x1B[0m ", fname);  			ERR("no function suffix specified, and could not generate one");  		}  		fprintf(stderr, "\x1B[1m%s:\x1B[0m ", fname); -		WARN("no function suffix specified. using `%s`...", r.suffix); +		WARN("no function suffix specified. using `%s`...", prs.suffix);  	} -	HASH_SORT(r.deftypes, sub_sort_deftypes); -	HASH_SORT(r.vars, sub_sort_vars); +	HASH_SORT(prs.deftypes, sub_sort_deftypes); +	HASH_SORT(prs.vars, sub_sort_vars); + +	memcpy(pr, &prs, sizeof(struct parse_result_s)); -	return r; +	return pr;  } -void parse_result_wipe(struct parse_result_s *r) +void parse_result_free(struct parse_result_s *pr)  {  	struct parse_var_s *vcur, *vtmp;  	struct parse_deftype_s *dcur, *dtmp; -	assert(r != NULL); +	assert(pr != NULL); -	if (r->vars != NULL) { -		HASH_ITER(hh, r->vars, vcur, vtmp) { -			HASH_DEL(r->vars, vcur); +	if (pr->vars != NULL) { +		HASH_ITER(hh, pr->vars, vcur, vtmp) { +			HASH_DEL(pr->vars, vcur);  			free(vcur);  		}  	} -	if (r->deftypes != NULL) { -		HASH_ITER(hh, r->deftypes, dcur, dtmp) { -			HASH_DEL(r->deftypes, dcur); +	if (pr->deftypes != NULL) { +		HASH_ITER(hh, pr->deftypes, dcur, dtmp) { +			HASH_DEL(pr->deftypes, dcur);  			free(dcur);  		}  	} +	free(pr);  } diff --git a/src/parse.h b/src/parse.h index 4f2645d..1ab2a19 100644 --- a/src/parse.h +++ b/src/parse.h @@ -7,7 +7,7 @@  #include <stdbool.h> -#define PARSE_DEFTYPE_MAX_LEN 32 +#define PARSE_DEFTYPE_MAX_LEN 128  /* very important these stay in order.   * things like ">= PARSE_TYPE_ARRAY_BOOL" used */ @@ -69,6 +69,7 @@ struct parse_deftype_s {  	bool is_used;  	bool is_in_array;  	bool is_in_hash; +	bool contains_heap;  	unsigned member_list_len;  	enum parse_type_e member_type_list[PARSE_DEFTYPE_MAX_LEN];  	char member_name_list[PARSE_DEFTYPE_MAX_LEN][TOK_MAX_LEN]; @@ -94,8 +95,12 @@ struct parse_result_s {  	struct parse_var_s *vars;  }; -struct parse_result_s parse(FILE *f, const char *fname); +extern const char *parse_typestrs[]; -void parse_result_wipe(struct parse_result_s *r); +int parse_typestr_to_type(const char *s); + +struct parse_result_s* parse(FILE *f, const char *fname); + +void parse_result_free(struct parse_result_s *pr);  #endif @@ -236,6 +236,8 @@ static void sub_match_header(void)  void tok_reset(FILE *f)  { +	assert(f != NULL); +  	curf = f;  	curtok.line = 1;  	curtok.col = 1; @@ -252,7 +254,7 @@ struct tok_s tok_get(void)  	if (unget) {  		unget = false;  		return curtok; -	}  +	}  	curtok.col += vlen;  	vlen = 0; | 
