Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.c
39586 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright (c) 2001 by Sun Microsystems, Inc.23* All rights reserved.24*/2526#pragma ident "%Z%%M% %I% %E% SMI"2728#include <sys/types.h>29#include <sys/sysmacros.h>30#include <strings.h>31#include <stdlib.h>32#include <stdio.h>3334#include "strtab.h"35#include "memory.h"3637#define STRTAB_HASHSZ 211 /* use a prime number of hash buckets */38#define STRTAB_BUFSZ (64 * 1024) /* use 64K data buffers by default */3940static void41strtab_grow(strtab_t *sp)42{43sp->str_nbufs++;44sp->str_bufs = xrealloc(sp->str_bufs, sp->str_nbufs * sizeof (char *));45sp->str_ptr = xmalloc(sp->str_bufsz);46sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr;47}4849void50strtab_create(strtab_t *sp)51{52sp->str_hash = xcalloc(STRTAB_HASHSZ * sizeof (strhash_t *));53sp->str_hashsz = STRTAB_HASHSZ;54sp->str_bufs = NULL;55sp->str_ptr = NULL;56sp->str_nbufs = 0;57sp->str_bufsz = STRTAB_BUFSZ;58sp->str_nstrs = 1;59sp->str_size = 1;6061strtab_grow(sp);62*sp->str_ptr++ = '\0';63}6465void66strtab_destroy(strtab_t *sp)67{68strhash_t *hp, *hq;69ulong_t i;7071for (i = 0; i < sp->str_hashsz; i++) {72for (hp = sp->str_hash[i]; hp != NULL; hp = hq) {73hq = hp->str_next;74free(hp);75}76}7778for (i = 0; i < sp->str_nbufs; i++)79free(sp->str_bufs[i]);8081free(sp->str_hash);82free(sp->str_bufs);83}8485static ulong_t86strtab_hash(const char *key, size_t *len)87{88ulong_t g, h = 0;89const char *p;90size_t n = 0;9192for (p = key; *p != '\0'; p++, n++) {93h = (h << 4) + *p;9495if ((g = (h & 0xf0000000)) != 0) {96h ^= (g >> 24);97h ^= g;98}99}100101*len = n;102return (h);103}104105static int106strtab_compare(strtab_t *sp, strhash_t *hp, const char *str, size_t len)107{108ulong_t b = hp->str_buf;109const char *buf = hp->str_data;110size_t resid, n;111int rv;112113while (len != 0) {114if (buf == sp->str_bufs[b] + sp->str_bufsz)115buf = sp->str_bufs[++b];116117resid = sp->str_bufs[b] + sp->str_bufsz - buf;118n = MIN(resid, len);119120if ((rv = strncmp(buf, str, n)) != 0)121return (rv);122123buf += n;124str += n;125len -= n;126}127128return (0);129}130131static void132strtab_copyin(strtab_t *sp, const char *str, size_t len)133{134ulong_t b = sp->str_nbufs - 1;135size_t resid, n;136137while (len != 0) {138if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) {139strtab_grow(sp);140b++;141}142143resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr;144n = MIN(resid, len);145bcopy(str, sp->str_ptr, n);146147sp->str_ptr += n;148str += n;149len -= n;150}151}152153size_t154strtab_insert(strtab_t *sp, const char *str)155{156strhash_t *hp;157size_t len;158ulong_t h;159160if (str == NULL || str[0] == '\0')161return (0); /* we keep a \0 at offset 0 to simplify things */162163h = strtab_hash(str, &len) % sp->str_hashsz;164165/*166* If the string is already in our hash table, just return the offset167* of the existing string element and do not add a duplicate string.168*/169for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) {170if (strtab_compare(sp, hp, str, len + 1) == 0)171return (hp->str_off);172}173174/*175* Create a new hash bucket, initialize it, and insert it at the front176* of the hash chain for the appropriate bucket.177*/178hp = xmalloc(sizeof (strhash_t));179180hp->str_data = sp->str_ptr;181hp->str_buf = sp->str_nbufs - 1;182hp->str_off = sp->str_size;183hp->str_len = len;184hp->str_next = sp->str_hash[h];185186sp->str_hash[h] = hp;187188/*189* Now copy the string data into our buffer list, and then update190* the global counts of strings and bytes. Return str's byte offset.191*/192strtab_copyin(sp, str, len + 1);193sp->str_nstrs++;194sp->str_size += len + 1;195196return (hp->str_off);197}198199size_t200strtab_size(const strtab_t *sp)201{202return (sp->str_size);203}204205ssize_t206strtab_write(const strtab_t *sp,207ssize_t (*func)(void *, size_t, void *), void *priv)208{209ssize_t res, total = 0;210ulong_t i;211size_t n;212213for (i = 0; i < sp->str_nbufs; i++, total += res) {214if (i == sp->str_nbufs - 1)215n = sp->str_ptr - sp->str_bufs[i];216else217n = sp->str_bufsz;218219if ((res = func(sp->str_bufs[i], n, priv)) <= 0)220break;221}222223if (total == 0 && sp->str_size != 0)224return (-1);225226return (total);227}228229void230strtab_print(const strtab_t *sp)231{232const strhash_t *hp;233ulong_t i;234235for (i = 0; i < sp->str_hashsz; i++) {236for (hp = sp->str_hash[i]; hp != NULL; hp = hp->str_next) {237const char *buf = hp->str_data;238ulong_t b = hp->str_buf;239size_t resid, len, n;240241(void) printf("[%lu] %lu \"", (ulong_t)hp->str_off, b);242243for (len = hp->str_len; len != 0; len -= n) {244if (buf == sp->str_bufs[b] + sp->str_bufsz)245buf = sp->str_bufs[++b];246247resid = sp->str_bufs[b] + sp->str_bufsz - buf;248n = MIN(resid, len);249250(void) printf("%.*s", (int)n, buf);251buf += n;252}253254(void) printf("\"\n");255}256}257}258259260