1 /* C string table handling.
2 Copyright (C) 2000, 2001 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
) __attribute_malloc__
;
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
);
95 ps
= sysconf (_SC_PAGESIZE
) - 2 * sizeof (void *);
96 assert (sizeof (struct memoryblock
) < ps
);
99 return (struct Strtab
*) calloc (1, sizeof (struct Strtab
));
104 morememory (struct Strtab
*st
, size_t len
)
106 struct memoryblock
*newmem
;
110 newmem
= (struct memoryblock
*) malloc (len
);
114 newmem
->next
= st
->memory
;
116 st
->backp
= newmem
->memory
;
117 st
->left
= len
- offsetof (struct memoryblock
, memory
);
122 strtabfree (struct Strtab
*st
)
124 struct memoryblock
*mb
= st
->memory
;
137 static struct Strent
*
138 newstring (struct Strtab
*st
, const char *str
, size_t len
)
140 struct Strent
*newstr
;
144 /* Compute the string length if the caller doesn't know it. */
146 len
= strlen (str
) + 1;
148 /* Compute the amount of padding needed to make the structure aligned. */
149 align
= ((__alignof__ (struct Strent
)
150 - (((uintptr_t) st
->backp
)
151 & (__alignof__ (struct Strent
) - 1)))
152 & (__alignof__ (struct Strent
) - 1));
154 /* Make sure there is enough room in the memory block. */
155 if (st
->left
< align
+ sizeof (struct Strent
) + len
)
157 morememory (st
, sizeof (struct Strent
) + len
);
161 /* Create the reserved string. */
162 newstr
= (struct Strent
*) (st
->backp
+ align
);
163 newstr
->string
= str
;
167 newstr
->right
= NULL
;
169 for (i
= len
- 2; i
>= 0; --i
)
170 newstr
->reverse
[i
] = str
[len
- 2 - i
];
171 newstr
->reverse
[len
- 1] = '\0';
172 st
->backp
+= align
+ sizeof (struct Strent
) + len
;
173 st
->left
-= align
+ sizeof (struct Strent
) + len
;
179 /* XXX This function should definitely be rewritten to use a balancing
180 tree algorith (AVL, red-black trees). For now a simple, correct
181 implementation is enough. */
182 static struct Strent
**
183 searchstring (struct Strent
**sep
, struct Strent
*newstr
)
194 /* Compare the strings. */
195 cmpres
= memcmp ((*sep
)->reverse
, newstr
->reverse
,
196 MIN ((*sep
)->len
, newstr
->len
));
198 /* We found a matching string. */
201 return searchstring (&(*sep
)->left
, newstr
);
203 return searchstring (&(*sep
)->right
, newstr
);
207 /* Add new string. The actual string is assumed to be permanent. */
209 strtabadd (struct Strtab
*st
, const char *str
, size_t len
)
211 struct Strent
*newstr
;
214 /* Allocate memory for the new string and its associated information. */
215 newstr
= newstring (st
, str
, len
);
217 /* Search in the array for the place to insert the string. If there
218 is no string with matching prefix and no string with matching
219 leading substring, create a new entry. */
220 sep
= searchstring (&st
->root
, newstr
);
223 /* This is not the same entry. This means we have a prefix match. */
224 if ((*sep
)->len
> newstr
->len
)
226 /* We have a new substring. This means we don't need the reverse
227 string of this entry anymore. */
228 st
->backp
-= newstr
->len
;
229 st
->left
+= newstr
->len
;
231 newstr
->next
= (*sep
)->next
;
232 (*sep
)->next
= newstr
;
234 else if ((*sep
)->len
!= newstr
->len
)
236 /* When we get here it means that the string we are about to
237 add has a common prefix with a string we already have but
238 it is longer. In this case we have to put it first. */
242 st
->total
+= newstr
->len
- (*sep
)->len
;
246 /* We have an exact match. Free the memory we allocated. */
247 st
->left
+= st
->backp
- (char *) newstr
;
248 st
->backp
= (char *) newstr
;
254 st
->total
+= newstr
->len
;
261 copystrings (struct Strent
*nodep
, char **freep
, size_t *offsetp
)
265 if (nodep
->left
!= NULL
)
266 copystrings (nodep
->left
, freep
, offsetp
);
268 /* Process the current node. */
269 nodep
->offset
= *offsetp
;
270 *freep
= (char *) mempcpy (*freep
, nodep
->string
, nodep
->len
);
271 *offsetp
+= nodep
->len
;
273 for (subs
= nodep
->next
; subs
!= NULL
; subs
= subs
->next
)
275 assert (subs
->len
< nodep
->len
);
276 subs
->offset
= nodep
->offset
+ nodep
->len
- subs
->len
;
279 if (nodep
->right
!= NULL
)
280 copystrings (nodep
->right
, freep
, offsetp
);
285 strtabfinalize (struct Strtab
*st
, size_t *size
)
291 /* Fill in the information. */
292 endp
= retval
= (char *) xmalloc (st
->total
+ 1);
294 /* Always put an empty string at the beginning so that a zero offset
298 /* Now run through the tree and add all the string while also updating
299 the offset members of the elfstrent records. */
301 copystrings (st
->root
, &endp
, ©len
);
302 assert (copylen
== st
->total
+ 1);
303 assert (endp
= retval
+ st
->total
+ 1);
311 strtaboffset (struct Strent
*se
)