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