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