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