added qse_awk_rtx_getrefvaltype()/qse_awk_rtx_getrefval()
finished asort() in awk added qse_sortx()
This commit is contained in:
		| @ -2958,6 +2958,21 @@ QSE_EXPORT qse_awk_int_t qse_awk_rtx_hashval ( | |||||||
| 	qse_awk_val_t* v | 	qse_awk_val_t* v | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_awk_rtx_getrefvaltype() function returns the type of the value | ||||||
|  |  * that the given reference points to. | ||||||
|  |  */ | ||||||
|  | QSE_EXPORT qse_awk_val_type_t qse_awk_rtx_getrefvaltype ( | ||||||
|  | 	qse_awk_rtx_t*     rtx, | ||||||
|  | 	qse_awk_val_ref_t* ref | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT qse_awk_val_t* qse_awk_rtx_getrefval ( | ||||||
|  | 	qse_awk_rtx_t*     rtx, | ||||||
|  | 	qse_awk_val_ref_t* ref | ||||||
|  | ); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The qse_awk_rtx_setrefval() function changes the value |  * The qse_awk_rtx_setrefval() function changes the value | ||||||
|  * of a variable referenced in \a ref.  |  * of a variable referenced in \a ref.  | ||||||
|  | |||||||
| @ -55,10 +55,23 @@ typedef int (*qse_search_comper_t) ( | |||||||
| 	void*       ctx | 	void*       ctx | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_search_comperx_t type defines a search callback function. | ||||||
|  |  * It should return 0 on success and -1 on failure. the comparsion | ||||||
|  |  * result must be put back into the variable pointed to by \a cv. | ||||||
|  |  */ | ||||||
|  | typedef int (*qse_search_comperx_t) ( | ||||||
|  | 	const void* ptr1,  | ||||||
|  | 	const void* ptr2,  | ||||||
|  | 	void*       ctx, | ||||||
|  | 	int *       cv | ||||||
|  | ); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The qse_sort_comper_t type defines a sort callback function. |  * The qse_sort_comper_t type defines a sort callback function. | ||||||
|  */ |  */ | ||||||
| typedef qse_search_comper_t qse_sort_comper_t; | typedef qse_search_comper_t qse_sort_comper_t; | ||||||
|  | typedef qse_search_comperx_t qse_sort_comperx_t; | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -134,6 +147,14 @@ QSE_EXPORT void qse_qsort ( | |||||||
| 	void*             ctx | 	void*             ctx | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT int qse_qsortx ( | ||||||
|  | 	void*              base, | ||||||
|  | 	qse_size_t         nmemb, | ||||||
|  | 	qse_size_t         size, | ||||||
|  | 	qse_sort_comperx_t comper, | ||||||
|  | 	void*              ctx | ||||||
|  | ); | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The qse_rand31() function implements Park-Miller's minimal standard |  * The qse_rand31() function implements Park-Miller's minimal standard | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi); | |||||||
|  * |  * | ||||||
|  * - v: value. pass it after normal evaluation. |  * - v: value. pass it after normal evaluation. | ||||||
|  * - r: pass a variable by reference |  * - r: pass a variable by reference | ||||||
|  * - x: regular expression as it it. not evaluated as /rex/ ~ $0. |  * - x: regular expression as it is. not evaluated as /rex/ ~ $0. | ||||||
|  * |  * | ||||||
|  * If the first character of the specifer is 'R', all |  * If the first character of the specifer is 'R', all | ||||||
|  * parameters are passed by reference regarless of the remaining |  * parameters are passed by reference regarless of the remaining | ||||||
| @ -67,30 +67,30 @@ static qse_awk_fnc_t sysfnctab[] = | |||||||
| 	{ {QSE_T("typename"), 8}, 0, { {1,     1, QSE_NULL},       fnc_typename,         0 }, QSE_NULL}, | 	{ {QSE_T("typename"), 8}, 0, { {1,     1, QSE_NULL},       fnc_typename,         0 }, QSE_NULL}, | ||||||
|  |  | ||||||
| 	/* array sort */ | 	/* array sort */ | ||||||
| 	{ {QSE_T("asort"),    5}, 0, { {1,     3, QSE_NULL},       fnc_asort,            0 }, QSE_NULL}, | 	{ {QSE_T("asort"),    5}, 0, { {1,     3, QSE_T("rrv")},   fnc_asort,            0 }, QSE_NULL}, | ||||||
|   |   | ||||||
| 	/* string functions */ | 	/* string functions */ | ||||||
| 	{ {QSE_T("gsub"),     4}, 0, { {2,     3, QSE_T("xvr")},  qse_awk_fnc_gsub,     0 }, QSE_NULL}, | 	{ {QSE_T("gsub"),     4}, 0, { {2,     3, QSE_T("xvr")},   qse_awk_fnc_gsub,     0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("index"),    5}, 0, { {2,     3, QSE_NULL},      qse_awk_fnc_index,    0 }, QSE_NULL}, | 	{ {QSE_T("index"),    5}, 0, { {2,     3, QSE_NULL},       qse_awk_fnc_index,    0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("length"),   6}, 1, { {0,     1, QSE_NULL},      qse_awk_fnc_length,   0 }, QSE_NULL}, | 	{ {QSE_T("length"),   6}, 1, { {0,     1, QSE_NULL},       qse_awk_fnc_length,   0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("match"),    5}, 0, { {2,     4, QSE_T("vxvr")}, qse_awk_fnc_match,    0 }, QSE_NULL}, | 	{ {QSE_T("match"),    5}, 0, { {2,     4, QSE_T("vxvr")},  qse_awk_fnc_match,    0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("split"),    5}, 0, { {2,     3, QSE_T("vrx")},  qse_awk_fnc_split,    0 }, QSE_NULL}, | 	{ {QSE_T("split"),    5}, 0, { {2,     3, QSE_T("vrx")},   qse_awk_fnc_split,    0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("sprintf"),  7}, 0, { {1, A_MAX, QSE_NULL},      qse_awk_fnc_sprintf,  0 }, QSE_NULL}, | 	{ {QSE_T("sprintf"),  7}, 0, { {1, A_MAX, QSE_NULL},       qse_awk_fnc_sprintf,  0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("sub"),      3}, 0, { {2,     3, QSE_T("xvr")},  qse_awk_fnc_sub,      0 }, QSE_NULL}, | 	{ {QSE_T("sub"),      3}, 0, { {2,     3, QSE_T("xvr")},   qse_awk_fnc_sub,      0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("substr"),   6}, 0, { {2,     3, QSE_NULL},      qse_awk_fnc_substr,   0 }, QSE_NULL}, | 	{ {QSE_T("substr"),   6}, 0, { {2,     3, QSE_NULL},       qse_awk_fnc_substr,   0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("tolower"),  7}, 0, { {1,     1, QSE_NULL},      qse_awk_fnc_tolower,  0 }, QSE_NULL}, | 	{ {QSE_T("tolower"),  7}, 0, { {1,     1, QSE_NULL},       qse_awk_fnc_tolower,  0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("toupper"),  7}, 0, { {1,     1, QSE_NULL},      qse_awk_fnc_toupper,  0 }, QSE_NULL}, | 	{ {QSE_T("toupper"),  7}, 0, { {1,     1, QSE_NULL},       qse_awk_fnc_toupper,  0 }, QSE_NULL}, | ||||||
|  |  | ||||||
| 	/* math functions */ | 	/* math functions */ | ||||||
| 	{ {QSE_T("sin"),      3}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("sin"),      3}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("cos"),      3}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("cos"),      3}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("tan"),      3}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("tan"),      3}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("atan"),     4}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("atan"),     4}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("atan2"),    5}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("atan2"),    5}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("log"),      3}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("log"),      3}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("log10"),    5}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("log10"),    5}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("exp"),      3}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("exp"),      3}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
| 	{ {QSE_T("sqrt"),     4}, 0, { {A_MAX, 0, QSE_T("math") },   QSE_NULL,         0 }, QSE_NULL}, | 	{ {QSE_T("sqrt"),     4}, 0, { {A_MAX, 0, QSE_T("math") },  QSE_NULL,         0 }, QSE_NULL}, | ||||||
|  |  | ||||||
| 	/* time functions */ | 	/* time functions */ | ||||||
| 	{ {QSE_T("mktime"),   6}, 0, { {A_MAX, 0, QSE_T("sys") },   QSE_NULL,          0 }, QSE_NULL}, | 	{ {QSE_T("mktime"),   6}, 0, { {A_MAX, 0, QSE_T("sys") },   QSE_NULL,          0 }, QSE_NULL}, | ||||||
| @ -704,7 +704,6 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 	a2 = (nargs >= 3)? qse_awk_rtx_getarg (rtx, 2): QSE_NULL; | 	a2 = (nargs >= 3)? qse_awk_rtx_getarg (rtx, 2): QSE_NULL; | ||||||
|  |  | ||||||
| 	a1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, a1); | 	a1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, a1); | ||||||
|  |  | ||||||
| 	QSE_ASSERT (a1_vtype == QSE_AWK_VAL_REF); | 	QSE_ASSERT (a1_vtype == QSE_AWK_VAL_REF); | ||||||
|  |  | ||||||
| 	str.ptr = qse_awk_rtx_getvalstr(rtx, a0, &str.len); | 	str.ptr = qse_awk_rtx_getvalstr(rtx, a0, &str.len); | ||||||
| @ -714,7 +713,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 	{ | 	{ | ||||||
| 		/* get the value from FS */ | 		/* get the value from FS */ | ||||||
| 		t1 = qse_awk_rtx_getgbl(rtx, QSE_AWK_GBL_FS); | 		t1 = qse_awk_rtx_getgbl(rtx, QSE_AWK_GBL_FS); | ||||||
| 		t1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, t1); | 		t1_vtype = QSE_AWK_RTX_GETVALTYPE(rtx, t1); | ||||||
| 		if (t1_vtype == QSE_AWK_VAL_NIL) | 		if (t1_vtype == QSE_AWK_VAL_NIL) | ||||||
| 		{ | 		{ | ||||||
| 			fs.ptr = QSE_T(" "); | 			fs.ptr = QSE_T(" "); | ||||||
| @ -727,7 +726,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			fs.ptr = qse_awk_rtx_valtostrdup (rtx, t1, &fs.len); | 			fs.ptr = qse_awk_rtx_valtostrdup(rtx, t1, &fs.len); | ||||||
| 			if (fs.ptr == QSE_NULL) goto oops; | 			if (fs.ptr == QSE_NULL) goto oops; | ||||||
| 			fs_free = (qse_char_t*)fs.ptr; | 			fs_free = (qse_char_t*)fs.ptr; | ||||||
| 		} | 		} | ||||||
| @ -801,15 +800,11 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
|  |  | ||||||
| 		if (fs.len <= 1) | 		if (fs.len <= 1) | ||||||
| 		{ | 		{ | ||||||
| 			p = qse_awk_rtx_strxntok (rtx,  | 			p = qse_awk_rtx_strxntok(rtx, p, str.len, fs.ptr, fs.len, &tok); | ||||||
| 				p, str.len, fs.ptr, fs.len, &tok); |  | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			p = qse_awk_rtx_strxntokbyrex ( | 			p = qse_awk_rtx_strxntokbyrex(rtx, str.ptr, org_len, p, str.len, fs_rex, &tok, &errnum);  | ||||||
| 				rtx, str.ptr, org_len, p, str.len,  |  | ||||||
| 				fs_rex, &tok, &errnum |  | ||||||
| 			);  |  | ||||||
| 			if (p == QSE_NULL && errnum != QSE_AWK_ENOERR) | 			if (p == QSE_NULL && errnum != QSE_AWK_ENOERR) | ||||||
| 			{ | 			{ | ||||||
| 				qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL); | 				qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL); | ||||||
| @ -821,7 +816,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 		{ | 		{ | ||||||
| 			/* no field at all*/ | 			/* no field at all*/ | ||||||
| 			break;  | 			break;  | ||||||
| 		}	 | 		} | ||||||
|  |  | ||||||
| 		QSE_ASSERT ((tok.ptr != QSE_NULL && tok.len > 0) || tok.len == 0); | 		QSE_ASSERT ((tok.ptr != QSE_NULL && tok.len > 0) || tok.len == 0); | ||||||
|  |  | ||||||
| @ -848,13 +843,13 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 	/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/ | 	/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/ | ||||||
| 	qse_awk_rtx_freevalstr (rtx, a0, str.ptr); | 	qse_awk_rtx_freevalstr (rtx, a0, str.ptr); | ||||||
|  |  | ||||||
| 	if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free); | 	if (fs_free) qse_awk_rtx_freemem (rtx, fs_free); | ||||||
|  |  | ||||||
| 	if (fs_rex_free)  | 	if (fs_rex_free)  | ||||||
| 	{ | 	{ | ||||||
| 		if (rtx->gbl.ignorecase) | 		if (rtx->gbl.ignorecase) | ||||||
| 			qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); | 			qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); | ||||||
| 		else	 | 		else | ||||||
| 			qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); | 			qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -870,13 +865,13 @@ oops: | |||||||
| 	/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/ | 	/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/ | ||||||
| 	if (str.ptr) qse_awk_rtx_freevalstr (rtx, a0, str.ptr); | 	if (str.ptr) qse_awk_rtx_freevalstr (rtx, a0, str.ptr); | ||||||
|  |  | ||||||
| 	if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free); | 	if (fs_free) qse_awk_rtx_freemem (rtx, fs_free); | ||||||
|  |  | ||||||
| 	if (fs_rex_free)  | 	if (fs_rex_free)  | ||||||
| 	{ | 	{ | ||||||
| 		if (rtx->gbl.ignorecase) | 		if (rtx->gbl.ignorecase) | ||||||
| 			qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); | 			qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); | ||||||
| 		else	 | 		else | ||||||
| 			qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); | 			qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); | ||||||
| 	} | 	} | ||||||
| 	return -1; | 	return -1; | ||||||
| @ -1531,31 +1526,58 @@ static int fnc_ismap (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static QSE_INLINE int asort_compare (const void* x1, const void* x2, void* ctx) | static QSE_INLINE int asort_compare (const void* x1, const void* x2, void* ctx, int* cv) | ||||||
| { | { | ||||||
| 	int n; | 	int n; | ||||||
| 	if (qse_awk_rtx_cmpval((qse_awk_rtx_t*)ctx, (qse_awk_val_t*)x1, (qse_awk_val_t*)x2, &n) <= -1) return -1; | 	if (qse_awk_rtx_cmpval((qse_awk_rtx_t*)ctx, *(qse_awk_val_t**)x1, *(qse_awk_val_t**)x2, &n) <= -1) return -1; | ||||||
| 	return n; | 	*cv = n; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct cud_t | ||||||
|  | { | ||||||
|  | 	qse_awk_rtx_t* rtx; | ||||||
|  | 	qse_awk_fun_t* fun; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static QSE_INLINE int asort_compare_ud (const void* x1, const void* x2, void* ctx, int* cv) | ||||||
|  | { | ||||||
|  | 	struct cud_t* cud = (struct cud_t*)ctx; | ||||||
|  | 	qse_awk_val_t* r, * args[2]; | ||||||
|  | 	qse_awk_int_t rv; | ||||||
|  |  | ||||||
|  | 	args[0] = *(qse_awk_val_t**)x1; | ||||||
|  | 	args[1] = *(qse_awk_val_t**)x2; | ||||||
|  | 	r = qse_awk_rtx_callfun(cud->rtx, cud->fun, args, 2);  | ||||||
|  | 	if (!r) return -1; | ||||||
|  | 	if (qse_awk_rtx_valtoint(cud->rtx, r,  &rv) <= -1) return -1; | ||||||
|  | 	*cv = rv; | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | ||||||
| { | { | ||||||
| 	qse_size_t nargs; | 	qse_size_t nargs; | ||||||
| 	qse_awk_val_t* a0, * a2; | 	qse_awk_val_t* a0, * a0_val, * a1, * a2; | ||||||
|  | 	qse_awk_val_type_t a0_type, v_type; | ||||||
| 	qse_awk_val_t* r, * rmap; | 	qse_awk_val_t* r, * rmap; | ||||||
| 	qse_awk_int_t rv = 0; /* as if no element in the map */ | 	qse_awk_int_t rv = 0; /* as if no element in the map */ | ||||||
| 	qse_awk_val_map_itr_t itr; | 	qse_awk_val_map_itr_t itr; | ||||||
| 	qse_awk_fun_t* fun; | 	qse_awk_fun_t* fun = QSE_NULL; | ||||||
| 	qse_size_t msz, i; | 	qse_size_t msz, i; | ||||||
| 	qse_awk_val_t** va; | 	qse_awk_val_t** va; | ||||||
|  | 	int x; | ||||||
|  |  | ||||||
| 	nargs = qse_awk_rtx_getnargs(rtx); | 	nargs = qse_awk_rtx_getnargs(rtx); | ||||||
|  |  | ||||||
| 	a0 = qse_awk_rtx_getarg(rtx, 0); | 	a0 = qse_awk_rtx_getarg(rtx, 0); | ||||||
| 	 | 	a0_type = QSE_AWK_RTX_GETVALTYPE(rtx, a0); | ||||||
| 	if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) != QSE_AWK_VAL_MAP) | 	QSE_ASSERT (a0_type == QSE_AWK_VAL_REF); | ||||||
|  |  | ||||||
|  | 	v_type = qse_awk_rtx_getrefvaltype(rtx, (qse_awk_val_ref_t*)a0); | ||||||
|  | 	if (v_type != QSE_AWK_VAL_MAP) | ||||||
| 	{ | 	{ | ||||||
| 		if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_NIL) | 		if (v_type == QSE_AWK_VAL_NIL) | ||||||
| 		{ | 		{ | ||||||
| 			/* treat it as an empty value */ | 			/* treat it as an empty value */ | ||||||
| 			goto done; | 			goto done; | ||||||
| @ -1565,30 +1587,43 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	a0_val = qse_awk_rtx_getrefval(rtx, (qse_awk_val_ref_t*)a0); | ||||||
|  | 	QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE(rtx, a0_val) == QSE_AWK_VAL_MAP); | ||||||
|  |  | ||||||
| 	if (nargs >= 2) | 	if (nargs >= 2) | ||||||
| 	{ | 	{ | ||||||
| 		a2 = qse_awk_rtx_getarg(rtx, 2); | 		a1 = qse_awk_rtx_getarg(rtx, 1); /* destination map */ | ||||||
| 		if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN) | 		 | ||||||
|  | 		if (nargs >= 3) | ||||||
| 		{ | 		{ | ||||||
| 			qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); | 			a2 = qse_awk_rtx_getarg(rtx, 2); | ||||||
| 			return -1; | 			if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN) | ||||||
| 		} | 			{ | ||||||
|  | 				qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 		fun = ((qse_awk_val_fun_t*)a2)->fun; | 			fun = ((qse_awk_val_fun_t*)a2)->fun; | ||||||
| 		if (fun->nargs < 2)  | 			if (fun->nargs < 2)  | ||||||
| 		{ | 			{ | ||||||
| 			/* the comparison accepts less than 2 arguments */ | 				/* the comparison accepts less than 2 arguments */ | ||||||
| 			qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); | 				qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); | ||||||
| 			return -1; | 				return -1; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		a1 = a0; /* let a0 be the destination. a0 is both source and destination */ | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (!qse_awk_rtx_getfirstmapvalitr(rtx, a0, &itr)) goto done; /* map empty */ |  | ||||||
|  |  | ||||||
| 	msz = qse_htb_getsize(((qse_awk_val_map_t*)a0)->map); | 	if (!qse_awk_rtx_getfirstmapvalitr(rtx, a0_val, &itr)) goto done; /* map empty */ | ||||||
|  |  | ||||||
|  | 	msz = qse_htb_getsize(((qse_awk_val_map_t*)a0_val)->map); | ||||||
| 	QSE_ASSERT (msz > 0); | 	QSE_ASSERT (msz > 0); | ||||||
|  |  | ||||||
| 	va = (qse_awk_val_t**)qse_awk_rtx_allocmem(rtx, msz * QSE_SIZEOF(qse_awk_val_t*)); | 	va = (qse_awk_val_t**)qse_awk_rtx_allocmem(rtx, msz * QSE_SIZEOF(*va)); | ||||||
| 	if (!va) return -1; | 	if (!va) return -1; | ||||||
|  |  | ||||||
| 	i = 0; | 	i = 0; | ||||||
| @ -1596,9 +1631,25 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 	{ | 	{ | ||||||
| 		va[i++] = (qse_awk_val_t*)QSE_AWK_VAL_MAP_ITR_VAL(&itr); | 		va[i++] = (qse_awk_val_t*)QSE_AWK_VAL_MAP_ITR_VAL(&itr); | ||||||
| 	} | 	} | ||||||
| 	while (qse_awk_rtx_getnextmapvalitr(rtx, a0, &itr)); | 	while (qse_awk_rtx_getnextmapvalitr(rtx, a0_val, &itr)); | ||||||
|  |  | ||||||
| 	qse_qsort (va, msz, QSE_SIZEOF(*va), asort_compare, rtx); | 	if (fun) | ||||||
|  | 	{ | ||||||
|  | 		struct cud_t cud; | ||||||
|  | 		cud.rtx = rtx; | ||||||
|  | 		cud.fun = fun; | ||||||
|  | 		x = qse_qsortx(va, msz, QSE_SIZEOF(*va), asort_compare_ud, &cud); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		x = qse_qsortx(va, msz, QSE_SIZEOF(*va), asort_compare, rtx); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (x <= -1) | ||||||
|  | 	{ | ||||||
|  | 		qse_awk_rtx_freemem (rtx, va); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	rmap = qse_awk_rtx_makemapval(rtx); | 	rmap = qse_awk_rtx_makemapval(rtx); | ||||||
| 	if (!rmap)  | 	if (!rmap)  | ||||||
| @ -1622,7 +1673,7 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 			QSE_NULL | 			QSE_NULL | ||||||
| 		); | 		); | ||||||
|  |  | ||||||
| 		if (qse_awk_rtx_setmapvalfld (rtx, rmap, ridx, ridx_len, va[i]) == QSE_NULL) | 		if (qse_awk_rtx_setmapvalfld(rtx, rmap, ridx, ridx_len, va[i]) == QSE_NULL) | ||||||
| 		{ | 		{ | ||||||
| 			qse_awk_rtx_freeval (rtx, rmap, 0); | 			qse_awk_rtx_freeval (rtx, rmap, 0); | ||||||
| 			qse_awk_rtx_freemem (rtx, va); | 			qse_awk_rtx_freemem (rtx, va); | ||||||
| @ -1630,30 +1681,13 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	{ |  | ||||||
| 	#if 0 |  | ||||||
| 		/* TODO: complete this function */ |  | ||||||
| 		r = qse_awk_rtx_callfun(rtx, fun, valargs, nargs); |  | ||||||
| 		if (qse_awk_rtx_valtoint(rtx, r,  &rv) <= -1) return -1; |  | ||||||
|  |  | ||||||
| 		if (rv > 0) |  | ||||||
| 		{ |  | ||||||
| 		} |  | ||||||
| 		else if (rv < 0) |  | ||||||
| 		{ |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 		} |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rv = msz; | 	rv = msz; | ||||||
| 	qse_awk_rtx_freemem (rtx, va); | 	qse_awk_rtx_freemem (rtx, va); | ||||||
| /* TODO: set the resulting map back to a0. |  | ||||||
|  *       or to a1 if a1 is given */ | 	qse_awk_rtx_refupval (rtx, rmap); | ||||||
| qse_awk_rtx_setretval (rtx, rmap); | 	x = qse_awk_rtx_setrefval (rtx, (qse_awk_val_ref_t*)a1, rmap); | ||||||
| return 0; | 	qse_awk_rtx_refdownval (rtx, rmap); | ||||||
|  | 	if (x <= -1) return -1; | ||||||
|  |  | ||||||
| done: | done: | ||||||
| 	r = qse_awk_rtx_makeintval(rtx, rv); | 	r = qse_awk_rtx_makeintval(rtx, rv); | ||||||
|  | |||||||
| @ -1650,7 +1650,7 @@ qse_awk_val_t* qse_awk_rtx_callfun ( | |||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		/* thr return value captured in termination by exit() | 		/* the return value captured in termination by exit() | ||||||
| 		 * is reference-counted up in capture_retval_on_exit(). | 		 * is reference-counted up in capture_retval_on_exit(). | ||||||
| 		 * let's do the same thing for the return value normally | 		 * let's do the same thing for the return value normally | ||||||
| 		 * returned. */ | 		 * returned. */ | ||||||
| @ -5996,7 +5996,7 @@ static qse_awk_val_t* __eval_call ( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* push all arguments onto the stack */ | 	/* push all arguments onto the stack */ | ||||||
| 	nargs = argpusher (run, call, apdata); | 	nargs = argpusher(run, call, apdata); | ||||||
| 	if (nargs == (qse_size_t)-1) | 	if (nargs == (qse_size_t)-1) | ||||||
| 	{ | 	{ | ||||||
| 		UNWIND_RTX_STACK_BASE (run); | 		UNWIND_RTX_STACK_BASE (run); | ||||||
| @ -6049,7 +6049,7 @@ static qse_awk_val_t* __eval_call ( | |||||||
| 		{ | 		{ | ||||||
| 			run->errinf.num = QSE_AWK_ENOERR; | 			run->errinf.num = QSE_AWK_ENOERR; | ||||||
|  |  | ||||||
| 			n = call->u.fnc.spec.impl (run, &call->u.fnc.info); | 			n = call->u.fnc.spec.impl(run, &call->u.fnc.info); | ||||||
|  |  | ||||||
| 			if (n <= -1) | 			if (n <= -1) | ||||||
| 			{ | 			{ | ||||||
|  | |||||||
| @ -1911,6 +1911,69 @@ qse_awk_int_t qse_awk_rtx_hashval (qse_awk_rtx_t* rtx, qse_awk_val_t* v) | |||||||
| 	return hv  & ~(((qse_awk_uint_t)1) << ((QSE_SIZEOF(qse_awk_uint_t) * 8) - 1)); | 	return hv  & ~(((qse_awk_uint_t)1) << ((QSE_SIZEOF(qse_awk_uint_t) * 8) - 1)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | qse_awk_val_type_t qse_awk_rtx_getrefvaltype (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref) | ||||||
|  | { | ||||||
|  | 	/* return the type of the value that the reference points to */ | ||||||
|  | 	switch (ref->id) | ||||||
|  | 	{ | ||||||
|  | 		case QSE_AWK_VAL_REF_POS: | ||||||
|  | 		{ | ||||||
|  | 			return QSE_AWK_VAL_STR; | ||||||
|  | 		} | ||||||
|  | 		case QSE_AWK_VAL_REF_GBL: | ||||||
|  | 		{ | ||||||
|  | 			qse_size_t idx; | ||||||
|  | 			qse_awk_val_t* v; | ||||||
|  | 			idx = (qse_size_t)ref->adr; | ||||||
|  | 			v = RTX_STACK_GBL(rtx, idx); | ||||||
|  | 			return QSE_AWK_RTX_GETVALTYPE(rtx, v); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 		{ | ||||||
|  | 			qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr; | ||||||
|  | 			qse_awk_val_t* v; | ||||||
|  |  | ||||||
|  | 			/* A reference value is not able to point to another  | ||||||
|  | 			 * refernce value for the way values are represented | ||||||
|  | 			 * in QSEAWK */ | ||||||
|  | 			v = *xref; | ||||||
|  | 			QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE(rtx, v) != QSE_AWK_VAL_REF);  | ||||||
|  | 			return QSE_AWK_RTX_GETVALTYPE(rtx, v); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | qse_awk_val_t* qse_awk_rtx_getrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref) | ||||||
|  | { | ||||||
|  | 	switch (ref->id) | ||||||
|  | 	{ | ||||||
|  | 		case QSE_AWK_VAL_REF_POS: | ||||||
|  | 		{ | ||||||
|  | 			/* a positional doesn't contain a value. you should use qse_awk_rtx_valtoXXX() | ||||||
|  | 			 * like qse_awk_rtx_valtostr(), qse_Awk_rtx_valtoint() */ | ||||||
|  | 			return QSE_NULL; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		case QSE_AWK_VAL_REF_GBL: | ||||||
|  | 		{ | ||||||
|  | 			qse_size_t idx; | ||||||
|  | 			idx = (qse_size_t)ref->adr; | ||||||
|  | 			return RTX_STACK_GBL(rtx, idx); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 		{ | ||||||
|  | 			qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr; | ||||||
|  | 			/* A reference value is not able to point to another  | ||||||
|  | 			 * refernce value for the way values are represented | ||||||
|  | 			 * in QSEAWK */ | ||||||
|  | 			QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE (rtx, *xref)!= QSE_AWK_VAL_REF);  | ||||||
|  | 			return *xref; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_val_t* val) | int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_val_t* val) | ||||||
| { | { | ||||||
| 	qse_awk_val_type_t vtype = QSE_AWK_RTX_GETVALTYPE (rtx, val); | 	qse_awk_val_type_t vtype = QSE_AWK_RTX_GETVALTYPE (rtx, val); | ||||||
| @ -2001,7 +2064,7 @@ int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_v | |||||||
| 			qse_awk_val_type_t rref_vtype; | 			qse_awk_val_type_t rref_vtype; | ||||||
|  |  | ||||||
| 			rref = (qse_awk_val_t**)ref->adr; /* old value pointer */ | 			rref = (qse_awk_val_t**)ref->adr; /* old value pointer */ | ||||||
| 			rref_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, *rref); /* old value type */ | 			rref_vtype = QSE_AWK_RTX_GETVALTYPE(rtx, *rref); /* old value type */ | ||||||
| 			if (vtype == QSE_AWK_VAL_MAP) | 			if (vtype == QSE_AWK_VAL_MAP) | ||||||
| 			{ | 			{ | ||||||
| 				/* new value: map, old value: nil or map => ok */ | 				/* new value: map, old value: nil or map => ok */ | ||||||
|  | |||||||
| @ -64,8 +64,8 @@ | |||||||
| /* | /* | ||||||
|  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". |  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". | ||||||
|  */ |  */ | ||||||
| #define swapcode(TYPE,parmi,parmj,n) { \ | #define swapcode(TYPE,parmi,parmj,n) do { \ | ||||||
| 	qse_size_t i = (n) / sizeof (TYPE); \ | 	qse_size_t i = (n) / QSE_SIZEOF (TYPE); \ | ||||||
| 	register TYPE *pi = (TYPE*)(parmi); \ | 	register TYPE *pi = (TYPE*)(parmi); \ | ||||||
| 	register TYPE *pj = (TYPE*)(parmj); \ | 	register TYPE *pj = (TYPE*)(parmj); \ | ||||||
| 	do { 						\ | 	do { 						\ | ||||||
| @ -73,29 +73,38 @@ | |||||||
| 		*pi++ = *pj;	\ | 		*pi++ = *pj;	\ | ||||||
| 		*pj++ = t;		\ | 		*pj++ = t;		\ | ||||||
| 	} while (--i > 0);	\ | 	} while (--i > 0);	\ | ||||||
| } | } while(0) | ||||||
|  |  | ||||||
| #define SWAPINIT(a,size) \ |  | ||||||
| 	swaptype = ((qse_byte_t*)a-(qse_byte_t*)0)%sizeof(long) || \ |  | ||||||
| 	           size % sizeof(long) ? 2 : size == sizeof(long)? 0 : 1; |  | ||||||
|  |  | ||||||
| static QSE_INLINE void swapfunc ( | #define get_swaptype(a, elemsize) (((qse_byte_t*)(a) - (qse_byte_t*)0) % QSE_SIZEOF(long) || elemsize % QSE_SIZEOF(long)? 2 : elemsize == QSE_SIZEOF(long)? 0 : 1) | ||||||
| 	qse_byte_t* a, qse_byte_t* b, int n, int swaptype) |  | ||||||
| { |  | ||||||
| 	if (swaptype <= 1)  |  | ||||||
| 		swapcode(long, a, b, n) |  | ||||||
| 	else |  | ||||||
| 		swapcode(qse_byte_t, a, b, n) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define swap(a, b) \ | #define swap(a, b, elemsize) do { \ | ||||||
| 	if (swaptype == 0) { \ | 	switch (swaptype) \ | ||||||
| 		long t = *(long*)(a); \ | 	{ \ | ||||||
| 		*(long*)(a) = *(long*)(b); \ | 		case 0: \ | ||||||
| 		*(long*)(b) = t; \ | 		{ \ | ||||||
| 	} else swapfunc(a, b, size, swaptype) | 			long t = *(long*)(a); \ | ||||||
|  | 			*(long*)(a) = *(long*)(b); \ | ||||||
| #define vecswap(a,b,n) if ((n) > 0) swapfunc(a, b, n, swaptype) | 			*(long*)(b) = t; \ | ||||||
|  | 			break; \ | ||||||
|  | 		} \ | ||||||
|  | 		case 1: \ | ||||||
|  | 			swapcode(long, a, b, elemsize); \ | ||||||
|  | 			break; \ | ||||||
|  | 		default: \ | ||||||
|  | 			swapcode(qse_byte_t, a, b, elemsize); \ | ||||||
|  | 			break; \ | ||||||
|  | 	} \ | ||||||
|  | } while(0) | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  | #define vecswap(a,b,n) do {  \ | ||||||
|  | 	if ((n) > 0)  \ | ||||||
|  | 	{ \ | ||||||
|  | 		if (swaptype <= 1) swapcode(long, a, b, n); \ | ||||||
|  | 		else swapcode(qse_byte_t, a, b, n);  \ | ||||||
|  | 	} \ | ||||||
|  | } while(0) | ||||||
|  |  | ||||||
| static QSE_INLINE qse_byte_t* med3 (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, qse_sort_comper_t comper, void* ctx) | static QSE_INLINE qse_byte_t* med3 (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, qse_sort_comper_t comper, void* ctx) | ||||||
| { | { | ||||||
| @ -111,26 +120,48 @@ static QSE_INLINE qse_byte_t* med3 (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static QSE_INLINE qse_byte_t* med3x (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, qse_sort_comperx_t comper, void* ctx) | ||||||
|  | { | ||||||
|  | 	int n; | ||||||
|  |  | ||||||
|  | 	if (comper(a, b, ctx, &n) <= -1) return QSE_NULL; | ||||||
|  | 	if (n < 0) | ||||||
|  | 	{ | ||||||
|  | 		if (comper(b, c, ctx, &n) <= -1) return QSE_NULL; | ||||||
|  | 		if (n < 0) return b; | ||||||
|  |  | ||||||
|  | 		if (comper(a, c, ctx, &n) <= -1) return QSE_NULL; | ||||||
|  | 		return (n < 0)? c: a; | ||||||
|  | 	} | ||||||
|  | 	else  | ||||||
|  | 	{ | ||||||
|  | 		if (comper(b, c, ctx, &n) <= -1) return QSE_NULL; | ||||||
|  | 		if (n > 0) return b; | ||||||
|  | 		if (comper(a, c, ctx, &n) <= -1) return QSE_NULL; | ||||||
|  | 		return (n > 0)? c: a; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| void qse_qsort (void* base, qse_size_t nmemb, qse_size_t size, qse_sort_comper_t comper, void* ctx) | void qse_qsort (void* base, qse_size_t nmemb, qse_size_t size, qse_sort_comper_t comper, void* ctx) | ||||||
| { | { | ||||||
| 	qse_byte_t*pa, *pb, *pc, *pd, *pl, *pm, *pn; | 	qse_byte_t* pa, * pb, * pc, * pd, * pl, * pm, * pn; | ||||||
| 	int swaptype, swap_cnt; | 	int swaptype, swap_cnt; | ||||||
| 	long r; | 	long r; | ||||||
| 	qse_size_t d; | 	qse_size_t d; | ||||||
| 	register qse_byte_t*a = (qse_byte_t*)base; | 	register qse_byte_t* a = (qse_byte_t*)base; | ||||||
|  |  | ||||||
| loop:	 | loop:	 | ||||||
| 	SWAPINIT(a, size); | 	swaptype = get_swaptype(a, size); | ||||||
|  |  | ||||||
| 	swap_cnt = 0; | 	swap_cnt = 0; | ||||||
| 	if (nmemb < 7)  | 	if (nmemb < 7)  | ||||||
| 	{ | 	{ | ||||||
| 		for (pm = (qse_byte_t*)a + size; | 		qse_byte_t* end = (qse_byte_t*)a + (nmemb * size); | ||||||
| 		     pm < (qse_byte_t*) a + nmemb * size; pm += size) | 		for (pm = (qse_byte_t*)a + size; pm < end; pm += size) | ||||||
| 		{ | 		{ | ||||||
| 			for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size) | 			for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size) | ||||||
| 			{ | 			{ | ||||||
| 				swap(pl, pl - size); | 				swap(pl, pl - size, size); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return; | 		return; | ||||||
| @ -149,7 +180,7 @@ loop: | |||||||
| 		} | 		} | ||||||
| 		pm = med3(pl, pm, pn, comper, ctx); | 		pm = med3(pl, pm, pn, comper, ctx); | ||||||
| 	} | 	} | ||||||
| 	swap(a, pm); | 	swap(a, pm, size); | ||||||
| 	pa = pb = (qse_byte_t*)a + size; | 	pa = pb = (qse_byte_t*)a + size; | ||||||
|  |  | ||||||
| 	pc = pd = (qse_byte_t*)a + (nmemb - 1) * size; | 	pc = pd = (qse_byte_t*)a + (nmemb - 1) * size; | ||||||
| @ -160,7 +191,7 @@ loop: | |||||||
| 			if (r == 0)  | 			if (r == 0)  | ||||||
| 			{ | 			{ | ||||||
| 				swap_cnt = 1; | 				swap_cnt = 1; | ||||||
| 				swap(pa, pb); | 				swap(pa, pb, size); | ||||||
| 				pa += size; | 				pa += size; | ||||||
| 			} | 			} | ||||||
| 			pb += size; | 			pb += size; | ||||||
| @ -170,13 +201,13 @@ loop: | |||||||
| 			if (r == 0)  | 			if (r == 0)  | ||||||
| 			{ | 			{ | ||||||
| 				swap_cnt = 1; | 				swap_cnt = 1; | ||||||
| 				swap(pc, pd); | 				swap(pc, pd, size); | ||||||
| 				pd -= size; | 				pd -= size; | ||||||
| 			} | 			} | ||||||
| 			pc -= size; | 			pc -= size; | ||||||
| 		} | 		} | ||||||
| 		if (pb > pc) break; | 		if (pb > pc) break; | ||||||
| 		swap (pb, pc); | 		swap (pb, pc, size); | ||||||
| 		swap_cnt = 1; | 		swap_cnt = 1; | ||||||
| 		pb += size; | 		pb += size; | ||||||
| 		pc -= size; | 		pc -= size; | ||||||
| @ -188,10 +219,9 @@ loop: | |||||||
| 		for (pm = (qse_byte_t*)a + size;  | 		for (pm = (qse_byte_t*)a + size;  | ||||||
| 		     pm < (qse_byte_t*)a + nmemb * size; pm += size) | 		     pm < (qse_byte_t*)a + nmemb * size; pm += size) | ||||||
| 		{ | 		{ | ||||||
| 			for (pl = pm; pl > (qse_byte_t*)a &&  | 			for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size) | ||||||
| 			              comper(pl - size, pl, ctx) > 0; pl -= size) |  | ||||||
| 			{ | 			{ | ||||||
| 				swap(pl, pl - size); | 				swap(pl, pl - size, size); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return; | 		return; | ||||||
| @ -215,6 +245,134 @@ loop: | |||||||
| /*	qsort(pn - r, r / size, size, comper);*/ | /*	qsort(pn - r, r / size, size, comper);*/ | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int qse_qsortx (void* base, qse_size_t nmemb, qse_size_t size, qse_sort_comperx_t comper, void* ctx) | ||||||
|  | { | ||||||
|  | 	qse_byte_t* pa, * pb, * pc, * pd, * pl, * pm, * pn; | ||||||
|  | 	int swaptype, swap_cnt; | ||||||
|  | 	long r; | ||||||
|  | 	int n; | ||||||
|  | 	qse_size_t d; | ||||||
|  | 	register qse_byte_t* a = (qse_byte_t*)base; | ||||||
|  |  | ||||||
|  | loop:	 | ||||||
|  | 	swaptype = get_swaptype(a, size); | ||||||
|  |  | ||||||
|  | 	swap_cnt = 0; | ||||||
|  | 	if (nmemb < 7)  | ||||||
|  | 	{ | ||||||
|  | 		qse_byte_t* end = (qse_byte_t*)a + (nmemb * size); | ||||||
|  | 		for (pm = (qse_byte_t*)a + size; pm < end; pm += size) | ||||||
|  | 		{ | ||||||
|  | 			pl = pm; | ||||||
|  | 			while (pl > (qse_byte_t*)a) | ||||||
|  | 			{ | ||||||
|  | 				qse_byte_t* pl2 = pl - size; | ||||||
|  | 				if (comper(pl2, pl, ctx, &n) <= -1) return -1; | ||||||
|  | 				if (n <= 0) break; | ||||||
|  | 				swap (pl, pl2, size); | ||||||
|  | 				pl = pl2; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	pm = (qse_byte_t*)a + (nmemb / 2) * size; | ||||||
|  | 	if (nmemb > 7)  | ||||||
|  | 	{ | ||||||
|  | 		pl = (qse_byte_t*)a; | ||||||
|  | 		pn = (qse_byte_t*)a + (nmemb - 1) * size; | ||||||
|  | 		if (nmemb > 40)  | ||||||
|  | 		{ | ||||||
|  | 			d = (nmemb / 8) * size; | ||||||
|  | 			pl = med3x(pl, pl + d, pl + 2 * d, comper, ctx); | ||||||
|  | 			if (!pl) return -1; | ||||||
|  | 			pm = med3x(pm - d, pm, pm + d, comper, ctx); | ||||||
|  | 			if (!pm) return -1; | ||||||
|  | 			pn = med3x(pn - 2 * d, pn - d, pn, comper, ctx); | ||||||
|  | 			if (!pn) return -1; | ||||||
|  | 		} | ||||||
|  | 		pm = med3x(pl, pm, pn, comper, ctx); | ||||||
|  | 		if (!pm) return -1; | ||||||
|  | 	} | ||||||
|  | 	swap(a, pm, size); | ||||||
|  | 	pa = pb = (qse_byte_t*)a + size; | ||||||
|  |  | ||||||
|  | 	pc = pd = (qse_byte_t*)a + (nmemb - 1) * size; | ||||||
|  | 	for (;;)  | ||||||
|  | 	{ | ||||||
|  | 		while (pb <= pc) | ||||||
|  | 		{ | ||||||
|  | 			if (comper(pb, a, ctx, &n) <= -1) return -1; | ||||||
|  | 			if (n > 0) break; | ||||||
|  |  | ||||||
|  | 			if (n == 0)  | ||||||
|  | 			{ | ||||||
|  | 				swap_cnt = 1; | ||||||
|  | 				swap(pa, pb, size); | ||||||
|  | 				pa += size; | ||||||
|  | 			} | ||||||
|  | 			pb += size; | ||||||
|  | 		} | ||||||
|  | 		while (pb <= pc) | ||||||
|  | 		{ | ||||||
|  | 			if (comper(pc, a, ctx, &n) <= -1) return -1; | ||||||
|  | 			if (n < 0) break; | ||||||
|  |  | ||||||
|  | 			if (n == 0)  | ||||||
|  | 			{ | ||||||
|  | 				swap_cnt = 1; | ||||||
|  | 				swap(pc, pd, size); | ||||||
|  | 				pd -= size; | ||||||
|  | 			} | ||||||
|  | 			pc -= size; | ||||||
|  | 		} | ||||||
|  | 		if (pb > pc) break; | ||||||
|  | 		swap (pb, pc, size); | ||||||
|  | 		swap_cnt = 1; | ||||||
|  | 		pb += size; | ||||||
|  | 		pc -= size; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (swap_cnt == 0)  | ||||||
|  | 	{ | ||||||
|  | 		/* switch to insertion sort */ | ||||||
|  | 		qse_byte_t* end = (qse_byte_t*)a + (nmemb * size); | ||||||
|  | 		for (pm = (qse_byte_t*)a + size; pm < end; pm += size) | ||||||
|  | 		{ | ||||||
|  | 			pl = pm; | ||||||
|  | 			while (pl > (qse_byte_t*)a) | ||||||
|  | 			{ | ||||||
|  | 				if (comper(pl - size, pl, ctx, &n) <= -1) return -1; | ||||||
|  | 				if (n <= 0) break; | ||||||
|  | 				swap(pl, pl - size, size); | ||||||
|  | 				pl = pl - size; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pn = (qse_byte_t*)a + nmemb * size; | ||||||
|  | 	r = qsort_min(pa - (qse_byte_t*)a, pb - pa); | ||||||
|  | 	vecswap (a, pb - r, r); | ||||||
|  | 	r = qsort_min (pd - pc, pn - pd - size); | ||||||
|  | 	vecswap (pb, pn - r, r); | ||||||
|  |  | ||||||
|  | 	if ((r = pb - pa) > size)  | ||||||
|  | 	{ | ||||||
|  | 		if (qse_qsortx(a, r / size, size, comper, ctx) <= -1) return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ((r = pd - pc) > size)  | ||||||
|  | 	{ | ||||||
|  | 		/* Iterate rather than recurse to save stack space */ | ||||||
|  | 		a = pn - r; | ||||||
|  | 		nmemb = r / size; | ||||||
|  | 		goto loop; | ||||||
|  | 	} | ||||||
|  | /*	qsortx(pn - r, r / size, size, comper);*/ | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| #if 0 | #if 0 | ||||||
|  |  | ||||||
| /*  | /*  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user