added another new hash table implementation based on fr
This commit is contained in:
		| @ -390,7 +390,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -546,7 +546,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -43,6 +43,7 @@ libqsecmn_la_SOURCES = \ | ||||
| 	env.c \ | ||||
| 	gdl.c \ | ||||
| 	htb.c \ | ||||
| 	htl.c \ | ||||
| 	fma.c \ | ||||
| 	fmt-intmax.c \ | ||||
| 	fmt-out.c \ | ||||
|  | ||||
| @ -143,8 +143,8 @@ am__DEPENDENCIES_1 = | ||||
| libqsecmn_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ | ||||
| 	$(am__DEPENDENCIES_1) | ||||
| am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \ | ||||
| 	alg-sort.c arr.c assert.c chr.c dll.c env.c gdl.c htb.c fma.c \ | ||||
| 	fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \ | ||||
| 	alg-sort.c arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c \ | ||||
| 	fma.c fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \ | ||||
| 	mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \ | ||||
| 	path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \ | ||||
| 	str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c \ | ||||
| @ -159,19 +159,19 @@ am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \ | ||||
| @ENABLE_XCMGRS_TRUE@am__objects_2 = cp949.lo cp950.lo | ||||
| am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \ | ||||
| 	alg-sort.lo arr.lo assert.lo chr.lo dll.lo env.lo gdl.lo \ | ||||
| 	htb.lo fma.lo fmt-intmax.lo fmt-out.lo hton.lo hwad.lo ipad.lo \ | ||||
| 	main.lo mb8.lo mbwc.lo mbwc-str.lo mem.lo oht.lo opt.lo \ | ||||
| 	path-base.lo path-canon.lo path-core.lo path-merge.lo pma.lo \ | ||||
| 	rbt.lo rex.lo sll.lo slmb.lo str-beg.lo str-cat.lo str-chr.lo \ | ||||
| 	str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo str-dup.lo \ | ||||
| 	str-dyn.lo str-end.lo str-excl.lo str-fcpy.lo str-fmt.lo \ | ||||
| 	str-fnmat.lo str-incl.lo str-join.lo str-len.lo str-pac.lo \ | ||||
| 	str-pbrk.lo str-put.lo str-rev.lo str-rot.lo str-set.lo \ | ||||
| 	str-spl.lo str-spn.lo str-str.lo str-subst.lo str-tok.lo \ | ||||
| 	str-trm.lo str-word.lo time.lo tmr.lo tre.lo tre-ast.lo \ | ||||
| 	tre-compile.lo tre-match-bt.lo tre-match-pa.lo tre-parse.lo \ | ||||
| 	tre-stack.lo uri.lo utf8.lo xma.lo $(am__objects_1) \ | ||||
| 	$(am__objects_2) | ||||
| 	htb.lo htl.lo fma.lo fmt-intmax.lo fmt-out.lo hton.lo hwad.lo \ | ||||
| 	ipad.lo main.lo mb8.lo mbwc.lo mbwc-str.lo mem.lo oht.lo \ | ||||
| 	opt.lo path-base.lo path-canon.lo path-core.lo path-merge.lo \ | ||||
| 	pma.lo rbt.lo rex.lo sll.lo slmb.lo str-beg.lo str-cat.lo \ | ||||
| 	str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo \ | ||||
| 	str-dup.lo str-dyn.lo str-end.lo str-excl.lo str-fcpy.lo \ | ||||
| 	str-fmt.lo str-fnmat.lo str-incl.lo str-join.lo str-len.lo \ | ||||
| 	str-pac.lo str-pbrk.lo str-put.lo str-rev.lo str-rot.lo \ | ||||
| 	str-set.lo str-spl.lo str-spn.lo str-str.lo str-subst.lo \ | ||||
| 	str-tok.lo str-trm.lo str-word.lo time.lo tmr.lo tre.lo \ | ||||
| 	tre-ast.lo tre-compile.lo tre-match-bt.lo tre-match-pa.lo \ | ||||
| 	tre-parse.lo tre-stack.lo uri.lo utf8.lo xma.lo \ | ||||
| 	$(am__objects_1) $(am__objects_2) | ||||
| libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) | ||||
| AM_V_lt = $(am__v_lt_@AM_V@) | ||||
| am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | ||||
| @ -443,7 +443,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
| @ -486,7 +485,7 @@ noinst_HEADERS = \ | ||||
| 	va_copy.h | ||||
|  | ||||
| libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \ | ||||
| 	arr.c assert.c chr.c dll.c env.c gdl.c htb.c fma.c \ | ||||
| 	arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c fma.c \ | ||||
| 	fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \ | ||||
| 	mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \ | ||||
| 	path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \ | ||||
| @ -608,6 +607,7 @@ distclean-compile: | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt-out.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htl.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hton.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwad.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad.Plo@am__quote@ | ||||
|  | ||||
							
								
								
									
										856
									
								
								qse/lib/cmn/htl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										856
									
								
								qse/lib/cmn/htl.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,856 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||
