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 2005 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 <stdlib.h>
58 #include <string.h>
59 #include <locale.h>
60 #include <sys/param.h>
61
62 #define ungetchar(c) ungetc(c, stdin)
63
64 #define NBUCKETS 511
65
66 static char usagestr[] = "usage: %s [ - ] mesgfile prefix file ...\n";
67
68 static FILE *mesgread, *mesgwrite;
69
70 static void process(void);
71 static int match(char *ocp);
72 static void copystr(void);
73 static int octdigit(char c);
74 static void inithash(void);
75 static int hashit(char *str, char really, unsigned int fakept);
76 static int fgetNUL(char *obuf, int rmdr, FILE *file);
77
78 int
main(int argc,char * argv[])79 main(int argc, char *argv[])
80 {
81 char addon = 0;
82 char *progname, *np, name[MAXPATHLEN];
83 size_t size = 0;
84 size_t len;
85
86 (void) setlocale(LC_ALL, "");
87
88 #if !defined(TEXT_DOMAIN)
89 #define TEXT_DOMAIN "SYS_TEST"
90 #endif
91 (void) textdomain(TEXT_DOMAIN);
92
93 argc--, progname = *argv++;
94 if (argc > 1 && argv[0][0] == '-')
95 addon++, argc--, argv++;
96 if (argc < 3)
97 (void) fprintf(stderr, gettext(usagestr), progname), exit(1);
98 mesgwrite = fopen(argv[0], addon ? "a" : "w");
99 if (mesgwrite == NULL)
100 perror(argv[0]), exit(1);
101 mesgread = fopen(argv[0], "r");
102 if (mesgread == NULL)
103 perror(argv[0]), exit(1);
104 inithash();
105 argc--, argv++;
106
107 if (strlcpy(name, argv[0], sizeof (name)) >= sizeof (name)) {
108 (void) fprintf(stderr, gettext("%s: %s: string too long"),
109 progname, argv[0]);
110 exit(1);
111 }
112
113 np = name + strlen(name);
114
115 len = strlen(name);
116 np = name + len;
117 size = sizeof (name) - len;
118 argc--, argv++;
119 do {
120 if (strlcpy(np, argv[0], size) >= size) {
121 (void) fprintf(stderr,
122 gettext("%s: %s: string too long"),
123 progname, argv[0]);
124 exit(1);
125 }
126 if (freopen(name, "w", stdout) == NULL)
127 perror(name), exit(1);
128 if (freopen(argv[0], "r", stdin) == NULL)
129 perror(argv[0]), exit(1);
130 process();
131 argc--, argv++;
132 } while (argc > 0);
133
134 return (0);
135 }
136
137 static void
process(void)138 process(void)
139 {
140 int c;
141
142 for (;;) {
143 c = getchar();
144 if (c == EOF)
145 return;
146 if (c != 'e') {
147 (void) putchar(c);
148 continue;
149 }
150 if (match("error(")) {
151 (void) printf(gettext("error("));
152 c = getchar();
153 if (c != '"')
154 (void) putchar(c);
155 else
156 copystr();
157 }
158 }
159 }
160
161 static int
match(char * ocp)162 match(char *ocp)
163 {
164 char *cp;
165 int c;
166
167 for (cp = ocp + 1; *cp; cp++) {
168 c = getchar();
169 if (c != *cp) {
170 while (ocp < cp)
171 (void) putchar(*ocp++);
172 (void) ungetchar(c);
173 return (0);
174 }
175 }
176 return (1);
177 }
178
179 static void
copystr(void)180 copystr(void)
181 {
182 int c, ch;
183 char buf[512];
184 char *cp = buf;
185
186 for (;;) {
187 c = getchar();
188 if (c == EOF)
189 break;
190 switch (c) {
191
192 case '"':
193 *cp++ = 0;
194 goto out;
195 case '\\':
196 c = getchar();
197 switch (c) {
198
199 case 'b':
200 c = '\b';
201 break;
202 case 't':
203 c = '\t';
204 break;
205 case 'r':
206 c = '\r';
207 break;
208 case 'n':
209 c = '\n';
210 break;
211 case '\n':
212 continue;
213 case 'f':
214 c = '\f';
215 break;
216 case '0':
217 c = 0;
218 break;
219 case '\\':
220 break;
221 default:
222 if (!octdigit(c))
223 break;
224 c -= '0';
225 ch = getchar();
226 if (!octdigit(ch))
227 break;
228 c <<= 7, c += ch - '0';
229 ch = getchar();
230 if (!octdigit(ch))
231 break;
232 c <<= 3, c += ch - '0', ch = -1;
233 break;
234 }
235 }
236 *cp++ = c;
237 }
238 out:
239 *cp = 0;
240 (void) printf("%d", hashit(buf, 1, NULL));
241 }
242
243 static int
octdigit(char c)244 octdigit(char c)
245 {
246
247 return (c >= '0' && c <= '7');
248 }
249
250 static void
inithash(void)251 inithash(void)
252 {
253 char buf[512];
254 int mesgpt = 0;
255
256 rewind(mesgread);
257 while (fgetNUL(buf, sizeof (buf), mesgread) != NULL) {
258 (void) hashit(buf, 0, mesgpt);
259 mesgpt += strlen(buf) + 2;
260 }
261 }
262
263 static struct hash {
264 long hval;
265 unsigned int hpt;
266 struct hash *hnext;
267 } *bucket[NBUCKETS];
268
269 static int
hashit(char * str,char really,unsigned int fakept)270 hashit(char *str, char really, unsigned int fakept)
271 {
272 int i;
273 struct hash *hp;
274 char buf[512];
275 long hashval = 0;
276 char *cp;
277
278 if (really)
279 (void) fflush(mesgwrite);
280 for (cp = str; *cp; )
281 hashval = (hashval << 1) + *cp++;
282 i = hashval % NBUCKETS;
283 if (i < 0)
284 i += NBUCKETS;
285 if (really != 0)
286 for (hp = bucket[i]; hp != 0; hp = hp->hnext)
287 if (hp->hval == hashval) {
288 (void) fseek(mesgread, (long)hp->hpt, 0);
289 (void) fgetNUL(buf, sizeof (buf), mesgread);
290 if (strcmp(buf, str) == 0)
291 break;
292 }
293 if (!really || hp == 0) {
294 hp = (struct hash *)calloc(1, sizeof (*hp));
295 hp->hnext = bucket[i];
296 hp->hval = hashval;
297 hp->hpt = really ? ftell(mesgwrite) : fakept;
298 if (really) {
299 (void) fwrite(str, sizeof (char), strlen(str) + 1,
300 mesgwrite);
301 (void) fwrite("\n", sizeof (char), 1, mesgwrite);
302 }
303 bucket[i] = hp;
304 }
305 return (hp->hpt);
306 }
307
308 static int
fgetNUL(char * obuf,int rmdr,FILE * file)309 fgetNUL(char *obuf, int rmdr, FILE *file)
310 {
311 int c;
312 char *buf = obuf;
313
314 while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF)
315 *buf++ = c;
316 *buf++ = 0;
317 (void) getc(file);
318 return ((feof(file) || ferror(file)) ? NULL : 1);
319 }
320