xref: /original-bsd/usr.bin/xstr/xstr.c (revision cc7f0fbb)
1 /*
2  * Copyright (c) 1980 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)xstr.c	5.7 (Berkeley) 02/26/91";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include "pathnames.h"
26 
27 /*
28  * xstr - extract and hash strings in a C program
29  *
30  * Bill Joy UCB
31  * November, 1978
32  */
33 
34 #define	ignore(a)	((void) a)
35 
36 off_t	tellpt;
37 off_t	hashit();
38 void	onintr();
39 char	*savestr();
40 off_t	yankstr();
41 
42 off_t	mesgpt;
43 char	*strings =	"strings";
44 
45 int	cflg;
46 int	vflg;
47 int	readstd;
48 
49 main(argc, argv)
50 	int argc;
51 	char *argv[];
52 {
53 
54 	argc--, argv++;
55 	while (argc > 0 && argv[0][0] == '-') {
56 		register char *cp = &(*argv++)[1];
57 
58 		argc--;
59 		if (*cp == 0) {
60 			readstd++;
61 			continue;
62 		}
63 		do switch (*cp++) {
64 
65 		case 'c':
66 			cflg++;
67 			continue;
68 
69 		case 'v':
70 			vflg++;
71 			continue;
72 
73 		default:
74 			fprintf(stderr, "usage: xstr [ -v ] [ -c ] [ - ] [ name ... ]\n");
75 		} while (*cp);
76 	}
77 	if (signal(SIGINT, SIG_IGN) == SIG_DFL)
78 		signal(SIGINT, onintr);
79 	if (cflg || argc == 0 && !readstd)
80 		inithash();
81 	else
82 		strings = mktemp(strdup(_PATH_TMP));
83 	while (readstd || argc > 0) {
84 		if (freopen("x.c", "w", stdout) == NULL)
85 			perror("x.c"), exit(1);
86 		if (!readstd && freopen(argv[0], "r", stdin) == NULL)
87 			perror(argv[0]), exit(2);
88 		process("x.c");
89 		if (readstd == 0)
90 			argc--, argv++;
91 		else
92 			readstd = 0;
93 	};
94 	flushsh();
95 	if (cflg == 0)
96 		xsdotc();
97 	if (strings[0] == '/')
98 		ignore(unlink(strings));
99 	exit(0);
100 }
101 
102 char linebuf[BUFSIZ];
103 
104 process(name)
105 	char *name;
106 {
107 	char *cp;
108 	register int c;
109 	register int incomm = 0;
110 	int ret;
111 
112 	printf("extern char\txstr[];\n");
113 	for (;;) {
114 		if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
115 			if (ferror(stdin)) {
116 				perror(name);
117 				exit(3);
118 			}
119 			break;
120 		}
121 		if (linebuf[0] == '#') {
122 			if (linebuf[1] == ' ' && isdigit(linebuf[2]))
123 				printf("#line%s", &linebuf[1]);
124 			else
125 				printf("%s", linebuf);
126 			continue;
127 		}
128 		for (cp = linebuf; c = *cp++;) switch (c) {
129 
130 		case '"':
131 			if (incomm)
132 				goto def;
133 			if ((ret = (int) yankstr(&cp)) == -1)
134 				goto out;
135 			printf("(&xstr[%d])", ret);
136 			break;
137 
138 		case '\'':
139 			if (incomm)
140 				goto def;
141 			putchar(c);
142 			if (*cp)
143 				putchar(*cp++);
144 			break;
145 
146 		case '/':
147 			if (incomm || *cp != '*')
148 				goto def;
149 			incomm = 1;
150 			cp++;
151 			printf("/*");
152 			continue;
153 
154 		case '*':
155 			if (incomm && *cp == '/') {
156 				incomm = 0;
157 				cp++;
158 				printf("*/");
159 				continue;
160 			}
161 			goto def;
162 
163 def:
164 		default:
165 			putchar(c);
166 			break;
167 		}
168 	}
169 out:
170 	if (ferror(stdout))
171 		perror("x.c"), onintr();
172 }
173 
174 off_t
175 yankstr(cpp)
176 	register char **cpp;
177 {
178 	register char *cp = *cpp;
179 	register int c, ch;
180 	char dbuf[BUFSIZ];
181 	register char *dp = dbuf;
182 	register char *tp;
183 
184 	while (c = *cp++) {
185 		switch (c) {
186 
187 		case '"':
188 			cp++;
189 			goto out;
190 
191 		case '\\':
192 			c = *cp++;
193 			if (c == 0)
194 				break;
195 			if (c == '\n') {
196 				if (fgets(linebuf, sizeof linebuf, stdin)
197 				    == NULL) {
198 					if (ferror(stdin)) {
199 						perror("x.c");
200 						exit(3);
201 					}
202 					return(-1);
203 				}
204 				cp = linebuf;
205 				continue;
206 			}
207 			for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; ch = *tp++; tp++)
208 				if (c == ch) {
209 					c = *tp;
210 					goto gotc;
211 				}
212 			if (!octdigit(c)) {
213 				*dp++ = '\\';
214 				break;
215 			}
216 			c -= '0';
217 			if (!octdigit(*cp))
218 				break;
219 			c <<= 3, c += *cp++ - '0';
220 			if (!octdigit(*cp))
221 				break;
222 			c <<= 3, c += *cp++ - '0';
223 			break;
224 		}
225 gotc:
226 		*dp++ = c;
227 	}
228 out:
229 	*cpp = --cp;
230 	*dp = 0;
231 	return (hashit(dbuf, 1));
232 }
233 
234 octdigit(c)
235 	char c;
236 {
237 
238 	return (isdigit(c) && c != '8' && c != '9');
239 }
240 
241 inithash()
242 {
243 	char buf[BUFSIZ];
244 	register FILE *mesgread = fopen(strings, "r");
245 
246 	if (mesgread == NULL)
247 		return;
248 	for (;;) {
249 		mesgpt = tellpt;
250 		if (fgetNUL(buf, sizeof buf, mesgread) == NULL)
251 			break;
252 		ignore(hashit(buf, 0));
253 	}
254 	ignore(fclose(mesgread));
255 }
256 
257 fgetNUL(obuf, rmdr, file)
258 	char *obuf;
259 	register int rmdr;
260 	FILE *file;
261 {
262 	register c;
263 	register char *buf = obuf;
264 
265 	while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
266 		*buf++ = c;
267 	*buf++ = 0;
268 	return ((feof(file) || ferror(file)) ? NULL : 1);
269 }
270 
271 xgetc(file)
272 	FILE *file;
273 {
274 
275 	tellpt++;
276 	return (getc(file));
277 }
278 
279 #define	BUCKETS	128
280 
281 struct	hash {
282 	off_t	hpt;
283 	char	*hstr;
284 	struct	hash *hnext;
285 	short	hnew;
286 } bucket[BUCKETS];
287 
288 off_t
289 hashit(str, new)
290 	char *str;
291 	int new;
292 {
293 	int i;
294 	register struct hash *hp, *hp0;
295 
296 	hp = hp0 = &bucket[lastchr(str) & 0177];
297 	while (hp->hnext) {
298 		hp = hp->hnext;
299 		i = istail(str, hp->hstr);
300 		if (i >= 0)
301 			return (hp->hpt + i);
302 	}
303 	if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL) {
304 		perror("xstr");
305 		exit(8);
306 	}
307 	hp->hpt = mesgpt;
308 	if (!(hp->hstr = strdup(str))) {
309 		(void)fprintf(stderr, "xstr: %s\n", strerror(errno));
310 		exit(1);
311 	}
312 	mesgpt += strlen(hp->hstr) + 1;
313 	hp->hnext = hp0->hnext;
314 	hp->hnew = new;
315 	hp0->hnext = hp;
316 	return (hp->hpt);
317 }
318 
319 flushsh()
320 {
321 	register int i;
322 	register struct hash *hp;
323 	register FILE *mesgwrit;
324 	register int old = 0, new = 0;
325 
326 	for (i = 0; i < BUCKETS; i++)
327 		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
328 			if (hp->hnew)
329 				new++;
330 			else
331 				old++;
332 	if (new == 0 && old != 0)
333 		return;
334 	mesgwrit = fopen(strings, old ? "r+" : "w");
335 	if (mesgwrit == NULL)
336 		perror(strings), exit(4);
337 	for (i = 0; i < BUCKETS; i++)
338 		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
339 			found(hp->hnew, hp->hpt, hp->hstr);
340 			if (hp->hnew) {
341 				fseek(mesgwrit, hp->hpt, 0);
342 				ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
343 				if (ferror(mesgwrit))
344 					perror(strings), exit(4);
345 			}
346 		}
347 	if (fclose(mesgwrit) == EOF)
348 		perror(strings), exit(4);
349 }
350 
351 found(new, off, str)
352 	int new;
353 	off_t off;
354 	char *str;
355 {
356 	if (vflg == 0)
357 		return;
358 	if (!new)
359 		fprintf(stderr, "found at %d:", (int) off);
360 	else
361 		fprintf(stderr, "new at %d:", (int) off);
362 	prstr(str);
363 	fprintf(stderr, "\n");
364 }
365 
366 prstr(cp)
367 	register char *cp;
368 {
369 	register int c;
370 
371 	while (c = (*cp++ & 0377))
372 		if (c < ' ')
373 			fprintf(stderr, "^%c", c + '`');
374 		else if (c == 0177)
375 			fprintf(stderr, "^?");
376 		else if (c > 0200)
377 			fprintf(stderr, "\\%03o", c);
378 		else
379 			fprintf(stderr, "%c", c);
380 }
381 
382 xsdotc()
383 {
384 	register FILE *strf = fopen(strings, "r");
385 	register FILE *xdotcf;
386 
387 	if (strf == NULL)
388 		perror(strings), exit(5);
389 	xdotcf = fopen("xs.c", "w");
390 	if (xdotcf == NULL)
391 		perror("xs.c"), exit(6);
392 	fprintf(xdotcf, "char\txstr[] = {\n");
393 	for (;;) {
394 		register int i, c;
395 
396 		for (i = 0; i < 8; i++) {
397 			c = getc(strf);
398 			if (ferror(strf)) {
399 				perror(strings);
400 				onintr();
401 			}
402 			if (feof(strf)) {
403 				fprintf(xdotcf, "\n");
404 				goto out;
405 			}
406 			fprintf(xdotcf, "0x%02x,", c);
407 		}
408 		fprintf(xdotcf, "\n");
409 	}
410 out:
411 	fprintf(xdotcf, "};\n");
412 	ignore(fclose(xdotcf));
413 	ignore(fclose(strf));
414 }
415 
416 lastchr(cp)
417 	register char *cp;
418 {
419 
420 	while (cp[0] && cp[1])
421 		cp++;
422 	return (*cp);
423 }
424 
425 istail(str, of)
426 	register char *str, *of;
427 {
428 	register int d = strlen(of) - strlen(str);
429 
430 	if (d < 0 || strcmp(&of[d], str) != 0)
431 		return (-1);
432 	return (d);
433 }
434 
435 void
436 onintr()
437 {
438 
439 	ignore(signal(SIGINT, SIG_IGN));
440 	if (strings[0] == '/')
441 		ignore(unlink(strings));
442 	ignore(unlink("x.c"));
443 	ignore(unlink("xs.c"));
444 	exit(7);
445 }
446