Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / usr.bin / xstr / xstr.c
blob853fc39765d62eab69d4f946d097ac536334d29d
1 /* $NetBSD: xstr.c,v 1.23 2009/04/14 09:18:41 lukem Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)xstr.c 8.1 (Berkeley) 6/9/93";
41 #else
42 __RCSID("$NetBSD: xstr.c,v 1.23 2009/04/14 09:18:41 lukem Exp $");
43 #endif
44 #endif /* not lint */
46 #include <sys/param.h>
47 #include <signal.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include <err.h>
55 #include "pathnames.h"
58 * xstr - extract and hash strings in a C program
60 * Bill Joy UCB
61 * November, 1978
64 static off_t hashit(const char *, int);
65 static void onintr(int);
66 static off_t yankstr(char **);
67 static int octdigit(char);
68 static void inithash(void);
69 static int fgetNUL(char *, int, FILE *);
70 static int xgetc(FILE *);
71 static void flushsh(void);
72 static void found(int, off_t, const char *);
73 static void prstr(const char *);
74 static void xsdotc(void);
75 static char lastchr(const char *);
76 static int istail(const char *, const char *);
77 static void process(const char *);
78 static void usage(void);
80 static off_t tellpt;
81 static off_t mesgpt;
82 static char stringtmpfile[MAXPATHLEN];
83 static const char *strings = "strings";
84 static const char *array = 0;
85 static int cflg;
86 static int vflg;
87 static int readstd;
88 static char linebuf[8192];
90 #define BUCKETS 128
92 static struct hash {
93 off_t hpt;
94 char *hstr;
95 struct hash *hnext;
96 short hnew;
97 } bucket[BUCKETS];
99 int main(int, char *[]);
102 main(int argc, char *argv[])
104 int c;
106 while ((c = getopt(argc, argv, "-cvl:")) != -1)
107 switch (c) {
108 case '-':
109 readstd++;
110 break;
111 case 'c':
112 cflg++;
113 break;
114 case 'v':
115 vflg++;
116 break;
117 case 'l':
118 array = optarg;
119 break;
120 default:
121 usage();
123 argc -= optind;
124 argv += optind;
126 if (array == 0)
127 array = "xstr";
129 if (signal(SIGINT, SIG_IGN) == SIG_DFL)
130 (void)signal(SIGINT, onintr);
131 if (cflg || (argc == 0 && !readstd))
132 inithash();
133 else {
134 int fd;
136 snprintf(stringtmpfile, sizeof(stringtmpfile),
137 "%s%s.XXXXXX", _PATH_TMP, "xstr");
138 strings = stringtmpfile;
139 fd = mkstemp(stringtmpfile);
140 if (fd == -1)
141 err(1, "mkstemp failed");
142 close(fd);
144 while (readstd || argc > 0) {
145 if (freopen("x.c", "w", stdout) == NULL)
146 err(1, "Cannot open `%s'", "x.c");
147 if (!readstd && freopen(argv[0], "r", stdin) == NULL)
148 err(1, "Cannot open `%s'", argv[0]);
149 process("x.c");
150 if (readstd == 0)
151 argc--, argv++;
152 else
153 readstd = 0;
155 flushsh();
156 if (cflg == 0)
157 xsdotc();
158 if (strings[0] == '/')
159 (void)unlink(strings);
160 exit(0);
163 static void
164 process(const char *name)
166 char *cp;
167 int c;
168 int incomm = 0;
169 int inasm = 0;
170 int asmparnest = 0;
171 int ret;
173 printf("extern char\t%s[];\n", array);
174 for (;;) {
175 if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
176 if (ferror(stdin))
177 err(1, "Error reading `%s'", name);
178 break;
180 if (linebuf[0] == '#') {
181 printf("%s", linebuf);
182 continue;
184 for (cp = linebuf; (c = *cp++);)
185 switch (c) {
187 case '"':
188 if (incomm || inasm)
189 goto def;
190 if ((ret = (int) yankstr(&cp)) == -1)
191 goto out;
192 printf("(&%s[%d])", array, ret);
193 break;
195 case '\'':
196 if (incomm || inasm)
197 goto def;
198 putchar(c);
199 if (*cp)
200 putchar(*cp++);
201 break;
203 case '/':
204 if (incomm || *cp != '*')
205 goto def;
206 incomm = 1;
207 cp++;
208 printf("/*");
209 continue;
211 case '*':
212 if (incomm && *cp == '/') {
213 incomm = 0;
214 cp++;
215 printf("*/");
216 continue;
218 goto def;
220 case '(':
221 if (!incomm && inasm)
222 asmparnest++;
223 goto def;
225 case ')':
226 if (!incomm && inasm && !--asmparnest)
227 inasm = 0;
228 goto def;
230 case '_':
231 if (incomm || inasm)
232 goto def;
233 if (!strncmp(cp, "_asm", 4)) {
234 cp += 4;
235 printf("__asm");
236 if (!strncmp(cp, "__", 2)) {
237 cp += 2;
238 printf("__");
240 if (isalnum((unsigned char)*cp) ||
241 *cp == '_')
242 goto def;
243 asmparnest = 0;
244 inasm = 1;
245 } else
246 goto def;
247 break;
248 def:
249 default:
250 putchar(c);
251 break;
254 out:
255 if (ferror(stdout)) {
256 warn("Error reading `%s'", "x.c");
257 onintr(1);
261 static off_t
262 yankstr(char **cpp)
264 char *cp = *cpp;
265 int c, ch;
266 char *dbuf, *dp, *edp;
267 const char *tp;
268 off_t hash;
269 size_t bsiz = BUFSIZ;
271 if ((dp = dbuf = malloc(bsiz)) == NULL)
272 err(1, "malloc");
273 edp = dbuf + bsiz;
275 while ((c = *cp++) != '\0') {
276 switch (c) {
278 case '"':
279 /* Look for a concatenated string */
280 for (;;) {
281 while (isspace((unsigned char)*cp))
282 cp++;
283 if (*cp == '\0') {
284 if (fgets(linebuf,
285 sizeof linebuf, stdin) == NULL) {
286 if (ferror(stdin))
287 err(1,
288 "Error reading `x.c'");
289 goto out;
291 cp = linebuf;
292 } else {
293 if (*cp == '"') {
294 cp++;
295 if (*cp == '"') {
296 cp++;
297 continue;
298 } else {
299 c = *cp++;
300 goto gotc;
302 } else {
303 cp++;
304 goto out;
308 /*NOTREACHED*/
309 case '\\':
310 c = *cp++;
311 if (c == 0)
312 break;
313 if (c == '\n') {
314 if (fgets(linebuf, sizeof linebuf, stdin)
315 == NULL) {
316 if (ferror(stdin))
317 err(1, "Error reading `x.c'");
318 return(-1);
320 cp = linebuf;
321 continue;
323 for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++); tp++)
324 if (c == ch) {
325 c = *tp;
326 goto gotc;
328 if (!octdigit(c)) {
329 *dp++ = '\\';
330 break;
332 c -= '0';
333 if (!octdigit(*cp))
334 break;
335 c <<= 3, c += *cp++ - '0';
336 if (!octdigit(*cp))
337 break;
338 c <<= 3, c += *cp++ - '0';
339 break;
341 gotc:
342 if (dp >= edp - 1) {
343 char *nbuf;
344 bsiz += BUFSIZ;
345 if ((nbuf = realloc(dbuf, bsiz)) == NULL) {
346 free(dbuf);
347 err(1, "realloc");
349 dp = nbuf + (dp - dbuf);
350 edp = nbuf + bsiz;
351 dbuf = nbuf;
353 *dp++ = c;
355 out:
356 *cpp = --cp;
357 *dp = '\0';
358 hash = hashit(dbuf, 1);
359 free(dbuf);
360 return hash;
363 static int
364 octdigit(char c)
367 return (isdigit((unsigned char)c) && c != '8' && c != '9');
370 static void
371 inithash(void)
373 char buf[BUFSIZ];
374 FILE *mesgread = fopen(strings, "r");
376 if (mesgread == NULL)
377 return;
378 for (;;) {
379 mesgpt = tellpt;
380 if (fgetNUL(buf, sizeof buf, mesgread) == 0)
381 break;
382 (void)hashit(buf, 0);
384 (void)fclose(mesgread);
387 static int
388 fgetNUL(char *obuf, int rmdr, FILE *file)
390 int c;
391 char *buf = obuf;
393 c = 0; /* XXXGCC -Wuninitialized */
395 while (--rmdr > 0 && (c = xgetc(file) != 0 && c != EOF))
396 *buf++ = c;
397 *buf++ = 0;
398 return (feof(file) || ferror(file)) ? 0 : 1;
401 static int
402 xgetc(FILE *file)
405 tellpt++;
406 return getc(file);
410 static off_t
411 hashit(const char *str, int new)
413 int i;
414 struct hash *hp, *hp0;
416 hp = hp0 = &bucket[lastchr(str) & 0177];
417 while (hp->hnext) {
418 hp = hp->hnext;
419 i = istail(str, hp->hstr);
420 if (i >= 0)
421 return (hp->hpt + i);
423 if ((hp = calloc(1, sizeof (*hp))) == NULL)
424 err(1, NULL);
425 hp->hpt = mesgpt;
426 if ((hp->hstr = strdup(str)) == NULL)
427 err(1, NULL);
428 mesgpt += strlen(hp->hstr) + 1;
429 hp->hnext = hp0->hnext;
430 hp->hnew = new;
431 hp0->hnext = hp;
432 return (hp->hpt);
435 static void
436 flushsh(void)
438 int i;
439 struct hash *hp;
440 FILE *mesgwrit;
441 int old = 0, new = 0;
443 for (i = 0; i < BUCKETS; i++)
444 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
445 if (hp->hnew)
446 new++;
447 else
448 old++;
449 if (new == 0 && old != 0)
450 return;
451 mesgwrit = fopen(strings, old ? "r+" : "w");
452 if (mesgwrit == NULL)
453 err(1, "Cannot open `%s'", strings);
454 for (i = 0; i < BUCKETS; i++)
455 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
456 found(hp->hnew, hp->hpt, hp->hstr);
457 if (hp->hnew) {
458 (void)fseek(mesgwrit, hp->hpt, 0);
459 (void)fwrite(hp->hstr, strlen(hp->hstr) + 1, 1,
460 mesgwrit);
461 if (ferror(mesgwrit))
462 err(1, "Error writing `%s'", strings);
465 if (fclose(mesgwrit) == EOF)
466 err(1, "Error closing `%s'", strings);
469 static void
470 found(int new, off_t off, const char *str)
472 if (vflg == 0)
473 return;
474 if (!new)
475 (void)fprintf(stderr, "found at %d:", (int) off);
476 else
477 (void)fprintf(stderr, "new at %d:", (int) off);
478 prstr(str);
479 (void)fprintf(stderr, "\n");
482 static void
483 prstr(const char *cp)
485 int c;
487 while ((c = (*cp++ & 0377)) != '\0')
488 if (c < ' ')
489 (void)fprintf(stderr, "^%c", c + '`');
490 else if (c == 0177)
491 (void)fprintf(stderr, "^?");
492 else if (c > 0200)
493 (void)fprintf(stderr, "\\%03o", c);
494 else
495 (void)fprintf(stderr, "%c", c);
498 static void
499 xsdotc(void)
501 FILE *strf = fopen(strings, "r");
502 FILE *xdotcf;
504 if (strf == NULL)
505 err(1, "Cannot open `%s'", strings);
506 xdotcf = fopen("xs.c", "w");
507 if (xdotcf == NULL)
508 err(1, "Cannot open `%s'", "xs.c");
509 (void)fprintf(xdotcf, "char\t%s[] = {\n", array);
510 for (;;) {
511 int i, c;
513 for (i = 0; i < 8; i++) {
514 c = getc(strf);
515 if (ferror(strf)) {
516 warn("Error reading `%s'", strings);
517 onintr(1);
519 if (feof(strf)) {
520 (void)fprintf(xdotcf, "\n");
521 goto out;
523 (void)fprintf(xdotcf, "0x%02x,", c);
525 (void)fprintf(xdotcf, "\n");
527 out:
528 (void)fprintf(xdotcf, "};\n");
529 (void)fclose(xdotcf);
530 (void)fclose(strf);
533 static char
534 lastchr(const char *cp)
537 while (cp[0] && cp[1])
538 cp++;
539 return (*cp);
542 static int
543 istail(const char *str, const char *of)
545 int d = strlen(of) - strlen(str);
547 if (d < 0 || strcmp(&of[d], str) != 0)
548 return (-1);
549 return (d);
552 static void
553 onintr(int dummy)
556 (void)signal(SIGINT, SIG_IGN);
557 if (strings[0] == '/')
558 (void)unlink(strings);
559 (void)unlink("x.c");
560 (void)unlink("xs.c");
561 exit(dummy);
564 static void
565 usage(void)
568 (void)fprintf(stderr, "usage: %s [-cv] [-l array] [-] [<name> ...]\n",
569 getprogname());
570 exit(1);