1 /*        Id: driver.c,v 1.7 2011/06/03 15:34:01 plunky Exp           */
2 /*        $NetBSD: driver.c,v 1.1.1.1 2011/09/01 12:47:04 plunky Exp $          */
3 
4 /*-
5  * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/wait.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include "driver.h"
44 #include "xalloc.h"
45 
46 #include "config.h"
47 
48 static volatile sig_atomic_t exit_now;
49 static volatile sig_atomic_t child;
50 
51 static void
sigterm_handler(int signum)52 sigterm_handler(int signum)
53 {
54           exit_now = 1;
55           if (child)
56                     kill(child, SIGTERM);
57 }
58 
59 static const char versionstr[] = VERSSTR;
60 
61 enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase =
62     DEFAULT;
63 
64 const char *isysroot = NULL;
65 const char *sysroot = "";
66 const char *preprocessor;
67 const char *compiler;
68 const char *assembler;
69 const char *linker;
70 
71 struct strlist crtdirs;
72 static struct strlist user_sysincdirs;
73 struct strlist sysincdirs;
74 struct strlist includes;
75 struct strlist incdirs;
76 struct strlist libdirs;
77 struct strlist progdirs;
78 struct strlist preprocessor_flags;
79 struct strlist compiler_flags;
80 struct strlist assembler_flags;
81 struct strlist early_linker_flags;
82 struct strlist middle_linker_flags;
83 struct strlist late_linker_flags;
84 struct strlist stdlib_flags;
85 struct strlist early_program_csu_files;
86 struct strlist late_program_csu_files;
87 struct strlist early_dso_csu_files;
88 struct strlist late_dso_csu_files;
89 struct strlist temp_outputs;
90 
91 const char *final_output;
92 static char *temp_directory;
93 static struct strlist inputs;
94 
95 int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */
96 int save_temps;
97 int debug_mode;
98 int profile_mode;
99 int nostdinc;
100 int nostdlib;
101 int nostartfiles;
102 int static_mode;
103 int shared_mode;
104 int use_pthread;
105 int verbose_mode;
106 
107 void
error(const char * fmt,...)108 error(const char *fmt, ...)
109 {
110           va_list arg;
111           va_start(arg, fmt);
112           vfprintf(stderr, fmt, arg);
113           putc('\n', stderr);
114           va_end(arg);
115           exit(1);
116 }
117 
118 static void
warning(const char * fmt,...)119 warning(const char *fmt, ...)
120 {
121           va_list arg;
122           va_start(arg, fmt);
123           vfprintf(stderr, fmt, arg);
124           putc('\n', stderr);
125           va_end(arg);
126 }
127 
128 static void
set_last_phase(enum phases phase)129 set_last_phase(enum phases phase)
130 {
131           assert(phase != DEFAULT);
132           if (last_phase != DEFAULT && phase != last_phase)
133                     error("conflicting compiler options specified");
134           last_phase = phase;
135 }
136 
137 static void
expand_sysroot(void)138 expand_sysroot(void)
139 {
140           struct string *s;
141           struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
142               &user_sysincdirs, &libdirs, &progdirs, NULL };
143           const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
144               sysroot, sysroot, NULL };
145           size_t i, sysroot_len, value_len;
146           char *path;
147 
148           assert(sizeof(lists) / sizeof(lists[0]) ==
149                  sizeof(sysroots) / sizeof(sysroots[0]));
150 
151           for (i = 0; lists[i] != NULL; ++i) {
152                     STRLIST_FOREACH(s, lists[i]) {
153                               if (s->value[0] != '=')
154                                         continue;
155                               sysroot_len = strlen(sysroots[i]);
156                               /* Skipped '=' compensates additional space for '\0' */
157                               value_len = strlen(s->value);
158                               path = xmalloc(sysroot_len + value_len);
159                               memcpy(path, sysroots[i], sysroot_len);
160                               memcpy(path + sysroot_len, s->value + 1, value_len);
161                               free(s->value);
162                               s->value = path;
163                     }
164           }
165 }
166 
167 static void
missing_argument(const char * argp)168 missing_argument(const char *argp)
169 {
170           error("Option `%s' required an argument", argp);
171 }
172 
173 static void
split_and_append(struct strlist * l,char * arg)174 split_and_append(struct strlist *l, char *arg)
175 {
176           char *next;
177 
178           for (; arg != NULL; arg = NULL) {
179                     next = strchr(arg, ',');
180                     if (next != NULL)
181                               *next++ = '\0';
182                     strlist_append(l, arg);
183           }
184 }
185 
186 static int
strlist_exec(struct strlist * l)187 strlist_exec(struct strlist *l)
188 {
189           char **argv;
190           size_t argc;
191           int result;
192 
193           strlist_make_array(l, &argv, &argc);
194           if (verbose_mode) {
195                     printf("Calling ");
196                     strlist_print(l, stdout);
197                     printf("\n");
198           }
199 
200           if (exit_now)
201                     return 1;
202 
203           switch ((child = fork())) {
204           case 0:
205                     execvp(argv[0], argv);
206                     result = write(STDERR_FILENO, "Exec of ", 8);
207                     result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
208                     result = write(STDERR_FILENO, "failed\n", 7);
209                     (void)result;
210                     _exit(127);
211           case -1:
212                     error("fork failed");
213           default:
214                     while (waitpid(child, &result, 0) == -1 && errno == EINTR)
215                               /* nothing */(void)0;
216                     result = WEXITSTATUS(result);
217                     if (result)
218                               error("%s terminated with status %d", argv[0], result);
219                     while (argc-- > 0)
220                               free(argv[argc]);
221                     free(argv);
222                     break;
223           }
224           return exit_now;
225 }
226 
227 static char *
find_file(const char * file,struct strlist * path,int mode)228 find_file(const char *file, struct strlist *path, int mode)
229 {
230           struct string *s;
231           char *f;
232           size_t lf, lp;
233           int need_sep;
234 
235           lf = strlen(file);
236           STRLIST_FOREACH(s, path) {
237                     lp = strlen(s->value);
238                     need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
239                     f = xmalloc(lp + lf + need_sep + 1);
240                     memcpy(f, s->value, lp);
241                     if (need_sep)
242                               f[lp] = '/';
243                     memcpy(f + lp + need_sep, file, lf + 1);
244                     if (access(f, mode) == 0)
245                               return f;
246                     free(f);
247           }
248           return xstrdup(file);
249 }
250 
251 static char *
output_name(const char * file,const char * new_suffix,int counter,int last)252 output_name(const char *file, const char *new_suffix, int counter, int last)
253 {
254           const char *old_suffix;
255           char *name;
256           size_t lf, ls, len;
257           int counter_len;
258 
259           if (last && final_output)
260                     return xstrdup(final_output);
261 
262           old_suffix = strrchr(file, '.');
263           if (old_suffix != NULL && strchr(old_suffix, '/') != NULL)
264                     old_suffix = NULL;
265           if (old_suffix == NULL)
266                     old_suffix = file + strlen(file);
267 
268           ls = strlen(new_suffix);
269           if (save_temps || last) {
270                     lf = old_suffix - file;
271                     name = xmalloc(lf + ls + 1);
272                     memcpy(name, file, lf);
273                     memcpy(name + lf, new_suffix, ls + 1);
274                     return name;
275           }
276           if (temp_directory == NULL) {
277                     const char *template;
278                     char *path;
279                     size_t template_len;
280                     int need_sep;
281 
282                     template = getenv("TMPDIR");
283                     if (template == NULL)
284                               template = "/tmp";
285                     template_len = strlen(template);
286                     if (template_len && template[template_len - 1] == '/')
287                               need_sep = 0;
288                     else
289                               need_sep = 1;
290                     path = xmalloc(template_len + need_sep + 6 + 1);
291                     memcpy(path, template, template_len);
292                     if (need_sep)
293                               path[template_len] = '/';
294                     memcpy(path + template_len + need_sep, "pcc-XXXXXX", 11);
295                     if (mkdtemp(path) == NULL)
296                               error("mkdtemp failed: %s", strerror(errno));
297                     temp_directory = path;
298           }
299           lf = strlen(temp_directory);
300           counter_len = snprintf(NULL, 0, "%d", counter);
301           if (counter_len < 1)
302                     error("snprintf failure");
303           len = lf + 1 + (size_t)counter_len + ls + 1;
304           name = xmalloc(len);
305           snprintf(name, len, "%s/%d%s", temp_directory, counter, new_suffix);
306           strlist_append(&temp_outputs, name);
307           return name;
308 }
309 
310 static int
preprocess_input(const char * file,char * input,char ** output,const char * suffix,int counter)311 preprocess_input(const char *file, char *input, char **output,
312     const char *suffix, int counter)
313 {
314           struct strlist args;
315           struct string *s;
316           char *out;
317           int retval;
318 
319           strlist_init(&args);
320           strlist_append_list(&args, &preprocessor_flags);
321           STRLIST_FOREACH(s, &includes) {
322                     strlist_append(&args, "-i");
323                     strlist_append(&args, s->value);
324           }
325           STRLIST_FOREACH(s, &incdirs) {
326                     strlist_append(&args, "-I");
327                     strlist_append(&args, s->value);
328           }
329           STRLIST_FOREACH(s, &user_sysincdirs) {
330                     strlist_append(&args, "-S");
331                     strlist_append(&args, s->value);
332           }
333           if (!nostdinc) {
334                     STRLIST_FOREACH(s, &sysincdirs) {
335                               strlist_append(&args, "-S");
336                               strlist_append(&args, s->value);
337                     }
338           }
339           strlist_append(&args, input);
340           if (last_phase == PREPROCESS && final_output == NULL)
341                     out = xstrdup("-");
342           else
343                     out = output_name(file, suffix, counter,
344                         last_phase == PREPROCESS);
345           if (strcmp(out, "-"))
346                     strlist_append(&args, out);
347           strlist_prepend(&args, find_file(preprocessor, &progdirs, X_OK));
348           *output = out;
349           retval = strlist_exec(&args);
350           strlist_free(&args);
351           return retval;
352 }
353 
354 static int
compile_input(const char * file,char * input,char ** output,const char * suffix,int counter)355 compile_input(const char *file, char *input, char **output,
356     const char *suffix, int counter)
357 {
358           struct strlist args;
359           char *out;
360           int retval;
361 
362           strlist_init(&args);
363           strlist_append_list(&args, &compiler_flags);
364           if (debug_mode)
365                     strlist_append(&args, "-g");
366           if (pic_mode)
367                     strlist_append(&args, "-k");
368           if (profile_mode)
369                     warning("-pg is currently ignored");
370           strlist_append(&args, input);
371           out = output_name(file, suffix, counter, last_phase == ASSEMBLE);
372           strlist_append(&args, out);
373           strlist_prepend(&args, find_file(compiler, &progdirs, X_OK));
374           *output = out;
375           retval = strlist_exec(&args);
376           strlist_free(&args);
377           return retval;
378 }
379 
380 static int
assemble_input(const char * file,char * input,char ** output,const char * suffix,int counter)381 assemble_input(const char *file, char *input, char **output,
382     const char *suffix, int counter)
383 {
384           struct strlist args;
385           char *out;
386           int retval;
387 
388           strlist_init(&args);
389           strlist_append_list(&args, &assembler_flags);
390           strlist_append(&args, input);
391           out = output_name(file, ".o", counter, last_phase == COMPILE);
392           strlist_append(&args, "-o");
393           strlist_append(&args, out);
394           strlist_prepend(&args, find_file(assembler, &progdirs, X_OK));
395           *output = out;
396           retval = strlist_exec(&args);
397           strlist_free(&args);
398           return retval;
399 }
400 
401 static int
handle_input(const char * file)402 handle_input(const char *file)
403 {
404           static int counter;
405           const char *suffix;
406           char *src;
407           int handled, retval;
408 
409           ++counter;
410 
411           if (strcmp(file, "-") == 0) {
412                     /* XXX see -x option */
413                     suffix = ".c";
414           } else {
415                     suffix = strrchr(file, '.');
416                     if (suffix != NULL && strchr(suffix, '/') != NULL)
417                               suffix = NULL;
418                     if (suffix == NULL)
419                               suffix = "";
420           }
421 
422           src = xstrdup(file);
423           if (strcmp(suffix, ".c") == 0) {
424                     suffix = ".i";
425                     retval = preprocess_input(file, src, &src, suffix, counter);
426                     if (retval)
427                               return retval;
428                     handled = 1;
429           } else if (strcmp(suffix, ".S") == 0) {
430                     suffix = ".s";
431                     retval = preprocess_input(file, src, &src, suffix, counter);
432                     if (retval)
433                               return retval;
434                     handled = 1;
435           }
436 
437           if (last_phase == PREPROCESS)
438                     goto done;
439 
440           if (strcmp(suffix, ".i") == 0) {
441                     suffix = ".s";
442                     retval = compile_input(file, src, &src, suffix, counter);
443                     if (retval)
444                               return retval;
445                     handled = 1;
446           }
447           if (last_phase == ASSEMBLE)
448                     goto done;
449 
450           if (strcmp(suffix, ".s") == 0) {
451                     suffix = ".o";
452                     retval = assemble_input(file, src, &src, suffix, counter);
453                     if (retval)
454                               return retval;
455                     handled = 1;
456           }
457           if (last_phase == COMPILE)
458                     goto done;
459           if (strcmp(suffix, ".o") == 0)
460                     handled = 1;
461           strlist_append(&middle_linker_flags, src);
462 done:
463           if (handled)
464                     return 0;
465           if (last_phase == LINK)
466                     warning("unknown suffix %s, passing file down to linker",
467                         suffix);
468           else
469                     warning("unknown suffix %s, skipped", suffix);
470           free(src);
471           return 0;
472 }
473 
474 static int
run_linker(void)475 run_linker(void)
476 {
477           struct strlist linker_flags;
478           struct strlist *early_csu, *late_csu;
479           struct string *s;
480           int retval;
481 
482           if (final_output) {
483                     strlist_prepend(&early_linker_flags, final_output);
484                     strlist_prepend(&early_linker_flags, "-o");
485           }
486           if (!nostdlib)
487                     strlist_append_list(&late_linker_flags, &stdlib_flags);
488           if (!nostartfiles) {
489                     if (shared_mode) {
490                               early_csu = &early_dso_csu_files;
491                               late_csu = &late_dso_csu_files;
492                     } else {
493                               early_csu = &early_program_csu_files;
494                               late_csu = &late_program_csu_files;
495                     }
496                     STRLIST_FOREACH(s, early_csu)
497                               strlist_append_nocopy(&middle_linker_flags,
498                                   find_file(s->value, &crtdirs, R_OK));
499                     STRLIST_FOREACH(s, late_csu)
500                               strlist_append_nocopy(&late_linker_flags,
501                                   find_file(s->value, &crtdirs, R_OK));
502           }
503           strlist_init(&linker_flags);
504           strlist_append_list(&linker_flags, &early_linker_flags);
505           strlist_append_list(&linker_flags, &middle_linker_flags);
506           strlist_append_list(&linker_flags, &late_linker_flags);
507           strlist_prepend(&linker_flags, find_file(linker, &progdirs, X_OK));
508 
509           retval = strlist_exec(&linker_flags);
510 
511           strlist_free(&linker_flags);
512           return retval;
513 }
514 
515 static void
cleanup(void)516 cleanup(void)
517 {
518           struct string *file;
519 
520           STRLIST_FOREACH(file, &temp_outputs) {
521                     if (unlink(file->value) == -1)
522                               warning("removal of ``%s'' failed: %s", file->value,
523                                   strerror(errno));
524           }
525           if (temp_directory && rmdir(temp_directory) == -1)
526                     warning("removal of ``%s'' failed: %s", temp_directory,
527                         strerror(errno));
528 }
529 
530 int
main(int argc,char ** argv)531 main(int argc, char **argv)
532 {
533           struct string *input;
534           char *argp;
535           int retval;
536 
537           strlist_init(&crtdirs);
538           strlist_init(&user_sysincdirs);
539           strlist_init(&sysincdirs);
540           strlist_init(&incdirs);
541           strlist_init(&includes);
542           strlist_init(&libdirs);
543           strlist_init(&progdirs);
544           strlist_init(&inputs);
545           strlist_init(&preprocessor_flags);
546           strlist_init(&compiler_flags);
547           strlist_init(&assembler_flags);
548           strlist_init(&early_linker_flags);
549           strlist_init(&middle_linker_flags);
550           strlist_init(&late_linker_flags);
551           strlist_init(&stdlib_flags);
552           strlist_init(&early_program_csu_files);
553           strlist_init(&late_program_csu_files);
554           strlist_init(&early_dso_csu_files);
555           strlist_init(&late_dso_csu_files);
556           strlist_init(&temp_outputs);
557 
558           init_platform_specific(TARGOS, TARGMACH);
559 
560           while (--argc) {
561                     ++argv;
562                     argp = *argv;
563 
564                     if (*argp != '-' || strcmp(argp, "-") == 0) {
565                               strlist_append(&inputs, argp);
566                               continue;
567                     }
568                     switch (argp[1]) {
569                     case '-':
570                               if (strcmp(argp, "--param") == 0) {
571                                         if (argc == 0)
572                                                   missing_argument(argp);
573                                         --argc;
574                                         ++argv;
575                                         /* Unused */
576                                         continue;
577                               }
578                               if (strncmp(argp, "--sysroot=", 10) == 0) {
579                                         sysroot = argp + 10;
580                                         continue;
581                               }
582                               if (strcmp(argp, "--version") == 0) {
583                                         printf("%s\n", versionstr);
584                                         exit(0);
585                               }
586                               break;
587                     case 'B':
588                               strlist_append(&crtdirs, argp);
589                               strlist_append(&libdirs, argp);
590                               strlist_append(&progdirs, argp);
591                               continue;
592                     case 'C':
593                               if (argp[2] == '\0') {
594                                         strlist_append(&preprocessor_flags, argp);
595                                         continue;
596                               }
597                               break;
598                     case 'c':
599                               if (argp[2] == '\0') {
600                                         set_last_phase(COMPILE);
601                                         continue;
602                               }
603                               break;
604                     case 'D':
605                               strlist_append(&preprocessor_flags, argp);
606                               if (argp[2] == '\0') {
607                                         if (argc == 0)
608                                                   missing_argument(argp);
609                                         --argc;
610                                         ++argv;
611                                         strlist_append(&preprocessor_flags, argp);
612                               }
613                               continue;
614                     case 'E':
615                               if (argp[2] == '\0') {
616                                         set_last_phase(PREPROCESS);
617                                         continue;
618                               }
619                               break;
620                     case 'f':
621                               if (strcmp(argp, "-fpic") == 0) {
622                                         pic_mode = 1;
623                                         continue;
624                               }
625                               if (strcmp(argp, "-fPIC") == 0) {
626                                         pic_mode = 2;
627                                         continue;
628                               }
629                               /* XXX GCC options */
630                               break;
631                     case 'g':
632                               if (argp[2] == '\0') {
633                                         debug_mode = 1;
634                                         continue;
635                               }
636                               /* XXX allow variants like -g1? */
637                               break;
638                     case 'I':
639                               if (argp[2] == '\0') {
640                                         if (argc == 0)
641                                                   missing_argument(argp);
642                                         --argc;
643                                         ++argv;
644                                         strlist_append(&incdirs, argp);
645                                         continue;
646                               }
647                               strlist_append(&incdirs, argp + 2);
648                               continue;
649                     case 'i':
650                               if (strcmp(argp, "-isystem") == 0) {
651                                         if (argc == 0)
652                                                   missing_argument(argp);
653                                         --argc;
654                                         ++argv;
655                                         strlist_append(&user_sysincdirs, argp);
656                                         continue;
657                               }
658                               if (strcmp(argp, "-include") == 0) {
659                                         if (argc == 0)
660                                                   missing_argument(argp);
661                                         --argc;
662                                         ++argv;
663                                         strlist_append(&includes, argp);
664                                         continue;
665                               }
666                               if (strcmp(argp, "-isysroot") == 0) {
667                                         if (argc == 0)
668                                                   missing_argument(argp);
669                                         --argc;
670                                         ++argv;
671                                         isysroot = argp;
672                                         continue;
673                               }
674                               /* XXX -idirafter */
675                               /* XXX -iquote */
676                               break;
677                     case 'k':
678                               if (argp[2] == '\0') {
679                                         pic_mode = 1;
680                                         continue;
681                               }
682                               break;
683                     case 'M':
684                               if (argp[2] == '\0') {
685                                         strlist_append(&preprocessor_flags, argp);
686                                         continue;
687                               }
688                               break;
689                     case 'm':
690                               /* XXX implement me */
691                               break;
692                     case 'n':
693                               if (strcmp(argp, "-nostdinc") == 0) {
694                                         nostdinc = 1;
695                                         continue;
696                               }
697                               if (strcmp(argp, "-nostdinc++") == 0)
698                                         continue;
699                               if (strcmp(argp, "-nostdlib") == 0) {
700                                         nostdlib = 1;
701                                         nostartfiles = 1;
702                                         continue;
703                               }
704                               if (strcmp(argp, "-nostartfiles") == 0) {
705                                         nostartfiles = 1;
706                                         continue;
707                               }
708                               break;
709                     case 'O':
710                               if (argp[2] != '\0' && argp[3] != '\0')
711                                         break;
712                               switch(argp[2]) {
713                               case '2':
714                               case '1': case '\0':
715                                         strlist_append(&compiler_flags, "-xtemps");
716                                         strlist_append(&compiler_flags, "-xdeljumps");
717                                         strlist_append(&compiler_flags, "-xinline");
718                               case '0':
719                                         continue;
720                               }
721                               break;
722                     case 'o':
723                               if (argp[2] == '\0') {
724                                         if (argc == 0)
725                                                   missing_argument(argp);
726                                         --argc;
727                                         ++argv;
728                                         if (final_output)
729                                                   error("Only one `-o' option allowed");
730                                         final_output = *argv;
731                                         continue;
732                               }
733                               break;
734                     case 'p':
735                               if (argp[2] == '\0' || strcmp(argp, "-pg") == 0) {
736                                         profile_mode = 1;
737                                         continue;
738                               }
739                               if (strcmp(argp, "-pedantic") == 0)
740                                         continue;
741                               if (strcmp(argp, "-pipe") == 0)
742                                         continue; /* XXX implement me */
743                               if (strcmp(argp, "-pthread") == 0) {
744                                         use_pthread = 1;
745                                         continue;
746                               }
747                               /* XXX -print-prog-name=XXX */
748                               /* XXX -print-multi-os-directory */
749                               break;
750                     case 'r':
751                               if (argp[2] == '\0') {
752                                         strlist_append(&middle_linker_flags, argp);
753                                         continue;
754                               }
755                               break;
756                     case 'S':
757                               if (argp[2] == '\0') {
758                                         set_last_phase(ASSEMBLE);
759                                         continue;
760                               }
761                               break;
762                     case 's':
763                               if (strcmp(argp, "-save-temps") == 0) {
764                                         save_temps = 1;
765                                         continue;
766                               }
767                               if (strcmp(argp, "-shared") == 0) {
768                                         shared_mode = 1;
769                                         continue;
770                               }
771                               if (strcmp(argp, "-static") == 0) {
772                                         static_mode = 1;
773                                         continue;
774                               }
775                               if (strncmp(argp, "-std=", 5) == 0)
776                                         continue; /* XXX sanitize me */
777                               break;
778                     case 't':
779                               if (argp[2] == '\0') {
780                                         strlist_append(&preprocessor_flags, argp);
781                                         continue;
782                               }
783                     case 'U':
784                               strlist_append(&preprocessor_flags, argp);
785                               if (argp[2] == '\0') {
786                                         if (argc == 0)
787                                                   missing_argument(argp);
788                                         --argc;
789                                         ++argv;
790                                         strlist_append(&preprocessor_flags, argp);
791                               }
792                               continue;
793                     case 'v':
794                               if (argp[2] == '\0') {
795                                         verbose_mode = 1;
796                                         continue;
797                               }
798                               break;
799                     case 'W':
800                               if (strncmp(argp, "-Wa,", 4) == 0) {
801                                         split_and_append(&assembler_flags, argp + 4);
802                                         continue;
803                               }
804                               if (strncmp(argp, "-Wl,", 4) == 0) {
805                                         split_and_append(&middle_linker_flags, argp + 4);
806                                         continue;
807                               }
808                               if (strncmp(argp, "-Wp,", 4) == 0) {
809                                         split_and_append(&preprocessor_flags, argp + 4);
810                                         continue;
811                               }
812                               /* XXX warning flags */
813                               break;
814                     case 'x':
815                               /* XXX -x c */
816                               /* XXX -c assembler-with-cpp */
817                               break;
818                     }
819                     error("unknown flag `%s'", argp);
820           }
821 
822           if (last_phase == DEFAULT)
823                     last_phase = LINK;
824 
825           if (verbose_mode)
826                     printf("%s\n", versionstr);
827 
828           if (isysroot == NULL)
829                     isysroot = sysroot;
830           expand_sysroot();
831 
832           if (last_phase != LINK && final_output && !STRLIST_EMPTY(&inputs) &&
833               !STRLIST_NEXT(STRLIST_FIRST(&inputs)))
834                     error("-o specified with more than one input");
835 
836           if (last_phase == PREPROCESS && final_output == NULL)
837                     final_output = "-";
838 
839           if (STRLIST_EMPTY(&inputs))
840                     error("No input specificed");
841 
842           retval = 0;
843 
844           signal(SIGTERM, sigterm_handler);
845 
846           STRLIST_FOREACH(input, &inputs) {
847                     if (handle_input(input->value))
848                               retval = 1;
849           }
850           if (!retval && last_phase == LINK) {
851                     if (run_linker())
852                               retval = 1;
853           }
854 
855           if (exit_now)
856                     warning("Received signal, terminating");
857 
858           cleanup();
859 
860           strlist_free(&crtdirs);
861           strlist_free(&user_sysincdirs);
862           strlist_free(&sysincdirs);
863           strlist_free(&incdirs);
864           strlist_free(&includes);
865           strlist_free(&libdirs);
866           strlist_free(&progdirs);
867           strlist_free(&inputs);
868           strlist_free(&preprocessor_flags);
869           strlist_free(&compiler_flags);
870           strlist_free(&assembler_flags);
871           strlist_free(&early_linker_flags);
872           strlist_free(&middle_linker_flags);
873           strlist_free(&late_linker_flags);
874           strlist_free(&stdlib_flags);
875           strlist_free(&early_program_csu_files);
876           strlist_free(&late_program_csu_files);
877           strlist_free(&early_dso_csu_files);
878           strlist_free(&late_dso_csu_files);
879           strlist_free(&temp_outputs);
880 
881           return retval;
882 }
883