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