4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/sysmacros.h>
38 #define STRTAB_HASHSZ 211 /* use a prime number of hash buckets */
39 #define STRTAB_BUFSZ (64 * 1024) /* use 64K data buffers by default */
42 strtab_grow(strtab_t
*sp
)
45 sp
->str_bufs
= xrealloc(sp
->str_bufs
, sp
->str_nbufs
* sizeof (char *));
46 sp
->str_ptr
= xmalloc(sp
->str_bufsz
);
47 sp
->str_bufs
[sp
->str_nbufs
- 1] = sp
->str_ptr
;
51 strtab_create(strtab_t
*sp
)
53 sp
->str_hash
= xcalloc(STRTAB_HASHSZ
* sizeof (strhash_t
*));
54 sp
->str_hashsz
= STRTAB_HASHSZ
;
58 sp
->str_bufsz
= STRTAB_BUFSZ
;
63 *sp
->str_ptr
++ = '\0';
67 strtab_destroy(strtab_t
*sp
)
72 for (i
= 0; i
< sp
->str_hashsz
; i
++) {
73 for (hp
= sp
->str_hash
[i
]; hp
!= NULL
; hp
= hq
) {
79 for (i
= 0; i
< sp
->str_nbufs
; i
++)
80 free(sp
->str_bufs
[i
]);
87 strtab_hash(const char *key
, size_t *len
)
93 for (p
= key
; *p
!= '\0'; p
++, n
++) {
96 if ((g
= (h
& 0xf0000000)) != 0) {
107 strtab_compare(strtab_t
*sp
, strhash_t
*hp
, const char *str
, size_t len
)
109 ulong_t b
= hp
->str_buf
;
110 const char *buf
= hp
->str_data
;
115 if (buf
== sp
->str_bufs
[b
] + sp
->str_bufsz
)
116 buf
= sp
->str_bufs
[++b
];
118 resid
= sp
->str_bufs
[b
] + sp
->str_bufsz
- buf
;
121 if ((rv
= strncmp(buf
, str
, n
)) != 0)
133 strtab_copyin(strtab_t
*sp
, const char *str
, size_t len
)
135 ulong_t b
= sp
->str_nbufs
- 1;
139 if (sp
->str_ptr
== sp
->str_bufs
[b
] + sp
->str_bufsz
) {
144 resid
= sp
->str_bufs
[b
] + sp
->str_bufsz
- sp
->str_ptr
;
146 bcopy(str
, sp
->str_ptr
, n
);
155 strtab_insert(strtab_t
*sp
, const char *str
)
161 if (str
== NULL
|| str
[0] == '\0')
162 return (0); /* we keep a \0 at offset 0 to simplify things */
164 h
= strtab_hash(str
, &len
) % sp
->str_hashsz
;
167 * If the string is already in our hash table, just return the offset
168 * of the existing string element and do not add a duplicate string.
170 for (hp
= sp
->str_hash
[h
]; hp
!= NULL
; hp
= hp
->str_next
) {
171 if (strtab_compare(sp
, hp
, str
, len
+ 1) == 0)
172 return (hp
->str_off
);
176 * Create a new hash bucket, initialize it, and insert it at the front
177 * of the hash chain for the appropriate bucket.
179 hp
= xmalloc(sizeof (strhash_t
));
181 hp
->str_data
= sp
->str_ptr
;
182 hp
->str_buf
= sp
->str_nbufs
- 1;
183 hp
->str_off
= sp
->str_size
;
185 hp
->str_next
= sp
->str_hash
[h
];
187 sp
->str_hash
[h
] = hp
;
190 * Now copy the string data into our buffer list, and then update
191 * the global counts of strings and bytes. Return str's byte offset.
193 strtab_copyin(sp
, str
, len
+ 1);
195 sp
->str_size
+= len
+ 1;
197 return (hp
->str_off
);
201 strtab_size(const strtab_t
*sp
)
203 return (sp
->str_size
);
207 strtab_write(const strtab_t
*sp
,
208 ssize_t (*func
)(const void *, size_t, void *), void *priv
)
210 ssize_t res
, total
= 0;
214 for (i
= 0; i
< sp
->str_nbufs
; i
++, total
+= res
) {
215 if (i
== sp
->str_nbufs
- 1)
216 n
= sp
->str_ptr
- sp
->str_bufs
[i
];
220 if ((res
= func(sp
->str_bufs
[i
], n
, priv
)) <= 0)
224 if (total
== 0 && sp
->str_size
!= 0)
231 strtab_print(const strtab_t
*sp
)
236 for (i
= 0; i
< sp
->str_hashsz
; i
++) {
237 for (hp
= sp
->str_hash
[i
]; hp
!= NULL
; hp
= hp
->str_next
) {
238 const char *buf
= hp
->str_data
;
239 ulong_t b
= hp
->str_buf
;
240 size_t resid
, len
, n
;
242 (void) printf("[%lu] %lu \"", (ulong_t
)hp
->str_off
, b
);
244 for (len
= hp
->str_len
; len
!= 0; len
-= n
) {
245 if (buf
== sp
->str_bufs
[b
] + sp
->str_bufsz
)
246 buf
= sp
->str_bufs
[++b
];
248 resid
= sp
->str_bufs
[b
] + sp
->str_bufsz
- buf
;
251 (void) printf("%.*s", (int)n
, buf
);
255 (void) printf("\"\n");