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