Annotation of src/usr.bin/xstr/xstr.c, Revision 1.12
1.12 ! avsm 1: /* $OpenBSD: xstr.c,v 1.11 2003/06/03 02:56:24 millert 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: #ifndef lint
34: static char copyright[] =
35: "@(#) Copyright (c) 1980, 1993\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)xstr.c 8.1 (Berkeley) 6/9/93";
42: #endif
1.12 ! avsm 43: static char rcsid[] = "$OpenBSD: xstr.c,v 1.11 2003/06/03 02:56:24 millert Exp $";
1.1 deraadt 44: #endif /* not lint */
45:
46: #include <sys/types.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 "pathnames.h"
55:
56: /*
57: * xstr - extract and hash strings in a C program
58: *
59: * Bill Joy UCB
60: * November, 1978
61: */
62:
1.7 deraadt 63: #define BUCKETS 128
1.1 deraadt 64:
65: off_t tellpt;
66: off_t mesgpt;
1.8 deraadt 67: char *strings = "strings";
68: char *array = 0;
1.1 deraadt 69:
70: int cflg;
71: int vflg;
72: int readstd;
73:
1.7 deraadt 74: struct hash {
75: off_t hpt;
76: char *hstr;
77: struct hash *hnext;
78: short hnew;
79: } bucket[BUCKETS];
80:
81: void process(char *);
82: off_t yankstr(char **);
83: int octdigit(char);
84: void inithash(void);
85: int fgetNUL(char *, int, FILE *);
86: int xgetc(FILE *);
87: off_t hashit(char *, int);
88: void flushsh(void);
89: void found(int, off_t, char *);
90: void prstr(char *);
91: void xsdotc(void);
92: char lastchr(char *);
93: int istail(char *, char *);
94: void onintr(void);
95:
96: int
97: main(int argc, char *argv[])
1.1 deraadt 98: {
99: int c;
1.4 bitblt 100: int fdesc;
1.1 deraadt 101:
1.10 millert 102: while ((c = getopt(argc, argv, "cvl:-")) != -1)
1.1 deraadt 103: switch (c) {
104: case '-':
105: readstd++;
106: break;
107: case 'c':
108: cflg++;
109: break;
110: case 'v':
111: vflg++;
112: break;
113: case 'l':
114: array = optarg;
115: break;
116: default:
1.8 deraadt 117: fprintf(stderr,
118: "usage: xstr [-vc] [-l array] [-] [name ...]\n");
119: exit(1);
1.1 deraadt 120: }
121: argc -= optind;
122: argv += optind;
123:
124: if (array == 0)
125: array = "xstr";
126:
127: if (signal(SIGINT, SIG_IGN) == SIG_DFL)
1.7 deraadt 128: signal(SIGINT, (void(*)(int))onintr);
129: if (cflg || (argc == 0 && !readstd))
1.1 deraadt 130: inithash();
1.4 bitblt 131: else {
132: strings = strdup (_PATH_TMPFILE);
133: if (strings == NULL) {
134: fprintf(stderr, "Unable to allocate memory: %s",
135: strerror (errno));
136: exit(1);
137: }
138: fdesc = mkstemp (strings);
139: if (fdesc < 0) {
140: fprintf(stderr, "Unable to create temporary file.\n");
141: exit(1);
142: }
143: close (fdesc);
144: }
145:
1.1 deraadt 146: while (readstd || argc > 0) {
1.8 deraadt 147: if (freopen("x.c", "w", stdout) == NULL) {
148: perror("x.c");
149: exit(1);
150: }
151: if (!readstd && freopen(argv[0], "r", stdin) == NULL) {
152: perror(argv[0]);
153: exit(2);
154: }
1.1 deraadt 155: process("x.c");
156: if (readstd == 0)
157: argc--, argv++;
158: else
159: readstd = 0;
1.8 deraadt 160: }
1.1 deraadt 161: flushsh();
162: if (cflg == 0)
163: xsdotc();
164: if (strings[0] == '/')
1.7 deraadt 165: unlink(strings);
1.1 deraadt 166: exit(0);
167: }
168:
169: char linebuf[BUFSIZ];
170:
1.7 deraadt 171: void
172: process(char *name)
1.1 deraadt 173: {
174: char *cp;
1.6 mpech 175: int c;
176: int incomm = 0;
1.1 deraadt 177: int ret;
178:
179: printf("extern char\t%s[];\n", array);
180: for (;;) {
181: if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
182: if (ferror(stdin)) {
183: perror(name);
184: exit(3);
185: }
186: break;
187: }
188: if (linebuf[0] == '#') {
189: if (linebuf[1] == ' ' && isdigit(linebuf[2]))
190: printf("#line%s", &linebuf[1]);
191: else
192: printf("%s", linebuf);
193: continue;
194: }
1.9 deraadt 195: for (cp = linebuf; (c = *cp++); )
1.7 deraadt 196: switch (c) {
197: case '"':
198: if (incomm)
199: goto def;
200: if ((ret = (int) yankstr(&cp)) == -1)
201: goto out;
202: printf("(&%s[%d])", array, ret);
203: break;
204: case '\'':
205: if (incomm)
206: goto def;
207: putchar(c);
208: if (*cp)
209: putchar(*cp++);
210: break;
211: case '/':
212: if (incomm || *cp != '*')
213: goto def;
214: incomm = 1;
1.1 deraadt 215: cp++;
1.7 deraadt 216: printf("/*");
1.1 deraadt 217: continue;
1.7 deraadt 218: case '*':
219: if (incomm && *cp == '/') {
220: incomm = 0;
221: cp++;
222: printf("*/");
223: continue;
224: }
225: goto def;
226: def:
227: default:
228: putchar(c);
229: break;
1.1 deraadt 230: }
231: }
232: out:
233: if (ferror(stdout))
234: perror("x.c"), onintr();
235: }
236:
237: off_t
1.7 deraadt 238: yankstr(char **cpp)
1.1 deraadt 239: {
1.6 mpech 240: char *cp = *cpp;
241: int c, ch;
1.1 deraadt 242: char dbuf[BUFSIZ];
1.6 mpech 243: char *dp = dbuf;
244: char *tp;
1.1 deraadt 245:
1.7 deraadt 246: while ((c = *cp++)) {
1.1 deraadt 247: switch (c) {
248: case '"':
249: cp++;
250: goto out;
251: case '\\':
252: c = *cp++;
253: if (c == 0)
254: break;
255: if (c == '\n') {
1.8 deraadt 256: if (fgets(linebuf, sizeof linebuf, stdin)
1.1 deraadt 257: == NULL) {
258: if (ferror(stdin)) {
259: perror("x.c");
260: exit(3);
261: }
262: return(-1);
263: }
264: cp = linebuf;
265: continue;
266: }
1.7 deraadt 267: for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++); tp++)
1.1 deraadt 268: if (c == ch) {
269: c = *tp;
270: goto gotc;
271: }
272: if (!octdigit(c)) {
273: *dp++ = '\\';
274: break;
275: }
276: c -= '0';
277: if (!octdigit(*cp))
278: break;
279: c <<= 3, c += *cp++ - '0';
280: if (!octdigit(*cp))
281: break;
282: c <<= 3, c += *cp++ - '0';
283: break;
284: }
285: gotc:
286: *dp++ = c;
287: }
288: out:
289: *cpp = --cp;
290: *dp = 0;
291: return (hashit(dbuf, 1));
292: }
293:
1.7 deraadt 294: int
295: octdigit(char c)
1.1 deraadt 296: {
297:
298: return (isdigit(c) && c != '8' && c != '9');
299: }
300:
1.7 deraadt 301: void
302: inithash(void)
1.1 deraadt 303: {
304: char buf[BUFSIZ];
1.6 mpech 305: FILE *mesgread = fopen(strings, "r");
1.1 deraadt 306:
307: if (mesgread == NULL)
308: return;
309: for (;;) {
310: mesgpt = tellpt;
1.12 ! avsm 311: if (fgetNUL(buf, sizeof buf, mesgread) == 0)
1.1 deraadt 312: break;
1.7 deraadt 313: hashit(buf, 0);
1.1 deraadt 314: }
1.7 deraadt 315: fclose(mesgread);
1.1 deraadt 316: }
317:
1.7 deraadt 318: int
319: fgetNUL(char *obuf, int rmdr, FILE *file)
1.1 deraadt 320: {
1.6 mpech 321: int c;
322: char *buf = obuf;
1.1 deraadt 323:
324: while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
325: *buf++ = c;
326: *buf++ = 0;
327: return ((feof(file) || ferror(file)) ? NULL : 1);
328: }
329:
1.7 deraadt 330: int
331: xgetc(FILE *file)
1.1 deraadt 332: {
333:
334: tellpt++;
335: return (getc(file));
336: }
337:
338:
339: off_t
1.7 deraadt 340: hashit(char *str, int new)
1.1 deraadt 341: {
342: int i;
1.6 mpech 343: struct hash *hp, *hp0;
1.1 deraadt 344:
345: hp = hp0 = &bucket[lastchr(str) & 0177];
346: while (hp->hnext) {
347: hp = hp->hnext;
348: i = istail(str, hp->hstr);
349: if (i >= 0)
350: return (hp->hpt + i);
351: }
352: if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL) {
353: perror("xstr");
354: exit(8);
355: }
356: hp->hpt = mesgpt;
357: if (!(hp->hstr = strdup(str))) {
358: (void)fprintf(stderr, "xstr: %s\n", strerror(errno));
359: exit(1);
360: }
361: mesgpt += strlen(hp->hstr) + 1;
362: hp->hnext = hp0->hnext;
363: hp->hnew = new;
364: hp0->hnext = hp;
365: return (hp->hpt);
366: }
367:
1.7 deraadt 368: void
369: flushsh(void)
1.1 deraadt 370: {
1.6 mpech 371: int i;
372: struct hash *hp;
373: FILE *mesgwrit;
374: int old = 0, new = 0;
1.1 deraadt 375:
376: for (i = 0; i < BUCKETS; i++)
377: for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
378: if (hp->hnew)
379: new++;
380: else
381: old++;
382: if (new == 0 && old != 0)
383: return;
384: mesgwrit = fopen(strings, old ? "r+" : "w");
1.8 deraadt 385: if (mesgwrit == NULL) {
386: perror(strings);
387: exit(4);
388: }
1.1 deraadt 389: for (i = 0; i < BUCKETS; i++)
390: for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
391: found(hp->hnew, hp->hpt, hp->hstr);
392: if (hp->hnew) {
393: fseek(mesgwrit, hp->hpt, 0);
1.7 deraadt 394: fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit);
1.8 deraadt 395: if (ferror(mesgwrit)) {
396: perror(strings);
397: exit(4);
398: }
1.1 deraadt 399: }
400: }
1.8 deraadt 401: if (fclose(mesgwrit) == EOF) {
402: perror(strings);
403: exit(4);
404: }
1.1 deraadt 405: }
406:
1.7 deraadt 407: void
408: found(int new, off_t off, char *str)
1.1 deraadt 409: {
410: if (vflg == 0)
411: return;
412: if (!new)
413: fprintf(stderr, "found at %d:", (int) off);
414: else
415: fprintf(stderr, "new at %d:", (int) off);
416: prstr(str);
417: fprintf(stderr, "\n");
418: }
419:
1.7 deraadt 420: void
421: prstr(char *cp)
1.1 deraadt 422: {
1.6 mpech 423: int c;
1.1 deraadt 424:
1.7 deraadt 425: while ((c = (*cp++ & 0377)))
1.1 deraadt 426: if (c < ' ')
427: fprintf(stderr, "^%c", c + '`');
428: else if (c == 0177)
429: fprintf(stderr, "^?");
430: else if (c > 0200)
431: fprintf(stderr, "\\%03o", c);
432: else
433: fprintf(stderr, "%c", c);
434: }
435:
1.7 deraadt 436: void
437: xsdotc(void)
1.1 deraadt 438: {
1.6 mpech 439: FILE *strf = fopen(strings, "r");
440: FILE *xdotcf;
1.1 deraadt 441:
1.8 deraadt 442: if (strf == NULL) {
443: perror(strings);
444: exit(5);
445: }
1.1 deraadt 446: xdotcf = fopen("xs.c", "w");
1.8 deraadt 447: if (xdotcf == NULL) {
448: perror("xs.c");
449: exit(6);
450: }
1.1 deraadt 451: fprintf(xdotcf, "char\t%s[] = {\n", array);
452: for (;;) {
1.6 mpech 453: int i, c;
1.1 deraadt 454:
455: for (i = 0; i < 8; i++) {
456: c = getc(strf);
457: if (ferror(strf)) {
458: perror(strings);
459: onintr();
460: }
461: if (feof(strf)) {
462: fprintf(xdotcf, "\n");
463: goto out;
464: }
465: fprintf(xdotcf, "0x%02x,", c);
466: }
467: fprintf(xdotcf, "\n");
468: }
469: out:
470: fprintf(xdotcf, "};\n");
1.7 deraadt 471: fclose(xdotcf);
472: fclose(strf);
1.1 deraadt 473: }
474:
1.7 deraadt 475: char
476: lastchr(char *cp)
1.1 deraadt 477: {
478:
479: while (cp[0] && cp[1])
480: cp++;
481: return (*cp);
482: }
483:
1.7 deraadt 484: int
485: istail(char *str, char *of)
1.1 deraadt 486: {
1.6 mpech 487: int d = strlen(of) - strlen(str);
1.1 deraadt 488:
489: if (d < 0 || strcmp(&of[d], str) != 0)
490: return (-1);
491: return (d);
492: }
493:
494: void
1.7 deraadt 495: onintr(void)
1.1 deraadt 496: {
497:
1.7 deraadt 498: signal(SIGINT, SIG_IGN);
1.1 deraadt 499: if (strings[0] == '/')
1.7 deraadt 500: unlink(strings);
501: unlink("x.c");
502: unlink("xs.c");
1.5 deraadt 503: _exit(7);
1.1 deraadt 504: }