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 #ifdef WIN32
530 xx(include);
531 xx(lib);
532 #endif
533 #undef xx
534 }
535
536 /* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
initinputs(void)537 static void initinputs(void) {
538 char *s = getenv("LCCINPUTS");
539 List b;
540 #ifdef WIN32
541 List list;
542 #endif
543
544 if (s == 0 || (s = inputs)[0] == 0)
545 s = ".";
546 if (s) {
547 lccinputs = path2list(s);
548 if ((b = lccinputs))
549 do {
550 b = b->link;
551 if (strcmp(b->str, ".") != 0) {
552 ilist = append(concat("-I", b->str), ilist);
553 if (strstr(com[1], "win32") == NULL)
554 llist[0] = append(concat("-L", b->str), llist[0]);
555 } else
556 b->str = "";
557 } while (b != lccinputs);
558 }
559 #ifdef WIN32
560 if ((list = b = path2list(getenv("include"))))
561 do {
562 b = b->link;
563 ilist = append(stringf("-I\"%s\"", b->str), ilist);
564 } while (b != list);
565 #endif
566 }
567
568 /* interrupt - catch interrupt signals */
interrupt(int n)569 static void interrupt(int n) {
570 rm(rmlist);
571 exit(n = 100);
572 }
573
574 /* opt - process option in arg */
opt(char * arg)575 static void opt(char *arg) {
576 switch (arg[1]) { /* multi-character options */
577 case 'W': /* -Wxarg */
578 if (arg[2] && arg[3])
579 switch (arg[2]) {
580 case 'o':
581 if (option(&arg[3]))
582 return;
583 break;
584 case 'p':
585 plist = append(&arg[3], plist);
586 return;
587 case 'f':
588 if (strcmp(&arg[3], "-C") || option("-b")) {
589 clist = append(&arg[3], clist);
590 return;
591 }
592 break; /* and fall thru */
593 case 'a':
594 alist = append(&arg[3], alist);
595 return;
596 case 'l':
597 llist[0] = append(&arg[3], llist[0]);
598 return;
599 }
600 fprintf(stderr, "%s: %s ignored\n", progname, arg);
601 return;
602 case 'd': /* -dn */
603 arg[1] = 's';
604 clist = append(arg, clist);
605 return;
606 case 't': /* -t -tname -tempdir=dir */
607 if (strncmp(arg, "-tempdir=", 9) == 0)
608 tempdir = arg + 9;
609 else
610 clist = append(arg, clist);
611 return;
612 case 'p': /* -p -pg */
613 if (option(arg))
614 clist = append(arg, clist);
615 else
616 fprintf(stderr, "%s: %s ignored\n", progname, arg);
617 return;
618 case 'D': /* -Dname -Dname=def */
619 case 'U': /* -Uname */
620 case 'I': /* -Idir */
621 plist = append(arg, plist);
622 return;
623 case 'B': /* -Bdir -Bstatic -Bdynamic */
624 #ifdef sparc
625 if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
626 llist[1] = append(arg, llist[1]);
627 else
628 #endif
629 {
630 static char *path;
631 if (path)
632 error("-B overwrites earlier option", 0);
633 path = arg + 2;
634 if (strstr(com[1], "win32") != NULL)
635 com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
636 else
637 com[0] = concat(path, "rcc");
638 if (path[0] == 0)
639 error("missing directory in -B option", 0);
640 }
641 return;
642 case 'h':
643 if (strcmp(arg, "-help") == 0) {
644 static int printed = 0;
645 case '?':
646 if (!printed)
647 help();
648 printed = 1;
649 return;
650 }
651 #ifdef linux
652 case 's':
653 if (strcmp(arg,"-static") == 0) {
654 if (!option(arg))
655 fprintf(stderr, "%s: %s ignored\n", progname, arg);
656 return;
657 }
658 #endif
659 }
660 if (arg[2] == 0)
661 switch (arg[1]) { /* single-character options */
662 case 'S':
663 Sflag++;
664 return;
665 case 'O':
666 fprintf(stderr, "%s: %s ignored\n", progname, arg);
667 return;
668 case 'A': case 'n': case 'w': case 'P':
669 clist = append(arg, clist);
670 return;
671 case 'g': case 'b':
672 if (option(arg))
673 clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
674 else
675 fprintf(stderr, "%s: %s ignored\n", progname, arg);
676 return;
677 case 'G':
678 if (option(arg)) {
679 clist = append("-g3", clist);
680 llist[0] = append("-N", llist[0]);
681 } else
682 fprintf(stderr, "%s: %s ignored\n", progname, arg);
683 return;
684 case 'E':
685 Eflag++;
686 return;
687 case 'c':
688 cflag++;
689 return;
690 case 'N':
691 if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
692 plist = append("-nostdinc", plist);
693 include[0] = 0;
694 ilist = 0;
695 return;
696 case 'v':
697 if (verbose++ == 0) {
698 if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
699 plist = append(arg, plist);
700 clist = append(arg, clist);
701 fprintf(stderr, "%s %s\n", progname, rcsid);
702 }
703 return;
704 }
705 if (cflag || Sflag || Eflag)
706 fprintf(stderr, "%s: %s ignored\n", progname, arg);
707 else
708 llist[1] = append(arg, llist[1]);
709 }
710
711 /* path2list - convert a colon- or semicolon-separated list to a list */
path2list(const char * path)712 static List path2list(const char *path) {
713 List list = NULL;
714 char sep = ':';
715
716 if (path == NULL)
717 return NULL;
718 if (strchr(path, ';'))
719 sep = ';';
720 while (*path) {
721 char *p, buf[512];
722 if ((p = strchr(path, sep))) {
723 assert(p - path < sizeof buf);
724 strncpy(buf, path, p - path);
725 buf[p-path] = '\0';
726 } else {
727 assert(strlen(path) < sizeof buf);
728 strcpy(buf, path);
729 }
730 if (!find(buf, list))
731 list = append(strsave(buf), list);
732 if (p == 0)
733 break;
734 path = p + 1;
735 }
736 return list;
737 }
738
739 /* replace - copy str, then replace occurrences of from with to, return the copy */
replace(const char * str,int from,int to)740 char *replace(const char *str, int from, int to) {
741 char *s = strsave(str), *p = s;
742
743 for ( ; (p = strchr(p, from)) != NULL; p++)
744 *p = to;
745 return s;
746 }
747
748 /* rm - remove files in list */
rm(List list)749 static void rm(List list) {
750 if (list) {
751 List b = list;
752 if (verbose)
753 fprintf(stderr, "rm");
754 do {
755 if (verbose)
756 fprintf(stderr, " %s", b->str);
757 if (verbose < 2)
758 remove(b->str);
759 } while ((b = b->link) != list);
760 if (verbose)
761 fprintf(stderr, "\n");
762 }
763 }
764
765 /* strsave - return a saved copy of string str */
strsave(const char * str)766 char *strsave(const char *str) {
767 return strcpy(alloc(strlen(str)+1), str);
768 }
769
770 /* stringf - format and return a string */
stringf(const char * fmt,...)771 char *stringf(const char *fmt, ...) {
772 char buf[1024];
773 va_list ap;
774 int n;
775
776 va_start(ap, fmt);
777 n = vsprintf(buf, fmt, ap);
778 va_end(ap);
779 return strsave(buf);
780 }
781
782 /* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
suffix(char * name,char * tails[],int n)783 int suffix(char *name, char *tails[], int n) {
784 int i, len = strlen(name);
785
786 for (i = 0; i < n; i++) {
787 char *s = tails[i], *t;
788 for ( ; (t = strchr(s, ';')); s = t + 1) {
789 int m = t - s;
790 if (len > m && strncmp(&name[len-m], s, m) == 0)
791 return i;
792 }
793 if (*s) {
794 int m = strlen(s);
795 if (len > m && strncmp(&name[len-m], s, m) == 0)
796 return i;
797 }
798 }
799 return -1;
800 }
801
802 /* tempname - generate a temporary file name in tempdir with given suffix */
tempname(char * suffix)803 char *tempname(char *suffix) {
804 static int n;
805 char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
806
807 if (strstr(com[1], "win32") != NULL)
808 name = replace(name, '/', '\\');
809 rmlist = append(name, rmlist);
810 return name;
811 }
812