mkstr.c revision 33648
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 const 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
41#if 0
42static char sccsid[] = "@(#)mkstr.c	8.1 (Berkeley) 6/6/93";
43#endif
44static const char rcsid[] =
45	"$Id: mkstr.c,v 1.2 1997/07/24 07:05:02 charnier Exp $";
46#endif /* not lint */
47
48#include <err.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52
53#define	ungetchar(c)	ungetc(c, stdin)
54
55/*
56 * mkstr - create a string error message file by massaging C source
57 *
58 * Bill Joy UCB August 1977
59 *
60 * Modified March 1978 to hash old messages to be able to recompile
61 * without addding messages to the message file (usually)
62 *
63 * Based on an earlier program conceived by Bill Joy and Chuck Haley
64 *
65 * Program to create a string error message file
66 * from a group of C programs.  Arguments are the name
67 * of the file where the strings are to be placed, the
68 * prefix of the new files where the processed source text
69 * is to be placed, and the files to be processed.
70 *
71 * The program looks for 'error("' in the source stream.
72 * Whenever it finds this, the following characters from the '"'
73 * to a '"' are replaced by 'seekpt' where seekpt is a
74 * pointer into the error message file.
75 * If the '(' is not immediately followed by a '"' no change occurs.
76 *
77 * The optional '-' causes strings to be added at the end of the
78 * existing error message file for recompilation of single routines.
79 */
80
81FILE	*mesgread, *mesgwrite;
82char	name[100], *np;
83
84void copystr __P((void));
85int fgetNUL __P((char *, int, FILE *));
86unsigned hashit __P((char *, char, unsigned));
87void inithash __P((void));
88int match __P((char *));
89int octdigit __P((char));
90void process __P((void));
91static void usage __P((void));
92
93int
94main(argc, argv)
95	int argc;
96	char *argv[];
97{
98	char addon = 0;
99
100	argc--, argv++;
101	if (argc > 1 && argv[0][0] == '-')
102		addon++, argc--, argv++;
103	if (argc < 3)
104		usage();
105	mesgwrite = fopen(argv[0], addon ? "a" : "w");
106	if (mesgwrite == NULL)
107		err(1, "%s", argv[0]);
108	mesgread = fopen(argv[0], "r");
109	if (mesgread == NULL)
110		err(1, "%s", argv[0]);
111	inithash();
112	argc--, argv++;
113	strcpy(name, argv[0]);
114	np = name + strlen(name);
115	argc--, argv++;
116	do {
117		strcpy(np, argv[0]);
118		if (freopen(name, "w", stdout) == NULL)
119			err(1, "%s", name);
120		if (freopen(argv[0], "r", stdin) == NULL)
121			err(1, "%s", argv[0]);
122		process();
123		argc--, argv++;
124	} while (argc > 0);
125	exit(0);
126}
127
128static void
129usage()
130{
131	fprintf(stderr, "usage: mkstr [ - ] mesgfile prefix file ...\n");
132	exit(1);
133}
134
135void
136process()
137{
138	register c;
139
140	for (;;) {
141		c = getchar();
142		if (c == EOF)
143			return;
144		if (c != 'e') {
145			putchar(c);
146			continue;
147		}
148		if (match("error(")) {
149			printf("error(");
150			c = getchar();
151			if (c != '"')
152				putchar(c);
153			else
154				copystr();
155		}
156	}
157}
158
159int
160match(ocp)
161	char *ocp;
162{
163	register char *cp;
164	register c;
165
166	for (cp = ocp + 1; *cp; cp++) {
167		c = getchar();
168		if (c != *cp) {
169			while (ocp < cp)
170				putchar(*ocp++);
171			ungetchar(c);
172			return (0);
173		}
174	}
175	return (1);
176}
177
178void
179copystr()
180{
181	register c, ch;
182	char buf[512];
183	register char *cp = buf;
184
185	for (;;) {
186		c = getchar();
187		if (c == EOF)
188			break;
189		switch (c) {
190
191		case '"':
192			*cp++ = 0;
193			goto out;
194		case '\\':
195			c = getchar();
196			switch (c) {
197
198			case 'b':
199				c = '\b';
200				break;
201			case 't':
202				c = '\t';
203				break;
204			case 'r':
205				c = '\r';
206				break;
207			case 'n':
208				c = '\n';
209				break;
210			case '\n':
211				continue;
212			case 'f':
213				c = '\f';
214				break;
215			case '0':
216				c = 0;
217				break;
218			case '\\':
219				break;
220			default:
221				if (!octdigit(c))
222					break;
223				c -= '0';
224				ch = getchar();
225				if (!octdigit(ch))
226					break;
227				c <<= 7, c += ch - '0';
228				ch = getchar();
229				if (!octdigit(ch))
230					break;
231				c <<= 3, c+= ch - '0', ch = -1;
232				break;
233			}
234		}
235		*cp++ = c;
236	}
237out:
238	*cp = 0;
239	printf("%d", hashit(buf, 1, NULL));
240}
241
242int
243octdigit(c)
244	char c;
245{
246
247	return (c >= '0' && c <= '7');
248}
249
250void
251inithash()
252{
253	char buf[512];
254	int mesgpt = 0;
255
256	rewind(mesgread);
257	while (fgetNUL(buf, sizeof buf, mesgread) != 0) {
258		hashit(buf, 0, mesgpt);
259		mesgpt += strlen(buf) + 2;
260	}
261}
262
263#define	NBUCKETS	511
264
265struct	hash {
266	long	hval;
267	unsigned hpt;
268	struct	hash *hnext;
269} *bucket[NBUCKETS];
270
271unsigned
272hashit(str, really, fakept)
273	char *str;
274	char really;
275	unsigned fakept;
276{
277	int i;
278	register struct hash *hp;
279	char buf[512];
280	long hashval = 0;
281	register char *cp;
282
283	if (really)
284		fflush(mesgwrite);
285	for (cp = str; *cp;)
286		hashval = (hashval << 1) + *cp++;
287	i = hashval % NBUCKETS;
288	if (i < 0)
289		i += NBUCKETS;
290	if (really != 0)
291		for (hp = bucket[i]; hp != 0; hp = hp->hnext)
292		if (hp->hval == hashval) {
293			fseek(mesgread, (long) hp->hpt, 0);
294			fgetNUL(buf, sizeof buf, mesgread);
295/*
296			fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf);
297*/
298			if (strcmp(buf, str) == 0)
299				break;
300		}
301	if (!really || hp == 0) {
302		hp = (struct hash *) calloc(1, sizeof *hp);
303		hp->hnext = bucket[i];
304		hp->hval = hashval;
305		hp->hpt = really ? ftell(mesgwrite) : fakept;
306		if (really) {
307			fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite);
308			fwrite("\n", sizeof (char), 1, mesgwrite);
309		}
310		bucket[i] = hp;
311	}
312/*
313	fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt);
314*/
315	return (hp->hpt);
316}
317
318#include <sys/types.h>
319#include <sys/stat.h>
320
321int
322fgetNUL(obuf, rmdr, file)
323	char *obuf;
324	register int rmdr;
325	FILE *file;
326{
327	register c;
328	register char *buf = obuf;
329
330	while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF)
331		*buf++ = c;
332	*buf++ = 0;
333	getc(file);
334	return ((feof(file) || ferror(file)) ? 0 : 1);
335}
336