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