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