2 * STRTABLE.C - String table routines
4 * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the
5 * COPYRIGHT file at the base of the distribution.
10 #define STR_MAGIC ((int)0xA5F3B211)
11 #define STR_HSIZE 16384
12 #define STR_HMASK (STR_HSIZE - 1)
14 typedef struct StrTable {
15 struct StrTable *st_Next;
17 int st_DataLen; /* does not including terminator */
20 int st_Enumerate; /* Enumeration helper for code gen */
22 void *st_Info; /* (used for run-time) */
23 char st_Data[0]; /* embedded binary or C string */
26 static StrTable * StrTableHash[STR_HSIZE];
29 strhash(const char *str, int bytes)
33 hv = (hv << 5) ^ *str ^ (hv >> 23);
37 return ((hv ^ (hv >> 16)) & STR_HMASK);
41 * Obtain a persistent shared string representing the passed binary data.
42 * Multple references to the same string will return the same shared pointer,
43 * a feature we depend on heavily in the rest of the codebase in order to
44 * avoid comparing strings over and over again.
46 * This code is content-agnostic and may be used for binary data.
48 * The caller has the choice of including the terminating zero for strings in
49 * the official length or not. This code always adds a terminating zero 'out
50 * of band' to make string handling easier.
53 StrTableAlloc(const char *ptr, int len, int special)
57 pst = &StrTableHash[strhash(ptr, len)];
58 while ((st = *pst) != NULL) {
60 * Look for match, bump ref count and return if found. Note that we
61 * can reuse a previously dereferenced but not-yet-freed string.
63 if (len == st->st_DataLen &&
64 bcmp(ptr, st->st_Data, len) == 0) {
66 st->st_Special = special;
73 if (st->st_Refs == 0) {
76 st->st_Magic = 0xDEADDEED;
77 zfree(st, sizeof(StrTable) + st->st_DataLen + 1);
82 st = zalloc(sizeof(StrTable) + len + 1);
84 st->st_Magic = STR_MAGIC;
87 st->st_Special = special;
88 bcopy(ptr, (char *)&st->st_Data[0], len);
89 ((char *)st->st_Data)[len] = 0; /* out of band terminator */
94 * Convert the string represented by the token into a string table string.
97 StrTableToken(token_t *tok)
99 return (StrTableAlloc(tok->t_Ptr, tok->t_Len, 0));
103 * Bump the ref count on a string that is already in the string table.
106 StrTableDup(const char *str)
108 StrTable *st = (StrTable *) (__DECONST(char *, str)-
109 offsetof(StrTable, st_Data[0]));
111 dassert(st->st_Magic == STR_MAGIC);
112 dassert(st->st_Refs > 0);
118 ReplaceStrTable(string_t *pstr, string_t id)
126 * Release a string in the string table. We do not free the structure
127 * immediately, allowing it to be potentially reused. The structure will be
128 * freed when a later StrTableRef() encounters it during a hash scan.
131 RelStrTable(string_t *pstr)
135 if ((str = *pstr) != NULL) {
139 st = (StrTable *) (__DECONST(char *, str)-
140 offsetof(StrTable, st_Data[0]));
141 dassert(st->st_Magic == STR_MAGIC);
142 dassert(st->st_Refs > 0);
144 /* do in-line free in later allocation */
149 StrTableSpecial(string_t id)
154 st = (StrTable *) (__DECONST(char *, id)-
155 offsetof(StrTable, st_Data[0]));
156 dassert(st->st_Magic == STR_MAGIC);
157 return (st->st_Special);
163 * Generate a unique id for this string table entry. Typically stored in the
164 * d_BackendId field of a declaration.
167 StrTableEnumerate(string_t id)
171 st = (StrTable *) (__DECONST(char *, id)-
172 offsetof(StrTable, st_Data[0]));
175 return st->st_Enumerate;
179 * Return the length, in bytes, of an identifier. The length does not
180 * include the terminating zero unless the original allocation included it in
184 StrTableLen(string_t id)
188 st = (StrTable *) (__DECONST(char *, id)-
189 offsetof(StrTable, st_Data[0]));
190 dassert(st->st_Magic == STR_MAGIC);
191 return (st->st_DataLen);
195 * Strip the identifier from the trailing element of the path. This routine
196 * takes a nul-terminated string and returns a pointer and length within the
200 StripPathId(const char *path, int *plen)
202 int len = strlen(path);
205 * strip any trailing slashes
207 while (len > 0 && path[len - 1] == '/')
211 * Locate the last element
213 while (len > 0 && path[len - 1] != '/')
218 * Parse the identifier until we hit a '/' or a '.' (extension)
221 while (path[len] && path[len] != '/' && path[len] != '.')
228 SimpleIntToken(token_t *tok, int *rv)
233 if (t != TOK_INTEGER) {
234 t = LexError(tok, TOK_ERR_EXPECTED_SIMPLE_INTEGER);
239 for (i = 0; i < tok->t_Len; ++i) {
240 char c = tok->t_Ptr[i];
243 } else if (c >= '0' && c <= '9') {
244 *rv = *rv * 10 + (c - '0');
247 TOK_ERR_EXPECTED_SIMPLE_INTEGER);
256 SimpleRunesizeToken(token_t *tok, urunesize_t *rv)
261 if (t != TOK_INTEGER) {
262 t = LexError(tok, TOK_ERR_EXPECTED_SIMPLE_INTEGER);
267 for (i = 0; i < tok->t_Len; ++i) {
268 char c = tok->t_Ptr[i];
271 } else if (c >= '0' && c <= '9') {
272 *rv = *rv * 10 + (c - '0');
275 TOK_ERR_EXPECTED_SIMPLE_INTEGER);
285 * StrTableEscapeQuotedString() - convert quoted string into actual string.
287 * NOTE: The length of the string in the string table includes the
288 * terminator. The string may also be concatenated.
290 * NOTE: the lexical analyzer does a more robust format check.
295 if (c >= '0' && c <= '9')
297 if (c >= 'a' && c <= 'f')
298 return (c + (10 - 'a'));
299 if (c >= 'A' && c <= 'F')
300 return (c + (10 - 'A'));
306 BufEscapeQuotedString(const char *str, int *lenp)
317 btype = len ? str[0] : 0;
325 for (i = 0; i < len; ++i) {
330 searching = 1 - searching;
334 searching = 1 - searching;
338 if (btype != TOK_BSTRING && c == '\\') {
341 switch ((c = str[i])) {
354 c = (hexDigit(str[i - 1]) << 4) |
360 dassert(c >= '0' && c <= '7');
366 c = (c << 3) | (str[i] & 7);
371 c = (c << 3) | (str[i] & 7);
382 dbuf = malloc(rlen + 1);
393 StrTableEscapeQuotedString(const char *str, int len, int term)
398 dbuf = BufEscapeQuotedString(str, &len);
400 dassert(term == 0 || term == 1);
401 id = StrTableAlloc(dbuf, len + term, 0);
408 StrTableSingleQuotedString(const char *str, int len, Type **typep)
414 dbuf = (uint8_t *)BufEscapeQuotedString(str, &len);
416 for (i = 0; i < len; ++i)
417 key = (key << 8) | dbuf[i];
427 *typep = &UInt16Type;
431 *typep = &UInt32Type;
437 *typep = &UInt64Type;
440 key = iscsi_crc32(dbuf, len) | 0x80000000U;
441 *typep = &UInt32Type;