1 /*
2 * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: ftsym.c,v 1.5 2003/04/26 03:12:03 maf Exp $
27 */
28
29 #include "ftconfig.h"
30
31 #if HAVE_INTTYPES_H
32 # include <inttypes.h> /* C99 uint8_t uint16_t uint32_t uint64_t */
33 #elif HAVE_STDINT_H
34 # include <stdint.h> /* or here */
35 #endif /* else commit suicide. later */
36
37 #include "ftlib.h"
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <fcntl.h>
46 #include <ctype.h>
47 #include <stddef.h>
48 #include <stdlib.h>
49
50 #if HAVE_STRINGS_H
51 #include <strings.h>
52 #endif
53 #if HAVE_STRING_H
54 #include <string.h>
55 #endif
56
57
58 /*
59 * function: ftsym_new
60 *
61 * allocate and initialize new symbol table structure
62 *
63 * fname - filename to load ASCII table
64 * returns allocated structure or 0L for error.
65 *
66 */
ftsym_new(const char * fname)67 struct ftsym *ftsym_new(const char *fname)
68 {
69 struct stat sb;
70 struct ftsym *ftsym;
71 struct ftchash_rec_sym ftch_recsym, *ftch_recsymp;
72 char *c, *buf, *end;
73 int fd, ret;
74 uint32_t hash;
75
76 /* no filename? */
77 if (!fname)
78 return (struct ftsym*)0L;
79
80 fd = -1;
81 ret = -1;
82
83 /* allocate ftsym structure */
84 if (!(ftsym = (struct ftsym*)malloc(sizeof (struct ftsym)))) {
85 fterr_warn("malloc(struct ftsym)");
86 goto ftsym_new_out;
87 }
88
89 /* init */
90 bzero(ftsym, sizeof (struct ftsym));
91 bzero(&ftch_recsym, sizeof ftch_recsym);
92
93 if ((fd = open(fname, O_RDONLY, 0)) < 0) {
94 fterr_warn("open(%s)", fname);
95 goto ftsym_new_out;
96 }
97
98 if (fstat(fd, &sb) < 0) {
99 fterr_warn("stat(%s)", fname);
100 goto ftsym_new_out;
101 }
102
103 /* allocate storage for file */
104 if (!(ftsym->fbuf = malloc(sb.st_size+1))) {
105 fterr_warn("malloc()");
106 goto ftsym_new_out;
107 }
108
109 /*
110 * file format:
111 *
112 * value<white space>symbol\n
113 * # comment\n
114 */
115
116 /* read in file */
117 if (read(fd, ftsym->fbuf, sb.st_size) != sb.st_size) {
118 fterr_warnx("read(): short");
119 goto ftsym_new_out;
120 }
121
122 /* null terminate file */
123 ftsym->fbuf[sb.st_size] = 0;
124
125 /* init hash table */
126 if (!(ftsym->ftch = ftchash_new(4096, sizeof (struct ftchash_rec_sym),
127 4, 256))) {
128 fterr_warnx("ftchash_new(): failed");
129 goto ftsym_new_out;
130 }
131
132 buf = ftsym->fbuf;
133 c = buf;
134
135 for (;;) {
136
137 /* skip to first char */
138 for (; *buf && isspace((int)*buf); ++buf);
139
140 /* done? */
141 if (!*buf)
142 break;
143
144 /* comment line */
145 if (*buf == '#') {
146 for (; *buf && *buf != '\n'; ++buf);
147 continue;
148 }
149
150 /* at first token (value), null terminate it */
151 c = buf;
152 for (; *c && !isspace((int)*c); ++c);
153 if (!*c) {
154 fterr_warnx("Missing field");
155 goto ftsym_new_out;
156 }
157 *c = 0;
158 ftch_recsym.val = strtoul(buf, (char **)0L, 0);
159
160 /* compute hash */
161 hash = ((ftch_recsym.val>>16) ^ (ftch_recsym.val & 0xFFFF)) & 0x0FFF;
162
163 /* store it in hash table */
164 if (!(ftch_recsymp = ftchash_update(ftsym->ftch, &ftch_recsym, hash))) {
165 fterr_warnx("ftch_update(): failed");
166 goto ftsym_new_out;
167 }
168
169 buf = ++c;
170
171 /* skip past white space */
172 for (; *buf && ((*buf == ' ') || (*buf == '\t')); ++buf);
173 if (!*buf) {
174 fterr_warnx("Missing field");
175 goto ftsym_new_out;
176 }
177
178 c = buf;
179
180 /* skip to next token (name), null terminate it */
181 for (; *c && (*c != '\n'); ++c);
182
183 /* prime for next line */
184 end = c;
185 if (*end)
186 ++end;
187
188 *c = 0;
189
190 /* backup over trailing white space */
191 --c;
192 for (; isspace((int)*c);--c);
193
194 /* update hash rec to point at string */
195 ftch_recsymp->str = buf;
196
197 buf = end;
198
199 }
200
201 ret = 0; /* good */
202
203 ftsym_new_out:
204
205 if (fd != -1)
206 close(fd);
207
208 if (ret != 0) {
209
210 if (ftsym) {
211
212 if (ftsym->fbuf)
213 free(ftsym->fbuf);
214
215 if (ftsym->ftch)
216 ftchash_free(ftsym->ftch);
217
218 free(ftsym);
219 ftsym = (struct ftsym*)0L;
220
221 }
222
223 }
224
225 return ftsym;
226
227 } /* ftsym_new */
228
229 /*
230 * function: ftsym_findbyname
231 *
232 * lookup entry by name (linear search)
233 *
234 * returns pointer to record found or null if not found.
235 */
ftsym_findbyname(struct ftsym * ftsym,const char * name,uint32_t * val)236 int ftsym_findbyname(struct ftsym *ftsym, const char *name, uint32_t *val)
237 {
238 struct ftchash_rec_sym *ftch_recsymp;
239
240 if (!ftsym)
241 return 0;
242
243 ftchash_first(ftsym->ftch);
244
245 while ((ftch_recsymp = ftchash_foreach(ftsym->ftch))) {
246
247 if (!strcasecmp(ftch_recsymp->str, name)) {
248 *val = ftch_recsymp->val;
249 return 1;
250 }
251
252 }
253
254 return 0;
255
256 } /* ftsym_findbyname */
257
258 /*
259 * function: ftsym_findbyval
260 *
261 * lookup entry by value (hashed search)
262 *
263 * returns pointer to record found or null if not found.
264 */
ftsym_findbyval(struct ftsym * ftsym,uint32_t val,char ** name)265 int ftsym_findbyval(struct ftsym *ftsym, uint32_t val, char **name)
266 {
267 struct ftchash_rec_sym *ftch_recsymp;
268 uint32_t hash;
269
270 if (!ftsym)
271 return 0;
272
273 hash = ((val>>16) ^ (val & 0xFFFF)) & 0x0FFF;
274
275 if (!(ftch_recsymp = ftchash_lookup(ftsym->ftch, &val, hash)))
276 return 0;
277
278 *name = ftch_recsymp->str;
279 return 1;
280
281 } /* ftsym_findbyval */
282
283 /*
284 * function: ftsym_free
285 *
286 * free resources allocated by ftsym_init
287 *
288 */
ftsym_free(struct ftsym * ftsym)289 void ftsym_free(struct ftsym *ftsym)
290 {
291 if (ftsym) {
292
293 if (ftsym->fbuf)
294 free(ftsym->fbuf);
295
296 if (ftsym->ftch)
297 ftchash_free(ftsym->ftch);
298
299 free(ftsym);
300
301 }
302 } /* ftsym_free */
303
304