xstr.c revision 1590
1/*
2 * Copyright (c) 1980, 1993
3 *	The Regents of the University of California.  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
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)xstr.c	8.1 (Berkeley) 6/9/93";
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
62off_t	tellpt;
63off_t	hashit();
64void	onintr();
65char	*savestr();
66off_t	yankstr();
67
68off_t	mesgpt;
69char	*strings =	"strings";
70
71int	cflg;
72int	vflg;
73int	readstd;
74
75main(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
128char linebuf[BUFSIZ];
129
130process(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
189def:
190		default:
191			putchar(c);
192			break;
193		}
194	}
195out:
196	if (ferror(stdout))
197		perror("x.c"), onintr();
198}
199
200off_t
201yankstr(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		}
251gotc:
252		*dp++ = c;
253	}
254out:
255	*cpp = --cp;
256	*dp = 0;
257	return (hashit(dbuf, 1));
258}
259
260octdigit(c)
261	char c;
262{
263
264	return (isdigit(c) && c != '8' && c != '9');
265}
266
267inithash()
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
283fgetNUL(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
297xgetc(file)
298	FILE *file;
299{
300
301	tellpt++;
302	return (getc(file));
303}
304
305#define	BUCKETS	128
306
307struct	hash {
308	off_t	hpt;
309	char	*hstr;
310	struct	hash *hnext;
311	short	hnew;
312} bucket[BUCKETS];
313
314off_t
315hashit(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
345flushsh()
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
377found(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
392prstr(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
408xsdotc()
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	}
436out:
437	fprintf(xdotcf, "};\n");
438	ignore(fclose(xdotcf));
439	ignore(fclose(strf));
440}
441
442lastchr(cp)
443	register char *cp;
444{
445
446	while (cp[0] && cp[1])
447		cp++;
448	return (*cp);
449}
450
451istail(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
461void
462onintr()
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