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
301590Srgrimes#ifndef lint
3127648Scharnierstatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341590Srgrimes#endif /* not lint */
351590Srgrimes
361590Srgrimes#ifndef lint
3727648Scharnier#if 0
381590Srgrimesstatic char sccsid[] = "@(#)mkstr.c	8.1 (Berkeley) 6/6/93";
3927648Scharnier#endif
401590Srgrimes#endif /* not lint */
411590Srgrimes
4294503Scharnier#include <sys/cdefs.h>
4394503Scharnier__FBSDID("$FreeBSD$");
4494503Scharnier
4527648Scharnier#include <err.h>
46106293Stjr#include <errno.h>
471590Srgrimes#include <stdio.h>
4827648Scharnier#include <stdlib.h>
4933648Sjb#include <string.h>
501590Srgrimes
511590Srgrimes#define	ungetchar(c)	ungetc(c, stdin)
521590Srgrimes
531590Srgrimes/*
541590Srgrimes * mkstr - create a string error message file by massaging C source
551590Srgrimes *
561590Srgrimes * Bill Joy UCB August 1977
571590Srgrimes *
581590Srgrimes * Modified March 1978 to hash old messages to be able to recompile
591590Srgrimes * without addding messages to the message file (usually)
601590Srgrimes *
611590Srgrimes * Based on an earlier program conceived by Bill Joy and Chuck Haley
621590Srgrimes *
631590Srgrimes * Program to create a string error message file
641590Srgrimes * from a group of C programs.  Arguments are the name
651590Srgrimes * of the file where the strings are to be placed, the
661590Srgrimes * prefix of the new files where the processed source text
671590Srgrimes * is to be placed, and the files to be processed.
681590Srgrimes *
691590Srgrimes * The program looks for 'error("' in the source stream.
701590Srgrimes * Whenever it finds this, the following characters from the '"'
711590Srgrimes * to a '"' are replaced by 'seekpt' where seekpt is a
721590Srgrimes * pointer into the error message file.
731590Srgrimes * If the '(' is not immediately followed by a '"' no change occurs.
741590Srgrimes *
751590Srgrimes * The optional '-' causes strings to be added at the end of the
761590Srgrimes * existing error message file for recompilation of single routines.
771590Srgrimes */
781590Srgrimes
791590SrgrimesFILE	*mesgread, *mesgwrite;
801590Srgrimeschar	name[100], *np;
811590Srgrimes
8292921Simpvoid copystr(void);
8392921Simpint fgetNUL(char *, int, FILE *);
8495642Smarkmunsigned hashit(char *, int, unsigned);
8592921Simpvoid inithash(void);
8692921Simpint match(const char *);
8792921Simpint octdigit(char);
8892921Simpvoid process(void);
8995642Smarkmvoid usage(void);
9027648Scharnier
9127648Scharnierint
9295642Smarkmmain(int argc, char *argv[])
931590Srgrimes{
941590Srgrimes	char addon = 0;
95106293Stjr	size_t namelen;
961590Srgrimes
9727648Scharnier	argc--, argv++;
981590Srgrimes	if (argc > 1 && argv[0][0] == '-')
991590Srgrimes		addon++, argc--, argv++;
1001590Srgrimes	if (argc < 3)
10127648Scharnier		usage();
1021590Srgrimes	mesgwrite = fopen(argv[0], addon ? "a" : "w");
1031590Srgrimes	if (mesgwrite == NULL)
10427648Scharnier		err(1, "%s", argv[0]);
1051590Srgrimes	mesgread = fopen(argv[0], "r");
1061590Srgrimes	if (mesgread == NULL)
10727648Scharnier		err(1, "%s", argv[0]);
1081590Srgrimes	inithash();
1091590Srgrimes	argc--, argv++;
110106293Stjr	namelen = strlcpy(name, argv[0], sizeof(name));
111106293Stjr	if (namelen >= sizeof(name)) {
112106293Stjr		errno = ENAMETOOLONG;
113106293Stjr		err(1, "%s", argv[0]);
114106293Stjr	}
115106293Stjr	np = name + namelen;
1161590Srgrimes	argc--, argv++;
1171590Srgrimes	do {
118106293Stjr		if (strlcpy(np, argv[0], sizeof(name) - namelen) >=
119106293Stjr		    sizeof(name) - namelen) {
120106293Stjr			errno = ENAMETOOLONG;
121106293Stjr			err(1, "%s%s", name, argv[0]);
122106293Stjr		}
1231590Srgrimes		if (freopen(name, "w", stdout) == NULL)
12427648Scharnier			err(1, "%s", name);
1251590Srgrimes		if (freopen(argv[0], "r", stdin) == NULL)
12627648Scharnier			err(1, "%s", argv[0]);
1271590Srgrimes		process();
1281590Srgrimes		argc--, argv++;
1291590Srgrimes	} while (argc > 0);
1301590Srgrimes	exit(0);
1311590Srgrimes}
1321590Srgrimes
13395642Smarkmvoid
13495642Smarkmusage(void)
13527648Scharnier{
13694503Scharnier	fprintf(stderr, "usage: mkstr [-] mesgfile prefix file ...\n");
13727648Scharnier	exit(1);
13827648Scharnier}
13927648Scharnier
14027648Scharniervoid
14195642Smarkmprocess(void)
1421590Srgrimes{
14387289Sdwmalone	int c;
1441590Srgrimes
1451590Srgrimes	for (;;) {
1461590Srgrimes		c = getchar();
1471590Srgrimes		if (c == EOF)
1481590Srgrimes			return;
1491590Srgrimes		if (c != 'e') {
1501590Srgrimes			putchar(c);
1511590Srgrimes			continue;
1521590Srgrimes		}
1531590Srgrimes		if (match("error(")) {
1541590Srgrimes			printf("error(");
1551590Srgrimes			c = getchar();
1561590Srgrimes			if (c != '"')
1571590Srgrimes				putchar(c);
1581590Srgrimes			else
1591590Srgrimes				copystr();
1601590Srgrimes		}
1611590Srgrimes	}
1621590Srgrimes}
1631590Srgrimes
16427648Scharnierint
16595642Smarkmmatch(const char *ocp)
1661590Srgrimes{
16787289Sdwmalone	const char *cp;
16887289Sdwmalone	int c;
1691590Srgrimes
1701590Srgrimes	for (cp = ocp + 1; *cp; cp++) {
1711590Srgrimes		c = getchar();
1721590Srgrimes		if (c != *cp) {
1731590Srgrimes			while (ocp < cp)
1741590Srgrimes				putchar(*ocp++);
1751590Srgrimes			ungetchar(c);
1761590Srgrimes			return (0);
1771590Srgrimes		}
1781590Srgrimes	}
1791590Srgrimes	return (1);
1801590Srgrimes}
1811590Srgrimes
18227648Scharniervoid
18395642Smarkmcopystr(void)
1841590Srgrimes{
18587289Sdwmalone	int c, ch;
1861590Srgrimes	char buf[512];
18795642Smarkm	char *cp = buf;
1881590Srgrimes
1891590Srgrimes	for (;;) {
190106294Stjr		if (cp == buf + sizeof(buf) - 2)
191106294Stjr			errx(1, "message too long");
1921590Srgrimes		c = getchar();
1931590Srgrimes		if (c == EOF)
1941590Srgrimes			break;
1951590Srgrimes		switch (c) {
1961590Srgrimes
1971590Srgrimes		case '"':
1981590Srgrimes			*cp++ = 0;
1991590Srgrimes			goto out;
2001590Srgrimes		case '\\':
2011590Srgrimes			c = getchar();
2021590Srgrimes			switch (c) {
2031590Srgrimes
2041590Srgrimes			case 'b':
2051590Srgrimes				c = '\b';
2061590Srgrimes				break;
2071590Srgrimes			case 't':
2081590Srgrimes				c = '\t';
2091590Srgrimes				break;
2101590Srgrimes			case 'r':
2111590Srgrimes				c = '\r';
2121590Srgrimes				break;
2131590Srgrimes			case 'n':
2141590Srgrimes				c = '\n';
2151590Srgrimes				break;
2161590Srgrimes			case '\n':
2171590Srgrimes				continue;
2181590Srgrimes			case 'f':
2191590Srgrimes				c = '\f';
2201590Srgrimes				break;
2211590Srgrimes			case '0':
2221590Srgrimes				c = 0;
2231590Srgrimes				break;
2241590Srgrimes			case '\\':
2251590Srgrimes				break;
2261590Srgrimes			default:
2271590Srgrimes				if (!octdigit(c))
2281590Srgrimes					break;
2291590Srgrimes				c -= '0';
2301590Srgrimes				ch = getchar();
2311590Srgrimes				if (!octdigit(ch))
2321590Srgrimes					break;
2331590Srgrimes				c <<= 7, c += ch - '0';
2341590Srgrimes				ch = getchar();
2351590Srgrimes				if (!octdigit(ch))
2361590Srgrimes					break;
2371590Srgrimes				c <<= 3, c+= ch - '0', ch = -1;
2381590Srgrimes				break;
2391590Srgrimes			}
2401590Srgrimes		}
2411590Srgrimes		*cp++ = c;
2421590Srgrimes	}
2431590Srgrimesout:
2441590Srgrimes	*cp = 0;
245126960Sbde	printf("%d", hashit(buf, 1, 0));
2461590Srgrimes}
2471590Srgrimes
24827648Scharnierint
24995642Smarkmoctdigit(char c)
2501590Srgrimes{
2511590Srgrimes
2521590Srgrimes	return (c >= '0' && c <= '7');
2531590Srgrimes}
2541590Srgrimes
25527648Scharniervoid
25695642Smarkminithash(void)
2571590Srgrimes{
2581590Srgrimes	char buf[512];
2591590Srgrimes	int mesgpt = 0;
2601590Srgrimes
2611590Srgrimes	rewind(mesgread);
26227648Scharnier	while (fgetNUL(buf, sizeof buf, mesgread) != 0) {
2631590Srgrimes		hashit(buf, 0, mesgpt);
2641590Srgrimes		mesgpt += strlen(buf) + 2;
2651590Srgrimes	}
2661590Srgrimes}
2671590Srgrimes
2681590Srgrimes#define	NBUCKETS	511
2691590Srgrimes
2701590Srgrimesstruct	hash {
2711590Srgrimes	long	hval;
2721590Srgrimes	unsigned hpt;
2731590Srgrimes	struct	hash *hnext;
2741590Srgrimes} *bucket[NBUCKETS];
2751590Srgrimes
27627648Scharnierunsigned
27795642Smarkmhashit(char *str, int really, unsigned fakept)
2781590Srgrimes{
2791590Srgrimes	int i;
28095642Smarkm	struct hash *hp;
2811590Srgrimes	char buf[512];
2821590Srgrimes	long hashval = 0;
28395642Smarkm	char *cp;
2841590Srgrimes
2851590Srgrimes	if (really)
2861590Srgrimes		fflush(mesgwrite);
2871590Srgrimes	for (cp = str; *cp;)
2881590Srgrimes		hashval = (hashval << 1) + *cp++;
2891590Srgrimes	i = hashval % NBUCKETS;
2901590Srgrimes	if (i < 0)
2911590Srgrimes		i += NBUCKETS;
2921590Srgrimes	if (really != 0)
2931590Srgrimes		for (hp = bucket[i]; hp != 0; hp = hp->hnext)
2941590Srgrimes		if (hp->hval == hashval) {
2951590Srgrimes			fseek(mesgread, (long) hp->hpt, 0);
2961590Srgrimes			fgetNUL(buf, sizeof buf, mesgread);
2971590Srgrimes/*
2981590Srgrimes			fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf);
2991590Srgrimes*/
3001590Srgrimes			if (strcmp(buf, str) == 0)
3011590Srgrimes				break;
3021590Srgrimes		}
3031590Srgrimes	if (!really || hp == 0) {
3041590Srgrimes		hp = (struct hash *) calloc(1, sizeof *hp);
30594503Scharnier		if (hp == NULL)
30694503Scharnier			err(1, NULL);
3071590Srgrimes		hp->hnext = bucket[i];
3081590Srgrimes		hp->hval = hashval;
3091590Srgrimes		hp->hpt = really ? ftell(mesgwrite) : fakept;
3101590Srgrimes		if (really) {
3111590Srgrimes			fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite);
3121590Srgrimes			fwrite("\n", sizeof (char), 1, mesgwrite);
3131590Srgrimes		}
3141590Srgrimes		bucket[i] = hp;
3151590Srgrimes	}
3161590Srgrimes/*
3171590Srgrimes	fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt);
3181590Srgrimes*/
3191590Srgrimes	return (hp->hpt);
3201590Srgrimes}
3211590Srgrimes
32227648Scharnierint
32395642SmarkmfgetNUL(char *obuf, int rmdr, FILE *file)
3241590Srgrimes{
32587289Sdwmalone	int c;
32695642Smarkm	char *buf = obuf;
3271590Srgrimes
3281590Srgrimes	while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF)
3291590Srgrimes		*buf++ = c;
3301590Srgrimes	*buf++ = 0;
3311590Srgrimes	getc(file);
33227648Scharnier	return ((feof(file) || ferror(file)) ? 0 : 1);
3331590Srgrimes}
334