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