[BACK]Return to strtab.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/strtab.c, Revision 1.7

1.7     ! xsa         1: /*     $OpenBSD: strtab.c,v 1.6 2005/07/25 12:05:43 xsa Exp $  */
1.1       jfb         2: /*
                      3:  * Copyright (c) 2005 Jean-Francois Brousseau <jfb@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26: /*
                     27:  * The hash table code uses the 32-bit Fowler/Noll/Vo (FNV-1) hash algorithm
                     28:  * for indexing.
                     29:  *     http://www.isthe.com/chongo/tech/comp/fnv/
                     30:  */
                     31:
                     32: #include <sys/types.h>
                     33: #include <sys/queue.h>
                     34:
                     35: #include <errno.h>
                     36: #include <stdio.h>
                     37: #include <stdlib.h>
1.5       xsa        38: #include <string.h>
1.1       jfb        39: #include <unistd.h>
                     40:
                     41: #include "cvs.h"
                     42: #include "log.h"
1.2       jfb        43: #include "strtab.h"
1.1       jfb        44:
1.6       xsa        45: #define CVS_STRTAB_HASHBITS    8
                     46: #define CVS_STRTAB_NBUCKETS    (1 << CVS_STRTAB_HASHBITS)
                     47: #define CVS_STRTAB_FNVPRIME    0x01000193
                     48: #define CVS_STRTAB_FNVINIT     0x811c9dc5
1.1       jfb        49:
                     50: struct cvs_str {
1.6       xsa        51:        char                    *cs_str;
                     52:        int                      cs_ref;
                     53:        SLIST_ENTRY(cvs_str)     cs_link;
1.1       jfb        54: };
                     55:
                     56: SLIST_HEAD(cvs_slist, cvs_str);
                     57:
1.6       xsa        58: static struct cvs_slist        cvs_strtab[CVS_STRTAB_NBUCKETS];
1.1       jfb        59:
                     60:
1.6       xsa        61: static struct cvs_str  *cvs_strtab_insert(const char *);
                     62: static struct cvs_str  *cvs_strtab_lookup(const char *);
                     63: static u_int32_t        cvs_strtab_hash(const char *);
                     64: static void             cvs_strtab_free(const char *);
1.1       jfb        65:
                     66:
                     67:
                     68: /*
                     69:  * cvs_strdup()
                     70:  *
                     71:  * Simple interface to the string table.
                     72:  */
1.6       xsa        73: char *
1.1       jfb        74: cvs_strdup(const char *s)
                     75: {
                     76:        struct cvs_str *csp;
                     77:
1.4       joris      78:        if ((csp = cvs_strtab_lookup(s)) == NULL) {
                     79:                if ((csp = cvs_strtab_insert(s)) == NULL)
                     80:                        return (NULL);
                     81:        } else {
1.1       jfb        82:                csp->cs_ref++;
1.4       joris      83:        }
1.1       jfb        84:
                     85:        return (csp->cs_str);
                     86: }
                     87:
                     88: /*
                     89:  * cvs_strfree()
                     90:  */
                     91: void
1.2       jfb        92: cvs_strfree(const char *s)
1.1       jfb        93: {
                     94:        cvs_strtab_free(s);
                     95: }
                     96:
                     97: /*
                     98:  *
                     99:  */
                    100: void
                    101: cvs_strtab_init(void)
                    102: {
                    103:        int i;
                    104:
                    105:        for (i = 0; i < CVS_STRTAB_NBUCKETS; i++)
                    106:                SLIST_INIT(&cvs_strtab[i]);
                    107: }
                    108:
                    109: /*
                    110:  * cvs_strtab_cleanup()
                    111:  *
                    112:  */
                    113: void
                    114: cvs_strtab_cleanup(void)
                    115: {
                    116:        int i, unfreed;
                    117:        struct cvs_str *sp;
                    118:
                    119:        unfreed = 0;
                    120:        for (i = 0; i < CVS_STRTAB_NBUCKETS; i++) {
1.3       joris     121:                SLIST_FOREACH(sp, &cvs_strtab[i], cs_link) {
                    122:                        cvs_log(LP_DEBUG, "string '%s' not freed", sp->cs_str);
1.1       jfb       123:                        unfreed++;
1.3       joris     124:                }
1.1       jfb       125:        }
                    126:
                    127:        if (unfreed > 0)
                    128:                cvs_log(LP_WARN, "%d unfreed string references in string table",
                    129:                    unfreed);
                    130: }
                    131:
                    132: /*
                    133:  * cvs_strtab_insert()
                    134:  *
                    135:  * Insert the string <str> in the string table.
                    136:  */
