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