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