386BSD 0.1 development
[unix-history] / usr / src / usr.bin / xstr / xstr.c
CommitLineData
30885fad
WJ
1/*
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35char copyright[] =
36"@(#) Copyright (c) 1980 The Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)xstr.c 5.7 (Berkeley) 2/26/91";
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <signal.h>
46#include <errno.h>
47#include <unistd.h>
48#include <stdio.h>
49#include <ctype.h>
50#include <string.h>
51#include "pathnames.h"
52
53/*
54 * xstr - extract and hash strings in a C program
55 *
56 * Bill Joy UCB
57 * November, 1978
58 */
59
60#define ignore(a) ((void) a)
61
62off_t tellpt;
63off_t hashit();
64void onintr();
65char *savestr();
66off_t yankstr();
67
68off_t mesgpt;
69char *strings = "strings";
70
71int cflg;
72int vflg;
73int readstd;
74
75main(argc, argv)
76 int argc;
77 char *argv[];
78{
79
80 argc--, argv++;
81 while (argc > 0 && argv[0][0] == '-') {
82 register char *cp = &(*argv++)[1];
83
84 argc--;
85 if (*cp == 0) {
86 readstd++;
87 continue;
88 }
89 do switch (*cp++) {
90
91 case 'c':
92 cflg++;
93 continue;
94
95 case 'v':
96 vflg++;
97 continue;
98
99 default:
100 fprintf(stderr, "usage: xstr [ -v ] [ -c ] [ - ] [ name ... ]\n");
101 } while (*cp);
102 }
103 if (signal(SIGINT, SIG_IGN) == SIG_DFL)
104 signal(SIGINT, onintr);
105 if (cflg || argc == 0 && !readstd)
106 inithash();
107 else
108 strings = mktemp(strdup(_PATH_TMP));
109 while (readstd || argc > 0) {
110 if (freopen("x.c", "w", stdout) == NULL)
111 perror("x.c"), exit(1);
112 if (!readstd && freopen(argv[0], "r", stdin) == NULL)
113 perror(argv[0]), exit(2);
114 process("x.c");
115 if (readstd == 0)
116 argc--, argv++;
117 else
118 readstd = 0;
119 };
120 flushsh();
121 if (cflg == 0)
122 xsdotc();
123 if (strings[0] == '/')
124 ignore(unlink(strings));
125 exit(0);
126}
127
128char linebuf[BUFSIZ];
129
130process(name)
131 char *name;
132{
133 char *cp;
134 register int c;
135 register int incomm = 0;
136 int ret;
137
138 printf("extern char\txstr[];\n");
139 for (;;) {
140 if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
141 if (ferror(stdin)) {
142 perror(name);
143 exit(3);
144 }
145 break;
146 }
147 if (linebuf[0] == '#') {
148 if (linebuf[1] == ' ' && isdigit(linebuf[2]))
149 printf("#line%s", &linebuf[1]);
150 else
151 printf("%s", linebuf);
152 continue;
153 }
154 for (cp = linebuf; c = *cp++;) switch (c) {
155
156 case '"':
157 if (incomm)
158 goto def;
159 if ((ret = (int) yankstr(&cp)) == -1)
160 goto out;
161 printf("(&xstr[%d])", ret);
162 break;
163
164 case '\'':
165 if (incomm)
166 goto def;
167 putchar(c);
168 if (*cp)
169 putchar(*cp++);
170 break;
171
172 case '/':
173 if (incomm || *cp != '*')
174 goto def;
175 incomm = 1;
176 cp++;
177 printf("/*");
178 continue;
179
180 case '*':
181 if (incomm && *cp == '/') {
182 incomm = 0;
183 cp++;
184 printf("*/");
185 continue;
186 }
187 goto def;
188
189def:
190 default:
191 putchar(c);
192 break;
193 }
194 }
195out:
196 if (ferror(stdout))
197 perror("x.c"), onintr();
198}
199
200off_t
201yankstr(cpp)
202 register char **cpp;
203{
204 register char *cp = *cpp;
205 register int c, ch;
206 char dbuf[BUFSIZ];
207 register char *dp = dbuf;
208 register char *tp;
209
210 while (c = *cp++) {
211 switch (c) {
212
213 case '"':
214 cp++;
215 goto out;
216
217 case '\\':
218 c = *cp++;
219 if (c == 0)
220 break;
221 if (c == '\n') {
222 if (fgets(linebuf, sizeof linebuf, stdin)
223 == NULL) {
224 if (ferror(stdin)) {
225 perror("x.c");
226 exit(3);
227 }
228 return(-1);
229 }
230 cp = linebuf;
231 continue;
232 }
233 for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; ch = *tp++; tp++)
234 if (c == ch) {
235 c = *tp;
236 goto gotc;
237 }
238 if (!octdigit(c)) {
239 *dp++ = '\\';
240 break;
241 }
242 c -= '0';
243 if (!octdigit(*cp))
244 break;
245 c <<= 3, c += *cp++ - '0';
246 if (!octdigit(*cp))
247 break;
248 c <<= 3, c += *cp++ - '0';
249 break;
250 }
251gotc:
252 *dp++ = c;
253 }
254out:
255 *cpp = --cp;
256 *dp = 0;
257 return (hashit(dbuf, 1));
258}
259
260octdigit(c)
261 char c;
262{
263
264 return (isdigit(c) && c != '8' && c != '9');
265}
266
267inithash()
268{
269 char buf[BUFSIZ];
270 register FILE *mesgread = fopen(strings, "r");
271
272 if (mesgread == NULL)
273 return;
274 for (;;) {
275 mesgpt = tellpt;
276 if (fgetNUL(buf, sizeof buf, mesgread) == NULL)
277 break;
278 ignore(hashit(buf, 0));
279 }
280 ignore(fclose(mesgread));
281}
282
283fgetNUL(obuf, rmdr, file)
284 char *obuf;
285 register int rmdr;
286 FILE *file;
287{
288 register c;
289 register char *buf = obuf;
290
291 while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
292 *buf++ = c;
293 *buf++ = 0;
294 return ((feof(file) || ferror(file)) ? NULL : 1);
295}
296
297xgetc(file)
298 FILE *file;
299{
300
301 tellpt++;
302 return (getc(file));
303}
304
305#define BUCKETS 128
306
307struct hash {
308 off_t hpt;
309 char *hstr;
310 struct hash *hnext;
311 short hnew;
312} bucket[BUCKETS];
313
314off_t
315hashit(str, new)
316 char *str;
317 int new;
318{
319 int i;
320 register struct hash *hp, *hp0;
321
322 hp = hp0 = &bucket[lastchr(str) & 0177];
323 while (hp->hnext) {
324 hp = hp->hnext;
325 i = istail(str, hp->hstr);
326 if (i >= 0)
327 return (hp->hpt + i);
328 }
329 if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL) {
330 perror("xstr");
331 exit(8);
332 }
333 hp->hpt = mesgpt;
334 if (!(hp->hstr = strdup(str))) {
335 (void)fprintf(stderr, "xstr: %s\n", strerror(errno));
336 exit(1);
337 }
338 mesgpt += strlen(hp->hstr) + 1;
339 hp->hnext = hp0->hnext;
340 hp->hnew = new;
341 hp0->hnext = hp;
342 return (hp->hpt);
343}
344
345flushsh()
346{
347 register int i;
348 register struct hash *hp;
349 register FILE *mesgwrit;
350 register int old = 0, new = 0;
351
352 for (i = 0; i < BUCKETS; i++)
353 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
354 if (hp->hnew)
355 new++;
356 else
357 old++;
358 if (new == 0 && old != 0)
359 return;
360 mesgwrit = fopen(strings, old ? "r+" : "w");
361 if (mesgwrit == NULL)
362 perror(strings), exit(4);
363 for (i = 0; i < BUCKETS; i++)
364 for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
365 found(hp->hnew, hp->hpt, hp->hstr);
366 if (hp->hnew) {
367 fseek(mesgwrit, hp->hpt, 0);
368 ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
369 if (ferror(mesgwrit))
370 perror(strings), exit(4);
371 }
372 }
373 if (fclose(mesgwrit) == EOF)
374 perror(strings), exit(4);
375}
376
377found(new, off, str)
378 int new;
379 off_t off;
380 char *str;
381{
382 if (vflg == 0)
383 return;
384 if (!new)
385 fprintf(stderr, "found at %d:", (int) off);
386 else
387 fprintf(stderr, "new at %d:", (int) off);
388 prstr(str);
389 fprintf(stderr, "\n");
390}
391
392prstr(cp)
393 register char *cp;
394{
395 register int c;
396
397 while (c = (*cp++ & 0377))
398 if (c < ' ')
399 fprintf(stderr, "^%c", c + '`');
400 else if (c == 0177)
401 fprintf(stderr, "^?");
402 else if (c > 0200)
403 fprintf(stderr, "\\%03o", c);
404 else
405 fprintf(stderr, "%c", c);
406}
407
408xsdotc()
409{
410 register FILE *strf = fopen(strings, "r");
411 register FILE *xdotcf;
412
413 if (strf == NULL)
414 perror(strings), exit(5);
415 xdotcf = fopen("xs.c", "w");
416 if (xdotcf == NULL)
417 perror("xs.c"), exit(6);
418 fprintf(xdotcf, "char\txstr[] = {\n");
419 for (;;) {
420 register int i, c;
421
422 for (i = 0; i < 8; i++) {
423 c = getc(strf);
424 if (ferror(strf)) {
425 perror(strings);
426 onintr();
427 }
428 if (feof(strf)) {
429 fprintf(xdotcf, "\n");
430 goto out;
431 }
432 fprintf(xdotcf, "0x%02x,", c);
433 }
434 fprintf(xdotcf, "\n");
435 }
436out:
437 fprintf(xdotcf, "};\n");
438 ignore(fclose(xdotcf));
439 ignore(fclose(strf));
440}
441
442lastchr(cp)
443 register char *cp;
444{
445
446 while (cp[0] && cp[1])
447 cp++;
448 return (*cp);
449}
450
451istail(str, of)
452 register char *str, *of;
453{
454 register int d = strlen(of) - strlen(str);
455
456 if (d < 0 || strcmp(&of[d], str) != 0)
457 return (-1);
458 return (d);
459}
460
461void
462onintr()
463{
464
465 ignore(signal(SIGINT, SIG_IGN));
466 if (strings[0] == '/')
467 ignore(unlink(strings));
468 ignore(unlink("x.c"));
469 ignore(unlink("xs.c"));
470 exit(7);
471}