]>
git.ipfire.org Git - thirdparty/glibc.git/blob - iconv/strtab.c
1 /* C string table handling.
2 Copyright (C) 2000, 2001, 2005, 2012 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, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
47 struct memoryblock
*next
;
55 struct memoryblock
*memory
;
64 /* Cache for the pagesize. We correct this value a bit so that `malloc'
65 is not allocating more than a page. */
69 extern void *xmalloc (size_t n
)
70 __attribute_malloc__
__attribute_alloc_size (1);
72 /* Prototypes for our functions that are used from iconvconfig.c. If
73 you change these, change also iconvconfig.c. */
74 /* Create new C string table object in memory. */
75 extern struct Strtab
*strtabinit (void);
77 /* Free resources allocated for C string table ST. */
78 extern void strtabfree (struct Strtab
*st
);
80 /* Add string STR (length LEN is != 0) to C string table ST. */
81 extern struct Strent
*strtabadd (struct Strtab
*st
, const char *str
,
84 /* Finalize string table ST and store size in *SIZE and return a pointer. */
85 extern void *strtabfinalize (struct Strtab
*st
, size_t *size
);
87 /* Get offset in string table for string associated with SE. */
88 extern size_t strtaboffset (struct Strent
*se
);
98 ps
= sysconf (_SC_PAGESIZE
) - 2 * sizeof (void *);
99 assert (sizeof (struct memoryblock
) < ps
);
102 ret
= (struct Strtab
*) calloc (1, sizeof (struct Strtab
));
106 ret
->null
.string
= "";
113 morememory (struct Strtab
*st
, size_t len
)
115 struct memoryblock
*newmem
;
119 newmem
= (struct memoryblock
*) malloc (len
);
123 newmem
->next
= st
->memory
;
125 st
->backp
= newmem
->memory
;
126 st
->left
= len
- offsetof (struct memoryblock
, memory
);
131 strtabfree (struct Strtab
*st
)
133 struct memoryblock
*mb
= st
->memory
;
146 static struct Strent
*
147 newstring (struct Strtab
*st
, const char *str
, size_t len
)
149 struct Strent
*newstr
;
153 /* Compute the amount of padding needed to make the structure aligned. */
154 align
= ((__alignof__ (struct Strent
)
155 - (((uintptr_t) st
->backp
)
156 & (__alignof__ (struct Strent
) - 1)))
157 & (__alignof__ (struct Strent
) - 1));
159 /* Make sure there is enough room in the memory block. */
160 if (st
->left
< align
+ sizeof (struct Strent
) + len
)
162 morememory (st
, sizeof (struct Strent
) + len
);
166 /* Create the reserved string. */
167 newstr
= (struct Strent
*) (st
->backp
+ align
);
168 newstr
->string
= str
;
172 newstr
->right
= NULL
;
174 for (i
= len
- 2; i
>= 0; --i
)
175 newstr
->reverse
[i
] = str
[len
- 2 - i
];
176 newstr
->reverse
[len
- 1] = '\0';
177 st
->backp
+= align
+ sizeof (struct Strent
) + len
;
178 st
->left
-= align
+ sizeof (struct Strent
) + len
;
184 /* XXX This function should definitely be rewritten to use a balancing
185 tree algorith (AVL, red-black trees). For now a simple, correct
186 implementation is enough. */
187 static struct Strent
**
188 searchstring (struct Strent
**sep
, struct Strent
*newstr
)
199 /* Compare the strings. */
200 cmpres
= memcmp ((*sep
)->reverse
, newstr
->reverse
,
201 MIN ((*sep
)->len
, newstr
->len
) - 1);
203 /* We found a matching string. */
206 return searchstring (&(*sep
)->left
, newstr
);
208 return searchstring (&(*sep
)->right
, newstr
);
212 /* Add new string. The actual string is assumed to be permanent. */
214 strtabadd (struct Strtab
*st
, const char *str
, size_t len
)
216 struct Strent
*newstr
;
219 /* Compute the string length if the caller doesn't know it. */
221 len
= strlen (str
) + 1;
223 /* Make sure all "" strings get offset 0. */
227 /* Allocate memory for the new string and its associated information. */
228 newstr
= newstring (st
, str
, len
);
230 /* Search in the array for the place to insert the string. If there
231 is no string with matching prefix and no string with matching
232 leading substring, create a new entry. */
233 sep
= searchstring (&st
->root
, newstr
);
236 /* This is not the same entry. This means we have a prefix match. */
237 if ((*sep
)->len
> newstr
->len
)
241 for (subs
= (*sep
)->next
; subs
; subs
= subs
->next
)
242 if (subs
->len
== newstr
->len
)
244 /* We have an exact match with a substring. Free the memory
246 st
->left
+= st
->backp
- (char *) newstr
;
247 st
->backp
= (char *) newstr
;
252 /* We have a new substring. This means we don't need the reverse
253 string of this entry anymore. */
254 st
->backp
-= newstr
->len
;
255 st
->left
+= newstr
->len
;
257 newstr
->next
= (*sep
)->next
;
258 (*sep
)->next
= newstr
;
260 else if ((*sep
)->len
!= newstr
->len
)
262 /* When we get here it means that the string we are about to
263 add has a common prefix with a string we already have but
264 it is longer. In this case we have to put it first. */
265 st
->total
+= newstr
->len
- (*sep
)->len
;
267 newstr
->left
= (*sep
)->left
;
268 newstr
->right
= (*sep
)->right
;
273 /* We have an exact match. Free the memory we allocated. */
274 st
->left
+= st
->backp
- (char *) newstr
;
275 st
->backp
= (char *) newstr
;
281 st
->total
+= newstr
->len
;
288 copystrings (struct Strent
*nodep
, char **freep
, size_t *offsetp
)
292 if (nodep
->left
!= NULL
)
293 copystrings (nodep
->left
, freep
, offsetp
);
295 /* Process the current node. */
296 nodep
->offset
= *offsetp
;
297 *freep
= (char *) mempcpy (*freep
, nodep
->string
, nodep
->len
);
298 *offsetp
+= nodep
->len
;
300 for (subs
= nodep
->next
; subs
!= NULL
; subs
= subs
->next
)
302 assert (subs
->len
< nodep
->len
);
303 subs
->offset
= nodep
->offset
+ nodep
->len
- subs
->len
;
306 if (nodep
->right
!= NULL
)
307 copystrings (nodep
->right
, freep
, offsetp
);
312 strtabfinalize (struct Strtab
*st
, size_t *size
)
318 /* Fill in the information. */
319 endp
= retval
= (char *) xmalloc (st
->total
+ 1);
321 /* Always put an empty string at the beginning so that a zero offset
325 /* Now run through the tree and add all the string while also updating
326 the offset members of the elfstrent records. */
328 copystrings (st
->root
, &endp
, ©len
);
329 assert (copylen
== st
->total
+ 1);
330 assert (endp
== retval
+ st
->total
+ 1);
338 strtaboffset (struct Strent
*se
)