1 /* C string table handling.
2 Copyright (C) 2000-2013 Free Software Foundation, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
46 struct memoryblock
*next
;
54 struct memoryblock
*memory
;
63 /* Cache for the pagesize. We correct this value a bit so that `malloc'
64 is not allocating more than a page. */
68 extern void *xmalloc (size_t n
)
69 __attribute_malloc__
__attribute_alloc_size (1);
71 /* Prototypes for our functions that are used from iconvconfig.c. If
72 you change these, change also iconvconfig.c. */
73 /* Create new C string table object in memory. */
74 extern struct Strtab
*strtabinit (void);
76 /* Free resources allocated for C string table ST. */
77 extern void strtabfree (struct Strtab
*st
);
79 /* Add string STR (length LEN is != 0) to C string table ST. */
80 extern struct Strent
*strtabadd (struct Strtab
*st
, const char *str
,
83 /* Finalize string table ST and store size in *SIZE and return a pointer. */
84 extern void *strtabfinalize (struct Strtab
*st
, size_t *size
);
86 /* Get offset in string table for string associated with SE. */
87 extern size_t strtaboffset (struct Strent
*se
);
97 ps
= sysconf (_SC_PAGESIZE
) - 2 * sizeof (void *);
98 assert (sizeof (struct memoryblock
) < ps
);
101 ret
= (struct Strtab
*) calloc (1, sizeof (struct Strtab
));
105 ret
->null
.string
= "";
112 morememory (struct Strtab
*st
, size_t len
)
114 struct memoryblock
*newmem
;
118 newmem
= (struct memoryblock
*) malloc (len
);
122 newmem
->next
= st
->memory
;
124 st
->backp
= newmem
->memory
;
125 st
->left
= len
- offsetof (struct memoryblock
, memory
);
130 strtabfree (struct Strtab
*st
)
132 struct memoryblock
*mb
= st
->memory
;
145 static struct Strent
*
146 newstring (struct Strtab
*st
, const char *str
, size_t len
)
148 struct Strent
*newstr
;
152 /* Compute the amount of padding needed to make the structure aligned. */
153 align
= ((__alignof__ (struct Strent
)
154 - (((uintptr_t) st
->backp
)
155 & (__alignof__ (struct Strent
) - 1)))
156 & (__alignof__ (struct Strent
) - 1));
158 /* Make sure there is enough room in the memory block. */
159 if (st
->left
< align
+ sizeof (struct Strent
) + len
)
161 morememory (st
, sizeof (struct Strent
) + len
);
165 /* Create the reserved string. */
166 newstr
= (struct Strent
*) (st
->backp
+ align
);
167 newstr
->string
= str
;
171 newstr
->right
= NULL
;
173 for (i
= len
- 2; i
>= 0; --i
)
174 newstr
->reverse
[i
] = str
[len
- 2 - i
];
175 newstr
->reverse
[len
- 1] = '\0';
176 st
->backp
+= align
+ sizeof (struct Strent
) + len
;
177 st
->left
-= align
+ sizeof (struct Strent
) + len
;
183 /* XXX This function should definitely be rewritten to use a balancing
184 tree algorith (AVL, red-black trees). For now a simple, correct
185 implementation is enough. */
186 static struct Strent
**
187 searchstring (struct Strent
**sep
, struct Strent
*newstr
)
198 /* Compare the strings. */
199 cmpres
= memcmp ((*sep
)->reverse
, newstr
->reverse
,
200 MIN ((*sep
)->len
, newstr
->len
) - 1);
202 /* We found a matching string. */
205 return searchstring (&(*sep
)->left
, newstr
);
207 return searchstring (&(*sep
)->right
, newstr
);
211 /* Add new string. The actual string is assumed to be permanent. */
213 strtabadd (struct Strtab
*st
, const char *str
, size_t len
)
215 struct Strent
*newstr
;
218 /* Compute the string length if the caller doesn't know it. */
220 len
= strlen (str
) + 1;
222 /* Make sure all "" strings get offset 0. */
226 /* Allocate memory for the new string and its associated information. */
227 newstr
= newstring (st
, str
, len
);
229 /* Search in the array for the place to insert the string. If there
230 is no string with matching prefix and no string with matching
231 leading substring, create a new entry. */
232 sep
= searchstring (&st
->root
, newstr
);
235 /* This is not the same entry. This means we have a prefix match. */
236 if ((*sep
)->len
> newstr
->len
)
240 for (subs
= (*sep
)->next
; subs
; subs
= subs
->next
)
241 if (subs
->len
== newstr
->len
)
243 /* We have an exact match with a substring. Free the memory
245 st
->left
+= st
->backp
- (char *) newstr
;
246 st
->backp
= (char *) newstr
;
251 /* We have a new substring. This means we don't need the reverse
252 string of this entry anymore. */
253 st
->backp
-= newstr
->len
;
254 st
->left
+= newstr
->len
;
256 newstr
->next
= (*sep
)->next
;
257 (*sep
)->next
= newstr
;
259 else if ((*sep
)->len
!= newstr
->len
)
261 /* When we get here it means that the string we are about to
262 add has a common prefix with a string we already have but
263 it is longer. In this case we have to put it first. */
264 st
->total
+= newstr
->len
- (*sep
)->len
;
266 newstr
->left
= (*sep
)->left
;
267 newstr
->right
= (*sep
)->right
;
272 /* We have an exact match. Free the memory we allocated. */
273 st
->left
+= st
->backp
- (char *) newstr
;
274 st
->backp
= (char *) newstr
;
280 st
->total
+= newstr
->len
;
287 copystrings (struct Strent
*nodep
, char **freep
, size_t *offsetp
)
291 if (nodep
->left
!= NULL
)
292 copystrings (nodep
->left
, freep
, offsetp
);
294 /* Process the current node. */
295 nodep
->offset
= *offsetp
;
296 *freep
= (char *) mempcpy (*freep
, nodep
->string
, nodep
->len
);
297 *offsetp
+= nodep
->len
;
299 for (subs
= nodep
->next
; subs
!= NULL
; subs
= subs
->next
)
301 assert (subs
->len
< nodep
->len
);
302 subs
->offset
= nodep
->offset
+ nodep
->len
- subs
->len
;
305 if (nodep
->right
!= NULL
)
306 copystrings (nodep
->right
, freep
, offsetp
);
311 strtabfinalize (struct Strtab
*st
, size_t *size
)
317 /* Fill in the information. */
318 endp
= retval
= (char *) xmalloc (st
->total
+ 1);
320 /* Always put an empty string at the beginning so that a zero offset
324 /* Now run through the tree and add all the string while also updating
325 the offset members of the elfstrent records. */
327 copystrings (st
->root
, &endp
, ©len
);
328 assert (copylen
== st
->total
+ 1);
329 assert (endp
== retval
+ st
->total
+ 1);
337 strtaboffset (struct Strent
*se
)