Handle possible null character inside string literal
[splint-patched.git] / src / lsymbol.c
blob8a33609bf410ef32c895ee6f024bc5f0c1c66315
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
25 ** lsymbol.c
27 ** String manager
29 ** This module implements an abstraction for efficiently managing
30 ** string comparisons. It alloctes and manages a string context,
31 ** which consists of three major data structures:
32 ** - a StringEntry table
33 ** - a character-string table
34 ** - a hash table
36 ** A StringEntry table is made of of StringEntries. StringEntries
37 ** are linked in hash-chains to support fast lookup. Every
38 ** allocated StringEntry corresponds to a unique character-string
39 ** in the character-string table. StringEntries can be referenced
40 ** via Symbol values.
42 ** A character-string table is composed of character-strings. A
43 ** character-string is a variable length byte array that is always
44 ** null-terminated ('\0').
46 ** A hash table manages the start of each hash-list of StringEntries.
47 ** StringEntries are entered into the hash-list by hashing on its
48 ** character-string representation.
50 ** This module provides routines for retrieving a unique Symbol for a
51 ** given character-string, and returning the character-string given its
52 ** corresponding Symbol. An item is allocated in both tables whenever a
53 ** new character-string is encountered, otherwise the Symbol for the
54 ** character-string is found and returned.
56 ** AUTHORS:
58 ** Shota Aki
60 ** MODIFICATION HISTORY:
62 ** {0} Aki at Digital -- 89.08.07 -- original
63 ** {1} Aki at Digital -- 89.11.13 -- context switchable
64 ** {2} Aki at Digital -- 89.11.28 -- removed use of TABLES interface
65 ** {3} Aki at Digital -- 89.11.29 -- moved to RC
66 ** {4} Aki at Digital -- 90.04.10 -- support primary-context
67 ** {5} McKeeman at Digital -- 90.05.08 -- C to Larch SL
68 ** {6} Wild at Digital -- 91.06.26 -- Update copyright notice.
69 ** {n} Who at Where -- yy.mm.dd -- what
72 # include "splintMacros.nf"
73 # include "basic.h"
75 /*@+ignorequals@*/
77 /*@constant int NULLFACTOR; @*/
78 # define NULLFACTOR 1
80 typedef Handle CharIndex;
82 typedef struct
84 lsymbol HashNext;
85 CharIndex i;
86 } StringEntry;
88 static void AllocCharSpace (unsigned p_newSize) /*@modifies internalState@*/ ;
89 static CharIndex AllocChar (/*@unique@*/ const char *p_name) /*@modifies internalState@*/ ;
90 static void AllocEntrySpace (unsigned p_newSize) /*@modifies internalState@*/ ;
91 static lsymbol AllocEntry (const char *p_name, long unsigned p_hashValue)
92 /*@modifies internalState@*/ ;
94 static /*@only@*/ /*@null@*/ lsymbol *hashArray = NULL;
96 static long unsigned MaxChar;
97 static CharIndex FreeChar;
98 static /*@only@*/ /*@null@*/ char *CharString;
100 static long unsigned MaxEntry;
101 static lsymbol FreeEntry;
102 static /*@only@*/ /*@null@*/ StringEntry *Entry;
104 lsymbol
105 lsymbol_fromString (cstring s)
107 if (cstring_isUndefined (s))
109 return lsymbol_undefined;
111 else
113 return (lsymbol_fromChars (cstring_toCharsSafe (s)));
117 lsymbol
118 lsymbol_fromChars (/*@temp@*/ const char *name)
120 lsymbol ss;
121 long unsigned hashValue;
122 unsigned h = 0;
123 const char *p = name;
125 while (*p != '\0')
127 h = (h << 1) + (unsigned) (*p);
128 p++;
131 hashValue = h & HASHMASK;
133 if (hashArray == NULL) /* evs - was MaxIndex == 0 */
135 /* nothing initialized */
136 ss = AllocEntry (name, hashValue);
138 else
140 ss = hashArray[hashValue]; /* start of hash chain */
142 if (ss == lsymbol_undefined)
144 /* hash not initialized */
145 ss = AllocEntry (name, hashValue);
147 else
150 * Traverse hash-chain. Loop terminates when
151 * a match is found or end of chain is encountered.
154 llassert (Entry != NULL);
155 llassert (CharString != NULL);
157 while (strcmp (&CharString[Entry[ss].i], name) != 0)
159 if (lsymbol_undefined == (ss = Entry[ss].HashNext))
161 ss = AllocEntry (name, hashValue);
162 break;
168 return ss;
171 cstring lsymbol_toString (lsymbol ss)
173 return (cstring_fromChars (lsymbol_toChars (ss)));
176 char *
177 lsymbol_toCharsSafe (lsymbol ss)
179 char *ret = lsymbol_toChars (ss);
181 if (ret == NULL)
183 ret = mstring_create (0);
186 return ret;
189 char *lsymbol_toChars (lsymbol ss)
191 if (lsymbol_isDefined (ss))
193 if (ss >= FreeEntry)
195 llcontbug (message ("lsymbol_toChars: invalid lsymbol: %d", ss));
196 return NULL;
199 llassert (Entry != NULL);
200 llassert (CharString != NULL);
202 return &CharString[Entry[ss].i];
204 else
206 return NULL;
210 static void
211 AllocCharSpace (unsigned newSize)
213 llassert (newSize > MaxChar);
215 CharString = (char *) drealloc ((void *) CharString, newSize * sizeof (*CharString));
216 MaxChar = newSize;
217 /*@-compdef@*/
218 } /*@=compdef@*/
220 static CharIndex
221 AllocChar (/*@unique@*/ const char *name)
223 int namelength;
224 CharIndex retVal;
225 long unsigned size;
226 CharIndex unused;
228 namelength = size_toInt (strlen (name));
229 unused = FreeChar;
230 size = MaxChar;
232 if ((unused + namelength + NULLFACTOR) > size)
234 if (size == 0)
235 size = INITCHARSTRING;
236 else
237 size = (unsigned) (DELTACHARSTRING * size);
239 AllocCharSpace (size);
242 llassert (CharString != NULL);
244 retVal = unused;
245 strcpy (&CharString[unused], name);
246 unused += namelength;
247 CharString[unused] = '\0';
248 unused += 1;
250 FreeChar = unused;
251 return retVal;
254 static void
255 AllocEntrySpace (unsigned newSize)
257 llassert (newSize > MaxEntry);
259 /* Casts mess up checking here. */
260 /*@-mustfree@*/
261 Entry = (StringEntry *) drealloc ((void *) Entry, newSize * sizeof (*Entry));
262 /*@=mustfree@*/
264 if (MaxEntry == 0) MaxEntry = 1;
266 FreeEntry = MaxEntry;
267 MaxEntry = newSize;
268 /*@-compdef@*/
269 } /*@=compdef@*/
271 static lsymbol AllocEntry (const char *name, long unsigned hashValue)
273 lsymbol retVal;
274 long unsigned size;
276 size = MaxEntry;
278 if ((retVal = FreeEntry) == size)
280 if (size == 0)
282 size = INITSTRINGENTRY;
284 else
286 size = (unsigned) (DELTASTRINGENTRY * size);
289 AllocEntrySpace (size);
290 retVal = FreeEntry;
293 FreeEntry = retVal + 1;
295 llassert (hashArray != NULL);
296 llassert (Entry != NULL);
298 Entry[retVal].HashNext = hashArray[hashValue];
299 hashArray[hashValue] = retVal;
300 Entry[retVal].i = AllocChar (name);
302 return retVal;
305 void
306 lsymbol_initMod (void)
307 /*@globals undef CharString, undef Entry; @*/
309 int i;
311 if (hashArray != NULL)
313 sfree (hashArray);
316 hashArray = (lsymbol *) dmalloc (HASHSIZE * sizeof (*hashArray));
318 for (i = 0; i < HASHSIZE; i++)
320 hashArray[i] = lsymbol_undefined;
323 MaxChar = 0;
324 MaxEntry = 0;
326 FreeChar = 0;
327 FreeEntry = 0;
329 CharString = (char *) 0;
330 Entry = (StringEntry *) 0;
331 /*@-compdef@*/
333 /*@=compdef@*/
335 void
336 lsymbol_destroyMod (void)
337 /*@globals killed Entry, killed CharString, killed hashArray@*/
339 sfree (Entry);
340 sfree (CharString);
341 sfree (hashArray);
344 # ifdef DEADCODE
345 void
346 lsymbol_printStats (void)
348 /* only for debugging */
349 printf ("Number of lsymbols generated = %d\n", (int) FreeEntry);
351 # endif /* DEADCODE */
354 ** note lsymbol_setbool, etc. defined in abstract.c