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