1.7     ! xsa       137: static struct cvs_str *
1.1       jfb       138: cvs_strtab_insert(const char *str)
                    139: {
                    140:        u_int32_t h;
                    141:        struct cvs_str *sp;
                    142:
                    143:        if ((sp = (struct cvs_str *)malloc(sizeof(*sp))) == NULL) {
                    144:                cvs_log(LP_ERRNO, "failed to insert string `%s'", str);
                    145:                return (NULL);
                    146:        }
                    147:
                    148:        if ((sp->cs_str = strdup(str)) == NULL) {
                    149:                free(sp);
                    150:                return (NULL);
                    151:        }
                    152:
                    153:        h = cvs_strtab_hash(str);
                    154:
                    155:        SLIST_INSERT_HEAD(&cvs_strtab[h], sp, cs_link);
                    156:
                    157:        sp->cs_ref = 1;
                    158:        return (sp);
                    159: }
                    160:
                    161: /*
                    162:  * cvs_strtab_hash()
                    163:  *
                    164:  * Generate a hash value from the string <str>.
                    165:  * The resulting hash value is bitwise AND'ed with the appropriate mask so
                    166:  * the returned index does not go out of the boundaries of the hash table.
                    167:  */
                    168: static u_int32_t
                    169: cvs_strtab_hash(const char *str)
                    170: {
                    171:        const char *np;
                    172:        u_int32_t h;
                    173:
                    174:        h = CVS_STRTAB_FNVINIT;
                    175:        for (np = str; *np != '\0'; np++) {
                    176:                h *= CVS_STRTAB_FNVPRIME;
                    177:                h ^= (u_int32_t)*np;
                    178:        }
                    179:
                    180:        return (h & (CVS_STRTAB_NBUCKETS - 1));
                    181: }
                    182:
                    183: /*
                    184:  * cvs_strtab_lookup()
                    185:  *
                    186:  * Lookup the string <str> in the string table.  If the corresponding entry
                    187:  * is found, a pointer to the string is returned and the entry's reference
                    188:  * count is increased.
                    189:  */
1.7     ! xsa       190: static struct cvs_str *
1.1       jfb       191: cvs_strtab_lookup(const char *str)
                    192: {
                    193:        u_int32_t h;
                    194:        struct cvs_str *sp;
                    195:
                    196:        h = cvs_strtab_hash(str);
                    197:
                    198:        SLIST_FOREACH(sp, &(cvs_strtab[h]), cs_link)
                    199:                if (strcmp(str, sp->cs_str) == 0) {
                    200:                        break;
                    201:                }
                    202:
                    203:        return (sp);
                    204: }
                    205:
                    206: /*
                    207:  * cvs_strtab_free()
                    208:  *
                    209:  * Release a reference to the string <str>.  If the reference count reaches 0,
                    210:  * the string is removed from the table and freed.
                    211:  */
                    212: static void
                    213: cvs_strtab_free(const char *str)
                    214: {
                    215:        u_int32_t h;
                    216:        struct cvs_str *sp;
                    217:
                    218:        if ((sp = cvs_strtab_lookup(str)) == NULL) {
                    219:                cvs_log(LP_WARN, "attempt to free unregistered string `%s'",
                    220:                    str);
                    221:                return;
                    222:        }
                    223:
                    224:        sp->cs_ref--;
                    225:        if (sp->cs_ref == 0) {
                    226:                /* no more references, free the file */
1.2       jfb       227:                h = cvs_strtab_hash(sp->cs_str);
1.1       jfb       228:
                    229:                SLIST_REMOVE(&(cvs_strtab[h]), sp, cvs_str, cs_link);
                    230:                free(sp->cs_str);
                    231:                free(sp);
                    232:        }
                    233: }