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 * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
3087687Smarkm#include <sys/cdefs.h>
3187687Smarkm
3287687Smarkm__FBSDID("$FreeBSD$");
3387687Smarkm
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";
3887687Smarkm#endif
391590Srgrimes
401590Srgrimes#ifndef lint
4187687Smarkmstatic const char sccsid[] = "@(#)xstr.c	8.1 (Berkeley) 6/9/93";
4228855Scharnier#endif
431590Srgrimes
441590Srgrimes#include <sys/types.h>
4587687Smarkm
4628855Scharnier#include <ctype.h>
4728855Scharnier#include <err.h>
4828855Scharnier#include <stdio.h>
4928855Scharnier#include <stdlib.h>
501590Srgrimes#include <signal.h>
5128855Scharnier#include <string.h>
521590Srgrimes#include <unistd.h>
5387687Smarkm
541590Srgrimes#include "pathnames.h"
551590Srgrimes
561590Srgrimes/*
571590Srgrimes * xstr - extract and hash strings in a C program
581590Srgrimes *
591590Srgrimes * Bill Joy UCB
601590Srgrimes * November, 1978
611590Srgrimes */
621590Srgrimes
631590Srgrimes#define	ignore(a)	((void) a)
641590Srgrimes
65227247Sedstatic off_t	tellpt;
661590Srgrimes
67227247Sedstatic off_t	mesgpt;
68227247Sedstatic char	cstrings[] =	"strings";
69227247Sedstatic char	*strings =	cstrings;
701590Srgrimes
71227247Sedstatic int	cflg;
72227247Sedstatic int	vflg;
73227247Sedstatic int	readstd;
741590Srgrimes
75227247Sedstatic char lastchr(char *);
7687687Smarkm
77227247Sedstatic int fgetNUL(char *, int, FILE *);
78227247Sedstatic int istail(char *, char *);
79227247Sedstatic int octdigit(char);
80227247Sedstatic int xgetc(FILE *);
8128855Scharnier
82227247Sedstatic off_t hashit(char *, int);
83227247Sedstatic off_t yankstr(char **);
8487687Smarkm
8592922Simpstatic void usage(void);
8687687Smarkm
87227247Sedstatic void flushsh(void);
88227247Sedstatic void found(int, off_t, char *);
89227247Sedstatic void inithash(void);
90227247Sedstatic void onintr(int);
91227247Sedstatic void process(const char *);
92227247Sedstatic void prstr(char *);
93227247Sedstatic void xsdotc(void);
9487687Smarkm
9528855Scharnierint
96102944Sdwmalonemain(int argc, char *argv[])
971590Srgrimes{
9828855Scharnier	int c;
99178973Skevlo	int fdesc;
1001590Srgrimes
10128855Scharnier	while ((c = getopt(argc, argv, "-cv")) != -1)
10228855Scharnier		switch (c) {
10328855Scharnier		case '-':
1041590Srgrimes			readstd++;
10528855Scharnier			break;
1061590Srgrimes		case 'c':
1071590Srgrimes			cflg++;
10828855Scharnier			break;
1091590Srgrimes		case 'v':
1101590Srgrimes			vflg++;
11128855Scharnier			break;
1121590Srgrimes		default:
11328855Scharnier			usage();
11428855Scharnier		}
11528855Scharnier	argc -= optind;
11628855Scharnier	argv += optind;
11728855Scharnier
1181590Srgrimes	if (signal(SIGINT, SIG_IGN) == SIG_DFL)
1191590Srgrimes		signal(SIGINT, onintr);
12028855Scharnier	if (cflg || (argc == 0 && !readstd))
1211590Srgrimes		inithash();
122178973Skevlo	else {
123178973Skevlo		strings = strdup(_PATH_TMP);
124178973Skevlo		if (strings == NULL)
125178973Skevlo			err(1, "strdup() failed");
126178973Skevlo		fdesc = mkstemp(strings);
127178973Skevlo		if (fdesc == -1)
128178973Skevlo			err(1, "Unable to create temporary file");
129178973Skevlo		close(fdesc);
130178973Skevlo	}
131178973Skevlo
1321590Srgrimes	while (readstd || argc > 0) {
1331590Srgrimes		if (freopen("x.c", "w", stdout) == NULL)
13428855Scharnier			err(1, "x.c");
1351590Srgrimes		if (!readstd && freopen(argv[0], "r", stdin) == NULL)
13628855Scharnier			err(2, "%s", argv[0]);
1371590Srgrimes		process("x.c");
1381590Srgrimes		if (readstd == 0)
1391590Srgrimes			argc--, argv++;
1401590Srgrimes		else
1411590Srgrimes			readstd = 0;
1421590Srgrimes	};
1431590Srgrimes	flushsh();
1441590Srgrimes	if (cflg == 0)
1451590Srgrimes		xsdotc();
1461590Srgrimes	if (strings[0] == '/')
1471590Srgrimes		ignore(unlink(strings));
1481590Srgrimes	exit(0);
1491590Srgrimes}
1501590Srgrimes
15128855Scharnierstatic void
152102944Sdwmaloneusage(void)
15328855Scharnier{
154146467Sru	fprintf(stderr, "usage: xstr [-cv] [-] [file ...]\n");
15528855Scharnier	exit (1);
15628855Scharnier}
15728855Scharnier
158227247Sedstatic char linebuf[BUFSIZ];
1591590Srgrimes
160227247Sedstatic void
161102944Sdwmaloneprocess(const char *name)
1621590Srgrimes{
1631590Srgrimes	char *cp;
16487687Smarkm	int c;
16587687Smarkm	int incomm = 0;
1661590Srgrimes	int ret;
1671590Srgrimes
1681590Srgrimes	printf("extern char\txstr[];\n");
1691590Srgrimes	for (;;) {
1701590Srgrimes		if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
17128855Scharnier			if (ferror(stdin))
17228855Scharnier				err(3, "%s", name);
1731590Srgrimes			break;
1741590Srgrimes		}
1751590Srgrimes		if (linebuf[0] == '#') {
1761590Srgrimes			if (linebuf[1] == ' ' && isdigit(linebuf[2]))
1771590Srgrimes				printf("#line%s", &linebuf[1]);
1781590Srgrimes			else
1791590Srgrimes				printf("%s", linebuf);
1801590Srgrimes			continue;
1811590Srgrimes		}
18228855Scharnier		for (cp = linebuf; (c = *cp++);) switch (c) {
1838874Srgrimes
1841590Srgrimes		case '"':
1851590Srgrimes			if (incomm)
1861590Srgrimes				goto def;
1871590Srgrimes			if ((ret = (int) yankstr(&cp)) == -1)
1881590Srgrimes				goto out;
1891590Srgrimes			printf("(&xstr[%d])", ret);
1901590Srgrimes			break;
1911590Srgrimes
1921590Srgrimes		case '\'':
1931590Srgrimes			if (incomm)
1941590Srgrimes				goto def;
1951590Srgrimes			putchar(c);
1961590Srgrimes			if (*cp)
1971590Srgrimes				putchar(*cp++);
1981590Srgrimes			break;
1991590Srgrimes
2001590Srgrimes		case '/':
2011590Srgrimes			if (incomm || *cp != '*')
2021590Srgrimes				goto def;
2031590Srgrimes			incomm = 1;
2041590Srgrimes			cp++;
2051590Srgrimes			printf("/*");
2061590Srgrimes			continue;
2071590Srgrimes
2081590Srgrimes		case '*':
2091590Srgrimes			if (incomm && *cp == '/') {
2101590Srgrimes				incomm = 0;
2111590Srgrimes				cp++;
2121590Srgrimes				printf("*/");
2131590Srgrimes				continue;
2141590Srgrimes			}
2151590Srgrimes			goto def;
2168874Srgrimes
2171590Srgrimesdef:
2181590Srgrimes		default:
2191590Srgrimes			putchar(c);
2201590Srgrimes			break;
2211590Srgrimes		}
2221590Srgrimes	}
2231590Srgrimesout:
2241590Srgrimes	if (ferror(stdout))
22587687Smarkm		warn("x.c"), onintr(0);
2261590Srgrimes}
2271590Srgrimes
228227247Sedstatic off_t
229102944Sdwmaloneyankstr(char **cpp)
2301590Srgrimes{
23187687Smarkm	char *cp = *cpp;
23287687Smarkm	int c, ch;
2331590Srgrimes	char dbuf[BUFSIZ];
23487687Smarkm	char *dp = dbuf;
23587687Smarkm	char *tp;
23687687Smarkm	static char tmp[] = "b\bt\tr\rn\nf\f\\\\\"\"";
2371590Srgrimes
23828855Scharnier	while ((c = *cp++)) {
239106296Stjr		if (dp == dbuf + sizeof(dbuf) - 3)
240106296Stjr			errx(1, "message too long");
2411590Srgrimes		switch (c) {
2421590Srgrimes
2431590Srgrimes		case '"':
2441590Srgrimes			cp++;
2451590Srgrimes			goto out;
2461590Srgrimes
2471590Srgrimes		case '\\':
2481590Srgrimes			c = *cp++;
2491590Srgrimes			if (c == 0)
2501590Srgrimes				break;
2511590Srgrimes			if (c == '\n') {
2528874Srgrimes				if (fgets(linebuf, sizeof linebuf, stdin)
2531590Srgrimes				    == NULL) {
25428855Scharnier					if (ferror(stdin))
25528855Scharnier						err(3, "x.c");
2561590Srgrimes					return(-1);
2571590Srgrimes				}
2581590Srgrimes				cp = linebuf;
2591590Srgrimes				continue;
2601590Srgrimes			}
26187687Smarkm			for (tp = tmp; (ch = *tp++); tp++)
2621590Srgrimes				if (c == ch) {
2631590Srgrimes					c = *tp;
2641590Srgrimes					goto gotc;
2651590Srgrimes				}
2661590Srgrimes			if (!octdigit(c)) {
2671590Srgrimes				*dp++ = '\\';
2681590Srgrimes				break;
2691590Srgrimes			}
2701590Srgrimes			c -= '0';
2711590Srgrimes			if (!octdigit(*cp))
2721590Srgrimes				break;
2731590Srgrimes			c <<= 3, c += *cp++ - '0';
2741590Srgrimes			if (!octdigit(*cp))
2751590Srgrimes				break;
2761590Srgrimes			c <<= 3, c += *cp++ - '0';
2771590Srgrimes			break;
2781590Srgrimes		}
2791590Srgrimesgotc:
2801590Srgrimes		*dp++ = c;
2811590Srgrimes	}
2821590Srgrimesout:
2831590Srgrimes	*cpp = --cp;
2841590Srgrimes	*dp = 0;
2851590Srgrimes	return (hashit(dbuf, 1));
2861590Srgrimes}
2871590Srgrimes
288227247Sedstatic int
289102944Sdwmaloneoctdigit(char c)
2901590Srgrimes{
2911590Srgrimes	return (isdigit(c) && c != '8' && c != '9');
2921590Srgrimes}
2931590Srgrimes
294227247Sedstatic void
295102944Sdwmaloneinithash(void)
2961590Srgrimes{
2971590Srgrimes	char buf[BUFSIZ];
29887687Smarkm	FILE *mesgread = fopen(strings, "r");
2991590Srgrimes
3001590Srgrimes	if (mesgread == NULL)
3011590Srgrimes		return;
3021590Srgrimes	for (;;) {
3031590Srgrimes		mesgpt = tellpt;
30428855Scharnier		if (fgetNUL(buf, sizeof buf, mesgread) == 0)
3051590Srgrimes			break;
3061590Srgrimes		ignore(hashit(buf, 0));
3071590Srgrimes	}
3081590Srgrimes	ignore(fclose(mesgread));
3091590Srgrimes}
3101590Srgrimes
311227247Sedstatic int
312102944SdwmalonefgetNUL(char *obuf, int rmdr, FILE *file)
3131590Srgrimes{
31487687Smarkm	int c;
31587687Smarkm	char *buf = obuf;
3161590Srgrimes
3171590Srgrimes	while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
3181590Srgrimes		*buf++ = c;
3191590Srgrimes	*buf++ = 0;
32028855Scharnier	return ((feof(file) || ferror(file)) ? 0 : 1);
3211590Srgrimes}
3221590Srgrimes
323227247Sedstatic int
324102944Sdwmalonexgetc(FILE *file)
3251590Srgrimes{
3261590Srgrimes
3271590Srgrimes	tellpt++;
3281590Srgrimes	return (getc(file));
3291590Srgrimes}
3301590Srgrimes
3311590Srgrimes#define	BUCKETS	128
3321590Srgrimes
333227247Sedstatic struct hash {
3341590Srgrimes	off_t	hpt;
3351590Srgrimes	char	*hstr;
3361590Srgrimes	struct	hash *hnext;
3371590Srgrimes	short	hnew;
3381590Srgrimes} bucket[BUCKETS];
3391590Srgrimes
340227247Sedstatic off_t
341102944Sdwmalonehashit(char *str, int new)
3421590Srgrimes{
3431590Srgrimes	int i;
34487687Smarkm	struct hash *hp, *hp0;
3451590Srgrimes
3461590Srgrimes	hp = hp0 = &bucket[lastchr(str) & 0177];
3471590Srgrimes	while (hp->hnext) {
3481590Srgrimes		hp = hp->hnext;
3491590Srgrimes		i = istail(str, hp->hstr);
3501590Srgrimes		if (i >= 0)
3511590Srgrimes			return (hp->hpt + i);
3521590Srgrimes	}
35328855Scharnier	if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL)
35428855Scharnier		errx(8, "calloc");
3551590Srgrimes	hp->hpt = mesgpt;
35628855Scharnier	if (!(hp->hstr = strdup(str)))
35728855Scharnier		err(1, NULL);
3581590Srgrimes	mesgpt += strlen(hp->hstr) + 1;
3591590Srgrimes	hp->hnext = hp0->hnext;
3601590Srgrimes	hp->hnew = new;
3611590Srgrimes	hp0->hnext = hp;
3621590Srgrimes	return (hp->hpt);
3631590Srgrimes}
3641590Srgrimes
365227247Sedstatic void
366102944Sdwmaloneflushsh(void)
3671590Srgrimes{
36887687Smarkm	int i;
36987687Smarkm	struct hash *hp;
37087687Smarkm	FILE *mesgwrit;
37187687Smarkm	int old = 0, new = 0;
3721590Srgrimes
3731590Srgrimes	for (i = 0; i < BUCKETS; i++)
3741590Srgrimes		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
3751590Srgrimes			if (hp->hnew)
3761590Srgrimes				new++;
3771590Srgrimes			else
3781590Srgrimes				old++;
3791590Srgrimes	if (new == 0 && old != 0)
3801590Srgrimes		return;
3811590Srgrimes	mesgwrit = fopen(strings, old ? "r+" : "w");
3821590Srgrimes	if (mesgwrit == NULL)
383132182Stjr		err(4, "%s", strings);
3841590Srgrimes	for (i = 0; i < BUCKETS; i++)
3851590Srgrimes		for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
3861590Srgrimes			found(hp->hnew, hp->hpt, hp->hstr);
3871590Srgrimes			if (hp->hnew) {
3881590Srgrimes				fseek(mesgwrit, hp->hpt, 0);
3891590Srgrimes				ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
3901590Srgrimes				if (ferror(mesgwrit))
39128855Scharnier					err(4, "%s", strings);
3921590Srgrimes			}
3931590Srgrimes		}
3941590Srgrimes	if (fclose(mesgwrit) == EOF)
39528855Scharnier		err(4, "%s", strings);
3961590Srgrimes}
3971590Srgrimes
398227247Sedstatic void
399102944Sdwmalonefound(int new, off_t off, 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
411227247Sedstatic void
412102944Sdwmaloneprstr(char *cp)
4131590Srgrimes{
41487687Smarkm	int c;
4151590Srgrimes
41628855Scharnier	while ((c = (*cp++ & 0377)))
4171590Srgrimes		if (c < ' ')
4181590Srgrimes			fprintf(stderr, "^%c", c + '`');
4191590Srgrimes		else if (c == 0177)
4201590Srgrimes			fprintf(stderr, "^?");
4211590Srgrimes		else if (c > 0200)
4221590Srgrimes			fprintf(stderr, "\\%03o", c);
4231590Srgrimes		else
4241590Srgrimes			fprintf(stderr, "%c", c);
4251590Srgrimes}
4261590Srgrimes
427227247Sedstatic void
428102944Sdwmalonexsdotc(void)
4291590Srgrimes{
43087687Smarkm	FILE *strf = fopen(strings, "r");
43187687Smarkm	FILE *xdotcf;
4321590Srgrimes
4331590Srgrimes	if (strf == NULL)
43428855Scharnier		err(5, "%s", strings);
4351590Srgrimes	xdotcf = fopen("xs.c", "w");
4361590Srgrimes	if (xdotcf == NULL)
43728855Scharnier		err(6, "xs.c");
4381590Srgrimes	fprintf(xdotcf, "char\txstr[] = {\n");
4391590Srgrimes	for (;;) {
44087687Smarkm		int i, c;
4411590Srgrimes
4421590Srgrimes		for (i = 0; i < 8; i++) {
4431590Srgrimes			c = getc(strf);
4441590Srgrimes			if (ferror(strf)) {
44528855Scharnier				warn("%s", strings);
44687687Smarkm				onintr(0);
4471590Srgrimes			}
4481590Srgrimes			if (feof(strf)) {
4491590Srgrimes				fprintf(xdotcf, "\n");
4501590Srgrimes				goto out;
4511590Srgrimes			}
4521590Srgrimes			fprintf(xdotcf, "0x%02x,", c);
4531590Srgrimes		}
4541590Srgrimes		fprintf(xdotcf, "\n");
4551590Srgrimes	}
4561590Srgrimesout:
4571590Srgrimes	fprintf(xdotcf, "};\n");
4581590Srgrimes	ignore(fclose(xdotcf));
4591590Srgrimes	ignore(fclose(strf));
4601590Srgrimes}
4611590Srgrimes
462227247Sedstatic char
463102944Sdwmalonelastchr(char *cp)
4641590Srgrimes{
4651590Srgrimes
4661590Srgrimes	while (cp[0] && cp[1])
4671590Srgrimes		cp++;
4681590Srgrimes	return (*cp);
4691590Srgrimes}
4701590Srgrimes
471227247Sedstatic int
472102944Sdwmaloneistail(char *str, char *of)
4731590Srgrimes{
47487687Smarkm	int d = strlen(of) - strlen(str);
4751590Srgrimes
4761590Srgrimes	if (d < 0 || strcmp(&of[d], str) != 0)
4771590Srgrimes		return (-1);
4781590Srgrimes	return (d);
4791590Srgrimes}
4801590Srgrimes
481227247Sedstatic void
482102944Sdwmaloneonintr(int dummy __unused)
4831590Srgrimes{
4841590Srgrimes
4851590Srgrimes	ignore(signal(SIGINT, SIG_IGN));
4861590Srgrimes	if (strings[0] == '/')
4871590Srgrimes		ignore(unlink(strings));
4881590Srgrimes	ignore(unlink("x.c"));
4891590Srgrimes	ignore(unlink("xs.c"));
4901590Srgrimes	exit(7);
4911590Srgrimes}
492