mkstr.c revision 331722
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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1980, 1993\n\
33	The Regents of the University of California.  All rights reserved.\n";
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)mkstr.c	8.1 (Berkeley) 6/6/93";
39#endif
40#endif /* not lint */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: stable/11/usr.bin/mkstr/mkstr.c 331722 2018-03-29 02:50:57Z eadler $");
44
45#include <err.h>
46#include <errno.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50
51#define	ungetchar(c)	ungetc(c, stdin)
52
53/*
54 * mkstr - create a string error message file by massaging C source
55 *
56 * Bill Joy UCB August 1977
57 *
58 * Modified March 1978 to hash old messages to be able to recompile
59 * without addding messages to the message file (usually)
60 *
61 * Based on an earlier program conceived by Bill Joy and Chuck Haley
62 *
63 * Program to create a string error message file
64 * from a group of C programs.  Arguments are the name
65 * of the file where the strings are to be placed, the
66 * prefix of the new files where the processed source text
67 * is to be placed, and the files to be processed.
68 *
69 * The program looks for 'error("' in the source stream.
70 * Whenever it finds this, the following characters from the '"'
71 * to a '"' are replaced by 'seekpt' where seekpt is a
72 * pointer into the error message file.
73 * If the '(' is not immediately followed by a '"' no change occurs.
74 *
75 * The optional '-' causes strings to be added at the end of the
76 * existing error message file for recompilation of single routines.
77 */
78
79static FILE	*mesgread, *mesgwrite;
80static char	name[100], *np;
81
82void copystr(void);
83int fgetNUL(char *, int, FILE *);
84unsigned hashit(char *, int, unsigned);
85void inithash(void);
86int match(const char *);
87int octdigit(char);
88void process(void);
89void usage(void);
90
91int
92main(int argc, char *argv[])
93{
94	char addon = 0;
95	size_t namelen;
96
97	argc--, argv++;
98	if (argc > 1 && argv[0][0] == '-')
99		addon++, argc--, argv++;
100	if (argc < 3)
101		usage();
102	mesgwrite = fopen(argv[0], addon ? "a" : "w");
103	if (mesgwrite == NULL)
104		err(1, "%s", argv[0]);
105	mesgread = fopen(argv[0], "r");
106	if (mesgread == NULL)
107		err(1, "%s", argv[0]);
108	inithash();
109	argc--, argv++;
110	namelen = strlcpy(name, argv[0], sizeof(name));
111	if (namelen >= sizeof(name)) {
112		errno = ENAMETOOLONG;
113		err(1, "%s", argv[0]);
114	}
115	np = name + namelen;
116	argc--, argv++;
117	do {
118		if (strlcpy(np, argv[0], sizeof(name) - namelen) >=
119		    sizeof(name) - namelen) {
120			errno = ENAMETOOLONG;
121			err(1, "%s%s", name, argv[0]);
122		}
123		if (freopen(name, "w", stdout) == NULL)
124			err(1, "%s", name);
125		if (freopen(argv[0], "r", stdin) == NULL)
126			err(1, "%s", argv[0]);
127		process();
128		argc--, argv++;
129	} while (argc > 0);
130	exit(0);
131}
132
133void
134usage(void)
135{
136	fprintf(stderr, "usage: mkstr [-] mesgfile prefix file ...\n");
137	exit(1);
138}
139
140void
141process(void)
142{
143	int c;
144
145	for (;;) {
146		c = getchar();
147		if (c == EOF)
148			return;
149		if (c != 'e') {
150			putchar(c);
151			continue;
152		}
153		if (match("error(")) {
154			printf("error(");
155			c = getchar();
156			if (c != '"')
157				putchar(c);
158			else
159				copystr();
160		}
161	}
162}
163
164int
165match(const char *ocp)
166{
167	const char *cp;
168	int c;
169
170	for (cp = ocp + 1; *cp; cp++) {
171		c = getchar();
172		if (c != *cp) {
173			while (ocp < cp)
174				putchar(*ocp++);
175			ungetchar(c);
176			return (0);
177		}
178	}
179	return (1);
180}
181
182void
183copystr(void)
184{
185	int c, ch;
186	char buf[512];
187	char *cp = buf;
188
189	for (;;) {
190		if (cp == buf + sizeof(buf) - 2)
191			errx(1, "message too long");
192		c = getchar();
193		if (c == EOF)
194			break;
195		switch (c) {
196
197		case '"':
198			*cp++ = 0;
199			goto out;
200		case '\\':
201			c = getchar();
202			switch (c) {
203
204			case 'b':
205				c = '\b';
206				break;
207			case 't':
208				c = '\t';
209				break;
210			case 'r':
211				c = '\r';
212				break;
213			case 'n':
214				c = '\n';
215				break;
216			case '\n':
217				continue;
218			case 'f':
219				c = '\f';
220				break;
221			case '0':
222				c = 0;
223				break;
224			case '\\':
225				break;
226			default:
227				if (!octdigit(c))
228					break;
229				c -= '0';
230				ch = getchar();
231				if (!octdigit(ch))
232					break;
233				c <<= 7, c += ch - '0';
234				ch = getchar();
235				if (!octdigit(ch))
236					break;
237				c <<= 3, c+= ch - '0', ch = -1;
238				break;
239			}
240		}
241		*cp++ = c;
242	}
243out:
244	*cp = 0;
245	printf("%d", hashit(buf, 1, 0));
246}
247
248int
249octdigit(char c)
250{
251
252	return (c >= '0' && c <= '7');
253}
254
255void
256inithash(void)
257{
258	char buf[512];
259	int mesgpt = 0;
260
261	rewind(mesgread);
262	while (fgetNUL(buf, sizeof buf, mesgread) != 0) {
263		hashit(buf, 0, mesgpt);
264		mesgpt += strlen(buf) + 2;
265	}
266}
267
268#define	NBUCKETS	511
269
270static struct	hash {
271	long	hval;
272	unsigned hpt;
273	struct	hash *hnext;
274} *bucket[NBUCKETS];
275
276unsigned
277hashit(char *str, int really, unsigned fakept)
278{
279	int i;
280	struct hash *hp;
281	char buf[512];
282	long hashval = 0;
283	char *cp;
284
285	if (really)
286		fflush(mesgwrite);
287	for (cp = str; *cp;)
288		hashval = (hashval << 1) + *cp++;
289	i = hashval % NBUCKETS;
290	if (i < 0)
291		i += NBUCKETS;
292	if (really != 0)
293		for (hp = bucket[i]; hp != 0; hp = hp->hnext)
294		if (hp->hval == hashval) {
295			fseek(mesgread, (long) hp->hpt, 0);
296			fgetNUL(buf, sizeof buf, mesgread);
297/*
298			fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf);
299*/
300			if (strcmp(buf, str) == 0)
301				break;
302		}
303	if (!really || hp == 0) {
304		hp = (struct hash *) calloc(1, sizeof *hp);
305		if (hp == NULL)
306			err(1, NULL);
307		hp->hnext = bucket[i];
308		hp->hval = hashval;
309		hp->hpt = really ? ftell(mesgwrite) : fakept;
310		if (really) {
311			fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite);
312			fwrite("\n", sizeof (char), 1, mesgwrite);
313		}
314		bucket[i] = hp;
315	}
316/*
317	fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt);
318*/
319	return (hp->hpt);
320}
321
322int
323fgetNUL(char *obuf, int rmdr, FILE *file)
324{
325	int c;
326	char *buf = obuf;
327
328	while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF)
329		*buf++ = c;
330	*buf++ = 0;
331	getc(file);
332	return ((feof(file) || ferror(file)) ? 0 : 1);
333}
334