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