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