1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate * All rights reserved.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
31*7c478bd9Sstevel@tonic-gate #include <strings.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate
35*7c478bd9Sstevel@tonic-gate #include "strtab.h"
36*7c478bd9Sstevel@tonic-gate #include "memory.h"
37*7c478bd9Sstevel@tonic-gate
38*7c478bd9Sstevel@tonic-gate #define STRTAB_HASHSZ 211 /* use a prime number of hash buckets */
39*7c478bd9Sstevel@tonic-gate #define STRTAB_BUFSZ (64 * 1024) /* use 64K data buffers by default */
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gate static void
strtab_grow(strtab_t * sp)42*7c478bd9Sstevel@tonic-gate strtab_grow(strtab_t *sp)
43*7c478bd9Sstevel@tonic-gate {
44*7c478bd9Sstevel@tonic-gate sp->str_nbufs++;
45*7c478bd9Sstevel@tonic-gate sp->str_bufs = xrealloc(sp->str_bufs, sp->str_nbufs * sizeof (char *));
46*7c478bd9Sstevel@tonic-gate sp->str_ptr = xmalloc(sp->str_bufsz);
47*7c478bd9Sstevel@tonic-gate sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr;
48*7c478bd9Sstevel@tonic-gate }
49*7c478bd9Sstevel@tonic-gate
50*7c478bd9Sstevel@tonic-gate void
strtab_create(strtab_t * sp)51*7c478bd9Sstevel@tonic-gate strtab_create(strtab_t *sp)
52*7c478bd9Sstevel@tonic-gate {
53*7c478bd9Sstevel@tonic-gate sp->str_hash = xcalloc(STRTAB_HASHSZ * sizeof (strhash_t *));
54*7c478bd9Sstevel@tonic-gate sp->str_hashsz = STRTAB_HASHSZ;
55*7c478bd9Sstevel@tonic-gate sp->str_bufs = NULL;
56*7c478bd9Sstevel@tonic-gate sp->str_ptr = NULL;
57*7c478bd9Sstevel@tonic-gate sp->str_nbufs = 0;
58*7c478bd9Sstevel@tonic-gate sp->str_bufsz = STRTAB_BUFSZ;
59*7c478bd9Sstevel@tonic-gate sp->str_nstrs = 1;
60*7c478bd9Sstevel@tonic-gate sp->str_size = 1;
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gate strtab_grow(sp);
63*7c478bd9Sstevel@tonic-gate *sp->str_ptr++ = '\0';
64*7c478bd9Sstevel@tonic-gate }
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gate void
strtab_destroy(strtab_t * sp)67*7c478bd9Sstevel@tonic-gate strtab_destroy(strtab_t *sp)
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate strhash_t *hp, *hq;
70*7c478bd9Sstevel@tonic-gate ulong_t i;
71*7c478bd9Sstevel@tonic-gate
72*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->str_hashsz; i++) {
73*7c478bd9Sstevel@tonic-gate for (hp = sp->str_hash[i]; hp != NULL; hp = hq) {
74*7c478bd9Sstevel@tonic-gate hq = hp->str_next;
75*7c478bd9Sstevel@tonic-gate free(hp);
76*7c478bd9Sstevel@tonic-gate }
77*7c478bd9Sstevel@tonic-gate }
78*7c478bd9Sstevel@tonic-gate
79*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->str_nbufs; i++)
80*7c478bd9Sstevel@tonic-gate free(sp->str_bufs[i]);
81*7c478bd9Sstevel@tonic-gate
82*7c478bd9Sstevel@tonic-gate free(sp->str_hash);
83*7c478bd9Sstevel@tonic-gate free(sp->str_bufs);
84*7c478bd9Sstevel@tonic-gate }
85*7c478bd9Sstevel@tonic-gate
86*7c478bd9Sstevel@tonic-gate static ulong_t
strtab_hash(const char * key,size_t * len)87*7c478bd9Sstevel@tonic-gate strtab_hash(const char *key, size_t *len)
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate ulong_t g, h = 0;
90*7c478bd9Sstevel@tonic-gate const char *p;
91*7c478bd9Sstevel@tonic-gate size_t n = 0;
92*7c478bd9Sstevel@tonic-gate
93*7c478bd9Sstevel@tonic-gate for (p = key; *p != '\0'; p++, n++) {
94*7c478bd9Sstevel@tonic-gate h = (h << 4) + *p;
95*7c478bd9Sstevel@tonic-gate
96*7c478bd9Sstevel@tonic-gate if ((g = (h & 0xf0000000)) != 0) {
97*7c478bd9Sstevel@tonic-gate h ^= (g >> 24);
98*7c478bd9Sstevel@tonic-gate h ^= g;
99*7c478bd9Sstevel@tonic-gate }
100*7c478bd9Sstevel@tonic-gate }
101*7c478bd9Sstevel@tonic-gate
102*7c478bd9Sstevel@tonic-gate *len = n;
103*7c478bd9Sstevel@tonic-gate return (h);
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate
106*7c478bd9Sstevel@tonic-gate static int
strtab_compare(strtab_t * sp,strhash_t * hp,const char * str,size_t len)107*7c478bd9Sstevel@tonic-gate strtab_compare(strtab_t *sp, strhash_t *hp, const char *str, size_t len)
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate ulong_t b = hp->str_buf;
110*7c478bd9Sstevel@tonic-gate const char *buf = hp->str_data;
111*7c478bd9Sstevel@tonic-gate size_t resid, n;
112*7c478bd9Sstevel@tonic-gate int rv;
113*7c478bd9Sstevel@tonic-gate
114*7c478bd9Sstevel@tonic-gate while (len != 0) {
115*7c478bd9Sstevel@tonic-gate if (buf == sp->str_bufs[b] + sp->str_bufsz)
116*7c478bd9Sstevel@tonic-gate buf = sp->str_bufs[++b];
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate resid = sp->str_bufs[b] + sp->str_bufsz - buf;
119*7c478bd9Sstevel@tonic-gate n = MIN(resid, len);
120*7c478bd9Sstevel@tonic-gate
121*7c478bd9Sstevel@tonic-gate if ((rv = strncmp(buf, str, n)) != 0)
122*7c478bd9Sstevel@tonic-gate return (rv);
123*7c478bd9Sstevel@tonic-gate
124*7c478bd9Sstevel@tonic-gate buf += n;
125*7c478bd9Sstevel@tonic-gate str += n;
126*7c478bd9Sstevel@tonic-gate len -= n;
127*7c478bd9Sstevel@tonic-gate }
128*7c478bd9Sstevel@tonic-gate
129*7c478bd9Sstevel@tonic-gate return (0);
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate
132*7c478bd9Sstevel@tonic-gate static void
strtab_copyin(strtab_t * sp,const char * str,size_t len)133*7c478bd9Sstevel@tonic-gate strtab_copyin(strtab_t *sp, const char *str, size_t len)
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate ulong_t b = sp->str_nbufs - 1;
136*7c478bd9Sstevel@tonic-gate size_t resid, n;
137*7c478bd9Sstevel@tonic-gate
138*7c478bd9Sstevel@tonic-gate while (len != 0) {
139*7c478bd9Sstevel@tonic-gate if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) {
140*7c478bd9Sstevel@tonic-gate strtab_grow(sp);
141*7c478bd9Sstevel@tonic-gate b++;
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate
144*7c478bd9Sstevel@tonic-gate resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr;
145*7c478bd9Sstevel@tonic-gate n = MIN(resid, len);
146*7c478bd9Sstevel@tonic-gate bcopy(str, sp->str_ptr, n);
147*7c478bd9Sstevel@tonic-gate
148*7c478bd9Sstevel@tonic-gate sp->str_ptr += n;
149*7c478bd9Sstevel@tonic-gate str += n;
150*7c478bd9Sstevel@tonic-gate len -= n;
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate }
153*7c478bd9Sstevel@tonic-gate
154*7c478bd9Sstevel@tonic-gate size_t
strtab_insert(strtab_t * sp,const char * str)155*7c478bd9Sstevel@tonic-gate strtab_insert(strtab_t *sp, const char *str)
156*7c478bd9Sstevel@tonic-gate {
157*7c478bd9Sstevel@tonic-gate strhash_t *hp;
158*7c478bd9Sstevel@tonic-gate size_t len;
159*7c478bd9Sstevel@tonic-gate ulong_t h;
160*7c478bd9Sstevel@tonic-gate
161*7c478bd9Sstevel@tonic-gate if (str == NULL || str[0] == '\0')
162*7c478bd9Sstevel@tonic-gate return (0); /* we keep a \0 at offset 0 to simplify things */
163*7c478bd9Sstevel@tonic-gate
164*7c478bd9Sstevel@tonic-gate h = strtab_hash(str, &len) % sp->str_hashsz;
165*7c478bd9Sstevel@tonic-gate
166*7c478bd9Sstevel@tonic-gate /*
167*7c478bd9Sstevel@tonic-gate * If the string is already in our hash table, just return the offset
168*7c478bd9Sstevel@tonic-gate * of the existing string element and do not add a duplicate string.
169*7c478bd9Sstevel@tonic-gate */
170*7c478bd9Sstevel@tonic-gate for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) {
171*7c478bd9Sstevel@tonic-gate if (strtab_compare(sp, hp, str, len + 1) == 0)
172*7c478bd9Sstevel@tonic-gate return (hp->str_off);
173*7c478bd9Sstevel@tonic-gate }
174*7c478bd9Sstevel@tonic-gate
175*7c478bd9Sstevel@tonic-gate /*
176*7c478bd9Sstevel@tonic-gate * Create a new hash bucket, initialize it, and insert it at the front
177*7c478bd9Sstevel@tonic-gate * of the hash chain for the appropriate bucket.
178*7c478bd9Sstevel@tonic-gate */
179*7c478bd9Sstevel@tonic-gate hp = xmalloc(sizeof (strhash_t));
180*7c478bd9Sstevel@tonic-gate
181*7c478bd9Sstevel@tonic-gate hp->str_data = sp->str_ptr;
182*7c478bd9Sstevel@tonic-gate hp->str_buf = sp->str_nbufs - 1;
183*7c478bd9Sstevel@tonic-gate hp->str_off = sp->str_size;
184*7c478bd9Sstevel@tonic-gate hp->str_len = len;
185*7c478bd9Sstevel@tonic-gate hp->str_next = sp->str_hash[h];
186*7c478bd9Sstevel@tonic-gate
187*7c478bd9Sstevel@tonic-gate sp->str_hash[h] = hp;
188*7c478bd9Sstevel@tonic-gate
189*7c478bd9Sstevel@tonic-gate /*
190*7c478bd9Sstevel@tonic-gate * Now copy the string data into our buffer list, and then update
191*7c478bd9Sstevel@tonic-gate * the global counts of strings and bytes. Return str's byte offset.
192*7c478bd9Sstevel@tonic-gate */
193*7c478bd9Sstevel@tonic-gate strtab_copyin(sp, str, len + 1);
194*7c478bd9Sstevel@tonic-gate sp->str_nstrs++;
195*7c478bd9Sstevel@tonic-gate sp->str_size += len + 1;
196*7c478bd9Sstevel@tonic-gate
197*7c478bd9Sstevel@tonic-gate return (hp->str_off);
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate
200*7c478bd9Sstevel@tonic-gate size_t
strtab_size(const strtab_t * sp)201*7c478bd9Sstevel@tonic-gate strtab_size(const strtab_t *sp)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate return (sp->str_size);
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate
206*7c478bd9Sstevel@tonic-gate ssize_t
strtab_write(const strtab_t * sp,ssize_t (* func)(const void *,size_t,void *),void * priv)207*7c478bd9Sstevel@tonic-gate strtab_write(const strtab_t *sp,
208*7c478bd9Sstevel@tonic-gate ssize_t (*func)(const void *, size_t, void *), void *priv)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate ssize_t res, total = 0;
211*7c478bd9Sstevel@tonic-gate ulong_t i;
212*7c478bd9Sstevel@tonic-gate size_t n;
213*7c478bd9Sstevel@tonic-gate
214*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->str_nbufs; i++, total += res) {
215*7c478bd9Sstevel@tonic-gate if (i == sp->str_nbufs - 1)
216*7c478bd9Sstevel@tonic-gate n = sp->str_ptr - sp->str_bufs[i];
217*7c478bd9Sstevel@tonic-gate else
218*7c478bd9Sstevel@tonic-gate n = sp->str_bufsz;
219*7c478bd9Sstevel@tonic-gate
220*7c478bd9Sstevel@tonic-gate if ((res = func(sp->str_bufs[i], n, priv)) <= 0)
221*7c478bd9Sstevel@tonic-gate break;
222*7c478bd9Sstevel@tonic-gate }
223*7c478bd9Sstevel@tonic-gate
224*7c478bd9Sstevel@tonic-gate if (total == 0 && sp->str_size != 0)
225*7c478bd9Sstevel@tonic-gate return (-1);
226*7c478bd9Sstevel@tonic-gate
227*7c478bd9Sstevel@tonic-gate return (total);
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate
230*7c478bd9Sstevel@tonic-gate void
strtab_print(const strtab_t * sp)231*7c478bd9Sstevel@tonic-gate strtab_print(const strtab_t *sp)
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate const strhash_t *hp;
234*7c478bd9Sstevel@tonic-gate ulong_t i;
235*7c478bd9Sstevel@tonic-gate
236*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->str_hashsz; i++) {
237*7c478bd9Sstevel@tonic-gate for (hp = sp->str_hash[i]; hp != NULL; hp = hp->str_next) {
238*7c478bd9Sstevel@tonic-gate const char *buf = hp->str_data;
239*7c478bd9Sstevel@tonic-gate ulong_t b = hp->str_buf;
240*7c478bd9Sstevel@tonic-gate size_t resid, len, n;
241*7c478bd9Sstevel@tonic-gate
242*7c478bd9Sstevel@tonic-gate (void) printf("[%lu] %lu \"", (ulong_t)hp->str_off, b);
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate for (len = hp->str_len; len != 0; len -= n) {
245*7c478bd9Sstevel@tonic-gate if (buf == sp->str_bufs[b] + sp->str_bufsz)
246*7c478bd9Sstevel@tonic-gate buf = sp->str_bufs[++b];
247*7c478bd9Sstevel@tonic-gate
248*7c478bd9Sstevel@tonic-gate resid = sp->str_bufs[b] + sp->str_bufsz - buf;
249*7c478bd9Sstevel@tonic-gate n = MIN(resid, len);
250*7c478bd9Sstevel@tonic-gate
251*7c478bd9Sstevel@tonic-gate (void) printf("%.*s", (int)n, buf);
252*7c478bd9Sstevel@tonic-gate buf += n;
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate
255*7c478bd9Sstevel@tonic-gate (void) printf("\"\n");
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate }
259