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