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