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