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