tic.c revision 1.12.2.1 1 1.12.2.1 riz /* $NetBSD: tic.c,v 1.12.2.1 2012/06/23 22:54:56 riz Exp $ */
2 1.1 roy
3 1.1 roy /*
4 1.5 roy * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
5 1.1 roy *
6 1.1 roy * This code is derived from software contributed to The NetBSD Foundation
7 1.1 roy * by Roy Marples.
8 1.1 roy *
9 1.1 roy * Redistribution and use in source and binary forms, with or without
10 1.1 roy * modification, are permitted provided that the following conditions
11 1.1 roy * are met:
12 1.1 roy * 1. Redistributions of source code must retain the above copyright
13 1.1 roy * notice, this list of conditions and the following disclaimer.
14 1.1 roy * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 roy * notice, this list of conditions and the following disclaimer in the
16 1.1 roy * documentation and/or other materials provided with the distribution.
17 1.1 roy *
18 1.1 roy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 1.1 roy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 1.1 roy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 1.1 roy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 1.1 roy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 1.1 roy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1 roy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1 roy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1 roy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 1.1 roy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 roy */
29 1.1 roy
30 1.1 roy #if HAVE_NBTOOL_CONFIG_H
31 1.1 roy #include "nbtool_config.h"
32 1.1 roy #endif
33 1.1 roy
34 1.1 roy #include <sys/cdefs.h>
35 1.12.2.1 riz __RCSID("$NetBSD: tic.c,v 1.12.2.1 2012/06/23 22:54:56 riz Exp $");
36 1.1 roy
37 1.1 roy #include <sys/types.h>
38 1.12.2.1 riz #include <sys/queue.h>
39 1.8 pgoyette
40 1.9 pgoyette #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
41 1.7 pgoyette #include <sys/endian.h>
42 1.8 pgoyette #endif
43 1.1 roy
44 1.12.2.1 riz #include <cdbw.h>
45 1.1 roy #include <ctype.h>
46 1.1 roy #include <err.h>
47 1.1 roy #include <errno.h>
48 1.1 roy #include <getopt.h>
49 1.1 roy #include <limits.h>
50 1.1 roy #include <fcntl.h>
51 1.12.2.1 riz #include <search.h>
52 1.1 roy #include <stdarg.h>
53 1.1 roy #include <stdlib.h>
54 1.1 roy #include <stdio.h>
55 1.1 roy #include <string.h>
56 1.1 roy #include <term_private.h>
57 1.1 roy #include <term.h>
58 1.12.2.1 riz #include <util.h>
59 1.12.2.1 riz
60 1.12.2.1 riz #define HASH_SIZE 16384 /* 2012-06-01: 3600 entries */
61 1.1 roy
62 1.1 roy /* We store the full list of terminals we have instead of iterating
63 1.1 roy through the database as the sequential iterator doesn't work
64 1.1 roy the the data size stored changes N amount which ours will. */
65 1.1 roy typedef struct term {
66 1.12.2.1 riz STAILQ_ENTRY(term) next;
67 1.1 roy char *name;
68 1.10 roy TIC *tic;
69 1.12.2.1 riz uint32_t id;
70 1.12.2.1 riz struct term *base_term;
71 1.1 roy } TERM;
72 1.12.2.1 riz static STAILQ_HEAD(, term) terms = STAILQ_HEAD_INITIALIZER(terms);
73 1.1 roy
74 1.1 roy static int error_exit;
75 1.10 roy static int Sflag;
76 1.12.2.1 riz static size_t nterm, nalias;
77 1.1 roy
78 1.12.2.1 riz static void __printflike(1, 2)
79 1.1 roy dowarn(const char *fmt, ...)
80 1.1 roy {
81 1.1 roy va_list va;
82 1.1 roy
83 1.1 roy error_exit = 1;
84 1.1 roy va_start(va, fmt);
85 1.1 roy vwarnx(fmt, va);
86 1.1 roy va_end(va);
87 1.1 roy }
88 1.1 roy
89 1.1 roy static char *
90 1.1 roy grow_tbuf(TBUF *tbuf, size_t len)
91 1.1 roy {
92 1.1 roy char *buf;
93 1.1 roy
94 1.10 roy buf = _ti_grow_tbuf(tbuf, len);
95 1.10 roy if (buf == NULL)
96 1.10 roy err(1, "_ti_grow_tbuf");
97 1.10 roy return buf;
98 1.5 roy }
99 1.5 roy
100 1.5 roy static int
101 1.12.2.1 riz save_term(struct cdbw *db, TERM *term)
102 1.5 roy {
103 1.10 roy uint8_t *buf;
104 1.10 roy ssize_t len;
105 1.12.2.1 riz size_t slen = strlen(term->name) + 1;
106 1.12.2.1 riz
107 1.12.2.1 riz if (term->base_term != NULL) {
108 1.12.2.1 riz len = (ssize_t)slen + 7;
109 1.12.2.1 riz buf = emalloc(len);
110 1.12.2.1 riz buf[0] = 2;
111 1.12.2.1 riz le32enc(buf + 1, term->base_term->id);
112 1.12.2.1 riz le16enc(buf + 5, slen);
113 1.12.2.1 riz memcpy(buf + 7, term->name, slen);
114 1.12.2.1 riz if (cdbw_put(db, term->name, slen, buf, len))
115 1.12.2.1 riz err(1, "cdbw_put");
116 1.12.2.1 riz return 0;
117 1.12.2.1 riz }
118 1.5 roy
119 1.10 roy len = _ti_flatten(&buf, term->tic);
120 1.10 roy if (len == -1)
121 1.5 roy return -1;
122 1.1 roy
123 1.12.2.1 riz if (cdbw_put_data(db, buf, len, &term->id))
124 1.12.2.1 riz err(1, "cdbw_put_data");
125 1.12.2.1 riz if (cdbw_put_key(db, term->name, slen, term->id))
126 1.12.2.1 riz err(1, "cdbw_put_key");
127 1.10 roy free(buf);
128 1.1 roy return 0;
129 1.1 roy }
130 1.1 roy
131 1.1 roy static TERM *
132 1.1 roy find_term(const char *name)
133 1.1 roy {
134 1.12.2.1 riz ENTRY elem, *elemp;
135 1.12.2.1 riz
136 1.12.2.1 riz elem.key = __UNCONST(name);
137 1.12.2.1 riz elem.data = NULL;
138 1.12.2.1 riz elemp = hsearch(elem, FIND);
139 1.12.2.1 riz return elemp ? (TERM *)elemp->data : NULL;
140 1.1 roy }
141 1.1 roy
142 1.1 roy static TERM *
143 1.12.2.1 riz store_term(const char *name, TERM *base_term)
144 1.1 roy {
145 1.1 roy TERM *term;
146 1.12.2.1 riz ENTRY elem;
147 1.12.2.1 riz
148 1.12.2.1 riz term = ecalloc(1, sizeof(*term));
149 1.12.2.1 riz term->name = estrdup(name);
150 1.12.2.1 riz STAILQ_INSERT_TAIL(&terms, term, next);
151 1.12.2.1 riz elem.key = estrdup(name);
152 1.12.2.1 riz elem.data = term;
153 1.12.2.1 riz hsearch(elem, ENTER);
154 1.12.2.1 riz
155 1.12.2.1 riz term->base_term = base_term;
156 1.12.2.1 riz if (base_term != NULL)
157 1.12.2.1 riz nalias++;
158 1.12.2.1 riz else
159 1.12.2.1 riz nterm++;
160 1.1 roy
161 1.1 roy return term;
162 1.1 roy }
163 1.1 roy
164 1.1 roy static int
165 1.10 roy process_entry(TBUF *buf, int flags)
166 1.1 roy {
167 1.10 roy char *p, *e, *alias;
168 1.1 roy TERM *term;
169 1.1 roy TIC *tic;
170 1.1 roy
171 1.1 roy if (buf->bufpos == 0)
172 1.1 roy return 0;
173 1.1 roy /* Terminate the string */
174 1.1 roy buf->buf[buf->bufpos - 1] = '\0';
175 1.1 roy /* First rewind the buffer for new entries */
176 1.1 roy buf->bufpos = 0;
177 1.1 roy
178 1.1 roy if (isspace((unsigned char)*buf->buf))
179 1.1 roy return 0;
180 1.1 roy
181 1.10 roy tic = _ti_compile(buf->buf, flags);
182 1.10 roy if (tic == NULL)
183 1.1 roy return 0;
184 1.10 roy
185 1.10 roy if (find_term(tic->name) != NULL) {
186 1.10 roy dowarn("%s: duplicate entry", tic->name);
187 1.10 roy _ti_freetic(tic);
188 1.1 roy return 0;
189 1.1 roy }
190 1.12.2.1 riz term = store_term(tic->name, NULL);
191 1.10 roy term->tic = tic;
192 1.1 roy
193 1.1 roy /* Create aliased terms */
194 1.10 roy if (tic->alias != NULL) {
195 1.12.2.1 riz alias = p = estrdup(tic->alias);
196 1.10 roy while (p != NULL && *p != '\0') {
197 1.10 roy e = strchr(p, '|');
198 1.10 roy if (e != NULL)
199 1.10 roy *e++ = '\0';
200 1.10 roy if (find_term(p) != NULL) {
201 1.1 roy dowarn("%s: has alias for already assigned"
202 1.10 roy " term %s", tic->name, p);
203 1.1 roy } else {
204 1.12.2.1 riz store_term(p, term);
205 1.1 roy }
206 1.10 roy p = e;
207 1.1 roy }
208 1.12.2.1 riz free(alias);
209 1.1 roy }
210 1.1 roy
211 1.1 roy return 0;
212 1.1 roy }
213 1.1 roy
214 1.1 roy static void
215 1.10 roy merge(TIC *rtic, TIC *utic, int flags)
216 1.1 roy {
217 1.1 roy char *cap, flag, *code, type, *str;
218 1.1 roy short ind, num;
219 1.1 roy size_t n;
220 1.1 roy
221 1.1 roy cap = utic->flags.buf;
222 1.1 roy for (n = utic->flags.entries; n > 0; n--) {
223 1.1 roy ind = le16dec(cap);
224 1.1 roy cap += sizeof(uint16_t);
225 1.1 roy flag = *cap++;
226 1.1 roy if (VALID_BOOLEAN(flag) &&
227 1.10 roy _ti_find_cap(&rtic->flags, 'f', ind) == NULL)
228 1.1 roy {
229 1.10 roy _ti_grow_tbuf(&rtic->flags, sizeof(uint16_t) + 1);
230 1.1 roy le16enc(rtic->flags.buf + rtic->flags.bufpos, ind);
231 1.1 roy rtic->flags.bufpos += sizeof(uint16_t);
232 1.1 roy rtic->flags.buf[rtic->flags.bufpos++] = flag;
233 1.1 roy rtic->flags.entries++;
234 1.1 roy }
235 1.1 roy }
236 1.1 roy
237 1.1 roy cap = utic->nums.buf;
238 1.1 roy for (n = utic->nums.entries; n > 0; n--) {
239 1.1 roy ind = le16dec(cap);
240 1.1 roy cap += sizeof(uint16_t);
241 1.1 roy num = le16dec(cap);
242 1.1 roy cap += sizeof(uint16_t);
243 1.1 roy if (VALID_NUMERIC(num) &&
244 1.10 roy _ti_find_cap(&rtic->nums, 'n', ind) == NULL)
245 1.1 roy {
246 1.1 roy grow_tbuf(&rtic->nums, sizeof(uint16_t) * 2);
247 1.1 roy le16enc(rtic->nums.buf + rtic->nums.bufpos, ind);
248 1.1 roy rtic->nums.bufpos += sizeof(uint16_t);
249 1.1 roy le16enc(rtic->nums.buf + rtic->nums.bufpos, num);
250 1.1 roy rtic->nums.bufpos += sizeof(uint16_t);
251 1.1 roy rtic->nums.entries++;
252 1.1 roy }
253 1.1 roy }
254 1.1 roy
255 1.1 roy cap = utic->strs.buf;
256 1.1 roy for (n = utic->strs.entries; n > 0; n--) {
257 1.1 roy ind = le16dec(cap);
258 1.1 roy cap += sizeof(uint16_t);
259 1.1 roy num = le16dec(cap);
260 1.1 roy cap += sizeof(uint16_t);
261 1.1 roy if (num > 0 &&
262 1.10 roy _ti_find_cap(&rtic->strs, 's', ind) == NULL)
263 1.1 roy {
264 1.1 roy grow_tbuf(&rtic->strs, (sizeof(uint16_t) * 2) + num);
265 1.1 roy le16enc(rtic->strs.buf + rtic->strs.bufpos, ind);
266 1.1 roy rtic->strs.bufpos += sizeof(uint16_t);
267 1.1 roy le16enc(rtic->strs.buf + rtic->strs.bufpos, num);
268 1.1 roy rtic->strs.bufpos += sizeof(uint16_t);
269 1.1 roy memcpy(rtic->strs.buf + rtic->strs.bufpos,
270 1.1 roy cap, num);
271 1.1 roy rtic->strs.bufpos += num;
272 1.1 roy rtic->strs.entries++;
273 1.1 roy }
274 1.1 roy cap += num;
275 1.1 roy }
276 1.1 roy
277 1.1 roy cap = utic->extras.buf;
278 1.1 roy for (n = utic->extras.entries; n > 0; n--) {
279 1.1 roy num = le16dec(cap);
280 1.1 roy cap += sizeof(uint16_t);
281 1.1 roy code = cap;
282 1.1 roy cap += num;
283 1.1 roy type = *cap++;
284 1.1 roy flag = 0;
285 1.1 roy str = NULL;
286 1.1 roy switch (type) {
287 1.1 roy case 'f':
288 1.1 roy flag = *cap++;
289 1.1 roy if (!VALID_BOOLEAN(flag))
290 1.1 roy continue;
291 1.1 roy break;
292 1.1 roy case 'n':
293 1.1 roy num = le16dec(cap);
294 1.1 roy cap += sizeof(uint16_t);
295 1.1 roy if (!VALID_NUMERIC(num))
296 1.1 roy continue;
297 1.1 roy break;
298 1.1 roy case 's':
299 1.1 roy num = le16dec(cap);
300 1.1 roy cap += sizeof(uint16_t);
301 1.1 roy str = cap;
302 1.1 roy cap += num;
303 1.1 roy if (num == 0)
304 1.1 roy continue;
305 1.1 roy break;
306 1.1 roy }
307 1.10 roy _ti_store_extra(rtic, 0, code, type, flag, num, str, num,
308 1.10 roy flags);
309 1.1 roy }
310 1.1 roy }
311 1.1 roy
312 1.1 roy static size_t
313 1.10 roy merge_use(int flags)
314 1.1 roy {
315 1.1 roy size_t skipped, merged, memn;
316 1.1 roy char *cap, *scap;
317 1.1 roy uint16_t num;
318 1.1 roy TIC *rtic, *utic;
319 1.1 roy TERM *term, *uterm;;
320 1.1 roy
321 1.1 roy skipped = merged = 0;
322 1.12.2.1 riz STAILQ_FOREACH(term, &terms, next) {
323 1.12.2.1 riz if (term->base_term != NULL)
324 1.1 roy continue;
325 1.10 roy rtic = term->tic;
326 1.10 roy while ((cap = _ti_find_extra(&rtic->extras, "use")) != NULL) {
327 1.1 roy if (*cap++ != 's') {
328 1.1 roy dowarn("%s: use is not string", rtic->name);
329 1.1 roy break;
330 1.1 roy }
331 1.1 roy cap += sizeof(uint16_t);
332 1.1 roy if (strcmp(rtic->name, cap) == 0) {
333 1.1 roy dowarn("%s: uses itself", rtic->name);
334 1.1 roy goto remove;
335 1.1 roy }
336 1.1 roy uterm = find_term(cap);
337 1.12.2.1 riz if (uterm != NULL && uterm->base_term != NULL)
338 1.12.2.1 riz uterm = uterm->base_term;
339 1.1 roy if (uterm == NULL) {
340 1.1 roy dowarn("%s: no use record for %s",
341 1.1 roy rtic->name, cap);
342 1.1 roy goto remove;
343 1.1 roy }
344 1.10 roy utic = uterm->tic;
345 1.1 roy if (strcmp(utic->name, rtic->name) == 0) {
346 1.1 roy dowarn("%s: uses itself", rtic->name);
347 1.1 roy goto remove;
348 1.1 roy }
349 1.10 roy if (_ti_find_extra(&utic->extras, "use") != NULL) {
350 1.1 roy skipped++;
351 1.1 roy break;
352 1.1 roy }
353 1.10 roy cap = _ti_find_extra(&rtic->extras, "use");
354 1.10 roy merge(rtic, utic, flags);
355 1.1 roy remove:
356 1.1 roy /* The pointers may have changed, find the use again */
357 1.10 roy cap = _ti_find_extra(&rtic->extras, "use");
358 1.1 roy if (cap == NULL)
359 1.1 roy dowarn("%s: use no longer exists - impossible",
360 1.1 roy rtic->name);
361 1.1 roy else {
362 1.1 roy scap = cap - (4 + sizeof(uint16_t));
363 1.1 roy cap++;
364 1.1 roy num = le16dec(cap);
365 1.1 roy cap += sizeof(uint16_t) + num;
366 1.1 roy memn = rtic->extras.bufpos -
367 1.1 roy (cap - rtic->extras.buf);
368 1.11 roy memmove(scap, cap, memn);
369 1.1 roy rtic->extras.bufpos -= cap - scap;
370 1.1 roy cap = scap;
371 1.1 roy rtic->extras.entries--;
372 1.1 roy merged++;
373 1.1 roy }
374 1.1 roy }
375 1.1 roy }
376 1.1 roy
377 1.1 roy if (merged == 0 && skipped != 0)
378 1.1 roy dowarn("circular use detected");
379 1.1 roy return merged;
380 1.1 roy }
381 1.1 roy
382 1.5 roy static int
383 1.5 roy print_dump(int argc, char **argv)
384 1.5 roy {
385 1.5 roy TERM *term;
386 1.10 roy uint8_t *buf;
387 1.5 roy int i, n;
388 1.5 roy size_t j, col;
389 1.10 roy ssize_t len;
390 1.5 roy
391 1.6 roy printf("struct compiled_term {\n");
392 1.6 roy printf("\tconst char *name;\n");
393 1.6 roy printf("\tconst char *cap;\n");
394 1.6 roy printf("\tsize_t caplen;\n");
395 1.6 roy printf("};\n\n");
396 1.6 roy
397 1.6 roy printf("const struct compiled_term compiled_terms[] = {\n");
398 1.6 roy
399 1.5 roy n = 0;
400 1.5 roy for (i = 0; i < argc; i++) {
401 1.5 roy term = find_term(argv[i]);
402 1.5 roy if (term == NULL) {
403 1.5 roy warnx("%s: no description for terminal", argv[i]);
404 1.5 roy continue;
405 1.5 roy }
406 1.12.2.1 riz if (term->base_term != NULL) {
407 1.5 roy warnx("%s: cannot dump alias", argv[i]);
408 1.5 roy continue;
409 1.5 roy }
410 1.10 roy /* Don't compile the aliases in, save space */
411 1.10 roy free(term->tic->alias);
412 1.10 roy term->tic->alias = NULL;
413 1.10 roy len = _ti_flatten(&buf, term->tic);
414 1.10 roy if (len == 0 || len == -1)
415 1.5 roy continue;
416 1.5 roy
417 1.6 roy printf("\t{\n");
418 1.6 roy printf("\t\t\"%s\",\n", argv[i]);
419 1.5 roy n++;
420 1.10 roy for (j = 0, col = 0; j < (size_t)len; j++) {
421 1.5 roy if (col == 0) {
422 1.6 roy printf("\t\t\"");
423 1.6 roy col = 16;
424 1.5 roy }
425 1.5 roy
426 1.10 roy col += printf("\\%03o", (uint8_t)buf[j]);
427 1.5 roy if (col > 75) {
428 1.5 roy printf("\"%s\n",
429 1.10 roy j + 1 == (size_t)len ? "," : "");
430 1.5 roy col = 0;
431 1.5 roy }
432 1.5 roy }
433 1.5 roy if (col != 0)
434 1.6 roy printf("\",\n");
435 1.10 roy printf("\t\t%zu\n", len);
436 1.6 roy printf("\t}");
437 1.6 roy if (i + 1 < argc)
438 1.6 roy printf(",");
439 1.6 roy printf("\n");
440 1.10 roy free(buf);
441 1.5 roy }
442 1.6 roy printf("};\n");
443 1.5 roy
444 1.5 roy return n;
445 1.5 roy }
446 1.5 roy
447 1.12.2.1 riz static void
448 1.12.2.1 riz write_database(const char *dbname)
449 1.12.2.1 riz {
450 1.12.2.1 riz struct cdbw *db;
451 1.12.2.1 riz char *tmp_dbname;
452 1.12.2.1 riz TERM *term;
453 1.12.2.1 riz int fd;
454 1.12.2.1 riz
455 1.12.2.1 riz db = cdbw_open();
456 1.12.2.1 riz if (db == NULL)
457 1.12.2.1 riz err(1, "cdbw_open failed");
458 1.12.2.1 riz /* Save the terms */
459 1.12.2.1 riz STAILQ_FOREACH(term, &terms, next)
460 1.12.2.1 riz save_term(db, term);
461 1.12.2.1 riz
462 1.12.2.1 riz easprintf(&tmp_dbname, "%s.XXXXXX", dbname);
463 1.12.2.1 riz fd = mkstemp(tmp_dbname);
464 1.12.2.1 riz if (fd == -1)
465 1.12.2.1 riz err(1, "creating temporary database %s failed", tmp_dbname);
466 1.12.2.1 riz if (cdbw_output(db, fd, "NetBSD terminfo", cdbw_stable_seeder))
467 1.12.2.1 riz err(1, "writing temporary database %s failed", tmp_dbname);
468 1.12.2.1 riz if (fchmod(fd, DEFFILEMODE))
469 1.12.2.1 riz err(1, "fchmod failed");
470 1.12.2.1 riz if (close(fd))
471 1.12.2.1 riz err(1, "writing temporary database %s failed", tmp_dbname);
472 1.12.2.1 riz if (rename(tmp_dbname, dbname))
473 1.12.2.1 riz err(1, "renaming %s to %s failed", tmp_dbname, dbname);
474 1.12.2.1 riz free(tmp_dbname);
475 1.12.2.1 riz cdbw_close(db);
476 1.12.2.1 riz }
477 1.12.2.1 riz
478 1.1 roy int
479 1.1 roy main(int argc, char **argv)
480 1.1 roy {
481 1.10 roy int ch, cflag, sflag, flags;
482 1.12.2.1 riz char *source, *dbname, *buf, *ofile;
483 1.1 roy FILE *f;
484 1.12.2.1 riz size_t buflen;
485 1.12 roy ssize_t len;
486 1.1 roy TBUF tbuf;
487 1.1 roy
488 1.1 roy cflag = sflag = 0;
489 1.1 roy ofile = NULL;
490 1.10 roy flags = TIC_ALIAS | TIC_DESCRIPTION | TIC_WARNING;
491 1.5 roy while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
492 1.1 roy switch (ch) {
493 1.5 roy case 'S':
494 1.5 roy Sflag = 1;
495 1.10 roy /* We still compile aliases so that use= works.
496 1.10 roy * However, it's removed before we flatten to save space. */
497 1.10 roy flags &= ~TIC_DESCRIPTION;
498 1.5 roy break;
499 1.1 roy case 'a':
500 1.10 roy flags |= TIC_COMMENT;
501 1.1 roy break;
502 1.1 roy case 'c':
503 1.4 roy cflag = 1;
504 1.1 roy break;
505 1.1 roy case 'o':
506 1.1 roy ofile = optarg;
507 1.1 roy break;
508 1.1 roy case 's':
509 1.4 roy sflag = 1;
510 1.1 roy break;
511 1.1 roy case 'x':
512 1.10 roy flags |= TIC_EXTRA;
513 1.1 roy break;
514 1.1 roy case '?': /* FALLTHROUGH */
515 1.1 roy default:
516 1.6 roy fprintf(stderr, "usage: %s [-acSsx] [-o file] source\n",
517 1.1 roy getprogname());
518 1.1 roy return EXIT_FAILURE;
519 1.1 roy }
520 1.1 roy
521 1.1 roy if (optind == argc)
522 1.1 roy errx(1, "No source file given");
523 1.1 roy source = argv[optind++];
524 1.1 roy f = fopen(source, "r");
525 1.1 roy if (f == NULL)
526 1.1 roy err(1, "fopen: %s", source);
527 1.1 roy
528 1.12.2.1 riz hcreate(HASH_SIZE);
529 1.12.2.1 riz
530 1.12.2.1 riz buf = tbuf.buf = NULL;
531 1.12 roy buflen = tbuf.buflen = tbuf.bufpos = 0;
532 1.12 roy while ((len = getline(&buf, &buflen, f)) != -1) {
533 1.1 roy /* Skip comments */
534 1.1 roy if (*buf == '#')
535 1.1 roy continue;
536 1.12 roy if (buf[len - 1] != '\n') {
537 1.10 roy process_entry(&tbuf, flags);
538 1.1 roy dowarn("last line is not a comment"
539 1.1 roy " and does not end with a newline");
540 1.1 roy continue;
541 1.1 roy }
542 1.1 roy /*
543 1.1 roy If the first char is space not a space then we have a
544 1.1 roy new entry, so process it.
545 1.1 roy */
546 1.1 roy if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
547 1.10 roy process_entry(&tbuf, flags);
548 1.1 roy
549 1.1 roy /* Grow the buffer if needed */
550 1.12 roy grow_tbuf(&tbuf, len);
551 1.1 roy /* Append the string */
552 1.12 roy memcpy(tbuf.buf + tbuf.bufpos, buf, len);
553 1.12 roy tbuf.bufpos += len;
554 1.1 roy }
555 1.12.2.1 riz free(buf);
556 1.1 roy /* Process the last entry if not done already */
557 1.10 roy process_entry(&tbuf, flags);
558 1.12.2.1 riz free(tbuf.buf);
559 1.1 roy
560 1.1 roy /* Merge use entries until we have merged all we can */
561 1.10 roy while (merge_use(flags) != 0)
562 1.1 roy ;
563 1.1 roy
564 1.6 roy if (Sflag) {
565 1.5 roy print_dump(argc - optind, argv + optind);
566 1.5 roy return error_exit;
567 1.5 roy }
568 1.5 roy
569 1.6 roy if (cflag)
570 1.1 roy return error_exit;
571 1.1 roy
572 1.12.2.1 riz if (ofile == NULL)
573 1.12.2.1 riz easprintf(&dbname, "%s.cdb", source);
574 1.12.2.1 riz else
575 1.12.2.1 riz dbname = ofile;
576 1.12.2.1 riz write_database(dbname);
577 1.1 roy
578 1.1 roy if (sflag != 0)
579 1.1 roy fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
580 1.12.2.1 riz nterm, nalias, dbname);
581 1.12.2.1 riz
582 1.12.2.1 riz #ifdef __VALGRIND__
583 1.12.2.1 riz if (ofile == NULL)
584 1.12.2.1 riz free(dbname);
585 1.12.2.1 riz while ((term = STAILQ_FIRST(&terms)) != NULL) {
586 1.12.2.1 riz STAILQ_REMOVE_HEAD(&terms, next);
587 1.12.2.1 riz _ti_freetic(term->tic);
588 1.12.2.1 riz free(term->name);
589 1.12.2.1 riz free(term);
590 1.12.2.1 riz }
591 1.12.2.1 riz hdestroy();
592 1.12.2.1 riz #endif
593 1.12.2.1 riz
594 1.1 roy
595 1.1 roy return EXIT_SUCCESS;
596 1.1 roy }
597