* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / lcc / etc / lcc.c
blob8595f2b061934c50132ca4948d6acb7a4f6a826f
1 /*
2 * lcc [ option ]... [ file | -llib ]...
3 * front end for the ANSI C compiler
4 */
5 static char rcsid[] = "Id: dummy rcsid";
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>
16 #ifndef TEMPDIR
17 #define TEMPDIR "/tmp"
18 #endif
20 typedef struct list *List;
21 struct list { /* circular list nodes: */
22 char *str; /* option or file name */
23 List link; /* next list element */
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 *);
51 #ifndef __sun
52 extern int getpid(void);
53 #endif
55 extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[];
56 extern int option(char *);
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 */
76 extern void UpdatePaths( const char *lccBinary );
78 int main(int argc, char *argv[]) {
79 int i, j, nf;
81 progname = argv[0];
83 UpdatePaths( progname );
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);
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);
120 outfile = argv[i];
121 continue;
122 } else {
123 error("unrecognized option `%s'", argv[i-1]);
124 exit(8);
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];
137 if ((cflag || Sflag) && outfile && nf != 1) {
138 fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
139 outfile = 0;
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);
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]);
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++;
171 rm(rmlist);
172 return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
175 /* alloc - allocate n bytes or die */
176 static void *alloc(int n) {
177 static char *avail, *limit;
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;
185 avail += n;
186 return avail - n;
189 /* append - append a node with string str onto list, return new list */
190 static List append(char *str, List list) {
191 List p = alloc(sizeof *p);
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;
202 /* basename - return base name for name, e.g. /usr/drh/foo.c => foo */
203 char *basename(char *name) {
204 char *s, *b, *t = 0;
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;
218 #ifdef WIN32
219 #include <process.h>
221 static char *escapeDoubleQuotes(const char *string) {
222 int stringLength = strlen(string);
223 int bufferSize = stringLength + 1;
224 int i, j;
225 char *newString;
227 if (string == NULL)
228 return NULL;
230 for (i = 0; i < stringLength; i++) {
231 if (string[i] == '"')
232 bufferSize++;
235 newString = (char*)malloc(bufferSize);
237 if (newString == NULL)
238 return NULL;
240 for (i = 0, j = 0; i < stringLength; i++) {
241 if (string[i] == '"')
242 newString[j++] = '\\';
244 newString[j++] = string[i];
247 newString[j] = '\0';
249 return newString;
252 static int spawn(const char *cmdname, char **argv) {
253 int argc = 0;
254 char **newArgv = argv;
255 int i;
256 intptr_t exitStatus;
258 // _spawnvp removes double quotes from arguments, so we
259 // have to escape them manually
260 while (*newArgv++ != NULL)
261 argc++;
263 newArgv = (char **)malloc(sizeof(char*) * (argc + 1));
265 for (i = 0; i < argc; i++)
266 newArgv[i] = escapeDoubleQuotes(argv[i]);
268 newArgv[argc] = NULL;
270 exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv);
272 for (i = 0; i < argc; i++)
273 free(newArgv[i]);
275 free(newArgv);
276 return exitStatus;
279 #else
281 #define _P_WAIT 0
282 #ifndef __sun
283 extern int fork(void);
284 #endif
285 extern int wait(int *);
287 static int spawn(const char *cmdname, char **argv) {
288 int pid, n, status;
290 switch (pid = fork()) {
291 case -1:
292 fprintf(stderr, "%s: no more processes\n", progname);
293 return 100;
294 case 0:
295 // TTimo removing hardcoded paths, searching in $PATH
296 execvp(cmdname, argv);
297 fprintf(stderr, "%s: ", progname);
298 perror(cmdname);
299 fflush(stdout);
300 exit(100);
302 while ((n = wait(&status)) != pid && n != -1)
304 if (n == -1)
305 status = -1;
306 if (status&0377) {
307 fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
308 status |= 0400;
310 return (status>>8)&0377;
312 #endif
314 /* callsys - execute the command described by av[0...], return status */
315 static int callsys(char **av) {
316 int i, status = 0;
317 static char **argv;
318 static int argc;
319 char *executable;
321 for (i = 0; av[i] != NULL; i++)
323 if (i + 1 > argc) {
324 argc = i + 1;
325 if (argv == NULL)
326 argv = malloc(argc*sizeof *argv);
327 else
328 argv = realloc(argv, argc*sizeof *argv);
329 assert(argv);
331 for (i = 0; status == 0 && av[i] != NULL; ) {
332 int j = 0;
333 char *s = NULL;
334 for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
335 argv[j++] = av[i];
336 if (s != NULL) {
337 if (s > av[i])
338 argv[j++] = stringf("%.*s", s - av[i], av[i]);
339 if (s[1] != '\0')
340 av[i] = s + 1;
341 else
342 i++;
344 argv[j] = NULL;
345 executable = strsave( argv[0] );
346 argv[0] = stringf( "\"%s\"", argv[0] );
347 if (verbose > 0) {
348 int k;
349 fprintf(stderr, "%s", argv[0]);
350 for (k = 1; argv[k] != NULL; k++)
351 fprintf(stderr, " %s", argv[k]);
352 fprintf(stderr, "\n");
354 if (verbose < 2)
355 status = spawn(executable, argv);
356 if (status == -1) {
357 fprintf(stderr, "%s: ", progname);
358 perror(argv[0]);
361 return status;
364 /* concat - return concatenation of strings s1 and s2 */
365 char *concat(char *s1, char *s2) {
366 int n = strlen(s1);
367 char *s = alloc(n + strlen(s2) + 1);
369 strcpy(s, s1);
370 strcpy(s + n, s2);
371 return s;
374 /* compile - compile src into dst, return status */
375 static int compile(char *src, char *dst) {
376 compose(com, clist, append(src, 0), append(dst, 0));
377 return callsys(av);
380 /* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
381 static void compose(char *cmd[], List a, List b, List c) {
382 int i, j;
383 List lists[3];
385 lists[0] = a;
386 lists[1] = b;
387 lists[2] = c;
388 for (i = j = 0; cmd[i]; i++) {
389 char *s = strchr(cmd[i], '$');
390 if (s && isdigit(s[1])) {
391 int k = s[1] - '0';
392 assert(k >=1 && k <= 3);
393 if ((b = lists[k-1])) {
394 b = b->link;
395 av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
396 strncpy(av[j], cmd[i], s - cmd[i]);
397 av[j][s-cmd[i]] = '\0';
398 strcat(av[j], b->str);
399 strcat(av[j++], s + 2);
400 while (b != lists[k-1]) {
401 b = b->link;
402 assert(j < ac);
403 av[j++] = b->str;
406 } else if (*cmd[i]) {
407 assert(j < ac);
408 av[j++] = cmd[i];
411 av[j] = NULL;
414 /* error - issue error msg according to fmt, bump error count */
415 static void error(char *fmt, char *msg) {
416 fprintf(stderr, "%s: ", progname);
417 fprintf(stderr, fmt, msg);
418 fprintf(stderr, "\n");
419 errcnt++;
422 /* exists - if `name' readable return its path name or return null */
423 static char *exists(char *name) {
424 List b;
426 if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':')
427 && access(name, 4) == 0)
428 return name;
429 if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
430 && (b = lccinputs))
431 do {
432 b = b->link;
433 if (b->str[0]) {
434 char buf[1024];
435 sprintf(buf, "%s/%s", b->str, name);
436 if (access(buf, 4) == 0)
437 return strsave(buf);
438 } else if (access(name, 4) == 0)
439 return name;
440 } while (b != lccinputs);
441 if (verbose > 1)
442 return name;
443 return 0;
446 /* first - return first component in semicolon separated list */
447 static char *first(char *list) {
448 char *s = strchr(list, ';');
450 if (s) {
451 char buf[1024];
452 strncpy(buf, list, s-list);
453 buf[s-list] = '\0';
454 return strsave(buf);
455 } else
456 return list;
459 /* filename - process file name argument `name', return status */
460 static int filename(char *name, char *base) {
461 int status = 0;
462 static char *stemp, *itemp;
464 if (base == 0)
465 base = basename(name);
466 switch (suffix(name, suffixes, 4)) {
467 case 0: /* C source files */
468 compose(cpp, plist, append(name, 0), 0);
469 if (Eflag) {
470 status = callsys(av);
471 break;
473 if (itemp == NULL)
474 itemp = tempname(first(suffixes[1]));
475 compose(cpp, plist, append(name, 0), append(itemp, 0));
476 status = callsys(av);
477 if (status == 0)
478 return filename(itemp, base);
479 break;
480 case 1: /* preprocessed source files */
481 if (Eflag)
482 break;
483 if (Sflag)
484 status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
485 else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0)
486 return filename(stemp, base);
487 break;
488 case 2: /* assembly language files */
489 if (Eflag)
490 break;
491 if (!Sflag) {
492 char *ofile;
493 if (cflag && outfile)
494 ofile = outfile;
495 else if (cflag)
496 ofile = concat(base, first(suffixes[3]));
497 else
498 ofile = tempname(first(suffixes[3]));
499 compose(as, alist, append(name, 0), append(ofile, 0));
500 status = callsys(av);
501 if (!find(ofile, llist[1]))
502 llist[1] = append(ofile, llist[1]);
504 break;
505 case 3: /* object files */
506 if (!find(name, llist[1]))
507 llist[1] = append(name, llist[1]);
508 break;
509 default:
510 if (Eflag) {
511 compose(cpp, plist, append(name, 0), 0);
512 status = callsys(av);
514 llist[1] = append(name, llist[1]);
515 break;
517 if (status)
518 errcnt++;
519 return status;
522 /* find - find 1st occurrence of str in list, return list node or 0 */
523 static List find(char *str, List list) {
524 List b;
526 if ((b = list))
527 do {
528 if (strcmp(str, b->str) == 0)
529 return b;
530 } while ((b = b->link) != list);
531 return 0;
534 /* help - print help message */
535 static void help(void) {
536 static char *msgs[] = {
537 "", " [ option | file ]...\n",
538 " except for -l, options are processed left-to-right before files\n",
539 " unrecognized options are taken to be linker options\n",
540 "-A warn about nonANSI usage; 2nd -A warns more\n",
541 "-b emit expression-level profiling code; see bprint(1)\n",
542 #ifdef sparc
543 "-Bstatic -Bdynamic specify static or dynamic libraries\n",
544 #endif
545 "-Bdir/ use the compiler named `dir/rcc'\n",
546 "-c compile only\n",
547 "-dn set switch statement density to `n'\n",
548 "-Dname -Dname=def define the preprocessor symbol `name'\n",
549 "-E run only the preprocessor on the named C programs and unsuffixed files\n",
550 "-g produce symbol table information for debuggers\n",
551 "-help or -? print this message\n",
552 "-Idir add `dir' to the beginning of the list of #include directories\n",
553 "-lx search library `x'\n",
554 "-N do not search the standard directories for #include files\n",
555 "-n emit code to check for dereferencing zero pointers\n",
556 "-O is ignored\n",
557 "-o file leave the output in `file'\n",
558 "-P print ANSI-style declarations for globals\n",
559 "-p -pg emit profiling code; see prof(1) and gprof(1)\n",
560 "-S compile to assembly language\n",
561 #ifdef linux
562 "-static specify static libraries (default is dynamic)\n",
563 #endif
564 "-t -tname emit function tracing calls to printf or to `name'\n",
565 "-target name is ignored\n",
566 "-tempdir=dir place temporary files in `dir/'", "\n"
567 "-Uname undefine the preprocessor symbol `name'\n",
568 "-v show commands as they are executed; 2nd -v suppresses execution\n",
569 "-w suppress warnings\n",
570 "-Woarg specify system-specific `arg'\n",
571 "-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
572 0 };
573 int i;
574 char *s;
576 msgs[0] = progname;
577 for (i = 0; msgs[i]; i++) {
578 fprintf(stderr, "%s", msgs[i]);
579 if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
580 fprintf(stderr, "; default=%s", tempdir);
582 #define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
583 xx(LCCINPUTS);
584 xx(LCCDIR);
585 #undef xx
588 /* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
589 static void initinputs(void) {
590 char *s = getenv("LCCINPUTS");
591 List b;
593 if (s == 0 || (s = inputs)[0] == 0)
594 s = ".";
595 if (s) {
596 lccinputs = path2list(s);
597 if ((b = lccinputs))
598 do {
599 b = b->link;
600 if (strcmp(b->str, ".") != 0) {
601 ilist = append(concat("-I", b->str), ilist);
602 if (strstr(com[1], "win32") == NULL)
603 llist[0] = append(concat("-L", b->str), llist[0]);
604 } else
605 b->str = "";
606 } while (b != lccinputs);
610 /* interrupt - catch interrupt signals */
611 static void interrupt(int n) {
612 rm(rmlist);
613 exit(n = 100);
616 /* opt - process option in arg */
617 static void opt(char *arg) {
618 switch (arg[1]) { /* multi-character options */
619 case 'W': /* -Wxarg */
620 if (arg[2] && arg[3])
621 switch (arg[2]) {
622 case 'o':
623 if (option(&arg[3]))
624 return;
625 break;
626 case 'p':
627 plist = append(&arg[3], plist);
628 return;
629 case 'f':
630 if (strcmp(&arg[3], "-C") || option("-b")) {
631 clist = append(&arg[3], clist);
632 return;
634 break; /* and fall thru */
635 case 'a':
636 alist = append(&arg[3], alist);
637 return;
638 case 'l':
639 llist[0] = append(&arg[3], llist[0]);
640 return;
642 fprintf(stderr, "%s: %s ignored\n", progname, arg);
643 return;
644 case 'd': /* -dn */
645 arg[1] = 's';
646 clist = append(arg, clist);
647 return;
648 case 't': /* -t -tname -tempdir=dir */
649 if (strncmp(arg, "-tempdir=", 9) == 0)
650 tempdir = arg + 9;
651 else
652 clist = append(arg, clist);
653 return;
654 case 'p': /* -p -pg */
655 if (option(arg))
656 clist = append(arg, clist);
657 else
658 fprintf(stderr, "%s: %s ignored\n", progname, arg);
659 return;
660 case 'D': /* -Dname -Dname=def */
661 case 'U': /* -Uname */
662 case 'I': /* -Idir */
663 plist = append(arg, plist);
664 return;
665 case 'B': /* -Bdir -Bstatic -Bdynamic */
666 #ifdef sparc
667 if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
668 llist[1] = append(arg, llist[1]);
669 else
670 #endif
672 static char *path;
673 if (path)
674 error("-B overwrites earlier option", 0);
675 path = arg + 2;
676 if (strstr(com[1], "win32") != NULL)
677 com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
678 else
679 com[0] = concat(path, "rcc");
680 if (path[0] == 0)
681 error("missing directory in -B option", 0);
683 return;
684 case 'h':
685 if (strcmp(arg, "-help") == 0) {
686 static int printed = 0;
687 case '?':
688 if (!printed)
689 help();
690 printed = 1;
691 return;
693 #ifdef linux
694 case 's':
695 if (strcmp(arg,"-static") == 0) {
696 if (!option(arg))
697 fprintf(stderr, "%s: %s ignored\n", progname, arg);
698 return;
700 #endif
702 if (arg[2] == 0)
703 switch (arg[1]) { /* single-character options */
704 case 'S':
705 Sflag++;
706 return;
707 case 'O':
708 fprintf(stderr, "%s: %s ignored\n", progname, arg);
709 return;
710 case 'A': case 'n': case 'w': case 'P':
711 clist = append(arg, clist);
712 return;
713 case 'g': case 'b':
714 if (option(arg))
715 clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
716 else
717 fprintf(stderr, "%s: %s ignored\n", progname, arg);
718 return;
719 case 'G':
720 if (option(arg)) {
721 clist = append("-g3", clist);
722 llist[0] = append("-N", llist[0]);
723 } else
724 fprintf(stderr, "%s: %s ignored\n", progname, arg);
725 return;
726 case 'E':
727 Eflag++;
728 return;
729 case 'c':
730 cflag++;
731 return;
732 case 'N':
733 if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
734 plist = append("-nostdinc", plist);
735 include[0] = 0;
736 ilist = 0;
737 return;
738 case 'v':
739 if (verbose++ == 0) {
740 if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
741 plist = append(arg, plist);
742 clist = append(arg, clist);
743 fprintf(stderr, "%s %s\n", progname, rcsid);
745 return;
747 if (cflag || Sflag || Eflag)
748 fprintf(stderr, "%s: %s ignored\n", progname, arg);
749 else
750 llist[1] = append(arg, llist[1]);
753 /* path2list - convert a colon- or semicolon-separated list to a list */
754 static List path2list(const char *path) {
755 List list = NULL;
756 char sep = ':';
758 if (path == NULL)
759 return NULL;
760 if (strchr(path, ';'))
761 sep = ';';
762 while (*path) {
763 char *p, buf[512];
764 if ((p = strchr(path, sep))) {
765 assert(p - path < sizeof buf);
766 strncpy(buf, path, p - path);
767 buf[p-path] = '\0';
768 } else {
769 assert(strlen(path) < sizeof buf);
770 strcpy(buf, path);
772 if (!find(buf, list))
773 list = append(strsave(buf), list);
774 if (p == 0)
775 break;
776 path = p + 1;
778 return list;
781 /* replace - copy str, then replace occurrences of from with to, return the copy */
782 char *replace(const char *str, int from, int to) {
783 char *s = strsave(str), *p = s;
785 for ( ; (p = strchr(p, from)) != NULL; p++)
786 *p = to;
787 return s;
790 /* rm - remove files in list */
791 static void rm(List list) {
792 if (list) {
793 List b = list;
794 if (verbose)
795 fprintf(stderr, "rm");
796 do {
797 if (verbose)
798 fprintf(stderr, " %s", b->str);
799 if (verbose < 2)
800 remove(b->str);
801 } while ((b = b->link) != list);
802 if (verbose)
803 fprintf(stderr, "\n");
807 /* strsave - return a saved copy of string str */
808 char *strsave(const char *str) {
809 return strcpy(alloc(strlen(str)+1), str);
812 /* stringf - format and return a string */
813 char *stringf(const char *fmt, ...) {
814 char buf[1024];
815 va_list ap;
817 va_start(ap, fmt);
818 vsprintf(buf, fmt, ap);
819 va_end(ap);
820 return strsave(buf);
823 /* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
824 int suffix(char *name, char *tails[], int n) {
825 int i, len = strlen(name);
827 for (i = 0; i < n; i++) {
828 char *s = tails[i], *t;
829 for ( ; (t = strchr(s, ';')); s = t + 1) {
830 int m = t - s;
831 if (len > m && strncmp(&name[len-m], s, m) == 0)
832 return i;
834 if (*s) {
835 int m = strlen(s);
836 if (len > m && strncmp(&name[len-m], s, m) == 0)
837 return i;
840 return -1;
843 /* tempname - generate a temporary file name in tempdir with given suffix */
844 char *tempname(char *suffix) {
845 static int n;
846 char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
848 if (strstr(com[1], "win32") != NULL)
849 name = replace(name, '/', '\\');
850 rmlist = append(name, rmlist);
851 return name;