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