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