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