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