Crossfire Server, Branches 1.12  R18729
shstr.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_shstr_c =
3  * "$Id: shstr.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <global.h>
20 #include <libproto.h> /* For LOG */
21 
22 #if defined(__sun__) && defined(StupidSunHeaders)
23 #include <sys/time.h>
24 #include "sunos.h"
25 #endif
26 
27 #include <logger.h>
28 
29 #define SS_STATISTICS
30 #include "shstr.h"
31 
32 #ifdef WIN32
33 #include <win32.h>
34 #else
35 #include <autoconf.h>
36 #endif
37 #ifdef HAVE_LIBDMALLOC
38 #include <dmalloc.h>
39 #endif
40 
43 
47 void init_hash_table(void) {
48  /* A static object should be zeroed out always */
49 #if !defined(__STDC__)
50  (void)memset((void *)hash_table, 0, TABLESIZE*sizeof(shared_string *));
51 #endif
52 }
53 
62 static unsigned long hashstr(const char *str) {
63  unsigned long hash = 0;
64  int i = 0;
65  unsigned rot = 0;
66  const char *p;
67 
68  GATHER(hash_stats.calls);
69 
70  for (p = str; i < MAXSTRING && *p; p++, i++) {
71  hash ^= (unsigned long)*p<<rot;
72  rot += 2;
73  if (rot >= (sizeof(unsigned long)-sizeof(char))*CHAR_BIT)
74  rot = 0;
75  }
76  return (hash%TABLESIZE);
77 }
78 
90 static shared_string *new_shared_string(const char *str) {
91  shared_string *ss;
92 
93  /* Allocate room for a struct which can hold str. Note
94  * that some bytes for the string are already allocated in the
95  * shared_string struct.
96  */
97  ss = (shared_string *)malloc(sizeof(shared_string)-PADDING+strlen(str)+1);
98  if (ss == NULL)
100  ss->u.previous = NULL;
101  ss->next = NULL;
102  ss->refcount = 1;
103  strcpy(ss->string, str);
104  return ss;
105 }
106 
116 sstring add_string(const char *str) {
117  shared_string *ss;
118  unsigned long ind;
119 
120  GATHER(add_stats.calls);
121 
122  /* Should really core dump here, since functions should not be calling
123  * add_string with a null parameter. But this will prevent a few
124  * core dumps.
125  */
126  if (str == NULL) {
127 #ifdef MANY_CORES
128  abort();
129 #else
130  return NULL;
131 #endif
132  }
133 
134  ind = hashstr(str);
135  ss = hash_table[ind];
136 
137  /* Is there an entry for that hash?
138  */
139  if (ss) {
140  /* Simple case first: See if the first pointer matches. */
141  if (str != ss->string) {
142  GATHER(add_stats.strcmps);
143  if (strcmp(ss->string, str)) {
144  /* Apparantly, a string with the same hash value has this
145  * slot. We must see in the list if "str" has been
146  * registered earlier.
147  */
148  while (ss->next) {
149  GATHER(add_stats.search);
150  ss = ss->next;
151  if (ss->string != str) {
152  GATHER(add_stats.strcmps);
153  if (strcmp(ss->string, str)) {
154  /* This wasn't the right string... */
155  continue;
156  }
157  }
158  /* We found an entry for this string. Fix the
159  * refcount and exit.
160  */
161  GATHER(add_stats.linked);
162  ++(ss->refcount);
163 
164  return ss->string;
165  }
166  /* There are no occurences of this string in the hash table. */
167  {
168  shared_string *new_ss;
169 
170  GATHER(add_stats.linked);
171  new_ss = new_shared_string(str);
172  ss->next = new_ss;
173  new_ss->u.previous = ss;
174  return new_ss->string;
175  }
176  }
177  /* Fall through. */
178  }
179  GATHER(add_stats.hashed);
180  ++(ss->refcount);
181  return ss->string;
182  } else {
183  /* The string isn't registered, and the slot is empty. */
184  GATHER(add_stats.hashed);
185  hash_table[ind] = new_shared_string(str);
186 
187  /* One bit in refcount is used to keep track of the union. */
188  hash_table[ind]->refcount |= TOPBIT;
189  hash_table[ind]->u.array = &(hash_table[ind]);
190 
191  return hash_table[ind]->string;
192  }
193 }
194 
203  GATHER(add_ref_stats.calls);
204  ++(SS(str)->refcount);
205  return str;
206 }
207 
217  return (SS(str)->refcount)&~TOPBIT;
218 }
219 
228 sstring find_string(const char *str) {
229  shared_string *ss;
230  unsigned long ind;
231 
232  GATHER(find_stats.calls);
233 
234  ind = hashstr(str);
235  ss = hash_table[ind];
236 
237  /* Is there an entry for that hash?
238  */
239  if (ss) {
240  /* Simple case first: Is the first string the right one? */
241  GATHER(find_stats.strcmps);
242  if (!strcmp(ss->string, str)) {
243  GATHER(find_stats.hashed);
244  return ss->string;
245  } else {
246  /* Recurse through the linked list, if there's one. */
247  while (ss->next) {
248  GATHER(find_stats.search);
249  GATHER(find_stats.strcmps);
250  ss = ss->next;
251  if (!strcmp(ss->string, str)) {
252  GATHER(find_stats.linked);
253  return ss->string;
254  }
255  }
256  /* No match. Fall through. */
257  }
258  }
259  return NULL;
260 }
261 
272 void free_string(sstring str) {
273  shared_string *ss;
274 
275  GATHER(free_stats.calls);
276 
277  ss = SS(str);
278 
279  if ((--ss->refcount&~TOPBIT) == 0) {
280  /* Remove this entry. */
281  if (ss->refcount&TOPBIT) {
282  /* We must put a new value into the hash_table[].
283  */
284  if (ss->next) {
285  *(ss->u.array) = ss->next;
286  ss->next->u.array = ss->u.array;
287  ss->next->refcount |= TOPBIT;
288  } else {
289  *(ss->u.array) = NULL;
290  }
291  free(ss);
292  } else {
293  /* Relink and free this struct. */
294  if (ss->next)
295  ss->next->u.previous = ss->u.previous;
296  ss->u.previous->next = ss->next;
297  free(ss);
298  }
299  }
300 }
301 
302 #ifdef SS_STATISTICS
303 
315 void ss_dump_statistics(char *buf, size_t size) {
316  static char line[80];
317 
318  snprintf(buf, size, "%-13s %6s %6s %6s %6s %6s\n", "", "calls", "hashed", "strcmp", "search", "linked");
319  snprintf(line, sizeof(line), "%-13s %6d %6d %6d %6d %6d\n", "add_string:", add_stats.calls, add_stats.hashed, add_stats.strcmps, add_stats.search, add_stats.linked);
320  snprintf(buf+strlen(buf), size-strlen(buf), "%s", line);
321  snprintf(line, sizeof(line), "%-13s %6d\n", "add_refcount:", add_ref_stats.calls);
322  snprintf(buf+strlen(buf), size-strlen(buf), "%s", line);
323  snprintf(line, sizeof(line), "%-13s %6d\n", "free_string:", free_stats.calls);
324  snprintf(buf+strlen(buf), size-strlen(buf), "%s", line);
325  snprintf(line, sizeof(line), "%-13s %6d %6d %6d %6d %6d\n", "find_string:", find_stats.calls, find_stats.hashed, find_stats.strcmps, find_stats.search, find_stats.linked);
326  snprintf(buf+strlen(buf), size-strlen(buf), "%s", line);
327  snprintf(line, sizeof(line), "%-13s %6d\n", "hashstr:", hash_stats.calls);
328  snprintf(buf+strlen(buf), size-strlen(buf), "%s", line);
329 }
330 #endif /* SS_STATISTICS */
331 
346 char *ss_dump_table(int what, char *buf, size_t size) {
347  int entries = 0, refs = 0, links = 0;
348  int i;
349 
350  for (i = 0; i < TABLESIZE; i++) {
351  shared_string *ss;
352 
353  if ((ss = hash_table[i]) != NULL) {
354  ++entries;
355  refs += (ss->refcount&~TOPBIT);
356  /* Can't use stderr any longer, need to include global.h and
357  if (what&SS_DUMP_TABLE)
358  * use logfile. */
359  LOG(llevDebug, "%4d -- %4d refs '%s' %c\n", i, (ss->refcount&~TOPBIT), ss->string, (ss->refcount&TOPBIT ? ' ' : '#'));
360 
361  while (ss->next) {
362  ss = ss->next;
363  ++links;
364  refs += (ss->refcount&~TOPBIT);
365 
366  if (what&SS_DUMP_TABLE)
367  LOG(llevDebug, " -- %4d refs '%s' %c\n", (ss->refcount&~TOPBIT), ss->string, (ss->refcount&TOPBIT ? '*' : ' '));
368  }
369  }
370  }
371 
372  if (what&SS_DUMP_TOTALS) {
373  snprintf(buf, size, "\n%d entries, %d refs, %d links.", entries, refs, links);
374  return buf;
375  }
376  return NULL;
377 }
378 
393 int buf_overflow(const char *buf1, const char *buf2, size_t bufsize) {
394  size_t len1 = 0, len2 = 0;
395 
396  if (buf1)
397  len1 = strlen(buf1);
398  if (buf2)
399  len2 = strlen(buf2);
400  if ((len1+len2) >= bufsize)
401  return 1;
402  return 0;
403 }
#define OUT_OF_MEMORY
Definition: define.h:94
union _shared_string::@3 u
sstring add_refcount(sstring str)
Definition: shstr.c:202
int query_refcount(sstring str)
Definition: shstr.c:216
void free_string(sstring str)
Definition: shstr.c:272
#define TABLESIZE
Definition: shstr.h:13
#define SS_DUMP_TOTALS
Definition: shstr.h:47
#define SS_DUMP_TABLE
Definition: shstr.h:46
struct _shared_string * previous
Definition: shstr.h:73
struct _shared_string * next
Definition: shstr.h:75
#define GATHER(n)
Definition: shstr.h:60
sstring find_string(const char *str)
Definition: shstr.c:228
void init_hash_table(void)
Definition: shstr.c:47
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
Definition: shstr.c:393
#define SS(x)
Definition: shstr.h:44
struct _shared_string ** array
Definition: shstr.h:72
#define TOPBIT
Definition: shstr.h:63
unsigned REFCOUNT_TYPE refcount
Definition: shstr.h:79
void fatal(int err)
Definition: glue.c:60
char * ss_dump_table(int what, char *buf, size_t size)
Definition: shstr.c:346
static shared_string * hash_table[TABLESIZE]
Definition: shstr.c:42
#define PADDING
Definition: shstr.h:65
const char * sstring
Definition: global.h:84
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
static unsigned long hashstr(const char *str)
Definition: shstr.c:62
#define MAXSTRING
Definition: config.h:597
char string[PADDING]
Definition: shstr.h:84
void ss_dump_statistics(char *buf, size_t size)
Definition: shstr.c:315
static shared_string * new_shared_string(const char *str)
Definition: shstr.c:90
sstring add_string(const char *str)
Definition: shstr.c:116
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63