|  | ||||
|     Redistribution and use in source and binary forms, with or without | ||||
|     modification, are permitted provided that the following conditions | ||||
|     are met: | ||||
|     1. Redistributions of source code must retain the above copyright | ||||
|        notice, this list of conditions and the following disclaimer. | ||||
|     2. Redistributions in binary form must reproduce the above copyright | ||||
|        notice, this list of conditions and the following disclaimer in the | ||||
|        documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * hash.c	Non-thread-safe split-ordered hash table. | ||||
|  * | ||||
|  *  The weird "reverse" function is based on an idea from | ||||
|  *  "Split-Ordered Lists - Lock-free Resizable Hash Tables", with | ||||
|  *  modifications so that they're not lock-free. :( | ||||
|  * | ||||
|  *  However, the split-order idea allows a fast & easy splitting of the | ||||
|  *  hash bucket chain when the hash table is resized.  Without it, we'd | ||||
|  *  have to check & update the pointers for every node in the buck chain, | ||||
|  *  rather than being able to move 1/2 of the entries in the chain with | ||||
|  *  one update. | ||||
|  * | ||||
|  * Version:	$Id$ | ||||
|  * | ||||
|  *   This library is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU Lesser General Public | ||||
|  *   License as published by the Free Software Foundation; either | ||||
|  *   version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  *   This library is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
|  *   Lesser General Public License for more details. | ||||
|  * | ||||
|  *   You should have received a copy of the GNU Lesser General Public | ||||
|  *   License along with this library; if not, write to the Free Software | ||||
|  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | ||||
|  * | ||||
|  *  Copyright 2005,2006  The FreeRADIUS server project | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include <qse/cmn/htl.h> | ||||
| #include "mem-prv.h" | ||||
|  | ||||
| /* | ||||
|  *	A reasonable number of buckets to start off with. | ||||
|  *	Should be a power of two. | ||||
|  */ | ||||
| #define QSE_HTL_NUM_BUCKETS (64) | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * perl -e 'foreach $i (0..255) {$r = 0; foreach $j (0 .. 7 ) { if (($i & ( 1<< $j)) != 0) { $r |= (1 << (7 - $j));}} print $r, ", ";if (($i & 7) == 7) {print "\n";}}' | ||||
|  */ | ||||
| static const qse_uint8_t reversed_byte[256] =  | ||||
| { | ||||
| 	0,  128, 64, 192, 32, 160, 96,  224, | ||||
| 	16, 144, 80, 208, 48, 176, 112, 240, | ||||
| 	8,  136, 72, 200, 40, 168, 104, 232, | ||||
| 	24, 152, 88, 216, 56, 184, 120, 248, | ||||
| 	4,  132, 68, 196, 36, 164, 100, 228, | ||||
| 	20, 148, 84, 212, 52, 180, 116, 244, | ||||
| 	12, 140, 76, 204, 44, 172, 108, 236, | ||||
| 	28, 156, 92, 220, 60, 188, 124, 252, | ||||
| 	2,  130, 66, 194, 34, 162, 98,  226, | ||||
| 	18, 146, 82, 210, 50, 178, 114, 242, | ||||
| 	10, 138, 74, 202, 42, 170, 106, 234, | ||||
| 	26, 154, 90, 218, 58, 186, 122, 250, | ||||
| 	6,  134, 70, 198, 38, 166, 102, 230, | ||||
| 	22, 150, 86, 214, 54, 182, 118, 246, | ||||
| 	14, 142, 78, 206, 46, 174, 110, 238, | ||||
| 	30, 158, 94, 222, 62, 190, 126, 254, | ||||
| 	1,  129, 65, 193, 33, 161, 97,  225, | ||||
| 	17, 145, 81, 209, 49, 177, 113, 241, | ||||
| 	9,  137, 73, 201, 41, 169, 105, 233, | ||||
| 	25, 153, 89, 217, 57, 185, 121, 249, | ||||
| 	5,  133, 69, 197, 37, 165, 101, 229, | ||||
| 	21, 149, 85, 213, 53, 181, 117, 245, | ||||
| 	13, 141, 77, 205, 45, 173, 109, 237, | ||||
| 	29, 157, 93, 221, 61, 189, 125, 253, | ||||
| 	3,  131, 67, 195, 35, 163, 99,  227, | ||||
| 	19, 147, 83, 211, 51, 179, 115, 243, | ||||
| 	11, 139, 75, 203, 43, 171, 107, 235, | ||||
| 	27, 155, 91, 219, 59, 187, 123, 251, | ||||
| 	7,  135, 71, 199, 39, 167, 103, 231, | ||||
| 	23, 151, 87, 215, 55, 183, 119, 247, | ||||
| 	15, 143, 79, 207, 47, 175, 111, 239, | ||||
| 	31, 159, 95, 223, 63, 191, 127, 255 | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * perl -e 'foreach $i (0..255) {$r = 0;foreach $j (0 .. 7) { $r = $i & (1 << (7 - $j)); last if ($r)} print $i & ~($r), ", ";if (($i & 7) == 7) {print "\n";}}' | ||||
|  */ | ||||
| static qse_uint8_t parent_byte[256] =  | ||||
| { | ||||
| 	0, 0, 0, 1, 0, 1, 2, 3, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, | ||||
| 	8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, | ||||
| 	8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 	16, 17, 18, 19, 20, 21, 22, 23, | ||||
| 	24, 25, 26, 27, 28, 29, 30, 31, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, | ||||
| 	8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 	16, 17, 18, 19, 20, 21, 22, 23, | ||||
| 	24, 25, 26, 27, 28, 29, 30, 31, | ||||
| 	32, 33, 34, 35, 36, 37, 38, 39, | ||||
| 	40, 41, 42, 43, 44, 45, 46, 47, | ||||
| 	48, 49, 50, 51, 52, 53, 54, 55, | ||||
| 	56, 57, 58, 59, 60, 61, 62, 63, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, | ||||
| 	8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 	16, 17, 18, 19, 20, 21, 22, 23, | ||||
| 	24, 25, 26, 27, 28, 29, 30, 31, | ||||
| 	32, 33, 34, 35, 36, 37, 38, 39, | ||||
| 	40, 41, 42, 43, 44, 45, 46, 47, | ||||
| 	48, 49, 50, 51, 52, 53, 54, 55, | ||||
| 	56, 57, 58, 59, 60, 61, 62, 63, | ||||
| 	64, 65, 66, 67, 68, 69, 70, 71, | ||||
| 	72, 73, 74, 75, 76, 77, 78, 79, | ||||
| 	80, 81, 82, 83, 84, 85, 86, 87, | ||||
| 	88, 89, 90, 91, 92, 93, 94, 95, | ||||
| 	96, 97, 98, 99, 100, 101, 102, 103, | ||||
| 	104, 105, 106, 107, 108, 109, 110, 111, | ||||
| 	112, 113, 114, 115, 116, 117, 118, 119, | ||||
| 	120, 121, 122, 123, 124, 125, 126, 127 | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  *	Reverse a key. | ||||
|  */ | ||||
| static qse_uint32_t reverse (qse_uint32_t key) | ||||
| { | ||||
| 	return ((reversed_byte[key & 0xff] << 24) | | ||||
| 		(reversed_byte[(key >> 8) & 0xff] << 16) | | ||||
| 		(reversed_byte[(key >> 16) & 0xff] << 8) | | ||||
| 		(reversed_byte[(key >> 24) & 0xff])); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Take the parent by discarding the highest bit that is set. | ||||
|  */ | ||||
| static qse_uint32_t parent_of (qse_uint32_t key) | ||||
| { | ||||
| 	if (key > 0x00ffffff) | ||||
| 		return (key & 0x00ffffff) | (parent_byte[key >> 24] << 24); | ||||
|  | ||||
| 	if (key > 0x0000ffff) | ||||
| 		return (key & 0x0000ffff) | (parent_byte[key >> 16] << 16); | ||||
|  | ||||
| 	if (key > 0x000000ff) | ||||
| 		return (key & 0x000000ff) | (parent_byte[key >> 8] << 8); | ||||
|  | ||||
| 	return parent_byte[key]; | ||||
| } | ||||
|  | ||||
|  | ||||
| static qse_htl_node_t *list_find (qse_htl_t* ht, qse_htl_node_t* head, qse_uint32_t reversed, const void* data) | ||||
| { | ||||
| 	qse_htl_node_t *cur; | ||||
|  | ||||
| 	for (cur = head; cur != &ht->null; cur = cur->next)  | ||||
| 	{ | ||||
| 		if (cur->reversed == reversed)  | ||||
| 		{ | ||||
| 			if (ht->comper)  | ||||
| 			{ | ||||
| 				int cmp = ht->comper(ht, data, cur->data); | ||||
| 				if (cmp > 0) break; | ||||
| 				if (cmp < 0) continue; | ||||
| 			} | ||||
| 			return cur; | ||||
| 		} | ||||
| 		if (cur->reversed > reversed) break; | ||||
| 	} | ||||
|  | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  *	Inserts a new entry into the list, in order. | ||||
|  */ | ||||
| static int list_insert (qse_htl_t* ht, qse_htl_node_t** head, qse_htl_node_t* node) | ||||
| { | ||||
| 	qse_htl_node_t **last, *cur; | ||||
|  | ||||
| 	last = head; | ||||
|  | ||||
| 	for (cur = *head; cur != &ht->null; cur = cur->next)  | ||||
| 	{ | ||||
| 		if (cur->reversed > node->reversed) break; | ||||
| 		last = &(cur->next); | ||||
|  | ||||
| 		if (cur->reversed == node->reversed)  | ||||
| 		{ | ||||
| 			if (ht->comper)  | ||||
| 			{ | ||||
| 				int cmp = ht->comper(ht, node->data, cur->data); | ||||
| 				if (cmp > 0) break; | ||||
| 				if (cmp < 0) continue; | ||||
| 			} | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	node->next = *last; | ||||
| 	*last = node; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  *	Delete an entry from the list. | ||||
|  */ | ||||
| static int list_delete (qse_htl_t* ht, qse_htl_node_t** head, qse_htl_node_t* node) | ||||
| { | ||||
| 	qse_htl_node_t **last, *cur; | ||||
|  | ||||
| 	last = head; | ||||
|  | ||||
| 	for (cur = *head; cur != &ht->null; cur = cur->next)  | ||||
| 	{ | ||||
| 		if (cur == node) break; | ||||
| 		last = &(cur->next); | ||||
| 	} | ||||
|  | ||||
| 	*last = node->next; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
|  | ||||
| static QSE_INLINE_ALWAYS qse_size_t default_hasher (qse_htl_t* htl, const void* data) | ||||
| { | ||||
| #if 0 | ||||
| 	qse_size_t h = 5381; | ||||
| 	const qse_byte_t* p = (const qse_byte_t*)data; | ||||
| 	const qse_byte_t* bound = p + htl->keysize; | ||||
| 	while (p < bound) h = ((h << 5) + h) + *p++; | ||||
| 	return h ;  | ||||
| #else | ||||
| 	return qse_genhash (data, htl->keysize); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static QSE_INLINE_ALWAYS int default_comper (qse_htl_t* htl, const void* data1, const void* data2) | ||||
| { | ||||
| 	return QSE_MEMCMP(data1, data2, htl->keysize); | ||||
| } | ||||
|  | ||||
| qse_htl_t* qse_htl_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, int keysize) | ||||
| { | ||||
| 	qse_htl_t* htl; | ||||
|  | ||||
| 	htl = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_htl_t) + xtnsize); | ||||
| 	if (htl == QSE_NULL) return QSE_NULL; | ||||
|  | ||||
| 	if (qse_htl_init (htl, mmgr, keysize) <= -1) | ||||
| 	{ | ||||
| 		QSE_MMGR_FREE (mmgr, htl); | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| 	QSE_MEMSET (htl + 1, 0, xtnsize); | ||||
| 	return htl; | ||||
| } | ||||
|  | ||||
| void qse_htl_close (qse_htl_t* htl) | ||||
| { | ||||
| 	qse_htl_fini (htl); | ||||
| 	QSE_MMGR_FREE (htl->mmgr, htl); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Create the table. | ||||
|  * | ||||
|  *	Memory usage in bytes is (20/3) * number of entries. | ||||
|  */ | ||||
| int qse_htl_init (qse_htl_t* ht, qse_mmgr_t* mmgr, int keysize) | ||||
| { | ||||
| 	QSE_MEMSET (ht, 0, sizeof(*ht)); | ||||
| 	ht->mmgr = mmgr; | ||||
| 	ht->keysize = keysize; | ||||
|  | ||||
| 	ht->hasher = default_hasher; | ||||
| 	ht->comper = default_comper; | ||||
| 	ht->freeer = QSE_NULL; | ||||
| 	ht->copier = QSE_NULL; | ||||
| 	ht->num_buckets = QSE_HTL_NUM_BUCKETS; | ||||
| 	ht->mask = ht->num_buckets - 1; | ||||
|  | ||||
| 	/* | ||||
| 	 *	Have a default load factor of 2.5.  In practice this | ||||
| 	 *	means that the average load will hit 3 before the | ||||
| 	 *	table grows. | ||||
| 	 */ | ||||
| 	ht->next_grow = (ht->num_buckets << 1) + (ht->num_buckets >> 1); | ||||
|  | ||||
| 	ht->buckets = QSE_MMGR_ALLOC (ht->mmgr, QSE_SIZEOF(*ht->buckets) * ht->num_buckets); | ||||
| 	if (!ht->buckets) return -1; | ||||
|  | ||||
| 	QSE_MEMSET (ht->buckets, 0, sizeof(*ht->buckets) * ht->num_buckets); | ||||
|  | ||||
| 	ht->null.reversed = ~0; | ||||
| 	ht->null.key = ~0; | ||||
| 	ht->null.next = &ht->null; | ||||
|  | ||||
| 	ht->buckets[0] = &ht->null; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void qse_htl_fini (qse_htl_t* ht) | ||||
| { | ||||
| 	int i; | ||||
| 	qse_htl_node_t *node, *next; | ||||
|  | ||||
| 	/* | ||||
| 	 *	Walk over the buckets, freeing them all. | ||||
| 	 */ | ||||
| 	for (i = 0; i < ht->num_buckets; i++)  | ||||
| 	{ | ||||
| 		if (ht->buckets[i])  | ||||
| 		{ | ||||
| 			for (node = ht->buckets[i]; node != &ht->null; node = next)  | ||||
| 			{ | ||||
| 				next = node->next; | ||||
|  | ||||
| 				if (!node->data) continue; /* dummy entry */ | ||||
|  | ||||
| 				if (ht->freeer) ht->freeer (ht, node->data); | ||||
| 				QSE_MMGR_FREE (ht->mmgr, node); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	QSE_MMGR_FREE (ht->mmgr, ht->buckets); | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| /* | ||||
|  *	If the current bucket is uninitialized, initialize it | ||||
|  *	by recursively copying information from the parent. | ||||
|  * | ||||
|  *	We may have a situation where entry E is a parent to 2 other | ||||
|  *	entries E' and E".  If we split E into E and E', then the | ||||
|  *	nodes meant for E" end up in E or E', either of which is | ||||
|  *	wrong.  To solve that problem, we walk down the whole chain, | ||||
|  *	inserting the elements into the correct place. | ||||
|  */ | ||||
| static void fixup (qse_htl_t *ht, qse_uint32_t entry) | ||||
| { | ||||
| 	qse_uint32_t parent_entry; | ||||
| 	qse_htl_node_t** last, * cur; | ||||
| 	qse_uint32_t thiss; | ||||
|  | ||||
| 	parent_entry = parent_of(entry); | ||||
|  | ||||
| 	/* parent_entry == entry if and only if entry == 0 */ | ||||
|  | ||||
| 	if (!ht->buckets[parent_entry])  | ||||
| 	{ | ||||
| 		fixup(ht, parent_entry); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 *	Keep walking down cur, trying to find entries that | ||||
| 	 *	don't belong here any more.  There may be multiple | ||||
| 	 *	ones, so we can't have a naive algorithm... | ||||
| 	 */ | ||||
| 	last = &ht->buckets[parent_entry]; | ||||
| 	thiss = parent_entry; | ||||
|  | ||||
| 	for (cur = *last; cur != &ht->null; cur = cur->next)  | ||||
| 	{ | ||||
| 		qse_uint32_t real_entry; | ||||
|  | ||||
| 		real_entry = cur->key & ht->mask; | ||||
| 		if (real_entry != thiss)  | ||||
| 		{ /* ht->buckets[real_entry] == QSE_NULL */ | ||||
| 			*last = &ht->null; | ||||
| 			ht->buckets[real_entry] = cur; | ||||
| 			thiss = real_entry; | ||||
| 		} | ||||
|  | ||||
| 		last = &(cur->next); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 *	We may NOT have initialized this bucket, so do it now. | ||||
| 	 */ | ||||
| 	if (!ht->buckets[entry]) ht->buckets[entry] = &ht->null; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	This should be a power of two.  Changing it to 4 doesn't seem | ||||
|  *	to make any difference. | ||||
|  */ | ||||
| #define GROW_FACTOR (2) | ||||
|  | ||||
| /* | ||||
|  *	Grow the hash table. | ||||
|  */ | ||||
| static void grow (qse_htl_t *ht) | ||||
| { | ||||
| 	qse_htl_node_t **buckets; | ||||
|  | ||||
| 	buckets = QSE_MMGR_ALLOC (ht->mmgr, QSE_SIZEOF(*buckets) * GROW_FACTOR * ht->num_buckets); | ||||
| 	if (!buckets) return; | ||||
|  | ||||
| 	QSE_MEMCPY (buckets, ht->buckets, QSE_SIZEOF(*buckets) * ht->num_buckets); | ||||
| 	QSE_MEMSET (&buckets[ht->num_buckets], 0, QSE_SIZEOF(*buckets) * ht->num_buckets); | ||||
|  | ||||
| 	QSE_MMGR_FREE (ht->mmgr, ht->buckets); | ||||
| 	ht->buckets = buckets; | ||||
| 	ht->num_buckets *= GROW_FACTOR; | ||||
| 	ht->next_grow *= GROW_FACTOR; | ||||
| 	ht->mask = ht->num_buckets - 1; | ||||
| } | ||||
|  | ||||
| qse_htl_node_t *qse_htl_search (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_uint32_t key; | ||||
| 	qse_uint32_t entry; | ||||
| 	qse_uint32_t reversed; | ||||
|  | ||||
| 	key = ht->hasher(ht, data); | ||||
| 	entry = key & ht->mask; | ||||
| 	reversed = reverse(key); | ||||
|  | ||||
| 	if (!ht->buckets[entry]) fixup(ht, entry); | ||||
| 	return list_find(ht, ht->buckets[entry], reversed, data); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Insert data. | ||||
|  */ | ||||
| qse_htl_node_t* qse_htl_insert (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_uint32_t key; | ||||
| 	qse_uint32_t entry; | ||||
| 	qse_uint32_t reversed; | ||||
| 	qse_htl_node_t *node; | ||||
|  | ||||
| 	key = ht->hasher(ht, data); | ||||
| 	entry = key & ht->mask; | ||||
| 	reversed = reverse(key); | ||||
|  | ||||
| 	if (!ht->buckets[entry]) fixup(ht, entry); | ||||
|  | ||||
| 	/* | ||||
| 	 *	If we try to do our own memory allocation here, the | ||||
| 	 *	speedup is only ~15% or so, which isn't worth it. | ||||
| 	 */ | ||||
| 	node = QSE_MMGR_ALLOC(ht->mmgr, QSE_SIZEOF(*node)); | ||||
| 	if (!node) return QSE_NULL; | ||||
| 	QSE_MEMSET (node, 0, QSE_SIZEOF(*node)); | ||||
|  | ||||
| 	node->next = &ht->null; | ||||
| 	node->reversed = reversed; | ||||
| 	node->key = key; | ||||
|  | ||||
| 	if (ht->copier)  | ||||
| 	{ | ||||
| 		node->data = ht->copier (ht, data); | ||||
| 		if (!node->data) | ||||
| 		{ | ||||
| 			QSE_MMGR_FREE (ht->mmgr, node); | ||||
| 			return QSE_NULL; | ||||
| 		} | ||||
| 	} | ||||
| 	else node->data = data; | ||||
|  | ||||
| 	/* already in the table, can't insert it */ | ||||
| 	if (!list_insert(ht, &ht->buckets[entry], node))  | ||||
| 	{ | ||||
| 		if (ht->freeer) ht->freeer (ht, node->data); | ||||
| 		QSE_MMGR_FREE (ht->mmgr, node); | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 *	Check the load factor, and grow the table if | ||||
| 	 *	necessary. | ||||
| 	 */ | ||||
| 	ht->num_elements++; | ||||
| 	if (ht->num_elements >= ht->next_grow) grow(ht); | ||||
|  | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Replace old data with new data, OR insert if there is no old. | ||||
|  */ | ||||
| qse_htl_node_t* qse_htl_upsert (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_htl_node_t *node; | ||||
| 	void* datap; | ||||
|  | ||||
| 	node = qse_htl_search(ht, data); | ||||
| 	if (!node) return qse_htl_insert(ht, data); | ||||
|  | ||||
| 	if (ht->copier)  | ||||
| 	{ | ||||
| 		datap = ht->copier (ht, data); | ||||
| 		if (!datap) return QSE_NULL; | ||||
| 	} | ||||
| 	else datap = data; | ||||
|  | ||||
| 	if (ht->freeer) ht->freeer(ht, node->data); | ||||
| 	node->data = datap; | ||||
|  | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| qse_htl_node_t* qse_htl_update (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_htl_node_t *node; | ||||
| 	void* datap; | ||||
|  | ||||
| 	node = qse_htl_search(ht, data); | ||||
| 	if (!node) return QSE_NULL; | ||||
|  | ||||
| 	if (ht->copier)  | ||||
| 	{ | ||||
| 		datap = ht->copier (ht, data); | ||||
| 		if (!datap) return QSE_NULL; | ||||
| 	} | ||||
| 	else datap = data; | ||||
|  | ||||
| 	if (ht->freeer) ht->freeer(ht, node->data); | ||||
| 	node->data = datap; | ||||
|  | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| qse_htl_node_t* qse_htl_ensert (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_htl_node_t *node; | ||||
|  | ||||
| 	node = qse_htl_search(ht, data); | ||||
| 	if (!node) return qse_htl_insert(ht, data); | ||||
|  | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Yank an entry from the hash table, without freeing the data. | ||||
|  */ | ||||
| void* qse_htl_yank (qse_htl_t* ht, void* data) | ||||
| { | ||||
| 	qse_uint32_t key; | ||||
| 	qse_uint32_t entry; | ||||
| 	qse_uint32_t reversed; | ||||
| 	void *old; | ||||
| 	qse_htl_node_t* node; | ||||
|  | ||||
| 	if (!ht) return QSE_NULL; | ||||
|  | ||||
| 	key = ht->hasher(ht, data); | ||||
| 	entry = key & ht->mask; | ||||
| 	reversed = reverse(key); | ||||
|  | ||||
| 	if (!ht->buckets[entry]) fixup(ht, entry); | ||||
|  | ||||
| 	node = list_find(ht, ht->buckets[entry], reversed, data); | ||||
| 	if (!node) return QSE_NULL; | ||||
|  | ||||
| 	list_delete(ht, &ht->buckets[entry], node); | ||||
| 	ht->num_elements--; | ||||
|  | ||||
| 	old = node->data; | ||||
| 	QSE_MMGR_FREE (ht->mmgr, node); | ||||
|  | ||||
| 	return old; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Delete a piece of data from the hash table. | ||||
|  */ | ||||
| int qse_htl_delete(qse_htl_t *ht, void* data) | ||||
| { | ||||
| 	void* old; | ||||
|  | ||||
| 	old = qse_htl_yank(ht, data); | ||||
| 	if (!old) return -1; | ||||
|  | ||||
| 	if (ht->freeer) ht->freeer(ht, old); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Walk over the nodes, allowing deletes & inserts to happen. | ||||
|  */ | ||||
| void qse_htl_walk (qse_htl_t *ht, qse_htl_walker_t walker, void *ctx) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = ht->num_buckets - 1; i >= 0; i--)  | ||||
| 	{ | ||||
| 		qse_htl_node_t* node, * next; | ||||
|  | ||||
| 		/* | ||||
| 		 *	Ensure that the current bucket is filled. | ||||
| 		 */ | ||||
| 		if (!ht->buckets[i]) fixup(ht, i); | ||||
|  | ||||
| 		for (node = ht->buckets[i]; node != &ht->null; node = next)  | ||||
| 		{ | ||||
| 			next = node->next; | ||||
| 			if (walker(ht, node->data, ctx) == QSE_HTL_WALK_STOP) return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| /* | ||||
|  *	Find data from a template | ||||
|  */ | ||||
| void *qse_htl_finddata(qse_htl_t *ht, const void *data) | ||||
| { | ||||
| 	qse_htl_node_t *node; | ||||
|  | ||||
| 	node = qse_htl_find(ht, data); | ||||
| 	if (!node) return NULL; | ||||
|  | ||||
| 	return node->data; | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef TESTING | ||||
| /* | ||||
|  *	Show what the hash table is doing. | ||||
|  */ | ||||
| int qse_htl_info(qse_htl_t *ht) | ||||
| { | ||||
| 	int i, a, collisions, uninitialized; | ||||
| 	int array[256]; | ||||
|  | ||||
| 	if (!ht) return 0; | ||||
|  | ||||
| 	uninitialized = collisions = 0; | ||||
| 	memset(array, 0, sizeof(array)); | ||||
|  | ||||
| 	for (i = 0; i < ht->num_buckets; i++) { | ||||
| 		qse_uint32_t key; | ||||
| 		int load; | ||||
| 		qse_htl_node_t *node, *next; | ||||
|  | ||||
| 		/* | ||||
| 		 *	If we haven't inserted or looked up an entry | ||||
| 		 *	in a bucket, it's uninitialized. | ||||
| 		 */ | ||||
| 		if (!ht->buckets[i]) { | ||||
| 			uninitialized++; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		load = 0; | ||||
| 		key = ~0; | ||||
| 		for (node = ht->buckets[i]; node != &ht->null; node = next) { | ||||
| 			if (node->reversed == key) { | ||||
| 				collisions++; | ||||
| 			} else { | ||||
| 				key = node->reversed; | ||||
| 			} | ||||
| 			next = node->next; | ||||
| 			load++; | ||||
| 		} | ||||
|  | ||||
| 		if (load > 255) load = 255; | ||||
| 		array[load]++; | ||||
| 	} | ||||
|  | ||||
| 	printf("HASH TABLE %p\tbuckets: %d\t(%d uninitialized)\n", ht, | ||||
| 		ht->num_buckets, uninitialized); | ||||
| 	printf("\tnum entries %d\thash collisions %d\n", | ||||
| 		ht->num_elements, collisions); | ||||
|  | ||||
| 	a = 0; | ||||
| 	for (i = 1; i < 256; i++) { | ||||
| 		if (!array[i]) continue; | ||||
| 		printf("%d\t%d\n", i, array[i]); | ||||
|  | ||||
| 		/* | ||||
| 		 *	Since the entries are ordered, the lookup cost | ||||
| 		 *	for any one element in a chain is (on average) | ||||
| 		 *	the cost of walking half of the chain. | ||||
| 		 */ | ||||
| 		if (i > 1) { | ||||
| 			a += array[i] * i; | ||||
| 		} | ||||
| 	} | ||||
| 	a /= 2; | ||||
| 	a += array[1]; | ||||
|  | ||||
| 	printf("\texpected lookup cost = %d/%d or %f\n\n", | ||||
| 	       ht->num_elements, a, | ||||
| 	       (float) ht->num_elements / (float) a); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
|  | ||||
| #define FNV_MAGIC_INIT (0x811c9dc5) | ||||
| #define FNV_MAGIC_PRIME (0x01000193) | ||||
|  | ||||
| /* | ||||
|  *	A fast hash function.  For details, see: | ||||
|  * | ||||
|  *	http://www.isthe.com/chongo/tech/comp/fnv/ | ||||
|  * | ||||
|  *	Which also includes public domain source.  We've re-written | ||||
|  *	it here for our purposes. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  *	Continue hashing data. | ||||
|  */ | ||||
| QSE_INLINE qse_uint32_t qse_genhash_update (const void* data, qse_size_t size, qse_uint32_t hash) | ||||
| { | ||||
| 	const qse_uint8_t *p = data; | ||||
| 	const qse_uint8_t *q = p + size; | ||||
|  | ||||
| 	/* | ||||
| 	 *	FNV-1 hash each octet in the buffer | ||||
| 	 */ | ||||
| 	while (p != q)  | ||||
| 	{ | ||||
| 		/* | ||||
| 		 *	XOR the 8-bit quantity into the bottom of | ||||
| 		 *	the hash. | ||||
| 		 */ | ||||
| 		hash ^= (qse_uint32_t) (*p++); | ||||
|  | ||||
| 		/* | ||||
| 		 *	Multiple by 32-bit magic FNV prime, mod 2^32 | ||||
| 		 */ | ||||
| 		hash *= FNV_MAGIC_PRIME; | ||||
| 	#if 0 | ||||
| 		/* | ||||
| 		 *	Potential optimization. | ||||
| 		 */ | ||||
| 		hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24); | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
|  | ||||
| qse_uint32_t qse_genhash (const void *data, qse_size_t size) | ||||
| { | ||||
| 	return qse_genhash_update (data, size, FNV_MAGIC_INIT); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *	Hash a C string, so we loop over it once. | ||||
|  */ | ||||
| qse_uint32_t qse_mbshash (const qse_mchar_t* p) | ||||
| { | ||||
| 	qse_uint32_t hash = FNV_MAGIC_INIT; | ||||
|  | ||||
| 	while (*p)  | ||||
| 	{ | ||||
| 		hash ^= (qse_uint32_t) (*p++); | ||||
| 		hash *= FNV_MAGIC_PRIME; | ||||
| 	} | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
|  | ||||
| qse_uint32_t qse_wcshash (const qse_wchar_t* p) | ||||
| { | ||||
|  | ||||
| 	qse_uint32_t hash = FNV_MAGIC_INIT; | ||||
|  | ||||
| 	while (*p)  | ||||
| 	{ | ||||
| #if (QSE_SIZEOF_WCHAR_T <= QSE_SIZEOF_UINT32_T) | ||||
| 		hash ^= (qse_uint32_t)(*p); | ||||
| 		hash *= FNV_MAGIC_PRIME; | ||||
| #else | ||||
| 		hash = qse_genhash_update (*p, QSE_SIZEOF(*p), hash); | ||||
| #endif | ||||
| 		p++; | ||||
| 	} | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| /* | ||||
|  *	Return a "folded" hash, where the lower "bits" are the | ||||
|  *	hash, and the upper bits are zero. | ||||
|  * | ||||
|  *	If you need a non-power-of-two hash, cope. | ||||
|  */ | ||||
| qse_uint32_t qse_foldhash (qse_uint32_t hash, int bits) | ||||
| { | ||||
| 	int count; | ||||
| 	qse_uint32_t result; | ||||
|  | ||||
| 	if ((bits <= 0) || (bits >= 32)) return hash; | ||||
|  | ||||
| 	result = hash; | ||||
|  | ||||
| 	/* | ||||
| 	 *	Never use the same bits twice in an xor. | ||||
| 	 */ | ||||
| 	for (count = 0; count < 32; count += bits)  | ||||
| 	{ | ||||
| 		hash >>= bits; | ||||
| 		result ^= hash; | ||||
| 	} | ||||
|  | ||||
| 	return result & (((qse_uint32_t) (1 << bits)) - 1); | ||||
| } | ||||
| #endif | ||||
| @ -377,7 +377,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -384,7 +384,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -377,7 +377,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
							
								
								
									
										1093
									
								
								qse/lib/rad/raddic.c
									
									
									
									
									
								
							
							
						
						
									
										1093
									
								
								qse/lib/rad/raddic.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -408,7 +408,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -26,9 +26,8 @@ | ||||
|  | ||||
| #include <qse/si/AppRoot.hpp> | ||||
| #include <qse/si/sinfo.h> | ||||
| #include <qse/cmn/mem.h> | ||||
| #include <qse/cmn/mbwc.h> | ||||
| #include "../cmn/syscall.h" | ||||
| #include <qse/cmn/mbwc.h> | ||||
|  | ||||
| ///////////////////////////////// | ||||
| QSE_BEGIN_NAMESPACE(QSE) | ||||
| @ -42,7 +41,6 @@ int AppRoot::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | ||||
| 	{ | ||||
| 		if (fork_count >= 2) | ||||
| 		{ | ||||
| 			struct sigaction sa; | ||||
| 			int n = QSE_FORK(); | ||||
| 			if (n == -1) return -1; | ||||
| 			if (n != 0) QSE_EXIT(0); | ||||
| @ -103,64 +101,53 @@ int AppRoot::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| int AppRoot::switchUser () QSE_CPP_NOEXCEPT | ||||
| { | ||||
| 	struct passwd* pw; | ||||
|  | ||||
| 	pw = getpwnam (username); | ||||
| 	if (!pw) | ||||
|  | ||||
|  | ||||
| 	if (QSE_SETGID(pw->pw_gid) == -1) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	QSE_SETEGID(gid); | ||||
| 	QSE_SETUID(uid); | ||||
| 	QSE_SETEUID(uid); | ||||
|  | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| int AppRoot::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT | ||||
| { | ||||
| 	int orgdirfd; | ||||
|  | ||||
| 	orgdirfd = QSE_OPEN (".", O_RDONLY, 0); | ||||
| 	if (orgdirfd == -1) return -1; | ||||
|  | ||||
| 	if (QSE_CHDIR(mpath) == -1) return -1; | ||||
| 	if (QSE_CHROOT(mpath) == -1) | ||||
| 	{ | ||||
| 		QSE_FCHDIR (orgdirfd); | ||||
| 		QSE_CLOSE (orgdirfd); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	QSE_CLOSE (orgdirfd); | ||||
| 	QSE_CHROOT ("/"); | ||||
|  | ||||
| 	return 0; | ||||
| 	return QSE_CHROOT (mpath); | ||||
| } | ||||
|  | ||||
| int AppRoot::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT | ||||
| { | ||||
| 	qse_mchar_t* mpath; | ||||
|  | ||||
| 	mpath = qse_wcstombsdup (wpath, QSE_NULL, QSE_MMGR_GETDFL()); | ||||
| 	mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr()); | ||||
| 	if (!mpath) return -1; | ||||
|  | ||||
| 	int n = AppRoot::chroot ((const qse_mchar_t*)mpath); | ||||
| 	QSE_MMGR_FREE (QSE_MMGR_GETDFL(), mpath); | ||||
| 	this->getMmgr()->dispose (mpath); | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| void AppRoot::on_signal () QSE_CPP_NOEXCEPT | ||||
| #if 0 | ||||
| int AppRoot::switchPrivilege (int gid, int uid, bool permanently) | ||||
| { | ||||
| 	gid = QSE_GETGID(); | ||||
| 	uid = QSE_GETUID(); | ||||
|  | ||||
| 	this->saved_egid = QSE_GETEGID(); | ||||
| 	this->saved_euid = QSE_GETEUID(); | ||||
| 	this->saved_ngroups = getgroups (QSE_COUNTOF(this->saved_groups), this->saved_groups); | ||||
|  | ||||
| 	if (this->saved_euid ==  0) setgrops (1, gid); | ||||
|  | ||||
| 	setegid (gid); | ||||
| 	//setregid (-1, gid); | ||||
|  | ||||
| 	if (uid != this->saved_euid) | ||||
| 	{ | ||||
| 		seteuid (uid); | ||||
| 		//setreuid (-1, uid); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int AppRoot::restorePrivilege () | ||||
| { | ||||
| 	if (QSE_GETEUID() != this->saved_euid) seteuid (this->saved_euid); | ||||
| 	if (QSE_GETEGID() != this->saved_egid) setegid (this->saved_egid); | ||||
| 	if (this->saved_euid == 0) setgroups (this->saved_ngroups, this->saved_groups); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if 0 | ||||
| int main () | ||||
| @ -168,8 +155,10 @@ int main () | ||||
| 	AppRoot app; | ||||
|  | ||||
| 	app.daemonize(); | ||||
| 	app.switchUser ("nobody", "nobody"); | ||||
| 	app.switchUser (10, 20); | ||||
| 	app.chuser (); | ||||
| 	app.chgroup (); | ||||
| 	app.chroot (); | ||||
|  | ||||
| 	app.catchSignal (SIGINT, xxxxx); | ||||
| 	app.catchSignal (SIGTERM, xxx); | ||||
|  | ||||
|  | ||||
| @ -423,7 +423,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
| @ -377,7 +377,6 @@ pdfdir = @pdfdir@ | ||||
| prefix = @prefix@ | ||||
| program_transform_name = @program_transform_name@ | ||||
| psdir = @psdir@ | ||||
| runstatedir = @runstatedir@ | ||||
| sbindir = @sbindir@ | ||||
| sharedstatedir = @sharedstatedir@ | ||||
| srcdir = @srcdir@ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user