source: trunk/emx/src/emxomf/grow.c@ 3669

Last change on this file since 3669 was 3669, checked in by bird, 15 years ago

grow.h/c: Store the string length, speeds up collition handling and adds strpool_len() for skipping strlen()'s. Fixed strpool_addnu/strpool_addu matching bug.

  • Property cvs2svn:cvs-rev set to 1.4
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 9.7 KB
Line 
1/* grow.c -- Growing arrays, growing buffers and string pools
2 Copyright (c) 1993-1995 Eberhard Mattes
3
4This file is part of emx.
5
6emx is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emx is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emx; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22/* Growing arrays. Such an array consists of two parts: A struct grow
23 which is used in this module for controlling the object, and a
24 pointer (the `associated pointer') of the desired type to the
25 array. The associated pointer may change when calling one of the
26 functions of these module for the struct grow of that array.*/
27
28/* Growing buffers. A growing buffer is an array of bytes. There are
29 functions for putting various binary types into the buffer, while
30 enlarging the buffer as required. */
31
32/* String pool. A string pool contains null-terminated strings of
33 arbitrary length. There are no duplicate strings in a string
34 pool. */
35
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39#include <assert.h>
40#include "defs.h"
41#include "grow.h"
42
43/* A program using this module has to define the following two
44 functions: */
45
46extern void *xrealloc (void *ptr, size_t n);
47extern void *xmalloc (size_t n);
48
49/* Initialize a growing array. G points to the struct grow used for
50 controlling the array, PTR is a pointer to the associated pointer
51 of the desired type -- that pointer is used for accessing the
52 array. SIZE is the size of one array element, INC is the number of
53 array elements to add when growing the array. The smaller SIZE is,
54 the bigger you should choose INC. */
55
56void grow_init (struct grow *g, void *ptr, size_t size, int inc)
57{
58 g->count = 0;
59 g->alloc = 0;
60 g->ptr = ptr;
61 g->size = size;
62 g->inc = inc;
63 *g->ptr = NULL;
64}
65
66
67/* Deallocate a growing array. Do not use the associated array
68 pointer after calling this function. */
69
70void grow_free (struct grow *g)
71{
72 if (g->ptr != NULL)
73 {
74 if (*g->ptr != NULL)
75 free (*g->ptr);
76 *g->ptr = NULL;
77 }
78 g->ptr = NULL;
79 g->count = 0;
80 g->alloc = 0;
81}
82
83
84/* Grow the growing array G to NEW_COUNT elements. If the array is
85 already big enough, nothing is done. Otherwise, the array is
86 enlarged by at least INC (of grow_init()) elements. The associated
87 array pointer may change. */
88
89void grow_to (struct grow *g, int new_count)
90{
91 if (new_count > g->alloc)
92 {
93 g->alloc += g->inc;
94 if (g->alloc < new_count)
95 g->alloc = new_count;
96 *g->ptr = xrealloc (*g->ptr, g->alloc * g->size);
97 }
98}
99
100
101/* Grow the growing array G to make it big enough for INC additional
102 elements. If the array is already big enough, nothing is done.
103 Otherwise, the array is enlarged by at least INC (of grow_init())
104 elements. The associated array pointer may change. */
105
106void grow_by (struct grow *g, int inc)
107{
108 grow_to (g, g->count + inc);
109}
110
111
112/* Initialize a growing buffer. B is a pointer to the buffer
113 descriptor. */
114
115void buffer_init (struct buffer *b)
116{
117 b->size = 0;
118 b->alloc = 0;
119 b->buf = NULL;
120}
121
122
123/* Deallocate a growing buffer. Do not use the buffer after calling
124 this function. */
125
126void buffer_free (struct buffer *b)
127{
128 if (b->buf != NULL)
129 {
130 free (b->buf);
131 b->buf = NULL;
132 }
133}
134
135
136/* Grow the buffer B by N bytes. The buffer size is always an
137 integral multiple of 512. The buffer may move in memory. */
138
139static void buffer_grow_by (struct buffer *b, size_t n)
140{
141 if (b->size + n > b->alloc)
142 {
143 n = (n | 0x1ff) + 1;
144 b->alloc += n;
145 b->buf = xrealloc (b->buf, b->alloc);
146 }
147}
148
149
150/* Append the 8-bit byte X to the buffer B. */
151
152void buffer_byte (struct buffer *b, byte x)
153{
154 buffer_grow_by (b, 1);
155 b->buf[b->size++] = x;
156}
157
158
159/* Append the 16-bit word X to the buffer B. The LSB comes first. */
160
161void buffer_word (struct buffer *b, word x)
162{
163 buffer_grow_by (b, 2);
164 b->buf[b->size++] = x & 0xff;
165 b->buf[b->size++] = (x >> 8) & 0xff;
166}
167
168
169/* Append the 32-bit word X to the buffer B. The LSB comes first. */
170
171void buffer_dword (struct buffer *b, dword x)
172{
173 buffer_grow_by (b, 4);
174 b->buf[b->size++] = x & 0xff;
175 b->buf[b->size++] = (x >> 8) & 0xff;
176 b->buf[b->size++] = (x >> 16) & 0xff;
177 b->buf[b->size++] = (x >> 24) & 0xff;
178}
179
180
181/* Append LEN bytes at MEM to the buffer B. */
182
183void buffer_mem (struct buffer *b, const void *mem, int len)
184{
185 buffer_grow_by (b, len);
186 memcpy (b->buf + b->size, mem, len);
187 b->size += len;
188}
189
190
191/* Append the string STR to the buffer B. The string is preceded by
192 its length (one byte). If the string length exceeds 255
193 characters, the string is truncated to 255 characters. */
194
195void buffer_nstr (struct buffer *b, const char *str)
196{
197 int len;
198
199 if (str == NULL)
200 buffer_byte (b, 0);
201 else
202 {
203 len = strlen (str);
204 if (len > 255)
205 len = 255;
206 buffer_byte (b, len);
207 buffer_mem (b, str, len);
208 }
209}
210
211
212/* Append the string STR to the buffer B. The string is preceded by
213 its length (one byte or two bytes). If the string length exceeds
214 32767 characters, the string is truncated to 32767 characters. */
215
216void buffer_enc (struct buffer *b, const char *str)
217{
218 size_t len;
219
220 len = strlen (str);
221 if (len > 0x7fff)
222 len = 0x7fff;
223 if (len <= 0x7f)
224 buffer_byte (b, len);
225 else
226 {
227 buffer_byte (b, (len >> 8) | 0x80);
228 buffer_byte (b, len & 0xff);
229 }
230 buffer_mem (b, str, len);
231}
232
233
234/* Patch the 16-bit word in the buffer B at offset INDEX to X. */
235
236void buffer_patch_word (struct buffer *b, int index, word x)
237{
238 b->buf[index+0] = x & 0xff;
239 b->buf[index+1] = (x >> 8) & 0xff;
240}
241
242
243/* The size of the string pool hash table. Should be prime. */
244
245#define STRPOOL_HASH_SIZE 211
246
247/* This structure holds one string. Note that the first character of
248 the string is part of this structure. */
249
250struct string
251{
252 struct string *next; /* Pointer to next string in same bucket */
253 int len; /* The string length. */
254 char string[1]; /* The string */
255};
256
257/* A string pool consists of its hash table. */
258
259struct strpool
260{
261 struct string *table[STRPOOL_HASH_SIZE];
262};
263
264
265/* Create and return a new string pool. Initially, the string pool is
266 empty. */
267
268struct strpool *strpool_init (void)
269{
270 int i;
271 struct strpool *p;
272
273 p = xmalloc (sizeof (*p));
274 for (i = 0; i < STRPOOL_HASH_SIZE; ++i)
275 p->table[i] = NULL;
276 return p;
277}
278
279/* Destroy the string pool P. The hash table and the strings are
280 deallocated. */
281
282void strpool_free (struct strpool *p)
283{
284 struct string *v1, *v2;
285 int i;
286
287 for (i = 0; i < STRPOOL_HASH_SIZE; ++i)
288 for (v1 = p->table[i]; v1 != NULL; v1 = v2)
289 {
290 v2 = v1->next;
291 free (v1);
292 }
293 free (p);
294}
295
296
297/* Add the string S of LEN characters to the string pool P. The
298 string must not contain null characters. A pointer to a string of
299 the string pool is returned. If a string identical to S already
300 exists in the string pool, a pointer to that string is returned.
301 Otherwise, a new string entry is added to the string pool. */
302
303const char *strpool_addn (struct strpool *p, const char *s, int len)
304{
305 unsigned hash;
306 int i;
307 struct string *v;
308
309 hash = 0;
310 for (i = 0; i < len; ++i)
311 hash = hash * 65599 + s[i];
312 hash %= STRPOOL_HASH_SIZE;
313 for (v = p->table[hash]; v != NULL; v = v->next)
314 if (v->len == len && memcmp (v->string, s, len) == 0)
315 return v->string;
316 v = xmalloc (sizeof (*v) + len);
317 assert(((uintptr_t)v & (sizeof(int) - 1)) == 0);
318 memcpy (v->string, s, len);
319 v->string[len] = 0;
320 v->len = len;
321 v->next = p->table[hash];
322 p->table[hash] = v;
323 return v->string;
324}
325
326
327/* Add the null-terminated string S to the string pool P. A pointer
328 to a string of the string pool is returned. If a string identical
329 to S already exists in the string pool, a pointer to that string is
330 returned. Otherwise, a new string entry is added to the string
331 pool. */
332
333const char *strpool_add (struct strpool *p, const char *s)
334{
335 if (s == NULL)
336 return NULL;
337 return strpool_addn (p, s, strlen (s));
338}
339
340/* Add the uppercased string S of LEN characters to the string pool P.
341 See strpool_addn for more details. */
342
343const char *strpool_addnu (struct strpool *p, const char *s, int len)
344{
345 unsigned hash;
346 int i;
347 struct string *v;
348
349 hash = 0;
350 for (i = 0; i < len; ++i)
351 hash = hash * 65599 + toupper(s[i]);
352 hash %= STRPOOL_HASH_SIZE;
353 for (v = p->table[hash]; v != NULL; v = v->next)
354 if (v->len == len)
355 {
356 i = len;
357 while (--i >= 0)
358 if (toupper(s[i]) != v->string[i])
359 break;
360 if (i < 0)
361 return v->string;
362 }
363 v = xmalloc (sizeof (*v) + len);
364 assert(((uintptr_t)v & (sizeof(int) - 1)) == 0);
365 memcpy (v->string, s, len);
366 v->string[len] = 0;
367 v->len = len;
368 strupr (v->string);
369 v->next = p->table[hash];
370 p->table[hash] = v;
371 return v->string;
372}
373
374/* Add the null-terminated uppercased string S to the string pool P.
375 See strpool_add for more details. */
376
377const char *strpool_addu (struct strpool *p, const char *s)
378{
379 if (s == NULL)
380 return NULL;
381 return strpool_addnu (p, s, strlen (s));
382}
383
384/* Get the length of a string pool string. This is very quick since we store
385 the lenght before the string data. */
386int strpool_len (const char *s)
387{
388 assert(((uintptr_t)s & (sizeof(int) - 1)) == 0);
389 if (!s)
390 return 0;
391 return ((size_t *)s)[-1];
392}
393
Note: See TracBrowser for help on using the repository browser.