added qse_xli_getnumpairsbyname()
This commit is contained in:
		| @ -350,6 +350,33 @@ void qse_xli_clear (qse_xli_t* xli) | ||||
| 	free_list (xli, &xli->root); | ||||
| } | ||||
|  | ||||
| static qse_size_t count_pair_byname ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||
| 	const qse_cstr_t* key, const qse_cstr_t* name) | ||||
| { | ||||
| 	qse_xli_atom_t* p; | ||||
| 	qse_size_t count = 0; | ||||
|  | ||||
| 	/* TODO: speed up. no linear search */ | ||||
| 	p = list->head; | ||||
| 	while (p) | ||||
| 	{ | ||||
| 		if (p->type == QSE_XLI_PAIR) | ||||
| 		{ | ||||
| 			qse_xli_pair_t* pair = (qse_xli_pair_t*)p; | ||||
| 			if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)  | ||||
| 			{ | ||||
| 				if (name == QSE_NULL ||  | ||||
| 				    qse_strxcmp (name->ptr, name->len, pair->name) == 0) count++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		p = p->next; | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| static qse_xli_pair_t* find_pair_byname ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||
| 	const qse_cstr_t* key, const qse_cstr_t* name) | ||||
| @ -403,8 +430,7 @@ static qse_xli_pair_t* find_pair_byindex ( | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| qse_xli_pair_t* qse_xli_findpairbyname ( | ||||
| 	qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name) | ||||
| qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name) | ||||
| { | ||||
| 	const qse_char_t* ptr; | ||||
| 	qse_cstr_t seg; | ||||
| @ -417,9 +443,7 @@ qse_xli_pair_t* qse_xli_findpairbyname ( | ||||
| 	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++; | ||||
| 		if (ptr == seg.ptr) goto inval; | ||||
| 		seg.len = ptr - seg.ptr; | ||||
|  | ||||
| @ -530,3 +554,139 @@ noent: | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name) | ||||
| { | ||||
| 	const qse_char_t* ptr; | ||||
| 	qse_cstr_t seg; | ||||
| 	qse_xli_list_t* curlist; | ||||
| 	qse_xli_pair_t* pair; | ||||
|  | ||||
| 	curlist = list? list: &xli->root; | ||||
|  | ||||
| 	ptr = name; | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		seg.ptr = ptr; | ||||
| 		while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++; | ||||
| 		if (ptr == seg.ptr) goto inval; | ||||
| 		seg.len = ptr - seg.ptr; | ||||
|  | ||||
| 		if (curlist->type != QSE_XLI_LIST)  | ||||
| 		{ | ||||
| 			/* 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 name easily. */ | ||||
| 			goto noent; | ||||
| 		} | ||||
|  | ||||
| 		if (*ptr == QSE_T('[')) | ||||
| 		{ | ||||
| 			/*  index is specified */ | ||||
| 			ptr++; | ||||
|  | ||||
| 			if (QSE_ISDIGIT(*ptr)) | ||||
| 			{ | ||||
| 				/* numeric index */ | ||||
| 				qse_size_t index = 0, count = 0; | ||||
| 				do  | ||||
| 				{ | ||||
| 					index = index * 10 + (*ptr++ - QSE_T('0'));  | ||||
| 					count++; | ||||
| 				} | ||||
| 				while (QSE_ISDIGIT(*ptr)); | ||||
|  | ||||
| 				if (*ptr != QSE_T(']')) goto inval; | ||||
|  | ||||
| 				pair = find_pair_byindex (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_byname (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_byname (xli, curlist, &seg, &idx); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				{ | ||||
| 					seg.len += idx.len + 4; /* adjustment for error message */ | ||||
| 					goto noent; | ||||
| 				} | ||||
| 			} | ||||
| 			else goto inval; | ||||
|  | ||||
| 			ptr++;  /* skip ] */ | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0'))  | ||||
| 			{ | ||||
| 				/* no more segments */ | ||||
| 				return 1; | ||||
| 			} | ||||
| 			else if (*ptr != QSE_T('.')) goto inval; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			pair = find_pair_byname (xli, curlist, &seg, QSE_NULL); | ||||
| 			if (pair == QSE_NULL) goto noent; | ||||
|  | ||||
| 			if (*ptr == QSE_T('\0'))  | ||||
| 			{ | ||||
| 				return count_pair_byname (xli, curlist, &seg, QSE_NULL); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				pair = find_pair_byname (xli, curlist, &seg, QSE_NULL); | ||||
| 				if (pair == QSE_NULL) goto noent; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* more segments to handle */ | ||||
| 		QSE_ASSERT (*ptr == QSE_T('.')); | ||||
| 		ptr++; | ||||
|  | ||||
| 		/* 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 name */ | ||||
| 		curlist = (qse_xli_list_t*)pair->val; | ||||
| 	} | ||||
|  | ||||
| 	return pair; | ||||
|  | ||||
| inval: | ||||
| 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||
| 	return 0; | ||||
|  | ||||
| noent: | ||||
| 	qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &seg); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user