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