xstr.c revision 28855
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3528855Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4128855Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)xstr.c	8.1 (Berkeley) 6/9/93";
4328855Scharnier#endif
4428855Scharnierstatic const char rcsid[] =
4528855Scharnier	"$Id$";
461590Srgrimes#endif /* not lint */
471590Srgrimes
481590Srgrimes#include <sys/types.h>
4928855Scharnier#include <ctype.h>
5028855Scharnier#include <err.h>
5128855Scharnier#include <stdio.h>
5228855Scharnier#include <stdlib.h>
531590Srgrimes#include <signal.h>
5428855Scharnier#include <string.h>
551590Srgrimes#include <unistd.h>
561590Srgrimes#include "pathnames.h"
571590Srgrimes
581590Srgrimes/*
591590Srgrimes * xstr - extract and hash strings in a C program
601590Srgrimes *
611590Srgrimes * Bill Joy UCB
621590Srgrimes * November, 1978
631590Srgrimes */
641590Srgrimes
651590Srgrimes#define	ignore(a)	((void) a)
661590Srgrimes
671590Srgrimesoff_t	tellpt;
681590Srgrimesoff_t	hashit();
691590Srgrimesvoid	onintr();
701590Srgrimeschar	*savestr();
711590Srgrimesoff_t	yankstr();
721590Srgrimes
731590Srgrimesoff_t	mesgpt;
741590Srgrimeschar	*strings =	"strings";
751590Srgrimes
761590Srgrimesint	cflg;
771590Srgrimesint	vflg;
781590Srgrimesint	readstd;
791590Srgrimes
8028855Scharnierstatic void usage __P((void));
8128855Scharnierint istail __P((char *, char *));
8228855Scharnierchar lastchr __P((char *));
8328855Scharniervoid xsdotc __P((void));
8428855Scharniervoid prstr __P((char *));
8528855Scharniervoid found __P((int, off_t, char *));
8628855Scharniervoid flushsh __P((void));
8728855Scharnierint xgetc __P((FILE *));
8828855Scharnierint fgetNUL __P((char *, int, FILE *));
8928855Scharniervoid inithash __P((void));
9028855Scharnierint octdigit __P((char));
9128855Scharniervoid process __P((char *));
9228855Scharnier
9328855Scharnierint
941590Srgrimesmain(argc, argv)
951590Srgrimes	int argc;
961590Srgrimes	char *argv[];
971590Srgrimes{
9828855Scharnier	int c;
991590Srgrimes
10028855Scharnier	while ((c = getopt(argc, argv, "-cv")) != -1)
10128855Scharnier		switch (c) {
10228855Scharnier		case '-':
1031590Srgrimes			readstd++;
10428855Scharnier			break;
1051590Srgrimes		case 'c':
1061590Srgrimes			cflg++;
10728855Scharnier			break;
1081590Srgrimes		case 'v':
1091590Srgrimes			vflg++;
11028855Scharnier			break;
1111590Srgrimes		default:
11228855Scharnier			usage();
11328855Scharnier		}
11428855Scharnier	argc -= optind;
11528855Scharnier	argv += optind;
11628855Scharnier
1171590Srgrimes	if (signal(SIGINT, SIG_IGN) == SIG_DFL)
1181590Srgrimes		signal(SIGINT, onintr);
11928855Scharnier	if (cflg || (argc == 0 && !readstd))
1201590Srgrimes		inithash();
1211590Srgrimes	else
1221590Srgrimes		strings = mktemp(strdup(_PATH_TMP));
1231590Srgrimes	while (readstd || argc > 0) {
1241590Srgrimes		if (freopen("x.c", "w", stdout) == NULL)
12528855Scharnier			err(1, "x.c");
1261590Srgrimes		if (!readstd && freopen(argv[0], "r", stdin) == NULL)
12728855Scharnier			err(2, "%s", argv[0]);
1281590Srgrimes		process("x.c");
1291590Srgrimes		if (readstd == 0)
1301590Srgrimes			argc--, argv++;
1311590Srgrimes		else
1321590Srgrimes			readstd = 0;
1331590Srgrimes	};
1341590Srgrimes	flushsh();
1351590Srgrimes	if (cflg == 0)
1361590Srgrimes		xsdotc();
1371590Srgrimes	if (strings[0] == '/')
1381590Srgrimes		ignore(unlink(strings));
1391590Srgrimes	exit(0);
1401590Srgrimes}
1411590Srgrimes
14228855Scharnierstatic void
14328855Scharnierusage()
14428855Scharnier{
14528855Scharnier	fprintf(stderr, "usage: xstr [-v] [-c] [-] [name ...]\n");
14628855Scharnier	exit (1);
14728855Scharnier}
14828855Scharnier
1491590Srgrimeschar linebuf[BUFSIZ];
1501590Srgrimes
15128855Scharniervoid
1521590Srgrimesprocess(name)
1531590Srgrimes	char *name;
1541590Srgrimes{
1551590Srgrimes	char *cp;
1561590Srgrimes	register int c;
1571590Srgrimes	register int incomm = 0;
1581590Srgrimes	int ret;
1591590Srgrimes
1601590Srgrimes	printf("extern char\txstr[];\n");
1611590Srgrimes	for (;;) {
1621590Srgrimes		if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
16328855Scharnier			if (ferror(stdin))
16428855Scharnier				err(3, "%s", name);
1651590Srgrimes			break;
1661590Srgrimes		}
1671590Srgrimes		if (linebuf[0] == '#') {
1681590Srgrimes			if (linebuf[1] == ' ' && isdigit(linebuf[2]))
1691590Srgrimes				printf("#line%s", &linebuf[1]);
1701590Srgrimes			else
1711590Srgrimes				printf("%s", linebuf);
1721590Srgrimes			continue;
1731590Srgrimes		}
17428855Scharnier		for (cp = linebuf; (c = *cp++);) switch (c) {
1758874Srgrimes
1761590Srgrimes		case '"':
1771590Srgrimes			if (incomm)
1781590Srgrimes				goto def;
1791590Srgrimes			if ((ret = (int) yankstr(&cp)) == -1)
1801590Srgrimes				goto out;
1811590Srgrimes			printf("(&xstr[%d])", ret);
1821590Srgrimes			break;
1831590Srgrimes
1841590Srgrimes		case '\'':
1851590Srgrimes			if (incomm)
1861590Srgrimes				goto def;
1871590Srgrimes			putchar(c);
1881590Srgrimes			if (*cp)
1891590Srgrimes				putchar(*cp++);
1901590Srgrimes			break;
1911590Srgrimes
1921590Srgrimes		case '/':
1931590Srgrimes			if (incomm || *cp != '*')
1941590Srgrimes				goto def;
1951590Srgrimes			incomm = 1;
1961590Srgrimes			cp++;
1971590Srgrimes			printf("/*");
1981590Srgrimes			continue;
1991590Srgrimes
2001590Srgrimes		case '*':
2011590Srgrimes			if (incomm && *cp == '/') {
2021590Srgrimes				incomm = 0;
2031590Srgrimes				cp++;
2041590Srgrimes				printf("*/");
2051590Srgrimes				continue;
2061590Srgrimes			}
2071590Srgrimes			goto def;
2088874Srgrimes
2091590Srgrimesdef:
2101590Srgrimes		default:
2111590Srgrimes			putchar(c);
2121590Srgrimes			break;
2131590Srgrimes		}
2141590Srgrimes	}
2151590Srgrimesout:
2161590Srgrimes	if (ferror(stdout))
21728855Scharnier		warn("x.c"), onintr();
2181590Srgrimes}
2191590Srgrimes
2201590Srgrimesoff_t
2211590Srgrimesyankstr(cpp)
2221590Srgrimes	register char **cpp;
2231590Srgrimes{
2241590Srgrimes	register char *cp = *cpp;
2251590Srgrimes	register int c, ch;
2261590Srgrimes	char dbuf[BUFSIZ];
2271590Srgrimes	register char *dp = dbuf;
2281590Srgrimes	register char *tp;
2291590Srgrimes
23028855Scharnier	while ((c = *cp++)) {
2311590Srgrimes		switch (c) {
2321590Srgrimes
2331590Srgrimes		case '"':
2341590Srgrimes			cp++;
2351590Srgrimes			goto out;
2361590Srgrimes
2371590Srgrimes		case '\\':
2381590Srgrimes			c = *cp++;
2391590Srgrimes			if (c == 0)
2401590Srgrimes				break;
2411590Srgrimes			if (c == '\n') {
2428874Srgrimes				if (fgets(linebuf, sizeof linebuf, stdin)
2431590Srgrimes				    == NULL) {
24428855Scharnier					if (ferror(stdin))
24528855Scharnier						err(3, "x.c");
2461590Srgrimes					return(-1);
2471590Srgrimes				}
2481590Srgrimes				cp = linebuf;
2491590Srgrimes				continue;
2501590Srgrimes			}
25128855Scharnier			for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++); tp++)
2521590Srgrimes				if (c == ch) {
2531590Srgrimes					c = *tp;
2541590Srgrimes					goto gotc;
2551590Srgrimes				}
2561590Srgrimes			if (!octdigit(c)) {
2571590Srgrimes				*dp++ = '\\';
2581590Srgrimes				break;
2591590Srgrimes			}
2601590Srgrimes			c -= '0';
2611590Srgrimes			if (!octdigit(*cp))
2621590Srgrimes				break;
2631590Srgrimes			c <<= 3, c += *cp++ - '0';
2641590Srgrimes			if (!octdigit(*cp))
2651590Srgrimes				break;
2661590Srgrimes			c <<= 3, c += *cp++ - '0';
2671590Srgrimes			break;
2681590Srgrimes		}
2691590Srgrimesgotc:
2701590Srgrimes		*dp++ = c;
2711590Srgrimes	}
2721590Srgrimesout:
2731590Srgrimes	*cpp = --cp;
2741590Srgrimes	*dp = 0;
2751590Srgrimes	return (hashit(dbuf, 1));
2761590Srgrimes}
2771590Srgrimes
27828855Scharnierint
2791590Srgrimesoctdigit(c)
2801590Srgrimes	char c;
2811590Srgrimes{
2821590Srgrimes	return (isdigit(c) && c != '8' && c != '9');
2831590Srgrimes}
2841590Srgrimes
28528855Scharniervoid
2861590Srgrimesinithash()
2871590Srgrimes{
2881590Srgrimes	char buf[BUFSIZ];
2891590Srgrimes	register FILE *mesgread = fopen(strings, "r");
2901590Srgrimes
2911590Srgrimes	if (mesgread == NULL)
2921590Srgrimes		return;
2931590Srgrimes	for (;;) {
2941590Srgrimes		mesgpt = tellpt;
29528855Scharnier		if (fgetNUL(buf, sizeof buf, mesgread) == 0)
2961590Srgrimes			break;
2971590Srgrimes		ignore(hashit(buf, 0));
2981590Srgrimes	}
2991590Srgrimes	ignore(fclose(mesgread));
3001590Srgrimes}
3011590Srgrimes
30228855Scharnierint
3031590SrgrimesfgetNUL(obuf, rmdr, file)
3041590Srgrimes	char *obuf;
3051590Srgrimes	register int rmdr;
3061590Srgrimes	FILE *file;
3071590Srgrimes{
3081590Srgrimes	register c;
3091590Srgrimes	register char *buf = obuf;
3101590Srgrimes
3111590Srgrimes	while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
3121590Srgrimes		*buf++ = c;
3131590Srgrimes	*buf++ = 0;
31428855Scharnier	return ((feof(file) || ferror(file)) ? 0 : 1);
3151590Srgrimes}
3161590Srgrimes
31728855Scharnierint
3181590Srgrimesxgetc(file)
3191590Srgrimes	FILE *file;
3201590Srgrimes{
3211590Srgrimes
3221590Srgrimes	tellpt++;
3231590Srgrimes	return (getc(file));
3241590Srgrimes}
3251590Srgrimes
3261590Srgrimes#define	BUCKETS	128
3271590Srgrimes
3281590Srgrimesstruct	hash {
3291590Srgrimes	off_t	hpt;
3301590Srgrimes	char	*hstr;
3311590Srgrimes	struct	hash *hnext;
3321590Srgrimes	short	hnew;
3331590Srgrimes} bucket[BUCKETS];
3341590Srgrimes
3351590Srgrimesoff_t
3361590Srgrimeshashit(str, new)
3371590Srgrimes	char *str;
3381590Srgrimes	int new;
3391590Srgrimes{
3401590Srgrimes	int i;
3411590Srgrimes	register struct hash *hp, *hp0;
3421590Srgrimes
3431590Srgrimes	hp = hp0 = &bucket[lastchr(str) & 0177];
3441590Srgrimes	while (hp->hnext) {
3451590Srgrimes		hp = hp->hnext;
3461590Srgrimes		i = istail(str, hp->hstr);
3471590Srgrimes		if (i >= 0)
3481590Srgrimes			return (hp->hpt + i);
3491590Srgrimes	}
35028855Scharnier	if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL)
35128855Scharnier		errx(8, "calloc");
3521590Srgrimes	hp->hpt = mesgpt;
35328855Scharnier	if (!(hp->hstr = strdup(str)))
35428855Scharnier		err(1, NULL);
3551590Srgrimes	mesgpt += strlen(hp->hstr) + 1;
3561590Srgrimes	hp->hnext = hp0->hnext;
3571590Srgrimes	hp->hnew = new;
3581590Srgrimes	hp0->hnext = hp;
3591590Srgrimes	return (hp->hpt);
3601590Srgrimes}
3611590Srgrimes
36228855Scharniervoid
3631590Srgrimesflushsh()
3641590Srgrimes{
3651590Srgrimes	register int i;
3661590Srgrimes	register struct hash *hp;
3671590Srgrimes	register FILE *mesgwrit;
3681590Srgrimes	register int old = 0, new = 0;
3691590Srgrimes
3701590Srgrimes	for (i = 0; i < BUCKETS; i++)
3711590Srgrimes		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
3721590Srgrimes			if (hp->hnew)
3731590Srgrimes				new++;
3741590Srgrimes			else
3751590Srgrimes				old++;
3761590Srgrimes	if (new == 0 && old != 0)
3771590Srgrimes		return;
3781590Srgrimes	mesgwrit = fopen(strings, old ? "r+" : "w");
3791590Srgrimes	if (mesgwrit == NULL)
3801590Srgrimes		perror(strings), exit(4);
3811590Srgrimes	for (i = 0; i < BUCKETS; i++)
3821590Srgrimes		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
3831590Srgrimes			found(hp->hnew, hp->hpt, hp->hstr);
3841590Srgrimes			if (hp->hnew) {
3851590Srgrimes				fseek(mesgwrit, hp->hpt, 0);
3861590Srgrimes				ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
3871590Srgrimes				if (ferror(mesgwrit))
38828855Scharnier					err(4, "%s", strings);
3891590Srgrimes			}
3901590Srgrimes		}
3911590Srgrimes	if (fclose(mesgwrit) == EOF)
39228855Scharnier		err(4, "%s", strings);
3931590Srgrimes}
3941590Srgrimes
39528855Scharniervoid
3961590Srgrimesfound(new, off, str)
3971590Srgrimes	int new;
3981590Srgrimes	off_t off;
3991590Srgrimes	char *str;
4001590Srgrimes{
4011590Srgrimes	if (vflg == 0)
4021590Srgrimes		return;
4031590Srgrimes	if (!new)
4041590Srgrimes		fprintf(stderr, "found at %d:", (int) off);
4051590Srgrimes	else
4061590Srgrimes		fprintf(stderr, "new at %d:", (int) off);
4071590Srgrimes	prstr(str);
4081590Srgrimes	fprintf(stderr, "\n");
4091590Srgrimes}
4101590Srgrimes
41128855Scharniervoid
4121590Srgrimesprstr(cp)
4131590Srgrimes	register char *cp;
4141590Srgrimes{
4151590Srgrimes	register int c;
4161590Srgrimes
41728855Scharnier	while ((c = (*cp++ & 0377)))
4181590Srgrimes		if (c < ' ')
4191590Srgrimes			fprintf(stderr, "^%c", c + '`');
4201590Srgrimes		else if (c == 0177)
4211590Srgrimes			fprintf(stderr, "^?");
4221590Srgrimes		else if (c > 0200)
4231590Srgrimes			fprintf(stderr, "\\%03o", c);
4241590Srgrimes		else
4251590Srgrimes			fprintf(stderr, "%c", c);
4261590Srgrimes}
4271590Srgrimes
42828855Scharniervoid
4291590Srgrimesxsdotc()
4301590Srgrimes{
4311590Srgrimes	register FILE *strf = fopen(strings, "r");
4321590Srgrimes	register FILE *xdotcf;
4331590Srgrimes
4341590Srgrimes	if (strf == NULL)
43528855Scharnier		err(5, "%s", strings);
4361590Srgrimes	xdotcf = fopen("xs.c", "w");
4371590Srgrimes	if (xdotcf == NULL)
43828855Scharnier		err(6, "xs.c");
4391590Srgrimes	fprintf(xdotcf, "char\txstr[] = {\n");
4401590Srgrimes	for (;;) {
4411590Srgrimes		register int i, c;
4421590Srgrimes
4431590Srgrimes		for (i = 0; i < 8; i++) {
4441590Srgrimes			c = getc(strf);
4451590Srgrimes			if (ferror(strf)) {
44628855Scharnier				warn("%s", strings);
4471590Srgrimes				onintr();
4481590Srgrimes			}
4491590Srgrimes			if (feof(strf)) {
4501590Srgrimes				fprintf(xdotcf, "\n");
4511590Srgrimes				goto out;
4521590Srgrimes			}
4531590Srgrimes			fprintf(xdotcf, "0x%02x,", c);
4541590Srgrimes		}
4551590Srgrimes		fprintf(xdotcf, "\n");
4561590Srgrimes	}
4571590Srgrimesout:
4581590Srgrimes	fprintf(xdotcf, "};\n");
4591590Srgrimes	ignore(fclose(xdotcf));
4601590Srgrimes	ignore(fclose(strf));
4611590Srgrimes}
4621590Srgrimes
46328855Scharnierchar
4641590Srgrimeslastchr(cp)
4651590Srgrimes	register char *cp;
4661590Srgrimes{
4671590Srgrimes
4681590Srgrimes	while (cp[0] && cp[1])
4691590Srgrimes		cp++;
4701590Srgrimes	return (*cp);
4711590Srgrimes}
4721590Srgrimes
47328855Scharnierint
4741590Srgrimesistail(str, of)
4751590Srgrimes	register char *str, *of;
4761590Srgrimes{
4771590Srgrimes	register int d = strlen(of) - strlen(str);
4781590Srgrimes
4791590Srgrimes	if (d < 0 || strcmp(&of[d], str) != 0)
4801590Srgrimes		return (-1);
4811590Srgrimes	return (d);
4821590Srgrimes}
4831590Srgrimes
4841590Srgrimesvoid
4851590Srgrimesonintr()
4861590Srgrimes{
4871590Srgrimes
4881590Srgrimes	ignore(signal(SIGINT, SIG_IGN));
4891590Srgrimes	if (strings[0] == '/')
4901590Srgrimes		ignore(unlink(strings));
4911590Srgrimes	ignore(unlink("x.c"));
4921590Srgrimes	ignore(unlink("xs.c"));
4931590Srgrimes	exit(7);
4941590Srgrimes}
495