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