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