1 /*
2 * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
8
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15 #include <stdio.h>
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 /*
24 * xstr - extract and hash strings in a C program
25 *
26 * Bill Joy UCB
27 * November, 1978
28 */
29
30 off_t tellpt;
31 off_t hashit(char *, int);
32 void onintr(void);
33 char *savestr(char *);
34 off_t yankstr(char **);
35 void cleanup(void);
36 void process(char *);
37 int octdigit(char);
38 void inithash(void);
39 void flushsh(void);
40 void found(int, off_t, char *);
41 void prstr(char *);
42 void xsdotc(void);
43 int fgetNUL(char *, int, FILE *);
44 int xgetc(FILE *);
45 int lastchr(char *);
46 int istail(char *, char *);
47
48 off_t mesgpt;
49 char *strings = "strings";
50
51 int cflg;
52 int vflg;
53 char *xname = "xstr";
54 int readstd;
55 int tmpfd;
56
57 int
main(int argc,char ** argv)58 main(int argc, char **argv)
59 {
60 argc--, argv++;
61 while (argc > 0 && argv[0][0] == '-') {
62 char *cp = &(*argv++)[1];
63
64 argc--;
65 if (*cp == 0) {
66 readstd++;
67 continue;
68 }
69 do switch (*cp++) {
70
71 case 'c':
72 cflg++;
73 continue;
74
75 case 'l':
76 xname = *argv++;
77 argc--;
78 continue;
79
80 case 'v':
81 vflg++;
82 continue;
83
84 default:
85 (void) fprintf(stderr,
86 "usage: xstr [ -v ] [ -c ] [ -l label ] [ - ] [ name ... ]\n");
87 } while (*cp);
88 }
89 if (signal(SIGINT, SIG_IGN) == SIG_DFL)
90 (void) signal(SIGINT, (void (*)(int))onintr);
91 if (cflg || argc == 0 && !readstd)
92 inithash();
93 else {
94 strings = savestr("/tmp/xstrXXXXXX");
95 tmpfd = mkstemp(strings);
96 if (tmpfd == -1) {
97 perror(strings);
98 (void) free(strings);
99 exit(9);
100 }
101 (void) close(tmpfd);
102 }
103 while (readstd || argc > 0) {
104 if (freopen("x.c", "w", stdout) == NULL)
105 perror("x.c"), (void) cleanup(), exit(1);
106 if (!readstd && freopen(argv[0], "r", stdin) == NULL)
107 perror(argv[0]), (void) cleanup(), exit(2);
108 process("x.c");
109 if (readstd == 0)
110 argc--, argv++;
111 else
112 readstd = 0;
113 }
114 flushsh();
115 if (cflg == 0)
116 xsdotc();
117 (void) cleanup();
118 return (0);
119 }
120
121 char linebuf[BUFSIZ];
122
123 void
process(char * name)124 process(char *name)
125 {
126 char *cp;
127 int c;
128 int incomm = 0;
129 int ret;
130
131 (void) printf("extern char\t%s[];\n", xname);
132 for (;;) {
133 if (fgets(linebuf, sizeof (linebuf), stdin) == NULL) {
134 if (ferror(stdin)) {
135 perror(name);
136 (void) cleanup();
137 exit(3);
138 }
139 break;
140 }
141 if (linebuf[0] == '#') {
142 if (linebuf[1] == ' ' && isdigit(linebuf[2]))
143 (void) printf("#line%s", &linebuf[1]);
144 else
145 (void) printf("%s", linebuf);
146 continue;
147 }
148 for (cp = linebuf; (c = *cp++) != 0; ) {
149 switch (c) {
150 case '"':
151 if (incomm)
152 goto def;
153 if ((ret = (int)yankstr(&cp)) == -1)
154 goto out;
155 (void) printf("(&%s[%d])", xname, ret);
156 break;
157
158 case '\'':
159 if (incomm)
160 goto def;
161 (void) putchar(c);
162 if (*cp)
163 (void) putchar(*cp++);
164 break;
165
166 case '/':
167 if (incomm || *cp != '*')
168 goto def;
169 incomm = 1;
170 cp++;
171 (void) printf("/*");
172 continue;
173
174 case '*':
175 if (incomm && *cp == '/') {
176 incomm = 0;
177 cp++;
178 (void) printf("*/");
179 continue;
180 }
181 goto def;
182 def:
183 default:
184 (void) putchar(c);
185 break;
186 }
187 }
188 }
189 out:
190 if (ferror(stdout))
191 perror("x.c"), onintr();
192 }
193
194 off_t
yankstr(char ** cpp)195 yankstr(char **cpp)
196 {
197 char *cp = *cpp;
198 int c, ch;
199 char dbuf[BUFSIZ];
200 char *dp = dbuf;
201 char *tp;
202
203 while ((c = *cp++) != 0) {
204 switch (c) {
205
206 case '"':
207 cp++;
208 goto out;
209
210 case '\\':
211 c = *cp++;
212 if (c == 0)
213 break;
214 if (c == '\n') {
215 if (fgets(linebuf, sizeof (linebuf), stdin)
216 == NULL) {
217 if (ferror(stdin)) {
218 perror("x.c");
219 (void) cleanup();
220 exit(3);
221 }
222 return (-1);
223
224 }
225 cp = linebuf;
226 continue;
227 }
228 for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++) != 0;
229 tp++)
230 if (c == ch) {
231 c = *tp;
232 goto gotc;
233 }
234 if (!octdigit(c)) {
235 *dp++ = '\\';
236 break;
237 }
238 c -= '0';
239 if (!octdigit(*cp))
240 break;
241 c <<= 3, c += *cp++ - '0';
242 if (!octdigit(*cp))
243 break;
244 c <<= 3, c += *cp++ - '0';
245 break;
246 }
247 gotc:
248 *dp++ = c;
249 }
250 out:
251 *cpp = --cp;
252 *dp = 0;
253 return (hashit(dbuf, 1));
254 }
255
256 int
octdigit(char c)257 octdigit(char c)
258 {
259
260 return (isdigit(c) && c != '8' && c != '9');
261 }
262
263 void
inithash(void)264 inithash(void)
265 {
266 char buf[BUFSIZ];
267 FILE *mesgread = fopen(strings, "r");
268
269 if (mesgread == NULL)
270 return;
271 for (;;) {
272 mesgpt = tellpt;
273 if (fgetNUL(buf, sizeof (buf), mesgread) == 0)
274 break;
275 (void) hashit(buf, 0);
276 }
277 (void) fclose(mesgread);
278 }
279
280 int
fgetNUL(char * obuf,int rmdr,FILE * file)281 fgetNUL(char *obuf, int rmdr, FILE *file)
282 {
283 int c;
284 char *buf = obuf;
285
286 while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
287 *buf++ = c;
288 *buf++ = 0;
289 return ((feof(file) || ferror(file)) ? 0 : 1);
290 }
291
292 int
xgetc(FILE * file)293 xgetc(FILE *file)
294 {
295
296 tellpt++;
297 return (getc(file));
298 }
299
300 #define BUCKETS 128
301
302 struct hash {
303 off_t hpt;
304 char *hstr;
305 struct hash *hnext;
306 short hnew;
307 } bucket[BUCKETS];
308
309 off_t
hashit(char * str,int new)310 hashit(char *str, int new)
311 {
312 int i;
313 struct hash *hp, *hp0;
314
315 hp = hp0 = &bucket[lastchr(str) & 0177];
316 while (hp->hnext) {
317 hp = hp->hnext;
318 i = istail(str, hp->hstr);
319 if (i >= 0)
320 return (hp->hpt + i);
321 }
322 if ((hp = calloc(1, sizeof (*hp))) == NULL) {
323 perror("xstr");
324 (void) cleanup();
325 exit(8);
326 }
327 hp->hpt = mesgpt;
328 hp->hstr = savestr(str);
329 mesgpt += strlen(hp->hstr) + 1;
330 hp->hnext = hp0->hnext;
331 hp->hnew = new;
332 hp0->hnext = hp;
333 return (hp->hpt);
334 }
335
336 void
flushsh(void)337 flushsh(void)
338 {
339 int i;
340 struct hash *hp;
341 FILE *mesgwrit;
342 int old = 0, new = 0;
343
344 for (i = 0; i < BUCKETS; i++)
345 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
346 if (hp->hnew)
347 new++;
348 else
349 old++;
350 if (new == 0 && old != 0)
351 return;
352 mesgwrit = fopen(strings, old ? "r+" : "w");
353 if (mesgwrit == NULL)
354 perror(strings), (void) cleanup(), exit(4);
355 for (i = 0; i < BUCKETS; i++)
356 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
357 found(hp->hnew, hp->hpt, hp->hstr);
358 if (hp->hnew) {
359 (void) fseek(mesgwrit, hp->hpt, 0);
360 (void) fwrite(hp->hstr,
361 strlen(hp->hstr) + 1, 1, mesgwrit);
362 if (ferror(mesgwrit)) {
363 perror(strings);
364 (void) cleanup();
365 exit(4);
366 }
367 }
368 }
369 if (fclose(mesgwrit) == EOF)
370 perror(strings), (void) cleanup(), exit(4);
371 }
372
373 void
found(int new,off_t off,char * str)374 found(int new, off_t off, char *str)
375 {
376 if (vflg == 0)
377 return;
378 if (!new)
379 (void) fprintf(stderr, "found at %d:", (int)off);
380 else
381 (void) fprintf(stderr, "new at %d:", (int)off);
382 prstr(str);
383 (void) fprintf(stderr, "\n");
384 }
385
386 void
prstr(char * cp)387 prstr(char *cp)
388 {
389 int c;
390
391 while ((c = (*cp++ & 0377)) != 0)
392 if (c < ' ')
393 (void) fprintf(stderr, "^%c", c + '`');
394 else if (c == 0177)
395 (void) fprintf(stderr, "^?");
396 else if (c > 0200)
397 (void) fprintf(stderr, "\\%03o", c);
398 else
399 (void) fprintf(stderr, "%c", c);
400 }
401
402 void
xsdotc(void)403 xsdotc(void)
404 {
405 FILE *strf = fopen(strings, "r");
406 FILE *xdotcf;
407
408 if (strf == NULL)
409 perror(strings), exit(5);
410 xdotcf = fopen("xs.c", "w");
411 if (xdotcf == NULL)
412 perror("xs.c"), exit(6);
413 (void) fprintf(xdotcf, "char\t%s[] = {\n", xname);
414 for (;;) {
415 int i, c;
416
417 for (i = 0; i < 8; i++) {
418 c = getc(strf);
419 if (ferror(strf)) {
420 perror(strings);
421 onintr();
422 }
423 if (feof(strf)) {
424 (void) fprintf(xdotcf, "\n");
425 goto out;
426 }
427 (void) fprintf(xdotcf, "0x%02x,", c);
428 }
429 (void) fprintf(xdotcf, "\n");
430 }
431 out:
432 (void) fprintf(xdotcf, "};\n");
433 (void) fclose(xdotcf);
434 (void) fclose(strf);
435 }
436
437 char *
savestr(char * cp)438 savestr(char *cp)
439 {
440 char *dp;
441
442 if ((dp = calloc(1, strlen(cp) + 1)) == NULL) {
443 perror("xstr");
444 exit(8);
445 }
446 return (strcpy(dp, cp));
447 }
448
449 int
lastchr(char * cp)450 lastchr(char *cp)
451 {
452
453 while (cp[0] && cp[1])
454 cp++;
455 return ((int)*cp);
456 }
457
458 int
istail(char * str,char * of)459 istail(char *str, char *of)
460 {
461 int d = strlen(of) - strlen(str);
462
463 if (d < 0 || strcmp(&of[d], str) != 0)
464 return (-1);
465 return (d);
466 }
467
468 void
onintr(void)469 onintr(void)
470 {
471
472 (void) signal(SIGINT, SIG_IGN);
473 (void) cleanup();
474 (void) unlink("x.c");
475 (void) unlink("xs.c");
476 exit(7);
477 }
478
479 void
cleanup(void)480 cleanup(void)
481 {
482 if (strings[0] == '/') {
483 (void) unlink(strings);
484 }
485 }
486