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