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