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