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