Annotation of src/usr.bin/xstr/xstr.c, Revision 1.17
1.17 ! miod 1: /* $OpenBSD: xstr.c,v 1.16 2009/10/27 23:59:50 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: xstr.c,v 1.5 1994/12/24 16:57:59 cgd Exp $ */
3:
4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.11 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #include <sys/types.h>
34: #include <signal.h>
35: #include <errno.h>
36: #include <unistd.h>
37: #include <stdio.h>
38: #include <ctype.h>
39: #include <string.h>
40: #include <stdlib.h>
41: #include "pathnames.h"
42:
43: /*
44: * xstr - extract and hash strings in a C program
45: *
46: * Bill Joy UCB
47: * November, 1978
48: */
49:
1.7 deraadt 50: #define BUCKETS 128
1.1 deraadt 51:
52: off_t tellpt;
53: off_t mesgpt;
1.8 deraadt 54: char *strings = "strings";
55: char *array = 0;
1.1 deraadt 56:
57: int cflg;
58: int vflg;
59: int readstd;
60:
1.7 deraadt 61: struct hash {
62: off_t hpt;
63: char *hstr;
64: struct hash *hnext;
65: short hnew;
66: } bucket[BUCKETS];
67:
68: void process(char *);
69: off_t yankstr(char **);
70: int octdigit(char);
71: void inithash(void);
72: int fgetNUL(char *, int, FILE *);
73: int xgetc(FILE *);
74: off_t hashit(char *, int);
75: void flushsh(void);
76: void found(int, off_t, char *);
77: void prstr(char *);
78: void xsdotc(void);
79: char lastchr(char *);
80: int istail(char *, char *);
81: void onintr(void);
82:
83: int
84: main(int argc, char *argv[])
1.1 deraadt 85: {
86: int c;
1.4 bitblt 87: int fdesc;
1.1 deraadt 88:
1.10 millert 89: while ((c = getopt(argc, argv, "cvl:-")) != -1)
1.1 deraadt 90: switch (c) {
91: case '-':
92: readstd++;
93: break;
94: case 'c':
95: cflg++;
96: break;
97: case 'v':
98: vflg++;
99: break;
100: case 'l':
101: array = optarg;
102: break;
103: default:
1.8 deraadt 104: fprintf(stderr,
1.13 jmc 105: "usage: xstr [-cv] [-l array] [-] [file ...]\n");
1.8 deraadt 106: exit(1);
1.1 deraadt 107: }
108: argc -= optind;
109: argv += optind;
110:
111: if (array == 0)
112: array = "xstr";
113:
114: if (signal(SIGINT, SIG_IGN) == SIG_DFL)
1.7 deraadt 115: signal(SIGINT, (void(*)(int))onintr);
116: if (cflg || (argc == 0 && !readstd))
1.1 deraadt 117: inithash();
1.4 bitblt 118: else {
119: strings = strdup (_PATH_TMPFILE);
120: if (strings == NULL) {
121: fprintf(stderr, "Unable to allocate memory: %s",
122: strerror (errno));
123: exit(1);
124: }
125: fdesc = mkstemp (strings);
126: if (fdesc < 0) {
127: fprintf(stderr, "Unable to create temporary file.\n");
128: exit(1);
129: }
130: close (fdesc);
131: }
132:
1.1 deraadt 133: while (readstd || argc > 0) {
1.8 deraadt 134: if (freopen("x.c", "w", stdout) == NULL) {
135: perror("x.c");
136: exit(1);
137: }
138: if (!readstd && freopen(argv[0], "r", stdin) == NULL) {
139: perror(argv[0]);
140: exit(2);
141: }
1.1 deraadt 142: process("x.c");
143: if (readstd == 0)
144: argc--, argv++;
145: else
146: readstd = 0;
1.8 deraadt 147: }
1.1 deraadt 148: flushsh();
149: if (cflg == 0)
150: xsdotc();
151: if (strings[0] == '/')
1.7 deraadt 152: unlink(strings);
1.1 deraadt 153: exit(0);
154: }
155:
156: char linebuf[BUFSIZ];
157:
1.7 deraadt 158: void
159: process(char *name)
1.1 deraadt 160: {
161: char *cp;
1.6 mpech 162: int c;
163: int incomm = 0;
1.1 deraadt 164: int ret;
165:
166: printf("extern char\t%s[];\n", array);
167: for (;;) {
168: if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
169: if (ferror(stdin)) {
170: perror(name);
171: exit(3);
172: }
173: break;
174: }
175: if (linebuf[0] == '#') {
176: if (linebuf[1] == ' ' && isdigit(linebuf[2]))
177: printf("#line%s", &linebuf[1]);
178: else
179: printf("%s", linebuf);
180: continue;
181: }
1.9 deraadt 182: for (cp = linebuf; (c = *cp++); )
1.7 deraadt 183: switch (c) {
184: case '"':
185: if (incomm)
186: goto def;
187: if ((ret = (int) yankstr(&cp)) == -1)
188: goto out;
189: printf("(&%s[%d])", array, ret);
190: break;
191: case '\'':
192: if (incomm)
193: goto def;
194: putchar(c);
195: if (*cp)
196: putchar(*cp++);
197: break;
198: case '/':
199: if (incomm || *cp != '*')
200: goto def;
201: incomm = 1;
1.1 deraadt 202: cp++;
1.7 deraadt 203: printf("/*");
1.1 deraadt 204: continue;
1.7 deraadt 205: case '*':
206: if (incomm && *cp == '/') {
207: incomm = 0;
208: cp++;
209: printf("*/");
210: continue;
211: }
212: goto def;
213: def:
214: default:
215: putchar(c);
216: break;
1.1 deraadt 217: }
218: }
219: out:
220: if (ferror(stdout))
221: perror("x.c"), onintr();
222: }
223:
224: off_t
1.7 deraadt 225: yankstr(char **cpp)
1.1 deraadt 226: {
1.6 mpech 227: char *cp = *cpp;
228: int c, ch;
1.1 deraadt 229: char dbuf[BUFSIZ];
1.6 mpech 230: char *dp = dbuf;
231: char *tp;
1.1 deraadt 232:
1.7 deraadt 233: while ((c = *cp++)) {
1.1 deraadt 234: switch (c) {
235: case '"':
236: cp++;
237: goto out;
238: case '\\':
239: c = *cp++;
240: if (c == 0)
241: break;
242: if (c == '\n') {
1.8 deraadt 243: if (fgets(linebuf, sizeof linebuf, stdin)
1.1 deraadt 244: == NULL) {
245: if (ferror(stdin)) {
246: perror("x.c");
247: exit(3);
248: }
249: return(-1);
250: }
251: cp = linebuf;
252: continue;
253: }
1.7 deraadt 254: for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++); tp++)
1.1 deraadt 255: if (c == ch) {
256: c = *tp;
257: goto gotc;
258: }
259: if (!octdigit(c)) {
260: *dp++ = '\\';
261: break;
262: }
263: c -= '0';
264: if (!octdigit(*cp))
265: break;
266: c <<= 3, c += *cp++ - '0';
267: if (!octdigit(*cp))
268: break;
269: c <<= 3, c += *cp++ - '0';
270: break;
271: }
272: gotc:
273: *dp++ = c;
274: }
275: out:
276: *cpp = --cp;
277: *dp = 0;
278: return (hashit(dbuf, 1));
279: }
280:
1.7 deraadt 281: int
282: octdigit(char c)
1.1 deraadt 283: {
284:
285: return (isdigit(c) && c != '8' && c != '9');
286: }
287:
1.7 deraadt 288: void
289: inithash(void)
1.1 deraadt 290: {
291: char buf[BUFSIZ];
1.6 mpech 292: FILE *mesgread = fopen(strings, "r");
1.1 deraadt 293:
294: if (mesgread == NULL)
295: return;
296: for (;;) {
297: mesgpt = tellpt;
1.12 avsm 298: if (fgetNUL(buf, sizeof buf, mesgread) == 0)
1.1 deraadt 299: break;
1.7 deraadt 300: hashit(buf, 0);
1.1 deraadt 301: }
1.7 deraadt 302: fclose(mesgread);
1.1 deraadt 303: }
304:
1.7 deraadt 305: int
306: fgetNUL(char *obuf, int rmdr, FILE *file)
1.1 deraadt 307: {
1.6 mpech 308: int c;
309: char *buf = obuf;
1.1 deraadt 310:
311: while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
312: *buf++ = c;
313: *buf++ = 0;
1.17 ! miod 314: return ((feof(file) || ferror(file)) ? 0 : 1);
1.1 deraadt 315: }
316:
1.7 deraadt 317: int
318: xgetc(FILE *file)
1.1 deraadt 319: {
320:
321: tellpt++;
322: return (getc(file));
323: }
324:
325:
326: off_t
1.7 deraadt 327: hashit(char *str, int new)
1.1 deraadt 328: {
329: int i;
1.6 mpech 330: struct hash *hp, *hp0;
1.1 deraadt 331:
332: hp = hp0 = &bucket[lastchr(str) & 0177];
333: while (hp->hnext) {
334: hp = hp->hnext;
335: i = istail(str, hp->hstr);
336: if (i >= 0)
337: return (hp->hpt + i);
338: }
339: if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL) {
340: perror("xstr");
341: exit(8);
342: }
343: hp->hpt = mesgpt;
344: if (!(hp->hstr = strdup(str))) {
345: (void)fprintf(stderr, "xstr: %s\n", strerror(errno));
346: exit(1);
347: }
348: mesgpt += strlen(hp->hstr) + 1;
349: hp->hnext = hp0->hnext;
350: hp->hnew = new;
351: hp0->hnext = hp;
352: return (hp->hpt);
353: }
354:
1.7 deraadt 355: void
356: flushsh(void)
1.1 deraadt 357: {
1.6 mpech 358: int i;
359: struct hash *hp;
360: FILE *mesgwrit;
361: int old = 0, new = 0;
1.1 deraadt 362:
363: for (i = 0; i < BUCKETS; i++)
364: for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
365: if (hp->hnew)
366: new++;
367: else
368: old++;
369: if (new == 0 && old != 0)
370: return;
371: mesgwrit = fopen(strings, old ? "r+" : "w");
1.8 deraadt 372: if (mesgwrit == NULL) {
373: perror(strings);
374: exit(4);
375: }
1.1 deraadt 376: for (i = 0; i < BUCKETS; i++)
377: for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
378: found(hp->hnew, hp->hpt, hp->hstr);
379: if (hp->hnew) {
1.14 tobias 380: fseek(mesgwrit, hp->hpt, SEEK_SET);
1.15 sobrado 381: fwrite(hp->hstr, strlen(hp->hstr) + 1, 1,
382: mesgwrit);
1.8 deraadt 383: if (ferror(mesgwrit)) {
384: perror(strings);
385: exit(4);
386: }
1.1 deraadt 387: }
388: }
1.8 deraadt 389: if (fclose(mesgwrit) == EOF) {
390: perror(strings);
391: exit(4);
392: }
1.1 deraadt 393: }
394:
1.7 deraadt 395: void
396: found(int new, off_t off, char *str)
1.1 deraadt 397: {
398: if (vflg == 0)
399: return;
400: if (!new)
401: fprintf(stderr, "found at %d:", (int) off);
402: else
403: fprintf(stderr, "new at %d:", (int) off);
404: prstr(str);
405: fprintf(stderr, "\n");
406: }
407:
1.7 deraadt 408: void
409: prstr(char *cp)
1.1 deraadt 410: {
1.6 mpech 411: int c;
1.1 deraadt 412:
1.7 deraadt 413: while ((c = (*cp++ & 0377)))
1.1 deraadt 414: if (c < ' ')
415: fprintf(stderr, "^%c", c + '`');
416: else if (c == 0177)
417: fprintf(stderr, "^?");
418: else if (c > 0200)
419: fprintf(stderr, "\\%03o", c);
420: else
421: fprintf(stderr, "%c", c);
422: }
423:
1.7 deraadt 424: void
425: xsdotc(void)
1.1 deraadt 426: {
1.6 mpech 427: FILE *strf = fopen(strings, "r");
428: FILE *xdotcf;
1.1 deraadt 429:
1.8 deraadt 430: if (strf == NULL) {
431: perror(strings);
432: exit(5);
433: }
1.1 deraadt 434: xdotcf = fopen("xs.c", "w");
1.8 deraadt 435: if (xdotcf == NULL) {
436: perror("xs.c");
437: exit(6);
438: }
1.1 deraadt 439: fprintf(xdotcf, "char\t%s[] = {\n", array);
440: for (;;) {
1.6 mpech 441: int i, c;
1.1 deraadt 442:
443: for (i = 0; i < 8; i++) {
444: c = getc(strf);
445: if (ferror(strf)) {
446: perror(strings);
447: onintr();
448: }
449: if (feof(strf)) {
450: fprintf(xdotcf, "\n");
451: goto out;
452: }
453: fprintf(xdotcf, "0x%02x,", c);
454: }
455: fprintf(xdotcf, "\n");
456: }
457: out:
458: fprintf(xdotcf, "};\n");
1.7 deraadt 459: fclose(xdotcf);
460: fclose(strf);
1.1 deraadt 461: }
462:
1.7 deraadt 463: char
464: lastchr(char *cp)
1.1 deraadt 465: {
466:
467: while (cp[0] && cp[1])
468: cp++;
469: return (*cp);
470: }
471:
1.7 deraadt 472: int
473: istail(char *str, char *of)
1.1 deraadt 474: {
1.6 mpech 475: int d = strlen(of) - strlen(str);
1.1 deraadt 476:
477: if (d < 0 || strcmp(&of[d], str) != 0)
478: return (-1);
479: return (d);
480: }
481:
482: void
1.7 deraadt 483: onintr(void)
1.1 deraadt 484: {
485:
1.7 deraadt 486: signal(SIGINT, SIG_IGN);
1.1 deraadt 487: if (strings[0] == '/')
1.7 deraadt 488: unlink(strings);
489: unlink("x.c");
490: unlink("xs.c");
1.5 deraadt 491: _exit(7);
1.1 deraadt 492: }