started adding simple xli validation
This commit is contained in:
		| @ -156,6 +156,7 @@ int qse_gettime (qse_ntime_t* t) | ||||
| 	struct timeval tv; | ||||
| 	int n; | ||||
|  | ||||
| 	/* TODO: consider using clock_gettime() if it's avaialble.. -lrt may be needed */ | ||||
| 	n = QSE_GETTIMEOFDAY (&tv, QSE_NULL); | ||||
| 	if (n == -1) return -1; | ||||
|  | ||||
| @ -227,13 +228,12 @@ int qse_settime (const qse_ntime_t* t) | ||||
| 	tv.tv_usec = QSE_NSEC_TO_USEC(t->nsec); | ||||
|  | ||||
| /* | ||||
| #if defined CLOCK_REALTIME && HAVE_CLOCK_SETTIME | ||||
| #if defined(CLOCK_REALTIME) && defined(HAVE_CLOCK_SETTIME) | ||||
| 	{ | ||||
| 		int r = clock_settime (CLOCK_REALTIME, ts); | ||||
| 		if (r == 0 || errno == EPERM) | ||||
| 		return r; | ||||
| 		if (r == 0 || errno == EPERM) return r; | ||||
| 	} | ||||
| #elif HAVE_STIME | ||||
| #elif defined(HAVE_STIME) | ||||
| 	return stime (&ts->tv_sec); | ||||
| #else | ||||
| */ | ||||
|  | ||||
| @ -48,7 +48,10 @@ const qse_char_t* qse_xli_dflerrstr ( | ||||
| 		QSE_T("'@include' not followed by a string"), | ||||
| 		QSE_T("invalid character '${0}'"), | ||||
| 		QSE_T("'${0}' not recognized"), | ||||
| 		QSE_T("@ not followed by a valid word") | ||||
| 		QSE_T("@ not followed by a valid word"), | ||||
| 		QSE_T("illegal key '${0}'"), | ||||
| 		QSE_T("illegal value for '${0}'"), | ||||
| 		QSE_T("too many string segments for '${0}'") | ||||
| 	}; | ||||
|  | ||||
| 	return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))? | ||||
|  | ||||
| @ -594,10 +594,17 @@ static int get_token (qse_xli_t* xli) | ||||
|  | ||||
| static int read_pair (qse_xli_t* xli) | ||||
| { | ||||
| 	qse_char_t* key = QSE_NULL; | ||||
| 	qse_char_t* name = QSE_NULL; | ||||
| 	qse_xstr_t key; | ||||
| 	qse_xli_loc_t kloc; | ||||
| 	qse_char_t* name; | ||||
| 	qse_xli_pair_t* pair; | ||||
| 	qse_xli_list_t* parlist; | ||||
| 	qse_size_t dotted_curkey_len; | ||||
| 	qse_xli_scm_t* scm = QSE_NULL; | ||||
|  | ||||
| 	key.ptr = QSE_NULL; | ||||
| 	name = QSE_NULL; | ||||
| 	dotted_curkey_len = (qse_size_t)-1; | ||||
|  | ||||
| 	parlist = xli->parlink->list; | ||||
|  | ||||
| @ -606,6 +613,7 @@ static int read_pair (qse_xli_t* xli) | ||||
| 		qse_xli_atom_t* atom; | ||||
|  | ||||
| 		/* find any key conflicts in the current scope */ | ||||
| 		/* TODO: optimization. no sequential search */ | ||||
| 		atom = parlist->tail; | ||||
| 		while (atom) | ||||
| 		{ | ||||
| @ -620,18 +628,47 @@ static int read_pair (qse_xli_t* xli) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	key = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr); | ||||
| 	if (key == QSE_NULL)  | ||||
| 	kloc = xli->tok.loc; | ||||
| 	key.len = QSE_STR_LEN(xli->tok.name); | ||||
| 	key.ptr = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr); | ||||
| 	if (key.ptr == QSE_NULL)  | ||||
| 	{ | ||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | ||||
| 		goto oops; | ||||
| 	} | ||||
|  | ||||
| 	dotted_curkey_len = QSE_STR_LEN (xli->dotted_curkey); | ||||
| 	if ((dotted_curkey_len > 0 && qse_str_cat (xli->dotted_curkey, QSE_T(".")) == (qse_size_t)-1) || | ||||
| 	    qse_str_cat (xli->dotted_curkey, key.ptr) == (qse_size_t)-1) | ||||
| 	{ | ||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | ||||
| 		goto oops; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	if (xli->opt.trait & QSE_XLI_VALIDATE)  | ||||
| 	{ | ||||
| 		qse_rbt_pair_t* pair; | ||||
|  | ||||
| 		pair = qse_rbt_search (xli->schema, QSE_STR_PTR(xli->dotted_curkey), QSE_STR_LEN(xli->dotted_curkey)); | ||||
| 		if (pair == QSE_NULL) | ||||
| 		{ | ||||
| 			qse_xli_seterror (xli, QSE_XLI_EILKEY, (const qse_cstr_t*)&key, &kloc); | ||||
| 			goto oops;	 | ||||
| 		} | ||||
|  | ||||
| 		scm = (qse_xli_scm_t*)QSE_RBT_VPTR(pair); | ||||
|  | ||||
| 		if (scm->flags & QSE_XLI_SCM_KEY_NODUP) | ||||
| 		{ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	xli->tok_status |= TOK_STATUS_ENABLE_NSTR; | ||||
|  | ||||
| 	if (get_token (xli) <= -1) goto oops; | ||||
|  | ||||
| 	if  (xli->opt.trait & QSE_XLI_KEYALIAS) | ||||
| 	if (xli->opt.trait & QSE_XLI_KEYALIAS) | ||||
| 	{ | ||||
| 		/* the name part must be unique for the same key(s) */ | ||||
| 		if (MATCH (xli, TOK_IDENT) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_SQSTR) || MATCH(xli, TOK_NSTR)) | ||||
| @ -643,7 +680,7 @@ static int read_pair (qse_xli_t* xli) | ||||
| 			{ | ||||
| 				if (atom->type == QSE_XLI_PAIR && | ||||
| 				    ((qse_xli_pair_t*)atom)->alias &&  | ||||
| 				    qse_strcmp (((qse_xli_pair_t*)atom)->key, key) == 0 && | ||||
| 				    qse_strcmp (((qse_xli_pair_t*)atom)->key, key.ptr) == 0 && | ||||
| 				    qse_strcmp (((qse_xli_pair_t*)atom)->alias, QSE_STR_PTR(xli->tok.name)) == 0) | ||||
| 				{ | ||||
| 					qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc); | ||||
| @ -670,11 +707,20 @@ static int read_pair (qse_xli_t* xli) | ||||
| 		if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH(xli, TOK_NSTR) || MATCH (xli, TOK_IDENT)) | ||||
| 		{ | ||||
| 			qse_xli_str_t* curstrseg; | ||||
| 			qse_size_t segcount = 0; | ||||
|  | ||||
| 			if (scm && !(scm->flags & QSE_XLI_SCM_VAL_STR)) | ||||
| 			{ | ||||
| 				/* check the value type */ | ||||
| 				qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc); | ||||
| 				goto oops;	 | ||||
| 			} | ||||
|  | ||||
| 			/* add a new pair with the initial string segment */ | ||||
| 			pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key, name, QSE_STR_CSTR(xli->tok.name)); | ||||
| 			pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key.ptr, name, QSE_STR_CSTR(xli->tok.name)); | ||||
| 			if (pair == QSE_NULL) goto oops; | ||||
|  | ||||
| 			segcount++; | ||||
| 			curstrseg = (qse_xli_str_t*)pair->val; | ||||
|  | ||||
| 			if (get_token (xli) <= -1) goto oops; | ||||
| @ -691,11 +737,11 @@ static int read_pair (qse_xli_t* xli) | ||||
| 						goto oops; | ||||
| 					} | ||||
|  | ||||
|  | ||||
| 					/* add an additional segment to the string */ | ||||
| 					curstrseg = qse_xli_addsegtostr (xli, curstrseg, QSE_STR_CSTR(xli->tok.name)); | ||||
| 					if (curstrseg == QSE_NULL) goto oops; | ||||
|  | ||||
| 					segcount++; | ||||
| 					if (get_token (xli) <= -1) goto oops; /* skip the value */ | ||||
| 				} | ||||
| 				while (MATCH (xli, TOK_COMMA)); | ||||
| @ -708,6 +754,13 @@ static int read_pair (qse_xli_t* xli) | ||||
| 				goto oops; | ||||
| 			} | ||||
|  | ||||
| 			if (scm && (segcount < scm->str_minseg || segcount > scm->str_maxseg)) | ||||
| 			{ | ||||
| 				/* too many string segments for the key */ | ||||
| 				qse_xli_seterror (xli, QSE_XLI_ESTRSEG, (const qse_cstr_t*)&key, &kloc); | ||||
| 				goto oops;	 | ||||
| 			} | ||||
|  | ||||
| 			if (get_token (xli) <= -1) goto oops; | ||||
| 		} | ||||
| 		else | ||||
| @ -716,13 +769,23 @@ static int read_pair (qse_xli_t* xli) | ||||
| 			goto oops;	 | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		/* TODO: check against schema */ | ||||
|  | ||||
| 	} | ||||
| 	else if (MATCH (xli, TOK_LBRACE)) | ||||
| 	{ | ||||
| 		if (scm && !(scm->flags & QSE_XLI_SCM_VAL_LIST)) | ||||
| 		{ | ||||
| 			/* check the value type */ | ||||
| 			qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc); | ||||
| 			goto oops;	 | ||||
| 		} | ||||
|  | ||||
| 		xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR; | ||||
|  | ||||
| 		/* insert a pair with an empty list */ | ||||
| 		pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key, name); | ||||
| 		pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key.ptr, name); | ||||
| 		if (pair == QSE_NULL) goto oops; | ||||
| 	 | ||||
| 		if (read_list (xli, (qse_xli_list_t*)pair->val) <= -1) goto oops; | ||||
| @ -741,17 +804,28 @@ static int read_pair (qse_xli_t* xli) | ||||
| 			/* skip the semicolon */ | ||||
| 			if (get_token (xli) <= -1) goto oops; | ||||
| 		} | ||||
|  | ||||
| 		/* TODO: check against schema */ | ||||
| 	} | ||||
| 	else if (MATCH (xli, TOK_SEMICOLON)) | ||||
| 	{ | ||||
| 		if (scm && !(scm->flags & QSE_XLI_SCM_VAL_NIL)) | ||||
| 		{ | ||||
| 			/* check the value type */ | ||||
| 			qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc); | ||||
| 			goto oops;	 | ||||
| 		} | ||||
|  | ||||
| 		xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR; | ||||
|  | ||||
| 		/* no value has been specified for the pair */ | ||||
| 		pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key, name, (qse_xli_val_t*)&xli->xnil); | ||||
| 		pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key.ptr, name, (qse_xli_val_t*)&xli->xnil); | ||||
| 		if (pair == QSE_NULL) goto oops; | ||||
|  | ||||
| 		/* skip the semicolon */ | ||||
| 		if (get_token (xli) <= -1) goto oops; | ||||
|  | ||||
| 		/* TODO: check against schema */ | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -760,13 +834,16 @@ static int read_pair (qse_xli_t* xli) | ||||
| 	} | ||||
|  | ||||
| 	QSE_MMGR_FREE (xli->mmgr, name); | ||||
| 	QSE_MMGR_FREE (xli->mmgr, key); | ||||
| 	QSE_MMGR_FREE (xli->mmgr, key.ptr); | ||||
| 	qse_str_setlen (xli->dotted_curkey, dotted_curkey_len); | ||||
| 	return 0; | ||||
| 	 | ||||
| oops: | ||||
| 	xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR; | ||||
| 	if (name) QSE_MMGR_FREE (xli->mmgr, name); | ||||
| 	if (key) QSE_MMGR_FREE (xli->mmgr, key); | ||||
| 	if (key.ptr) QSE_MMGR_FREE (xli->mmgr, key.ptr); | ||||
| 	if (dotted_curkey_len != (qse_size_t)-1) | ||||
| 		qse_str_setlen (xli->dotted_curkey, dotted_curkey_len); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| @ -894,6 +971,8 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io) | ||||
| 	qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);  | ||||
| 	qse_xli_clearrionames (xli); | ||||
|  | ||||
| 	QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0); | ||||
|  | ||||
| 	n = xli->rio.impl (xli, QSE_XLI_IO_OPEN, xli->rio.inp, QSE_NULL, 0); | ||||
| 	if (n <= -1) | ||||
| 	{ | ||||
| @ -915,6 +994,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io) | ||||
|  | ||||
| 	QSE_ASSERT (xli->rio.inp == &xli->rio.top); | ||||
| 	close_current_stream (xli); | ||||
| 	qse_str_clear (xli->tok.name); | ||||
| 	return 0; | ||||
|  | ||||
| oops: | ||||
| @ -935,5 +1015,6 @@ oops: | ||||
| 	} | ||||
| 	 | ||||
| 	close_current_stream (xli); | ||||
| 	qse_str_clear (xli->tok.name); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| @ -56,26 +56,35 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr) | ||||
| 	xli->mmgr = mmgr; | ||||
| 	xli->errstr = qse_xli_dflerrstr; | ||||
|  | ||||
| 	xli->dotted_curkey = qse_str_open (mmgr, 0, 128); | ||||
| 	if (xli->dotted_curkey == QSE_NULL) goto oops; | ||||
|  | ||||
| 	xli->tok.name = qse_str_open (mmgr, 0, 128); | ||||
| 	if (xli->tok.name == QSE_NULL) goto oops; | ||||
|  | ||||
| 	xli->schema = qse_rbt_open (mmgr, 0, QSE_SIZEOF(qse_char_t), 1); | ||||
| 	if (xli->schema == QSE_NULL) goto oops; | ||||
|  | ||||
| 	xli->root.type = QSE_XLI_LIST; | ||||
| 	xli->xnil.type = QSE_XLI_NIL; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| oops: | ||||
| 	qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | ||||
| 	if (xli->schema) qse_rbt_close (xli->schema); | ||||
| 	if (xli->tok.name) qse_str_close (xli->tok.name); | ||||
| 	if (xli->dotted_curkey) qse_str_close (xli->dotted_curkey); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void qse_xli_fini (qse_xli_t* xli) | ||||
| { | ||||
| 	qse_xli_clear (xli); | ||||
| 	qse_str_close (xli->tok.name); | ||||
|  | ||||
| 	qse_xli_clearrionames (xli); | ||||
| 	qse_xli_clearwionames (xli); | ||||
| 	qse_rbt_close (xli->schema); | ||||
| 	qse_str_close (xli->tok.name); | ||||
| 	qse_str_close (xli->dotted_curkey); | ||||
| } | ||||
|  | ||||
| qse_mmgr_t* qse_xli_getmmgr (qse_xli_t* xli) | ||||
| @ -156,13 +165,6 @@ void qse_xli_freemem (qse_xli_t* xli, void* ptr) | ||||
| } | ||||
| /* ------------------------------------------------------ */ | ||||
|  | ||||
| qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli) | ||||
| { | ||||
| 	return &xli->root; | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------ */ | ||||
|  | ||||
| static void insert_atom ( | ||||
| 	qse_xli_t* xli, qse_xli_list_t* parent,  | ||||
| 	qse_xli_atom_t* peer, qse_xli_atom_t* atom) | ||||
| @ -375,9 +377,31 @@ static void free_list (qse_xli_t* xli, qse_xli_list_t* list) | ||||
| void qse_xli_clear (qse_xli_t* xli) | ||||
| { | ||||
| 	free_list (xli, &xli->root); | ||||
| 	qse_rbt_clear (xli->schema); | ||||
|  | ||||
| 	qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL); | ||||
| 	qse_xli_clearrionames (xli); | ||||
| 	qse_xli_clearwionames (xli); | ||||
| } | ||||
|  | ||||
| static qse_size_t count_pair_byalias ( | ||||
| qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli) | ||||
| { | ||||
| 	return &xli->root; | ||||
| } | ||||
|  | ||||
| void qse_xli_clearroot (qse_xli_t* xli) | ||||
| { | ||||
| 	free_list (xli, &xli->root); | ||||
| } | ||||
|  | ||||
| void qse_xli_clearschema (qse_xli_t* xli) | ||||
| { | ||||
| 	qse_rbt_clear (xli->schema); | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------ */ | ||||
|  | ||||
| static qse_size_t count_pairs_by_key_and_alias ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||
| 	const qse_cstr_t* key, const qse_cstr_t* alias) | ||||
| { | ||||
| @ -404,7 +428,7 @@ static qse_size_t count_pair_byalias ( | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| static qse_xli_pair_t* find_pair_byalias ( | ||||
| static qse_xli_pair_t* find_pair_by_key_and_alias ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||
| 	const qse_cstr_t* key, const qse_cstr_t* alias) | ||||
| { | ||||
| @ -430,7 +454,7 @@ static qse_xli_pair_t* find_pair_byalias ( | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| static qse_xli_pair_t* find_pair_byindex ( | ||||
| static qse_xli_pair_t* find_pair_by_key_and_index ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||
| 	const qse_cstr_t* key, qse_size_t index) | ||||
| { | ||||
| @ -457,7 +481,7 @@ static qse_xli_pair_t* find_pair_byindex ( | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias) | ||||
| qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name) | ||||
| { | ||||
| 	const qse_char_t* ptr; | ||||
| 	const qse_xli_list_t* curlist; | ||||
| @ -466,11 +490,11 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l | ||||
|  | ||||
| 	curlist = list? list: &xli->root; | ||||
|  | ||||
| 	ptr = alias; | ||||
| 	ptr = dotted_name; | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		seg.ptr = ptr; | ||||
| 		while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++; | ||||
| 		while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++; | ||||
| 		if (ptr == seg.ptr) goto inval; | ||||
| 		seg.len = ptr - seg.ptr; | ||||
|  | ||||
| @ -479,14 +503,14 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l | ||||
| 			/* check the type of curlist. this check is needed | ||||
| 			 * because of the unconditional switching at the bottom of the  | ||||
| 			 * this loop. this implementation strategy has been chosen | ||||
| 			 * to provide the segment alias easily. */ | ||||
| 			 * to provide the segment name easily. */ | ||||
| 			goto noent; | ||||
| 		} | ||||
|  | ||||
| 		if (*ptr == QSE_T('[')) | ||||
| 		{ | ||||
| 			/*  index is specified */ | ||||
| 			ptr++; | ||||
| 			ptr++; /* skip [ */ | ||||
|  | ||||
| 			if (QSE_ISDIGIT(*ptr)) | ||||
| 			{ | ||||
| @ -501,50 +525,13 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l | ||||
|  | ||||
| 				if (*ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byindex (xli, curlist, &seg, index); | ||||
| 				pair = find_pair_by_key_and_index (xli, curlist, &seg, index); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += count + 2; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (QSE_ISALPHA(*ptr)) | ||||
| 			{ | ||||
| 				/* word index */ | ||||
| 				qse_cstr_t idx; | ||||
|  | ||||
| 				idx.ptr = ptr; | ||||
| 				do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-')); | ||||
| 				idx.len = ptr - idx.ptr; | ||||
| 	 | ||||
| 				if (*ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byalias (xli, curlist, &seg, &idx); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += idx.len + 2; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"')) | ||||
| 			{ | ||||
| 				qse_cstr_t idx; | ||||
| 				qse_char_t cc = *ptr++; | ||||
|  | ||||
| 				idx.ptr = ptr; | ||||
| 				do ptr++; while (*ptr != cc && *ptr != QSE_T('\0')); | ||||
| 				idx.len = ptr - idx.ptr; | ||||
| 		 | ||||
| 				if (*ptr != cc) goto inval; | ||||
| 				if (*++ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byalias (xli, curlist, &seg, &idx); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += idx.len + 4; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else goto inval; | ||||
|  | ||||
| 			ptr++;  /* skip ] */ | ||||
| @ -552,9 +539,37 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l | ||||
| 			if (*ptr == QSE_T('\0')) break; /* no more segments */ | ||||
| 			else if (*ptr != QSE_T('.')) goto inval; | ||||
| 		} | ||||
| 		else if (*ptr == QSE_T('{')) | ||||
| 		{ | ||||
| 			/* word index - alias */ | ||||
| 			qse_cstr_t idx; | ||||
|  | ||||
| 			ptr++; /* skip { */ | ||||
|  | ||||
| 			/* no escaping is supported for the alias inside {}. | ||||
| 			 * so if your alias contains these characters (in a quoted string),  | ||||
| 			 * you can't reference it using a dotted key name. */ | ||||
| 			idx.ptr = ptr; | ||||
| 			while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++; | ||||
| 			idx.len = ptr - idx.ptr; | ||||
|  | ||||
| 			if (*ptr != QSE_T('}') || idx.len == 0) goto inval; | ||||
|  | ||||
| 			pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx); | ||||
| 			if (pair == QSE_NULL)  | ||||
| 			{ | ||||
| 				seg.len += idx.len + 2; /* adjustment for error message */ | ||||
| 				goto noent; | ||||
| 			} | ||||
|  | ||||
| 			ptr++;  /* skip } */ | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0')) break; /* no more segments */ | ||||
| 			else if (*ptr != QSE_T('.')) goto inval; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL); | ||||
| 			pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL); | ||||
| 			if (pair == QSE_NULL) goto noent; | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0')) break; /* no more segments */ | ||||
| @ -581,7 +596,7 @@ noent: | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias) | ||||
| qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name) | ||||
| { | ||||
| 	const qse_char_t* ptr; | ||||
| 	const qse_xli_list_t* curlist; | ||||
| @ -590,11 +605,11 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis | ||||
|  | ||||
| 	curlist = list? list: &xli->root; | ||||
|  | ||||
| 	ptr = alias; | ||||
| 	ptr = dotted_name; | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		seg.ptr = ptr; | ||||
| 		while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++; | ||||
| 		while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++; | ||||
| 		if (ptr == seg.ptr) goto inval; | ||||
| 		seg.len = ptr - seg.ptr; | ||||
|  | ||||
| @ -603,14 +618,14 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis | ||||
| 			/* check the type of curlist. this check is needed | ||||
| 			 * because of the unconditional switching at the bottom of the  | ||||
| 			 * this loop. this implementation strategy has been chosen | ||||
| 			 * to provide the segment alias easily. */ | ||||
| 			 * to provide the segment name easily. */ | ||||
| 			goto noent; | ||||
| 		} | ||||
|  | ||||
| 		if (*ptr == QSE_T('[')) | ||||
| 		{ | ||||
| 			/*  index is specified */ | ||||
| 			ptr++; | ||||
| 			ptr++; /* skip [ */ | ||||
|  | ||||
| 			if (QSE_ISDIGIT(*ptr)) | ||||
| 			{ | ||||
| @ -625,50 +640,13 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis | ||||
|  | ||||
| 				if (*ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byindex (xli, curlist, &seg, index); | ||||
| 				pair = find_pair_by_key_and_index (xli, curlist, &seg, index); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += count + 2; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (QSE_ISALPHA(*ptr)) | ||||
| 			{ | ||||
| 				/* word index */ | ||||
| 				qse_cstr_t idx; | ||||
|  | ||||
| 				idx.ptr = ptr; | ||||
| 				do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-')); | ||||
| 				idx.len = ptr - idx.ptr; | ||||
| 	 | ||||
| 				if (*ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byalias (xli, curlist, &seg, &idx); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += idx.len + 2; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"')) | ||||
| 			{ | ||||
| 				qse_cstr_t idx; | ||||
| 				qse_char_t cc = *ptr++; | ||||
|  | ||||
| 				idx.ptr = ptr; | ||||
| 				do ptr++; while (*ptr != cc && *ptr != QSE_T('\0')); | ||||
| 				idx.len = ptr - idx.ptr; | ||||
| 		 | ||||
| 				if (*ptr != cc) goto inval; | ||||
| 				if (*++ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byalias (xli, curlist, &seg, &idx); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += idx.len + 4; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else goto inval; | ||||
|  | ||||
| 			ptr++;  /* skip ] */ | ||||
| @ -680,18 +658,47 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis | ||||
| 			} | ||||
| 			else if (*ptr != QSE_T('.')) goto inval; | ||||
| 		} | ||||
| 		else if (*ptr == QSE_T('{')) | ||||
| 		{ | ||||
| 			/* word index - alias */ | ||||
| 			qse_cstr_t idx; | ||||
|  | ||||
| 			ptr++; /* skip { */ | ||||
|  | ||||
| 			idx.ptr = ptr; | ||||
| 			while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++; | ||||
| 			idx.len = ptr - idx.ptr; | ||||
|  | ||||
| 			if (*ptr != QSE_T('}') || idx.len == 0) goto inval; | ||||
|  | ||||
| 			pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx); | ||||
| 			if (pair == QSE_NULL)  | ||||
| 			{ | ||||
| 				seg.len += idx.len + 2; /* adjustment for error message */ | ||||
| 				goto noent; | ||||
| 			} | ||||
|  | ||||
| 			ptr++;  /* skip } */ | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0'))  | ||||
| 			{ | ||||
| 				/* no more segments */ | ||||
| 				return 1; | ||||
| 			} | ||||
| 			else if (*ptr != QSE_T('.')) goto inval; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL); | ||||
| 			pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL); | ||||
| 			if (pair == QSE_NULL) goto noent; | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0'))  | ||||
| 			{ | ||||
| 				return count_pair_byalias (xli, curlist, &seg, QSE_NULL); | ||||
| 				return count_pairs_by_key_and_alias (xli, curlist, &seg, QSE_NULL); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL); | ||||
| 				pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL); | ||||
| 				if (pair == QSE_NULL) goto noent; | ||||
| 			} | ||||
| 		} | ||||
| @ -702,7 +709,7 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis | ||||
|  | ||||
| 		/* switch to the value regardless of its type. | ||||
| 		 * check if it is a list in the beginning of the loop | ||||
| 		 * just after having gotten the next segment alias */ | ||||
| 		 * just after having gotten the next segment name */ | ||||
| 		curlist = (qse_xli_list_t*)pair->val; | ||||
| 	} | ||||
|  | ||||
| @ -760,3 +767,25 @@ qse_char_t* qse_xli_dupflatstr (qse_xli_t* xli, qse_xli_str_t* str, qse_size_t* | ||||
|  | ||||
| 	return tmp; | ||||
| } | ||||
|  | ||||
|  | ||||
| int qse_xli_setschema (qse_xli_t* xli, const qse_char_t* dotted_name, const qse_xli_scm_t* scm) | ||||
| { | ||||
| 	int tmp; | ||||
|  | ||||
| 	tmp = scm->flags & (QSE_XLI_SCM_VAL_LIST | QSE_XLI_SCM_VAL_STR | QSE_XLI_SCM_VAL_NIL); | ||||
| 	if (tmp != QSE_XLI_SCM_VAL_LIST && tmp != QSE_XLI_SCM_VAL_STR && tmp != QSE_XLI_SCM_VAL_NIL) | ||||
| 	{ | ||||
| 		/* VAL_LIST, VAL_STR, VAL_NIL can't co-exist */ | ||||
| 		qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (qse_rbt_upsert (xli->schema, dotted_name, qse_strlen(dotted_name), scm, QSE_SIZEOF(scm)) == QSE_NULL) | ||||
| 	{ | ||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
|  | ||||
| #include <qse/xli/xli.h> | ||||
| #include <qse/cmn/str.h> | ||||
| #include <qse/cmn/rbt.h> | ||||
| #include "../cmn/mem.h" | ||||
|  | ||||
| typedef struct qse_xli_tok_t qse_xli_tok_t; | ||||
| @ -60,7 +61,11 @@ struct qse_xli_t | ||||
|  | ||||
| 	qse_xli_nil_t xnil; | ||||
| 	qse_xli_list_t root; | ||||
| 	qse_xli_list_link_t* parlink; | ||||
|  | ||||
| 	qse_xli_list_link_t* parlink; /* link that points to the list being read currently */ | ||||
|  | ||||
| 	qse_str_t* dotted_curkey; | ||||
| 	qse_rbt_t* schema; | ||||
|  | ||||
| 	qse_xli_tok_t tok; | ||||
| 	int tok_status; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user