lcc.c (19499B)
1 /* 2 * lcc [ option ]... [ file | -llib ]... 3 * front end for the ANSI C compiler 4 */ 5 static char rcsid[] = "Id: dummy rcsid"; 6 7 #include <stdio.h> 8 #include <stdarg.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <assert.h> 12 #include <ctype.h> 13 #include <signal.h> 14 15 #ifndef TEMPDIR 16 #define TEMPDIR "/tmp" 17 #endif 18 19 typedef struct list *List; 20 struct list { /* circular list nodes: */ 21 char *str; /* option or file name */ 22 List link; /* next list element */ 23 }; 24 25 static void *alloc(int); 26 static List append(char *,List); 27 extern char *basepath(char *); 28 static int callsys(char *[]); 29 extern char *concat(char *, char *); 30 static int compile(char *, char *); 31 static void compose(char *[], List, List, List); 32 static void error(char *, char *); 33 static char *exists(char *); 34 static char *first(char *); 35 static int filename(char *, char *); 36 static List find(char *, List); 37 static void help(void); 38 static void initinputs(void); 39 static void interrupt(int); 40 static void opt(char *); 41 static List path2list(const char *); 42 extern int main(int, char *[]); 43 extern char *replace(const char *, int, int); 44 static void rm(List); 45 extern char *strsave(const char *); 46 extern char *stringf(const char *, ...); 47 extern int suffix(char *, char *[], int); 48 extern char *tempname(char *); 49 50 extern int access(char *, int); 51 extern int getpid(void); 52 53 extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[]; 54 extern int option(char *); 55 56 static int errcnt; /* number of errors */ 57 static int Eflag; /* -E specified */ 58 static int Sflag; /* -S specified */ 59 static int cflag; /* -c specified */ 60 static int verbose; /* incremented for each -v */ 61 static List llist[2]; /* loader files, flags */ 62 static List alist; /* assembler flags */ 63 static List clist; /* compiler flags */ 64 static List plist; /* preprocessor flags */ 65 static List ilist; /* list of additional includes from LCCINPUTS */ 66 static List rmlist; /* list of files to remove */ 67 static char *outfile; /* ld output file or -[cS] object file */ 68 static int ac; /* argument count */ 69 static char **av; /* argument vector */ 70 char *tempdir = TEMPDIR; /* directory for temporary files */ 71 static char *progname; 72 static List lccinputs; /* list of input directories */ 73 74 main(int argc, char *argv[]) { 75 int i, j, nf; 76 77 progname = argv[0]; 78 ac = argc + 50; 79 av = alloc(ac*sizeof(char *)); 80 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 81 signal(SIGINT, interrupt); 82 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 83 signal(SIGTERM, interrupt); 84 #ifdef SIGHUP 85 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 86 signal(SIGHUP, interrupt); 87 #endif 88 if (getenv("TMP")) 89 tempdir = getenv("TMP"); 90 else if (getenv("TEMP")) 91 tempdir = getenv("TEMP"); 92 else if (getenv("TMPDIR")) 93 tempdir = getenv("TMPDIR"); 94 assert(tempdir); 95 i = strlen(tempdir); 96 for (; i > 0 && tempdir[i-1] == '/' || tempdir[i-1] == '\\'; i--) 97 tempdir[i-1] = '\0'; 98 if (argc <= 1) { 99 help(); 100 exit(0); 101 } 102 plist = append("-D__LCC__", 0); 103 initinputs(); 104 if (getenv("LCCDIR")) 105 option(stringf("-lccdir=%s", getenv("LCCDIR"))); 106 for (nf = 0, i = j = 1; i < argc; i++) { 107 if (strcmp(argv[i], "-o") == 0) { 108 if (++i < argc) { 109 if (suffix(argv[i], suffixes, 2) >= 0) { 110 error("-o would overwrite %s", argv[i]); 111 exit(8); 112 } 113 outfile = argv[i]; 114 continue; 115 } else { 116 error("unrecognized option `%s'", argv[i-1]); 117 exit(8); 118 } 119 } else if (strcmp(argv[i], "-target") == 0) { 120 if (argv[i+1] && *argv[i+1] != '-') 121 i++; 122 continue; 123 } else if (*argv[i] == '-' && argv[i][1] != 'l') { 124 opt(argv[i]); 125 continue; 126 } else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0) 127 nf++; 128 argv[j++] = argv[i]; 129 } 130 if ((cflag || Sflag) && outfile && nf != 1) { 131 fprintf(stderr, "%s: -o %s ignored\n", progname, outfile); 132 outfile = 0; 133 } 134 argv[j] = 0; 135 for (i = 0; include[i]; i++) 136 plist = append(include[i], plist); 137 if (ilist) { 138 List b = ilist; 139 do { 140 b = b->link; 141 plist = append(b->str, plist); 142 } while (b != ilist); 143 } 144 ilist = 0; 145 for (i = 1; argv[i]; i++) 146 if (*argv[i] == '-') 147 opt(argv[i]); 148 else { 149 char *name = exists(argv[i]); 150 if (name) { 151 if (strcmp(name, argv[i]) != 0 152 || nf > 1 && suffix(name, suffixes, 3) >= 0) 153 fprintf(stderr, "%s:\n", name); 154 filename(name, 0); 155 } else 156 error("can't find `%s'", argv[i]); 157 } 158 if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) { 159 compose(ld, llist[0], llist[1], 160 append(outfile ? outfile : concat("a", first(suffixes[4])), 0)); 161 if (callsys(av)) 162 errcnt++; 163 } 164 rm(rmlist); 165 return errcnt ? EXIT_FAILURE : EXIT_SUCCESS; 166 } 167 168 /* alloc - allocate n bytes or die */ 169 static void *alloc(int n) { 170 static char *avail, *limit; 171 172 n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1); 173 if (n >= limit - avail) { 174 avail = malloc(n + 4*1024); 175 assert(avail); 176 limit = avail + n + 4*1024; 177 } 178 avail += n; 179 return avail - n; 180 } 181 182 /* append - append a node with string str onto list, return new list */ 183 static List append(char *str, List list) { 184 List p = alloc(sizeof *p); 185 186 p->str = str; 187 if (list) { 188 p->link = list->link; 189 list->link = p; 190 } else 191 p->link = p; 192 return p; 193 } 194 195 /* basepath - return base name for name, e.g. /usr/drh/foo.c => foo */ 196 char *basepath(char *name) { 197 char *s, *b, *t = 0; 198 199 for (b = s = name; *s; s++) 200 if (*s == '/' || *s == '\\') { 201 b = s + 1; 202 t = 0; 203 } else if (*s == '.') 204 t = s; 205 s = strsave(b); 206 if (t) 207 s[t-b] = 0; 208 return s; 209 } 210 211 #ifdef WIN32 212 #include <process.h> 213 #else 214 #define _P_WAIT 0 215 extern int fork(void); 216 extern int wait(int *); 217 extern void execv(const char *, char *[]); 218 219 static int _spawnvp(int mode, const char *cmdname, char *argv[]) { 220 int pid, n, status; 221 222 switch (pid = fork()) { 223 case -1: 224 fprintf(stderr, "%s: no more processes\n", progname); 225 return 100; 226 case 0: 227 // TTimo removing hardcoded paths, searching in $PATH 228 execvp(cmdname, argv); 229 fprintf(stderr, "%s: ", progname); 230 perror(cmdname); 231 fflush(stdout); 232 exit(100); 233 } 234 while ((n = wait(&status)) != pid && n != -1) 235 ; 236 if (n == -1) 237 status = -1; 238 if (status&0377) { 239 fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname); 240 status |= 0400; 241 } 242 return (status>>8)&0377; 243 } 244 #endif 245 246 /* callsys - execute the command described by av[0...], return status */ 247 static int callsys(char **av) { 248 int i, status = 0; 249 static char **argv; 250 static int argc; 251 252 for (i = 0; av[i] != NULL; i++) 253 ; 254 if (i + 1 > argc) { 255 argc = i + 1; 256 if (argv == NULL) 257 argv = malloc(argc*sizeof *argv); 258 else 259 argv = realloc(argv, argc*sizeof *argv); 260 assert(argv); 261 } 262 for (i = 0; status == 0 && av[i] != NULL; ) { 263 int j = 0; 264 char *s; 265 for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++) 266 argv[j++] = av[i]; 267 if (s != NULL) { 268 if (s > av[i]) 269 argv[j++] = stringf("%.*s", s - av[i], av[i]); 270 if (s[1] != '\0') 271 av[i] = s + 1; 272 else 273 i++; 274 } 275 argv[j] = NULL; 276 if (verbose > 0) { 277 int k; 278 fprintf(stderr, "%s", argv[0]); 279 for (k = 1; argv[k] != NULL; k++) 280 fprintf(stderr, " %s", argv[k]); 281 fprintf(stderr, "\n"); 282 } 283 if (verbose < 2) 284 status = _spawnvp(_P_WAIT, argv[0], argv); 285 if (status == -1) { 286 fprintf(stderr, "%s: ", progname); 287 perror(argv[0]); 288 } 289 } 290 return status; 291 } 292 293 /* concat - return concatenation of strings s1 and s2 */ 294 char *concat(char *s1, char *s2) { 295 int n = strlen(s1); 296 char *s = alloc(n + strlen(s2) + 1); 297 298 strcpy(s, s1); 299 strcpy(s + n, s2); 300 return s; 301 } 302 303 /* compile - compile src into dst, return status */ 304 static int compile(char *src, char *dst) { 305 compose(com, clist, append(src, 0), append(dst, 0)); 306 return callsys(av); 307 } 308 309 /* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */ 310 static void compose(char *cmd[], List a, List b, List c) { 311 int i, j; 312 List lists[3]; 313 314 lists[0] = a; 315 lists[1] = b; 316 lists[2] = c; 317 for (i = j = 0; cmd[i]; i++) { 318 char *s = strchr(cmd[i], '$'); 319 if (s && isdigit(s[1])) { 320 int k = s[1] - '0'; 321 assert(k >=1 && k <= 3); 322 if (b = lists[k-1]) { 323 b = b->link; 324 av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1); 325 strncpy(av[j], cmd[i], s - cmd[i]); 326 av[j][s-cmd[i]] = '\0'; 327 strcat(av[j], b->str); 328 strcat(av[j++], s + 2); 329 while (b != lists[k-1]) { 330 b = b->link; 331 assert(j < ac); 332 av[j++] = b->str; 333 }; 334 } 335 } else if (*cmd[i]) { 336 assert(j < ac); 337 av[j++] = cmd[i]; 338 } 339 } 340 av[j] = NULL; 341 } 342 343 /* error - issue error msg according to fmt, bump error count */ 344 static void error(char *fmt, char *msg) { 345 fprintf(stderr, "%s: ", progname); 346 fprintf(stderr, fmt, msg); 347 fprintf(stderr, "\n"); 348 errcnt++; 349 } 350 351 /* exists - if `name' readable return its path name or return null */ 352 static char *exists(char *name) { 353 List b; 354 355 if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':') 356 && access(name, 4) == 0) 357 return name; 358 if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':') 359 && (b = lccinputs)) 360 do { 361 b = b->link; 362 if (b->str[0]) { 363 char buf[1024]; 364 sprintf(buf, "%s/%s", b->str, name); 365 if (access(buf, 4) == 0) 366 return strsave(buf); 367 } else if (access(name, 4) == 0) 368 return name; 369 } while (b != lccinputs); 370 if (verbose > 1) 371 return name; 372 return 0; 373 } 374 375 /* first - return first component in semicolon separated list */ 376 static char *first(char *list) { 377 char *s = strchr(list, ';'); 378 379 if (s) { 380 char buf[1024]; 381 strncpy(buf, list, s-list); 382 buf[s-list] = '\0'; 383 return strsave(buf); 384 } else 385 return list; 386 } 387 388 /* filename - process file name argument `name', return status */ 389 static int filename(char *name, char *base) { 390 int status = 0; 391 static char *stemp, *itemp; 392 393 if (base == 0) 394 base = basepath(name); 395 switch (suffix(name, suffixes, 4)) { 396 case 0: /* C source files */ 397 compose(cpp, plist, append(name, 0), 0); 398 if (Eflag) { 399 status = callsys(av); 400 break; 401 } 402 if (itemp == NULL) 403 itemp = tempname(first(suffixes[1])); 404 compose(cpp, plist, append(name, 0), append(itemp, 0)); 405 status = callsys(av); 406 if (status == 0) 407 return filename(itemp, base); 408 break; 409 case 1: /* preprocessed source files */ 410 if (Eflag) 411 break; 412 if (Sflag) 413 status = compile(name, outfile ? outfile : concat(base, first(suffixes[2]))); 414 else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0) 415 return filename(stemp, base); 416 break; 417 case 2: /* assembly language files */ 418 if (Eflag) 419 break; 420 if (!Sflag) { 421 char *ofile; 422 if (cflag && outfile) 423 ofile = outfile; 424 else if (cflag) 425 ofile = concat(base, first(suffixes[3])); 426 else 427 ofile = tempname(first(suffixes[3])); 428 compose(as, alist, append(name, 0), append(ofile, 0)); 429 status = callsys(av); 430 if (!find(ofile, llist[1])) 431 llist[1] = append(ofile, llist[1]); 432 } 433 break; 434 case 3: /* object files */ 435 if (!find(name, llist[1])) 436 llist[1] = append(name, llist[1]); 437 break; 438 default: 439 if (Eflag) { 440 compose(cpp, plist, append(name, 0), 0); 441 status = callsys(av); 442 } 443 llist[1] = append(name, llist[1]); 444 break; 445 } 446 if (status) 447 errcnt++; 448 return status; 449 } 450 451 /* find - find 1st occurrence of str in list, return list node or 0 */ 452 static List find(char *str, List list) { 453 List b; 454 455 if (b = list) 456 do { 457 if (strcmp(str, b->str) == 0) 458 return b; 459 } while ((b = b->link) != list); 460 return 0; 461 } 462 463 /* help - print help message */ 464 static void help(void) { 465 static char *msgs[] = { 466 "", " [ option | file ]...\n", 467 " except for -l, options are processed left-to-right before files\n", 468 " unrecognized options are taken to be linker options\n", 469 "-A warn about nonANSI usage; 2nd -A warns more\n", 470 "-b emit expression-level profiling code; see bprint(1)\n", 471 #ifdef sparc 472 "-Bstatic -Bdynamic specify static or dynamic libraries\n", 473 #endif 474 "-Bdir/ use the compiler named `dir/rcc'\n", 475 "-c compile only\n", 476 "-dn set switch statement density to `n'\n", 477 "-Dname -Dname=def define the preprocessor symbol `name'\n", 478 "-E run only the preprocessor on the named C programs and unsuffixed files\n", 479 "-g produce symbol table information for debuggers\n", 480 "-help or -? print this message\n", 481 "-Idir add `dir' to the beginning of the list of #include directories\n", 482 "-lx search library `x'\n", 483 "-N do not search the standard directories for #include files\n", 484 "-n emit code to check for dereferencing zero pointers\n", 485 "-O is ignored\n", 486 "-o file leave the output in `file'\n", 487 "-P print ANSI-style declarations for globals\n", 488 "-p -pg emit profiling code; see prof(1) and gprof(1)\n", 489 "-S compile to assembly language\n", 490 #ifdef linux 491 "-static specify static libraries (default is dynamic)\n", 492 #endif 493 "-t -tname emit function tracing calls to printf or to `name'\n", 494 "-target name is ignored\n", 495 "-tempdir=dir place temporary files in `dir/'", "\n" 496 "-Uname undefine the preprocessor symbol `name'\n", 497 "-v show commands as they are executed; 2nd -v suppresses execution\n", 498 "-w suppress warnings\n", 499 "-Woarg specify system-specific `arg'\n", 500 "-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n", 501 0 }; 502 int i; 503 char *s; 504 505 msgs[0] = progname; 506 for (i = 0; msgs[i]; i++) { 507 fprintf(stderr, "%s", msgs[i]); 508 if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir) 509 fprintf(stderr, "; default=%s", tempdir); 510 } 511 #define xx(v) if (s = getenv(#v)) fprintf(stderr, #v "=%s\n", s) 512 xx(LCCINPUTS); 513 xx(LCCDIR); 514 #ifdef WIN32 515 xx(include); 516 xx(lib); 517 #endif 518 #undef xx 519 } 520 521 /* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */ 522 static void initinputs(void) { 523 char *s = getenv("LCCINPUTS"); 524 List list, b; 525 526 if (s == 0 || (s = inputs)[0] == 0) 527 s = "."; 528 if (s) { 529 lccinputs = path2list(s); 530 if (b = lccinputs) 531 do { 532 b = b->link; 533 if (strcmp(b->str, ".") != 0) { 534 ilist = append(concat("-I", b->str), ilist); 535 if (strstr(com[1], "win32") == NULL) 536 llist[0] = append(concat("-L", b->str), llist[0]); 537 } else 538 b->str = ""; 539 } while (b != lccinputs); 540 } 541 #ifdef WIN32 542 if (list = b = path2list(getenv("include"))) 543 do { 544 b = b->link; 545 ilist = append(stringf("-I\"%s\"", b->str), ilist); 546 } while (b != list); 547 #endif 548 } 549 550 /* interrupt - catch interrupt signals */ 551 static void interrupt(int n) { 552 rm(rmlist); 553 exit(n = 100); 554 } 555 556 /* opt - process option in arg */ 557 static void opt(char *arg) { 558 switch (arg[1]) { /* multi-character options */ 559 case 'W': /* -Wxarg */ 560 if (arg[2] && arg[3]) 561 switch (arg[2]) { 562 case 'o': 563 if (option(&arg[3])) 564 return; 565 break; 566 case 'p': 567 plist = append(&arg[3], plist); 568 return; 569 case 'f': 570 if (strcmp(&arg[3], "-C") || option("-b")) { 571 clist = append(&arg[3], clist); 572 return; 573 } 574 break; /* and fall thru */ 575 case 'a': 576 alist = append(&arg[3], alist); 577 return; 578 case 'l': 579 llist[0] = append(&arg[3], llist[0]); 580 return; 581 } 582 fprintf(stderr, "%s: %s ignored\n", progname, arg); 583 return; 584 case 'd': /* -dn */ 585 arg[1] = 's'; 586 clist = append(arg, clist); 587 return; 588 case 't': /* -t -tname -tempdir=dir */ 589 if (strncmp(arg, "-tempdir=", 9) == 0) 590 tempdir = arg + 9; 591 else 592 clist = append(arg, clist); 593 return; 594 case 'p': /* -p -pg */ 595 if (option(arg)) 596 clist = append(arg, clist); 597 else 598 fprintf(stderr, "%s: %s ignored\n", progname, arg); 599 return; 600 case 'D': /* -Dname -Dname=def */ 601 case 'U': /* -Uname */ 602 case 'I': /* -Idir */ 603 plist = append(arg, plist); 604 return; 605 case 'B': /* -Bdir -Bstatic -Bdynamic */ 606 #ifdef sparc 607 if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0) 608 llist[1] = append(arg, llist[1]); 609 else 610 #endif 611 { 612 static char *path; 613 if (path) 614 error("-B overwrites earlier option", 0); 615 path = arg + 2; 616 if (strstr(com[1], "win32") != NULL) 617 com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4]))); 618 else 619 com[0] = concat(path, "rcc"); 620 if (path[0] == 0) 621 error("missing directory in -B option", 0); 622 } 623 return; 624 case 'h': 625 if (strcmp(arg, "-help") == 0) { 626 static int printed = 0; 627 case '?': 628 if (!printed) 629 help(); 630 printed = 1; 631 return; 632 } 633 #ifdef linux 634 case 's': 635 if (strcmp(arg,"-static") == 0) { 636 if (!option(arg)) 637 fprintf(stderr, "%s: %s ignored\n", progname, arg); 638 return; 639 } 640 #endif 641 } 642 if (arg[2] == 0) 643 switch (arg[1]) { /* single-character options */ 644 case 'S': 645 Sflag++; 646 return; 647 case 'O': 648 fprintf(stderr, "%s: %s ignored\n", progname, arg); 649 return; 650 case 'A': case 'n': case 'w': case 'P': 651 clist = append(arg, clist); 652 return; 653 case 'g': case 'b': 654 if (option(arg)) 655 clist = append(arg[1] == 'g' ? "-g2" : arg, clist); 656 else 657 fprintf(stderr, "%s: %s ignored\n", progname, arg); 658 return; 659 case 'G': 660 if (option(arg)) { 661 clist = append("-g3", clist); 662 llist[0] = append("-N", llist[0]); 663 } else 664 fprintf(stderr, "%s: %s ignored\n", progname, arg); 665 return; 666 case 'E': 667 Eflag++; 668 return; 669 case 'c': 670 cflag++; 671 return; 672 case 'N': 673 if (strcmp(basepath(cpp[0]), "gcc-cpp") == 0) 674 plist = append("-nostdinc", plist); 675 include[0] = 0; 676 ilist = 0; 677 return; 678 case 'v': 679 if (verbose++ == 0) { 680 if (strcmp(basepath(cpp[0]), "gcc-cpp") == 0) 681 plist = append(arg, plist); 682 clist = append(arg, clist); 683 fprintf(stderr, "%s %s\n", progname, rcsid); 684 } 685 return; 686 } 687 if (cflag || Sflag || Eflag) 688 fprintf(stderr, "%s: %s ignored\n", progname, arg); 689 else 690 llist[1] = append(arg, llist[1]); 691 } 692 693 /* path2list - convert a colon- or semicolon-separated list to a list */ 694 static List path2list(const char *path) { 695 List list = NULL; 696 char sep = ':'; 697 698 if (path == NULL) 699 return NULL; 700 if (strchr(path, ';')) 701 sep = ';'; 702 while (*path) { 703 char *p, buf[512]; 704 if (p = strchr(path, sep)) { 705 assert(p - path < sizeof buf); 706 strncpy(buf, path, p - path); 707 buf[p-path] = '\0'; 708 } else { 709 assert(strlen(path) < sizeof buf); 710 strcpy(buf, path); 711 } 712 if (!find(buf, list)) 713 list = append(strsave(buf), list); 714 if (p == 0) 715 break; 716 path = p + 1; 717 } 718 return list; 719 } 720 721 /* replace - copy str, then replace occurrences of from with to, return the copy */ 722 char *replace(const char *str, int from, int to) { 723 char *s = strsave(str), *p = s; 724 725 for ( ; (p = strchr(p, from)) != NULL; p++) 726 *p = to; 727 return s; 728 } 729 730 /* rm - remove files in list */ 731 static void rm(List list) { 732 if (list) { 733 List b = list; 734 if (verbose) 735 fprintf(stderr, "rm"); 736 do { 737 if (verbose) 738 fprintf(stderr, " %s", b->str); 739 if (verbose < 2) 740 remove(b->str); 741 } while ((b = b->link) != list); 742 if (verbose) 743 fprintf(stderr, "\n"); 744 } 745 } 746 747 /* strsave - return a saved copy of string str */ 748 char *strsave(const char *str) { 749 return strcpy(alloc(strlen(str)+1), str); 750 } 751 752 /* stringf - format and return a string */ 753 char *stringf(const char *fmt, ...) { 754 char buf[1024]; 755 va_list ap; 756 int n; 757 758 va_start(ap, fmt); 759 n = vsprintf(buf, fmt, ap); 760 va_end(ap); 761 return strsave(buf); 762 } 763 764 /* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */ 765 int suffix(char *name, char *tails[], int n) { 766 int i, len = strlen(name); 767 768 for (i = 0; i < n; i++) { 769 char *s = tails[i], *t; 770 for ( ; t = strchr(s, ';'); s = t + 1) { 771 int m = t - s; 772 if (len > m && strncmp(&name[len-m], s, m) == 0) 773 return i; 774 } 775 if (*s) { 776 int m = strlen(s); 777 if (len > m && strncmp(&name[len-m], s, m) == 0) 778 return i; 779 } 780 } 781 return -1; 782 } 783 784 /* tempname - generate a temporary file name in tempdir with given suffix */ 785 char *tempname(char *suffix) { 786 static int n; 787 char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix); 788 789 if (strstr(com[1], "win32") != NULL) 790 name = replace(name, '/', '\\'); 791 rmlist = append(name, rmlist); 792 return name; 793 }