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