UNIXworkcode

1 /******************************************************************************* 2 * * 3 * refString.c -- Nirvana editor string handling * 4 * * 5 * Copyright (C) 200 Scott Tringali * 6 * * 7 * This is free software; you can redistribute it and/or modify it under the * 8 * terms of the GNU General Public License as published by the Free Software * 9 * Foundation; either version 2 of the License, or (at your option) any later * 10 * version. In addition, you may distribute versions of this program linked to * 11 * Motif or Open Motif. See README for details. * 12 * * 13 * This software is distributed in the hope that it will be useful, but WITHOUT * 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * 16 * for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License along with * 19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple * 20 * Place, Suite 330, Boston, MA 02111-1307 USA * 21 * * 22 * Nirvana Text Editor * 23 * July, 1993 * 24 * * 25 * Written by Mark Edel * 26 * * 27 *******************************************************************************/ 28 29 #include "refString.h" 30 #include "nedit_malloc.h" 31 #include <string.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 35 #define RCS_SIZE 0x10000 36 37 struct rcs; 38 39 struct rcs_stats 40 { 41 int talloc, tshar, tgiveup, tbytes, tbyteshared; 42 }; 43 44 struct rcs 45 { 46 struct rcs *next; 47 char *string; 48 int usage; 49 }; 50 51 static struct rcs *Rcs[RCS_SIZE]; 52 static struct rcs_stats RcsStats; 53 54 static unsigned const DJB2_SEED = 5381u; 55 /* djb2s hash for null-terminated string, seeded version */ 56 static unsigned djb2s(char const* key, unsigned hash) 57 { 58 char c; 59 while (!!(c = *key++)) 60 hash = ((hash << 5) + hash) ^ c; 61 return hash; 62 } 63 64 /* Compute hash address from a string key */ 65 unsigned StringHashAddr(const char *key) 66 { 67 return djb2s(key, DJB2_SEED); 68 } 69 70 /* Compute hash address from a null-termintated list of strings */ 71 unsigned StringsHashAddr(const char** keys) 72 { 73 unsigned hash = DJB2_SEED; 74 char const* key; 75 while (!!(key = *keys++)) 76 hash = djb2s(key, hash); 77 return hash; 78 } 79 80 /* 81 ** Take a normal string, create a shared string from it if need be, 82 ** and return pointer to that shared string. 83 ** 84 ** Returned strings are const because they are shared. Do not modify them! 85 */ 86 87 const char *RefStringDup(const char *str) 88 { 89 unsigned bucket; 90 size_t len; 91 struct rcs *rp; 92 char *newstr; 93 94 if (str == NULL) 95 return NULL; 96 97 len = strlen(str); 98 99 RcsStats.talloc++; 100 101 /* Find it in hash */ 102 bucket = StringHashAddr(str) % RCS_SIZE; 103 rp = Rcs[bucket]; 104 for (; rp; rp = rp->next) 105 if (!strcmp(str, rp->string)) break; 106 107 newstr = NULL; 108 if (rp) /* It exists, return it and bump ref ct */ 109 { 110 rp->usage++; 111 newstr = rp->string; 112 113 RcsStats.tshar++; 114 RcsStats.tbyteshared += len; 115 } 116 else /* Doesn't exist, conjure up a new one. */ 117 { 118 rp = NEditNew(struct rcs); 119 rp->usage = 1; 120 rp->next = Rcs[bucket]; 121 Rcs[bucket] = rp; 122 123 rp->string = (char*) NEditMalloc(len + 1); 124 memcpy(rp->string, str, len + 1); 125 126 newstr = rp->string; 127 } 128 129 RcsStats.tbytes += len; 130 return newstr; 131 } 132 133 /* 134 ** Decrease the reference count on a shared string. When the reference 135 ** count reaches zero, free the master string. 136 */ 137 138 void RefStringFree(const char *rcs_str) 139 { 140 int bucket; 141 struct rcs *rp; 142 struct rcs *prev = NULL; 143 144 if (rcs_str == NULL) 145 return; 146 147 bucket = StringHashAddr(rcs_str) % RCS_SIZE; 148 149 /* find it in hash */ 150 for (rp = Rcs[bucket]; rp; rp = rp->next) 151 { 152 if (rcs_str == rp->string) 153 break; 154 prev = rp; 155 } 156 157 if (rp) /* It's a shared string, decrease ref count */ 158 { 159 rp->usage--; 160 161 if (rp->usage < 0) /* D'OH! */ 162 { 163 fprintf(stderr, "XNEdit: internal error deallocating shared string."); 164 return; 165 } 166 167 if (rp->usage == 0) /* Last one- free the storage */ 168 { 169 NEditFree(rp->string); 170 if (prev) 171 prev->next = rp->next; 172 else 173 Rcs[bucket] = rp->next; 174 NEditFree(rp); 175 } 176 } 177 else /* Doesn't appear to be a shared string */ 178 { 179 fprintf(stderr, "XNEdit: attempt to free a non-shared string."); 180 return; 181 } 182 } 183 184