Fix typo
[freeradius.git] / scripts / jlibtool.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #if !defined(__MINGW32__)
23 #include <sys/wait.h>
24 #endif
25 #include <unistd.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <assert.h>
29
30 #ifdef __EMX__
31 #  define SHELL_CMD  "sh"
32 #  define GEN_EXPORTS "emxexp"
33 #  define DEF2IMPLIB_CMD "emximp"
34 #  define SHARE_SW   "-Zdll -Zmtd"
35 #  define USE_OMF 1
36 #  define TRUNCATE_DLL_NAME
37 #  define DYNAMIC_LIB_EXT "dll"
38 #  define EXE_EXT ".exe"
39
40 #  if USE_OMF
41      /* OMF is the native format under OS/2 */
42 #    define STATIC_LIB_EXT "lib"
43 #    define OBJECT_EXT     "obj"
44 #    define LIBRARIAN      "emxomfar"
45 #    define LIBRARIAN_OPTS "cr"
46 #  else
47      /* but the alternative, a.out, can fork() which is sometimes necessary */
48 #    define STATIC_LIB_EXT "a"
49 #    define OBJECT_EXT     "o"
50 #    define LIBRARIAN      "ar"
51 #    define LIBRARIAN_OPTS "cr"
52 #  endif
53 #endif
54
55 #if defined(__APPLE__)
56 #  define SHELL_CMD  "/bin/sh"
57 #  define DYNAMIC_LIB_EXT "dylib"
58 #  define MODULE_LIB_EXT  "bundle"
59 #  define STATIC_LIB_EXT "a"
60 #  define OBJECT_EXT     "o"
61 #  define LIBRARIAN      "ar"
62 #  define LIBRARIAN_OPTS "cr"
63 /* man libtool(1) documents ranlib option of -c.  */
64 #  define RANLIB "ranlib"
65 #  define PIC_FLAG "-fPIC -fno-common"
66 #  define SHARED_OPTS "-dynamiclib"
67 #  define MODULE_OPTS "-bundle -dynamic"
68 #  define DYNAMIC_LINK_OPTS "-flat_namespace"
69 #  define DYNAMIC_LINK_UNDEFINED "-undefined suppress"
70 #  define dynamic_link_version_func darwin_dynamic_link_function
71 #  define DYNAMIC_INSTALL_NAME "-install_name"
72 #  define DYNAMIC_LINK_NO_INSTALL "-dylib_file"
73 #  define HAS_REALPATH
74 /*-install_name  /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
75 #  define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH"
76 #  define LD_LIBRARY_PATH_LOCAL "DYLD_FALLBACK_LIBRARY_PATH"
77 #endif
78
79 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
80 #  define SHELL_CMD  "/bin/sh"
81 #  define DYNAMIC_LIB_EXT "so"
82 #  define MODULE_LIB_EXT  "so"
83 #  define STATIC_LIB_EXT "a"
84 #  define OBJECT_EXT     "o"
85 #  define LIBRARIAN      "ar"
86 #  define LIBRARIAN_OPTS "cr"
87 #  define RANLIB "ranlib"
88 #  define PIC_FLAG "-fPIC"
89 #  define RPATH "-rpath"
90 #  define SHARED_OPTS "-shared"
91 #  define MODULE_OPTS "-shared"
92 #  define DYNAMIC_LINK_OPTS "-export-dynamic"
93 #  define LINKER_FLAG_PREFIX "-Wl,"
94 #  define ADD_MINUS_L
95 #  define LD_RUN_PATH "LD_RUN_PATH"
96 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
97 #  define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
98 #endif
99
100 #if defined(sun)
101 #  define SHELL_CMD  "/bin/sh"
102 #  define DYNAMIC_LIB_EXT "so"
103 #  define MODULE_LIB_EXT  "so"
104 #  define STATIC_LIB_EXT "a"
105 #  define OBJECT_EXT     "o"
106 #  define LIBRARIAN      "ar"
107 #  define LIBRARIAN_OPTS "cr"
108 #  define RANLIB "ranlib"
109 #  define PIC_FLAG "-KPIC"
110 #  define RPATH "-R"
111 #  define SHARED_OPTS "-G"
112 #  define MODULE_OPTS "-G"
113 #  define DYNAMIC_LINK_OPTS ""
114 #  define LINKER_FLAG_NO_EQUALS
115 #  define ADD_MINUS_L
116 #  define HAS_REALPATH
117 #  define LD_RUN_PATH "LD_RUN_PATH"
118 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
119 #  define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
120 #endif
121
122 #if defined(_OSD_POSIX)
123 #  define SHELL_CMD  "/usr/bin/sh"
124 #  define DYNAMIC_LIB_EXT "so"
125 #  define MODULE_LIB_EXT  "so"
126 #  define STATIC_LIB_EXT "a"
127 #  define OBJECT_EXT     "o"
128 #  define LIBRARIAN      "ar"
129 #  define LIBRARIAN_OPTS "cr"
130 #  define SHARED_OPTS "-G"
131 #  define MODULE_OPTS "-G"
132 #  define LINKER_FLAG_PREFIX "-Wl,"
133 #  define NEED_SNPRINTF
134 #endif
135
136 #if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
137 #  define SHELL_CMD  "/usr/bin/sh"
138 #  define DYNAMIC_LIB_EXT "so"
139 #  define MODULE_LIB_EXT  "so"
140 #  define STATIC_LIB_EXT "a"
141 #  define OBJECT_EXT     "o"
142 #  define LIBRARIAN      "ar"
143 #  define LIBRARIAN_OPTS "cr"
144 #  define RPATH "-Brpath"
145 #  define SHARED_OPTS "-G"
146 #  define MODULE_OPTS "-G"
147 #  define DYNAMIC_LINK_OPTS "-Wl,-Blargedynsym"
148 #  define LINKER_FLAG_PREFIX "-Wl,"
149 #  define NEED_SNPRINTF
150 #  define LD_RUN_PATH "LD_RUN_PATH"
151 #  define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
152 #  define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
153 #endif
154
155 #if defined(__MINGW32__)
156 #  define SHELL_CMD "sh"
157 #  define DYNAMIC_LIB_EXT "dll"
158 #  define MODULE_LIB_EXT  "dll"
159 #  define STATIC_LIB_EXT "a"
160 #  define OBJECT_EXT     "o"
161 #  define LIBRARIAN      "ar"
162 #  define LIBRARIAN_OPTS "cr"
163 #  define RANLIB "ranlib"
164 #  define LINKER_FLAG_PREFIX "-Wl,"
165 #  define SHARED_OPTS "-shared"
166 #  define MODULE_OPTS "-shared"
167 #  define MKDIR_NO_UMASK
168 #  define EXE_EXT ".exe"
169 #endif
170
171 #ifndef CC
172 #define CC "gcc"
173 #endif
174
175 #ifndef CXX
176 #define CXX "g++"
177 #endif
178
179 #ifndef LINK_c
180 #define LINK_c "gcc"
181 #endif
182
183 #ifndef LINK_cxx
184 #define LINK_cxx "g++"
185 #endif
186
187 #ifndef LIBDIR
188 #define LIBDIR "/usr/local/lib"
189 #endif
190
191 #define OBJDIR ".libs"
192
193 #ifndef SHELL_CMD
194 #error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
195 #endif
196
197 #ifdef NEED_SNPRINTF
198 #include <stdarg.h>
199 #endif
200
201 #ifdef __EMX__
202 #include <process.h>
203 #endif
204
205 #ifndef PATH_MAX
206 #define PATH_MAX 1024
207 #endif
208
209
210 /* We want to say we are libtool 1.4 for shlibtool compatibility. */
211 #define VERSION "1.4"
212
213 enum tool_mode_t {
214     mUnknown,
215     mCompile,
216     mLink,
217     mExecute,
218     mInstall,
219 };
220
221 enum output_t {
222     otGeneral,
223     otObject,
224     otProgram,
225     otLibrary,
226     otStaticLibraryOnly,
227     otDynamicLibraryOnly,
228     otModule,
229 };
230
231 enum pic_mode_e {
232     pic_UNKNOWN,
233     pic_PREFER,
234     pic_AVOID,
235 };
236
237 enum shared_mode_e {
238     share_UNSET,
239     share_STATIC,
240     share_SHARED,
241 };
242
243 enum lib_type {
244     type_UNKNOWN,
245     type_STATIC_LIB,
246     type_DYNAMIC_LIB,
247     type_MODULE_LIB,
248     type_OBJECT,
249 };
250
251 typedef struct {
252     const char **vals;
253     int num;
254 } count_chars;
255
256 typedef struct {
257     const char *normal;
258     const char *install;
259 } library_name;
260
261 typedef struct {
262     count_chars *normal;
263     count_chars *install;
264     count_chars *dependencies;
265 } library_opts;
266
267 typedef struct {
268     int silent;
269     int debug;
270     enum shared_mode_e shared;
271     int export_all;
272     int dry_run;
273     enum pic_mode_e pic_mode;
274     int export_dynamic;
275     int no_install;
276 } options_t;
277
278 typedef struct {
279     enum tool_mode_t mode;
280     enum output_t output;
281     options_t options;
282
283     char *output_name;
284     char *fake_output_name;
285     char *basename;
286
287     const char *install_path;
288     const char *compiler;
289     const char *program;
290     count_chars *program_opts;
291
292     count_chars *arglist;
293     count_chars *tmp_dirs;
294     count_chars *obj_files;
295     count_chars *dep_rpaths;
296     count_chars *rpaths;
297
298     library_name static_name;
299     library_name shared_name;
300     library_name module_name;
301
302     library_opts static_opts;
303     library_opts shared_opts;
304
305     const char *version_info;
306     const char *undefined_flag;
307 } command_t;
308
309 #ifdef RPATH
310 static void add_rpath(count_chars *cc, const char *path);
311 #endif
312
313 static void usage(int code)
314 {
315         printf("Usage: jlibtool [OPTIONS...] COMMANDS...\n");
316         printf("jlibtool is a replacement for GNU libtool with similar functionality.\n\n");
317
318         printf("    --config          show all configuration variables\n");
319         printf("    --debug           enable verbose shell tracing\n");
320         printf("    --dry-run         display commands without modifying any files\n");
321         printf("    --help            display this help message and exit\n");
322         printf("    --mode=MODE       use operational mode MODE (you *must* set mode)\n");
323
324         printf("    --silent          don't print informational messages\n");
325         printf("    --tag=TAG         Ignored for libtool compatibility\n");
326         printf("    --version         print version information\n");
327
328
329         printf("    --shared          Build shared libraries when using --mode=link\n");
330         printf("    --export-all      Try to export 'def' file on some platforms\n");
331
332         printf("\nMODE must be one of the following:\n\n");
333         printf("      compile         compile a source file into a jlibtool object\n");
334         printf("      execute         automatically set library path, then run a program\n");
335         printf("      install         install libraries or executables\n");
336         printf("      link            create a library or an executable\n");
337
338         printf("\nMODE-ARGS can be the following:\n\n");
339         printf("      -export-dynamic  accepted and ignored\n");
340         printf("      -module          create a module when linking\n");
341         printf("      -shared          create a shared library when linking\n");
342         printf("      -prefer-pic      prefer position-independent-code when compiling\n");
343         printf("      -prefer-non-pic  prefer non position-independent-code when compiling\n");
344         printf("      -static          create a static library when linking\n");
345         printf("      -no-install      link libraries locally\n");
346         printf("      -rpath arg       Set install path for shared libraries\n");
347         printf("      -l arg           pass '-l arg' to the link stage\n");
348         printf("      -L arg           pass '-L arg' to the link stage\n");
349         printf("      -R dir           add 'dir' to runtime library search path.\n");
350         printf("      -Zexe            accepted and ignored\n");
351         printf("      -avoid-version   accepted and ignored\n");
352
353         exit(code);
354 }
355
356 #if defined(NEED_SNPRINTF)
357 /* Write at most n characters to the buffer in str, return the
358  * number of chars written or -1 if the buffer would have been
359  * overflowed.
360  *
361  * This is portable to any POSIX-compliant system has /dev/null
362  */
363 static FILE *f=NULL;
364 static int vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
365 {
366        int res;
367
368        if (f == NULL)
369                f = fopen("/dev/null","w");
370        if (f == NULL)
371                return -1;
372
373        setvbuf( f, str, _IOFBF, n );
374
375        res = vfprintf( f, fmt, ap );
376
377        if ( res > 0 && res < n ) {
378                res = vsprintf( str, fmt, ap );
379        }
380        return res;
381 }
382 static int snprintf( char *str, size_t n, const char *fmt, ... )
383 {
384         va_list ap;
385         int res;
386
387         va_start( ap, fmt );
388         res = vsnprintf( str, n, fmt, ap );
389         va_end( ap );
390         return res;
391 }
392 #endif
393
394 static void init_count_chars(count_chars *cc)
395 {
396     cc->vals = (const char**)malloc(PATH_MAX*sizeof(char*));
397     cc->num = 0;
398 }
399
400 static void clear_count_chars(count_chars *cc)
401 {
402     int i;
403     for (i = 0; i < cc->num; i++) {
404         cc->vals[i] = 0;
405     }
406
407     cc->num = 0;
408 }
409
410 static void push_count_chars(count_chars *cc, const char *newval)
411 {
412     cc->vals[cc->num++] = newval;
413 }
414
415 static void pop_count_chars(count_chars *cc)
416 {
417     cc->num--;
418 }
419
420 static void insert_count_chars(count_chars *cc, const char *newval, int position)
421 {
422     int i;
423
424     for (i = cc->num; i > position; i--) {
425         cc->vals[i] = cc->vals[i-1];
426     }
427
428     cc->vals[position] = newval;
429     cc->num++;
430 }
431
432 static void append_count_chars(count_chars *cc, count_chars *cctoadd)
433 {
434     int i;
435     for (i = 0; i < cctoadd->num; i++) {
436         if (cctoadd->vals[i]) {
437             push_count_chars(cc, cctoadd->vals[i]);
438         }
439     }
440 }
441
442 static const char *flatten_count_chars(count_chars *cc, int space)
443 {
444     int i, size;
445     char *newval;
446
447     size = 0;
448     for (i = 0; i < cc->num; i++) {
449         if (cc->vals[i]) {
450             size += strlen(cc->vals[i]) + 1;
451             if (space) {
452               size++;
453             }
454         }
455     }
456
457     newval = (char*)malloc(size + 1);
458     newval[0] = 0;
459
460     for (i = 0; i < cc->num; i++) {
461         if (cc->vals[i]) {
462             strcat(newval, cc->vals[i]);
463             if (space) {
464                 strcat(newval, " ");
465             }
466         }
467     }
468
469     return newval;
470 }
471
472 static char *shell_esc(const char *str)
473 {
474     int in_quote = 0;
475     char *cmd;
476     unsigned char *d;
477     const unsigned char *s;
478
479     cmd = (char *)malloc(2 * strlen(str) + 3);
480     d = (unsigned char *)cmd;
481     s = (const unsigned char *)str;
482
483 #ifdef __MINGW32__
484     *d++ = '\"';
485 #endif
486
487     for (; *s; ++s) {
488         if (*s == '"') {
489             *d++ = '\\';
490             in_quote++;
491         }
492         else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
493             *d++ = '\\';
494         }
495         *d++ = *s;
496     }
497
498 #ifdef __MINGW32__
499     *d++ = '\"';
500 #endif
501
502     *d = '\0';
503     return cmd;
504 }
505
506 static int external_spawn(command_t *cmd, const char *file, const char **argv)
507 {
508     file = file;                /* -Wunused */
509
510     if (!cmd->options.silent) {
511         const char **argument = argv;
512         printf("Executing: ");
513         while (*argument) {
514             printf("%s ", *argument);
515             argument++;
516         }
517         puts("");
518     }
519
520     if (cmd->options.dry_run) {
521         return 0;
522     }
523 #if defined(__EMX__) || defined(__MINGW32__)
524     return spawnvp(P_WAIT, argv[0], argv);
525 #else
526     {
527         pid_t pid;
528         pid = fork();
529         if (pid == 0) {
530             return execvp(argv[0], (char**)argv);
531         }
532         else {
533             int statuscode;
534             waitpid(pid, &statuscode, 0);
535             if (WIFEXITED(statuscode)) {
536                 return WEXITSTATUS(statuscode);
537             }
538             return 0;
539         }
540     }
541 #endif
542 }
543
544 static int run_command(command_t *cmd_data, count_chars *cc)
545 {
546     char *command;
547     const char *spawn_args[4];
548     count_chars tmpcc;
549
550     init_count_chars(&tmpcc);
551
552     if (cmd_data->program) {
553         push_count_chars(&tmpcc, cmd_data->program);
554     }
555
556     append_count_chars(&tmpcc, cmd_data->program_opts);
557
558     append_count_chars(&tmpcc, cc);
559
560     command = shell_esc(flatten_count_chars(&tmpcc, 1));
561
562     spawn_args[0] = SHELL_CMD;
563     spawn_args[1] = "-c";
564     spawn_args[2] = command;
565     spawn_args[3] = NULL;
566     return external_spawn(cmd_data, spawn_args[0], spawn_args);
567 }
568
569 /*
570  * print configuration
571  * shlibpath_var is used in configure.
572  */
573 #define printc(_x,_y) if (!value || !strcmp(value, _x)) printf(_x "=\"%s\"\n", _y)
574
575 static void print_config(const char *value)
576 {
577 #ifdef LD_RUN_PATH
578     printc("runpath_var", LD_RUN_PATH);
579 #endif
580 #ifdef LD_LIBRARY_PATH
581     printc("shlibpath_var", LD_LIBRARY_PATH);
582 #endif
583 #ifdef LD_LIBRARY_PATH_LOCAL
584     printc("shlocallibpath_var", LD_LIBRARY_PATH_LOCAL);
585 #endif
586 #ifdef SHELL_CMD
587     printc("SHELL", SHELL_CMD);
588 #endif
589 #ifdef OBJECT_EXT
590     printc("objext", OBJECT_EXT);
591 #endif
592 #ifdef OBJDIR
593     printc("objdir", OBJDIR);
594 #endif
595 #ifdef DYNAMIC_LIB_EXT
596     /* add a '.' prefix because libtool does that. */
597     printc("shrext_cmds", "echo ." DYNAMIC_LIB_EXT);
598     /* add a '.' prefix because libtool does that. */
599     printc("shrext", "." DYNAMIC_LIB_EXT);
600 #endif
601 #ifdef EXE_EXT
602     printc("exeext", EXE_EXT);
603 #endif
604 #ifdef STATIC_LIB_EXT
605     printc("libext", STATIC_LIB_EXT);
606 #endif
607 #ifdef LIBRARIAN
608     printc("AR", LIBRARIAN);
609 #endif
610 #ifdef LIBRARIAN_OPTS
611     printc("AR_FLAGS", LIBRARIAN_OPTS);
612 #endif
613 #ifdef LINKER_FLAG_PREFIX
614     printc("wl", LINKER_FLAG_PREFIX);
615 #endif
616 #ifdef RANLIB
617     printc("ranlib", RANLIB);
618 #endif
619
620 }
621 /*
622  * Add a directory to the runtime library search path.
623  */
624 static void add_runtimedirlib(char *arg, command_t *cmd_data)
625 {
626 #ifdef RPATH
627     add_rpath(cmd_data->shared_opts.dependencies, arg);
628 #else
629     arg = arg;                  /* -Wunused */
630     cmd_data = cmd_data;
631 #endif
632 }
633
634 static int parse_long_opt(char *arg, command_t *cmd_data)
635 {
636     char *equal_pos = strchr(arg, '=');
637     char var[50];
638     char value[500];
639
640     if (equal_pos) {
641         strncpy(var, arg, equal_pos - arg);
642         var[equal_pos - arg] = 0;
643         strcpy(value, equal_pos + 1);
644     } else {
645         strcpy(var, arg);
646         value[0] = '\0';
647     }
648
649     if (strcmp(var, "silent") == 0) {
650         cmd_data->options.silent = 1;
651     } else if (strcmp(var, "debug") == 0) {
652         cmd_data->options.debug = 1;
653     } else if (strcmp(var, "mode") == 0) {
654         if (cmd_data->mode != mUnknown) {
655                 fprintf(stderr, "Cannot set --mode twice\n");
656                 exit(1);
657         }
658
659         if (strcmp(value, "compile") == 0) {
660             cmd_data->mode = mCompile;
661             cmd_data->output = otObject;
662
663         } else if (strcmp(value, "link") == 0) {
664             cmd_data->mode = mLink;
665             cmd_data->output = otLibrary;
666
667         } else if (strcmp(value, "install") == 0) {
668             cmd_data->mode = mInstall;
669
670         } else if (strcmp(value, "execute") == 0) {
671             cmd_data->mode = mExecute;
672
673         } else {
674             printf("Unknown mode \"%s\"\n", value);
675         }
676     } else if (strcmp(var, "shared") == 0) {
677       if ((cmd_data->mode == mLink) &&
678           (cmd_data->output == otGeneral)) {
679             cmd_data->output = otDynamicLibraryOnly;
680         }
681         cmd_data->options.shared = share_SHARED;
682     } else if (strcmp(var, "export-all") == 0) {
683         cmd_data->options.export_all = 1;
684     } else if (strcmp(var, "dry-run") == 0) {
685         printf("Dry-run mode on!\n");
686         cmd_data->options.dry_run = 1;
687     } else if (strcmp(var, "version") == 0) {
688         printf("Version " VERSION "\n");
689     } else if (strcmp(var, "help") == 0) {
690         usage(0);
691     } else if (strcmp(var, "config") == 0) {
692         print_config(value);
693         exit(0);
694     } else if (strcmp(var, "tag") == 0) {
695         if (strcmp(value, "CC") == 0) {
696             /* Do nothing. */
697         }
698         if (strcmp(value, "CXX") == 0) {
699             /* Do nothing. */
700         }
701     } else {
702         return 0;
703     }
704
705     return 1;
706 }
707
708 /* Return 1 if we eat it. */
709 static int parse_short_opt(char *arg, command_t *cmd_data)
710 {
711     if (strcmp(arg, "export-dynamic") == 0) {
712         cmd_data->options.export_dynamic = 1;
713         return 1;
714     }
715
716     if (strcmp(arg, "module") == 0) {
717         cmd_data->output = otModule;
718         return 1;
719     }
720
721     if (strcmp(arg, "shared") == 0) {
722         if (cmd_data->mode == mLink) {
723             cmd_data->output = otDynamicLibraryOnly;
724         }
725         cmd_data->options.shared = share_SHARED;
726         return 1;
727     }
728
729     if (strcmp(arg, "Zexe") == 0) {
730         return 1;
731     }
732
733     if (strcmp(arg, "avoid-version") == 0) {
734         return 1;
735     }
736
737     if (strcmp(arg, "prefer-pic") == 0) {
738         cmd_data->options.pic_mode = pic_PREFER;
739         return 1;
740     }
741
742     if (strcmp(arg, "prefer-non-pic") == 0) {
743         cmd_data->options.pic_mode = pic_AVOID;
744         return 1;
745     }
746
747     if (strcmp(arg, "static") == 0) {
748        if ((cmd_data->mode == mLink) &&
749           (cmd_data->output == otLibrary)) {
750             cmd_data->output = otStaticLibraryOnly;
751         }
752         cmd_data->options.shared = share_STATIC;
753         return 1;
754     }
755
756     if (cmd_data->mode == mLink) {
757         if (strcmp(arg, "no-install") == 0) {
758             cmd_data->options.no_install = 1;
759             return 1;
760         }
761         if (arg[0] == 'L' || arg[0] == 'l') {
762             /* Hack... */
763             arg--;
764             push_count_chars(cmd_data->shared_opts.dependencies, arg);
765             return 1;
766         } else if (arg[0] == 'R' && arg[1]) {
767             /* -Rdir Add dir to runtime library search path. */
768             add_runtimedirlib(&arg[1], cmd_data);
769             return 1;
770         }
771     }
772     return 0;
773 }
774
775 #ifdef TRUNCATE_DLL_NAME
776 static char *truncate_dll_name(char *path)
777 {
778     /* Cut DLL name down to 8 characters after removing any mod_ prefix */
779     char *tmppath = strdup(path);
780     char *newname = strrchr(tmppath, '/') + 1;
781     char *ext = strrchr(newname, '.');
782     int len;
783
784     if (ext == NULL)
785         return tmppath;
786
787     len = ext - newname;
788
789     if (strncmp(newname, "mod_", 4) == 0) {
790         strcpy(newname, newname + 4);
791         len -= 4;
792     }
793
794     if (len > 8) {
795         strcpy(newname + 8, strchr(newname, '.'));
796     }
797
798     return tmppath;
799 }
800 #endif
801
802 static long safe_strtol(const char *nptr, const char **endptr, int base)
803 {
804     long rv;
805
806     errno = 0;
807
808     rv = strtol(nptr, (char**)endptr, 10);
809
810     if (errno == ERANGE) {
811         return 0;
812     }
813
814     return rv;
815 }
816
817 static void safe_mkdir(const char *path)
818 {
819     mode_t old_umask;
820
821     old_umask = umask(0);
822     umask(old_umask);
823
824 #ifdef MKDIR_NO_UMASK
825     mkdir(path);
826 #else
827     mkdir(path, ~old_umask);
828 #endif
829 }
830
831 /* returns just a file's name without the path */
832 static const char *jlibtool_basename(const char *fullpath)
833 {
834     const char *name = strrchr(fullpath, '/');
835
836     if (name == NULL) {
837         name = strrchr(fullpath, '\\');
838     }
839
840     if (name == NULL) {
841         name = fullpath;
842     } else {
843         name++;
844     }
845
846     return name;
847 }
848
849 #ifdef GEN_EXPORTS
850 /* returns just a file's name without path or extension */
851 static const char *nameof(const char *fullpath)
852 {
853     const char *name;
854     const char *ext;
855
856     name = jlibtool_basename(fullpath);
857     ext = strrchr(name, '.');
858
859     if (ext) {
860         char *trimmed;
861         trimmed = malloc(ext - name + 1);
862         strncpy(trimmed, name, ext - name);
863         trimmed[ext-name] = 0;
864         return trimmed;
865     }
866
867     return name;
868 }
869 #endif
870
871 /* version_info is in the form of MAJOR:MINOR:PATCH */
872 static const char *darwin_dynamic_link_function(const char *version_info)
873 {
874     char *newarg;
875     long major, minor, patch;
876
877     major = 0;
878     minor = 0;
879     patch = 0;
880
881     if (version_info) {
882         major = safe_strtol(version_info, &version_info, 10);
883
884         if (version_info) {
885             if (version_info[0] == ':') {
886                 version_info++;
887             }
888
889             minor = safe_strtol(version_info, &version_info, 10);
890
891             if (version_info) {
892                 if (version_info[0] == ':') {
893                     version_info++;
894                 }
895
896                 patch = safe_strtol(version_info, &version_info, 10);
897
898             }
899         }
900     }
901
902     /* Avoid -dylib_compatibility_version must be greater than zero errors. */
903     if (major == 0) {
904         major = 1;
905     }
906     newarg = (char*)malloc(100);
907     snprintf(newarg, 99,
908              "-compatibility_version %ld -current_version %ld.%ld",
909              major, major, minor);
910
911     return newarg;
912 }
913
914
915 /*
916  *      Add a '.libs/' to the buffer.  The caller ensures that
917  *      The buffer is large enough to handle 6 extra characters.
918  */
919 static void add_dotlibs(char *buffer)
920 {
921         char *name = strrchr(buffer, '/');
922
923         if (!name) {
924                 if (!buffer[0]) {
925                         strcpy(buffer, ".libs/");
926                         return;
927                 }
928                 name = buffer;
929         } else {
930                 name++;
931         }
932         memmove(name + 6, name, strlen(name));
933         memcpy(name, ".libs/", 6);
934 }
935
936 static char *gen_library_name(const char *name, enum lib_type genlib)
937 {
938     char *newarg, *newext;
939
940     newarg = (char *)malloc(strlen(name) + 11);
941
942     if (genlib == type_MODULE_LIB && strncmp(name, "lib", 3) == 0) {
943         name += 3;
944     }
945
946     if (genlib == type_MODULE_LIB) {
947         strcat(newarg, jlibtool_basename(name));
948     }
949     else {
950         strcat(newarg, name);
951     }
952
953     newext = strrchr(newarg, '.') + 1;
954
955     switch (genlib) {
956     case type_STATIC_LIB:
957         strcpy(newext, STATIC_LIB_EXT);
958         break;
959     case type_DYNAMIC_LIB:
960         strcpy(newext, DYNAMIC_LIB_EXT);
961         break;
962     case type_MODULE_LIB:
963         strcpy(newext, MODULE_LIB_EXT);
964         break;
965
966     default:
967         break;
968     }
969
970     add_dotlibs(newarg);
971
972     return newarg;
973 }
974
975 static char *gen_install_name(const char *name, enum lib_type genlib)
976 {
977     struct stat sb;
978     char *newname;
979     int rv;
980
981     newname = gen_library_name(name, genlib);
982
983     /* Check if it exists. If not, return NULL.  */
984     rv = stat(newname, &sb);
985
986     if (rv) {
987         return NULL;
988     }
989
990     return newname;
991 }
992
993 static const char *check_object_exists(command_t *cmd, const char *arg, int arglen)
994 {
995     char *newarg, *ext;
996     int pass, rv;
997
998     newarg = (char *)malloc(arglen + 10);
999     memcpy(newarg, arg, arglen);
1000     newarg[arglen] = 0;
1001     ext = newarg + arglen;
1002
1003     pass = 0;
1004
1005     do {
1006         struct stat sb;
1007
1008         switch (pass) {
1009         case 0:
1010             strcpy(ext, OBJECT_EXT);
1011             break;
1012 /*
1013         case 1:
1014             strcpy(ext, NO_PIC_EXT);
1015             break;
1016 */
1017         default:
1018             break;
1019         }
1020
1021         if (cmd->options.debug) {
1022             printf("Checking (obj): %s\n", newarg);
1023         }
1024         rv = stat(newarg, &sb);
1025     }
1026     while (rv != 0 && ++pass < 1);
1027
1028     if (rv == 0) {
1029         if (pass == 1) {
1030             cmd->options.pic_mode = pic_AVOID;
1031         }
1032         return newarg;
1033     }
1034
1035     return NULL;
1036 }
1037
1038 /* libdircheck values:
1039  * 0 - no .libs suffix
1040  * 1 - .libs suffix
1041  */
1042 static char *check_library_exists(command_t *cmd, const char *arg, int pathlen,
1043                            int libdircheck, enum lib_type *libtype)
1044 {
1045     char *newarg, *ext;
1046     int pass, rv, newpathlen;
1047
1048     newarg = (char *)malloc(strlen(arg) + 10);
1049     strcpy(newarg, arg);
1050     newarg[pathlen] = 0;
1051
1052     newpathlen = pathlen;
1053     if (libdircheck) {
1054         add_dotlibs(newarg);
1055         newpathlen += sizeof(".libs/") - 1;
1056     }
1057
1058     strcpy(newarg+newpathlen, arg+pathlen);
1059     ext = strrchr(newarg, '.') + 1;
1060
1061     pass = 0;
1062
1063     do {
1064         struct stat sb;
1065
1066         switch (pass) {
1067         case 0:
1068             if (cmd->options.pic_mode != pic_AVOID &&
1069                 cmd->options.shared != share_STATIC) {
1070                 strcpy(ext, DYNAMIC_LIB_EXT);
1071                 *libtype = type_DYNAMIC_LIB;
1072                 break;
1073             }
1074             pass = 1;
1075             /* Fall through */
1076         case 1:
1077             strcpy(ext, STATIC_LIB_EXT);
1078             *libtype = type_STATIC_LIB;
1079             break;
1080         case 2:
1081             strcpy(ext, MODULE_LIB_EXT);
1082             *libtype = type_MODULE_LIB;
1083             break;
1084         case 3:
1085             strcpy(ext, OBJECT_EXT);
1086             *libtype = type_OBJECT;
1087             break;
1088         default:
1089             *libtype = type_UNKNOWN;
1090             break;
1091         }
1092
1093         if (cmd->options.debug) {
1094             printf("Checking (lib): %s\n", newarg);
1095         }
1096         rv = stat(newarg, &sb);
1097     }
1098     while (rv != 0 && ++pass < 4);
1099
1100     if (rv == 0) {
1101         return newarg;
1102     }
1103
1104     return NULL;
1105 }
1106
1107 static char * load_install_path(const char *arg)
1108 {
1109     FILE *f;
1110     char *path;
1111
1112     path = malloc(PATH_MAX);
1113
1114     f = fopen(arg,"r");
1115     if (f == NULL) {
1116         return NULL;
1117     }
1118     fgets(path, PATH_MAX, f);
1119     fclose(f);
1120     if (path[strlen(path)-1] == '\n') {
1121         path[strlen(path)-1] = '\0';
1122     }
1123     /* Check that we have an absolute path.
1124      * Otherwise the file could be a GNU libtool file.
1125      */
1126     if (path[0] != '/') {
1127         return NULL;
1128     }
1129     return path;
1130 }
1131
1132 static char * load_noinstall_path(const char *arg, int pathlen)
1133 {
1134     char *newarg, *expanded_path;
1135     int newpathlen;
1136
1137     newarg = (char *)malloc(strlen(arg) + 10);
1138     strcpy(newarg, arg);
1139     newarg[pathlen] = 0;
1140
1141     newpathlen = pathlen;
1142     strcat(newarg, ".libs");
1143     newpathlen += sizeof(".libs") - 1;
1144     newarg[newpathlen] = 0;
1145
1146 #ifdef HAS_REALPATH
1147     expanded_path = malloc(PATH_MAX);
1148     expanded_path = realpath(newarg, expanded_path);
1149     /* Uh, oh.  There was an error.  Fall back on our first guess. */
1150     if (!expanded_path) {
1151         expanded_path = newarg;
1152     }
1153 #else
1154     /* We might get ../ or something goofy.  Oh, well. */
1155     expanded_path = newarg;
1156 #endif
1157
1158     return expanded_path;
1159 }
1160
1161 static void add_dynamic_link_opts(command_t *cmd_data, count_chars *args)
1162 {
1163 #ifdef DYNAMIC_LINK_OPTS
1164     if (cmd_data->options.pic_mode != pic_AVOID) {
1165         if (cmd_data->options.debug) {
1166            printf("Adding: %s\n", DYNAMIC_LINK_OPTS);
1167         }
1168         push_count_chars(args, DYNAMIC_LINK_OPTS);
1169         if (cmd_data->undefined_flag) {
1170             push_count_chars(args, "-undefined");
1171 #if defined(__APPLE__)
1172             /* -undefined dynamic_lookup is used by the bundled Python in
1173              * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
1174              * we'll get a linker error if we pass this flag.
1175              */
1176             if (strcasecmp(cmd_data->undefined_flag,
1177                            "dynamic_lookup") == 0) {
1178                 insert_count_chars(cmd_data->program_opts,
1179                                    "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
1180             }
1181 #endif
1182             push_count_chars(args, cmd_data->undefined_flag);
1183         }
1184         else {
1185 #ifdef DYNAMIC_LINK_UNDEFINED
1186             if (cmd_data->options.debug) {
1187                 printf("Adding: %s\n", DYNAMIC_LINK_UNDEFINED);
1188             }
1189             push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
1190 #endif
1191         }
1192     }
1193 #endif
1194 }
1195
1196 /* Read the final install location and add it to runtime library search path. */
1197 #ifdef RPATH
1198 static void add_rpath(count_chars *cc, const char *path)
1199 {
1200     int size = 0;
1201     char *tmp;
1202
1203 #ifdef LINKER_FLAG_PREFIX
1204     size = strlen(LINKER_FLAG_PREFIX);
1205 #endif
1206     size = size + strlen(path) + strlen(RPATH) + 2;
1207     tmp = malloc(size);
1208     if (tmp == NULL) {
1209         return;
1210     }
1211 #ifdef LINKER_FLAG_PREFIX
1212     strcpy(tmp, LINKER_FLAG_PREFIX);
1213     strcat(tmp, RPATH);
1214 #else
1215     strcpy(tmp, RPATH);
1216 #endif
1217 #ifndef LINKER_FLAG_NO_EQUALS
1218     strcat(tmp, "=");
1219 #endif
1220     strcat(tmp, path);
1221
1222     push_count_chars(cc, tmp);
1223 }
1224
1225 static void add_rpath_file(count_chars *cc, const char *arg)
1226 {
1227     const char *path;
1228
1229     path = load_install_path(arg);
1230     if (path) {
1231         add_rpath(cc, path);
1232     }
1233 }
1234
1235 static void add_rpath_noinstall(count_chars *cc, const char *arg, int pathlen)
1236 {
1237     const char *path;
1238
1239     path = load_noinstall_path(arg, pathlen);
1240     if (path) {
1241         add_rpath(cc, path);
1242     }
1243 }
1244 #endif
1245
1246 #ifdef DYNAMIC_LINK_NO_INSTALL
1247 static void add_dylink_noinstall(count_chars *cc, const char *arg, int pathlen,
1248                           int extlen)
1249 {
1250     const char *install_path, *current_path, *name;
1251     char *exp_argument;
1252     int i_p_len, c_p_len, name_len, dyext_len, cur_len;
1253
1254     install_path = load_install_path(arg);
1255     current_path = load_noinstall_path(arg, pathlen);
1256
1257     if (!install_path || !current_path) {
1258         return;
1259     }
1260
1261     push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
1262
1263     i_p_len = strlen(install_path);
1264     c_p_len = strlen(current_path);
1265
1266     name = arg+pathlen;
1267     name_len = extlen-pathlen;
1268     dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
1269
1270     /* No, we need to replace the extension. */
1271     exp_argument = (char *)malloc(i_p_len + c_p_len + (name_len*2) +
1272                                   (dyext_len*2) + 2);
1273
1274     cur_len = 0;
1275     strcpy(exp_argument, install_path);
1276     cur_len += i_p_len;
1277     exp_argument[cur_len++] = '/';
1278     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1279     cur_len += name_len;
1280     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1281     cur_len += dyext_len;
1282     exp_argument[cur_len++] = ':';
1283     strcpy(exp_argument+cur_len, current_path);
1284     cur_len += c_p_len;
1285     exp_argument[cur_len++] = '/';
1286     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1287     cur_len += name_len;
1288     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1289     cur_len += dyext_len;
1290
1291     push_count_chars(cc, exp_argument);
1292 }
1293 #endif
1294
1295 #ifdef ADD_MINUS_L
1296 /* use -L -llibname to allow to use installed libraries */
1297 static void add_minus_l(count_chars *cc, const char *arg)
1298 {
1299     char *newarg;
1300     char *name = strrchr(arg, '/');
1301     char *file = strrchr(arg, '.');
1302     char *lib  = strstr(name, "lib");
1303
1304     if (name !=NULL && file != NULL && lib == name+1) {
1305         *name = '\0';
1306         *file = '\0';
1307         file = name;
1308         file = file+4;
1309         push_count_chars(cc, "-L");
1310         push_count_chars(cc, arg);
1311         /* we need one argument like -lapr-1 */
1312         newarg = malloc(strlen(file) + 3);
1313         strcpy(newarg, "-l");
1314         strcat(newarg, file);
1315         push_count_chars(cc, newarg);
1316     } else {
1317         push_count_chars(cc, arg);
1318     }
1319 }
1320 #endif
1321
1322 #if 0
1323 static void add_linker_flag_prefix(count_chars *cc, const char *arg)
1324 {
1325 #ifndef LINKER_FLAG_PREFIX
1326     push_count_chars(cc, arg);
1327 #else
1328     char *newarg;
1329     newarg = (char*)malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
1330     strcpy(newarg, LINKER_FLAG_PREFIX);
1331     strcat(newarg, arg);
1332     push_count_chars(cc, newarg);
1333 #endif
1334 }
1335 #endif
1336
1337 static int explode_static_lib(command_t *cmd_data, const char *lib)
1338 {
1339     count_chars tmpdir_cc, libname_cc;
1340     const char *tmpdir, *libname;
1341     char savewd[PATH_MAX];
1342     const char *name;
1343     DIR *dir;
1344     struct dirent *entry;
1345     const char *lib_args[4];
1346
1347     /* Bah! */
1348     if (cmd_data->options.dry_run) {
1349         return 0;
1350     }
1351
1352     name = jlibtool_basename(lib);
1353
1354     init_count_chars(&tmpdir_cc);
1355     push_count_chars(&tmpdir_cc, ".libs/");
1356     push_count_chars(&tmpdir_cc, name);
1357     push_count_chars(&tmpdir_cc, ".exploded/");
1358     tmpdir = flatten_count_chars(&tmpdir_cc, 0);
1359
1360     if (!cmd_data->options.silent) {
1361         printf("Making: %s\n", tmpdir);
1362     }
1363     safe_mkdir(tmpdir);
1364
1365     push_count_chars(cmd_data->tmp_dirs, tmpdir);
1366
1367     getcwd(savewd, sizeof(savewd));
1368
1369     if (chdir(tmpdir) != 0) {
1370         if (!cmd_data->options.silent) {
1371             printf("Warning: could not explode %s\n", lib);
1372         }
1373         return 1;
1374     }
1375
1376     if (lib[0] == '/') {
1377         libname = lib;
1378     }
1379     else {
1380         init_count_chars(&libname_cc);
1381         push_count_chars(&libname_cc, "../../");
1382         push_count_chars(&libname_cc, lib);
1383         libname = flatten_count_chars(&libname_cc, 0);
1384     }
1385
1386     lib_args[0] = LIBRARIAN;
1387     lib_args[1] = "x";
1388     lib_args[2] = libname;
1389     lib_args[3] = NULL;
1390
1391     external_spawn(cmd_data, LIBRARIAN, lib_args);
1392
1393     chdir(savewd);
1394     dir = opendir(tmpdir);
1395
1396     while ((entry = readdir(dir)) != NULL) {
1397 #if defined(__APPLE__) && defined(RANLIB)
1398         /* Apple inserts __.SYMDEF which isn't needed.
1399          * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
1400          * much fun either.  Just skip them.
1401          */
1402         if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
1403             continue;
1404         }
1405 #endif
1406         if (entry->d_name[0] != '.') {
1407             push_count_chars(&tmpdir_cc, entry->d_name);
1408             name = flatten_count_chars(&tmpdir_cc, 0);
1409             if (cmd_data->options.debug) {
1410                 printf("Adding: %s\n", name);
1411             }
1412             push_count_chars(cmd_data->obj_files, name);
1413             pop_count_chars(&tmpdir_cc);
1414         }
1415     }
1416
1417     closedir(dir);
1418     return 0;
1419 }
1420
1421 static int parse_input_file_name(char *arg, command_t *cmd_data)
1422 {
1423     const char *ext = strrchr(arg, '.');
1424     const char *name;
1425     int pathlen;
1426     enum lib_type libtype;
1427     const char *newarg;
1428
1429     if (!ext) {
1430         return 0;
1431     }
1432
1433     ext++;
1434     name = jlibtool_basename(arg);
1435
1436     pathlen = name - arg;
1437
1438     if (strcmp(ext, "lo") == 0) {
1439         newarg = check_object_exists(cmd_data, arg, ext - arg);
1440         if (!newarg) {
1441             fprintf(stderr, "Can not find suitable object file for %s\n", arg);
1442             exit(1);
1443         }
1444         if (cmd_data->mode != mLink) {
1445             push_count_chars(cmd_data->arglist, newarg);
1446         }
1447         else {
1448             push_count_chars(cmd_data->obj_files, newarg);
1449         }
1450         return 1;
1451     }
1452
1453     if (strcmp(ext, "la") == 0) {
1454         switch (cmd_data->mode) {
1455         case mLink:
1456             /* Try the .libs dir first! */
1457             newarg = check_library_exists(cmd_data, arg, pathlen, 1, &libtype);
1458             if (!newarg) {
1459                 /* Try the normal dir next. */
1460                 newarg = check_library_exists(cmd_data, arg, pathlen, 0, &libtype);
1461                 if (!newarg) {
1462                     fprintf(stderr, "Can not find suitable library for %s\n", arg);
1463                     exit(1);
1464                 }
1465             }
1466
1467             /* It is not ok to just add the file: a library may added with:
1468                1 - -L path library_name. (For *.so in Linux).
1469                2 - library_name.
1470              */
1471 #ifdef ADD_MINUS_L
1472             if (libtype == type_DYNAMIC_LIB) {
1473                  add_minus_l(cmd_data->shared_opts.dependencies, newarg);
1474             } else if (cmd_data->output == otLibrary &&
1475                        libtype == type_STATIC_LIB) {
1476                 explode_static_lib(cmd_data, newarg);
1477             } else {
1478                  push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1479             }
1480 #else
1481             if (cmd_data->output == otLibrary && libtype == type_STATIC_LIB) {
1482                 explode_static_lib(cmd_data, newarg);
1483             }
1484             else {
1485                 push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1486             }
1487 #endif
1488             if (libtype == type_DYNAMIC_LIB) {
1489                 if (cmd_data->options.no_install) {
1490 #ifdef RPATH
1491                     add_rpath_noinstall(cmd_data->shared_opts.dependencies,
1492                                         arg, pathlen);
1493 #endif
1494 #ifdef DYNAMIC_LINK_NO_INSTALL
1495                     /*
1496                      * This doesn't work as Darwin's linker has no way to
1497                      * override at link-time the search paths for a
1498                      * non-installed library.
1499                      */
1500                     /*
1501                     add_dylink_noinstall(cmd_data->shared_opts.dependencies,
1502                                          arg, pathlen, ext - arg);
1503                     */
1504 #endif
1505                 }
1506                 else {
1507 #ifdef RPATH
1508                     add_rpath_file(cmd_data->shared_opts.dependencies, arg);
1509 #endif
1510                 }
1511             }
1512             break;
1513         case mInstall:
1514             /* If we've already recorded a library to install, we're most
1515              * likely getting the .la file that we want to install as.
1516              * The problem is that we need to add it as the directory,
1517              * not the .la file itself.  Otherwise, we'll do odd things.
1518              */
1519             if (cmd_data->output == otLibrary) {
1520                 arg[pathlen] = '\0';
1521                 push_count_chars(cmd_data->arglist, arg);
1522             }
1523             else {
1524                 cmd_data->output = otLibrary;
1525                 cmd_data->output_name = arg;
1526                 cmd_data->static_name.install = gen_install_name(arg, 0);
1527                 cmd_data->shared_name.install = gen_install_name(arg, 1);
1528                 cmd_data->module_name.install = gen_install_name(arg, 2);
1529             }
1530             break;
1531         default:
1532             break;
1533         }
1534         return 1;
1535     }
1536
1537     if (strcmp(ext, "c") == 0) {
1538         /* If we don't already have an idea what our output name will be. */
1539         if (cmd_data->basename == NULL) {
1540             cmd_data->basename = (char *)malloc(strlen(arg) + 4);
1541             strcpy(cmd_data->basename, arg);
1542             strcpy(strrchr(cmd_data->basename, '.') + 1, "lo");
1543
1544             cmd_data->fake_output_name = strrchr(cmd_data->basename, '/');
1545             if (cmd_data->fake_output_name) {
1546                 cmd_data->fake_output_name++;
1547             }
1548             else {
1549                 cmd_data->fake_output_name = cmd_data->basename;
1550             }
1551         }
1552     }
1553
1554     return 0;
1555 }
1556
1557 static int parse_output_file_name(char *arg, command_t *cmd_data)
1558 {
1559     const char *name;
1560     const char *ext;
1561     char *newarg = NULL;
1562     int pathlen;
1563
1564     cmd_data->fake_output_name = arg;
1565
1566     name = jlibtool_basename(arg);
1567     ext = strrchr(name, '.');
1568
1569 #ifdef EXE_EXT
1570     if (!ext || strcmp(ext, EXE_EXT) == 0) {
1571 #else
1572     if (!ext) {
1573 #endif
1574         cmd_data->basename = arg;
1575         cmd_data->output = otProgram;
1576 #if defined(_OSD_POSIX)
1577         cmd_data->options.pic_mode = pic_AVOID;
1578 #endif
1579         newarg = (char *)malloc(strlen(arg) + 5);
1580         strcpy(newarg, arg);
1581 #ifdef EXE_EXT
1582         if (!ext) {
1583           strcat(newarg, EXE_EXT);
1584         }
1585 #endif
1586         cmd_data->output_name = newarg;
1587         return 1;
1588     }
1589
1590     ext++;
1591     pathlen = name - arg;
1592
1593     if (strcmp(ext, "la") == 0) {
1594         assert(cmd_data->mode == mLink);
1595
1596         cmd_data->basename = arg;
1597         cmd_data->static_name.normal = gen_library_name(arg, type_STATIC_LIB);
1598         cmd_data->shared_name.normal = gen_library_name(arg, type_DYNAMIC_LIB);
1599         cmd_data->module_name.normal = gen_library_name(arg, type_MODULE_LIB);
1600         cmd_data->static_name.install = gen_install_name(arg, type_STATIC_LIB);
1601         cmd_data->shared_name.install = gen_install_name(arg, type_DYNAMIC_LIB);
1602         cmd_data->module_name.install = gen_install_name(arg, type_MODULE_LIB);
1603
1604         if (!cmd_data->options.dry_run) {
1605                 char *newname;
1606                 char *newext;
1607                 newname = malloc(strlen(cmd_data->static_name.normal) + 1);
1608
1609                 strcpy(newname, cmd_data->static_name.normal);
1610                 newext = strrchr(newname, '/');
1611                 if (!newext) {
1612                         /* Check first to see if the dir already exists! */
1613                         safe_mkdir(".libs");
1614                 } else {
1615                         *newext = '\0';
1616                         safe_mkdir(newname);
1617                 }
1618                 free(newname);
1619         }
1620
1621 #ifdef TRUNCATE_DLL_NAME
1622         if (shared) {
1623           arg = truncate_dll_name(arg);
1624         }
1625 #endif
1626
1627         cmd_data->output_name = arg;
1628         return 1;
1629     }
1630
1631     if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1632         assert(cmd_data->mode == mLink);
1633
1634         cmd_data->basename = arg;
1635         cmd_data->options.shared = share_STATIC;
1636         cmd_data->output = otStaticLibraryOnly;
1637         cmd_data->static_name.normal = gen_library_name(arg, type_STATIC_LIB);
1638         cmd_data->static_name.install = gen_install_name(arg, type_STATIC_LIB);
1639
1640         if (!cmd_data->options.dry_run) {
1641                 char *newname;
1642                 char *newext;
1643                 newname = malloc(strlen(cmd_data->static_name.normal) + 1);
1644
1645                 strcpy(newname, cmd_data->static_name.normal);
1646                 newext = strrchr(newname, '/');
1647                 if (!newext) {
1648                         /* Check first to see if the dir already exists! */
1649                         safe_mkdir(".libs");
1650                 } else {
1651                         *newext = '\0';
1652                         safe_mkdir(newname);
1653                 }
1654                 free(newname);
1655         }
1656
1657         cmd_data->output_name = arg;
1658         return 1;
1659     }
1660
1661     if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1662         assert(cmd_data->mode == mLink);
1663
1664         cmd_data->basename = arg;
1665         cmd_data->options.shared = share_SHARED;
1666         cmd_data->output = otDynamicLibraryOnly;
1667         cmd_data->shared_name.normal = gen_library_name(arg, type_DYNAMIC_LIB);
1668         cmd_data->module_name.normal = gen_library_name(arg, type_MODULE_LIB);
1669         cmd_data->shared_name.install = gen_install_name(arg, type_DYNAMIC_LIB);
1670         cmd_data->module_name.install = gen_install_name(arg, type_MODULE_LIB);
1671
1672         if (!cmd_data->options.dry_run) {
1673                 char *newname;
1674                 char *newext;
1675                 newname = malloc(strlen(cmd_data->shared_name.normal) + 1);
1676
1677                 strcpy(newname, cmd_data->shared_name.normal);
1678                 newext = strrchr(newname, '/');
1679                 if (!newext) {
1680                         /* Check first to see if the dir already exists! */
1681                         safe_mkdir(".libs");
1682                 } else {
1683                         *newext = '\0';
1684                         safe_mkdir(newname);
1685                 }
1686                 free(newname);
1687         }
1688
1689         cmd_data->output_name = arg;
1690         return 1;
1691     }
1692
1693     if (strcmp(ext, "lo") == 0) {
1694         char *newext;
1695         cmd_data->basename = arg;
1696         cmd_data->output = otObject;
1697         newarg = (char *)malloc(strlen(arg) + 2);
1698         strcpy(newarg, arg);
1699         newext = strrchr(newarg, '.') + 1;
1700         strcpy(newext, OBJECT_EXT);
1701         cmd_data->output_name = newarg;
1702         return 1;
1703     }
1704
1705     if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1706       fprintf(stderr, "Please build libraries with .la target, not ."
1707               DYNAMIC_LIB_EXT "\n");
1708       exit(1);
1709     }
1710
1711     if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1712       fprintf(stderr, "Please build libraries with .la target, not ."
1713               STATIC_LIB_EXT "\n");
1714       exit(1);
1715     }
1716
1717     return 0;
1718 }
1719
1720 static char *automode(char *arg, command_t *cmd_data)
1721 {
1722         if (cmd_data->mode != mUnknown) return arg;
1723
1724         if (strcmp(arg, "CC") == 0) {
1725                 arg = CC;
1726                 cmd_data->mode = mCompile;
1727
1728         } else if (strcmp(arg, "CXX") == 0) {
1729                 arg = CXX;
1730                 cmd_data->mode = mCompile;
1731
1732         } else if (strcmp(arg, "LINK") == 0) {
1733                 arg = LINK_c;
1734                 cmd_data->mode = mLink;
1735
1736         } else if (strcmp(arg, "LINK.c") == 0) {
1737                 arg = LINK_c;
1738                 cmd_data->mode = mLink;
1739
1740         } else if (strcmp(arg, "LINK.cxx") == 0) {
1741                 arg = LINK_cxx;
1742                 cmd_data->mode = mLink;
1743         }
1744         
1745         return arg;
1746 }
1747
1748 static void parse_args(int argc, char *argv[], command_t *cmd_data)
1749 {
1750     int a;
1751     char *arg, *base;
1752     int argused;
1753
1754     /*
1755      *  We now take a major step past libtool.
1756      *
1757      *  IF there's no "--mode=...", AND we recognise
1758      *  the binary as a "special" name, THEN replace it
1759      *  with the correct one, and set the correct mode.
1760      */
1761     base = jlibtool_basename(argv[0]);
1762     arg = automode(base, cmd_data);
1763     
1764     if (arg != base) {
1765             if (cmd_data->options.debug) {
1766                     printf("Adding: %s\n", arg);
1767             }
1768             push_count_chars(cmd_data->arglist, arg);
1769             assert(cmd_data->mode != mUnknown);
1770     }
1771
1772     /*
1773      *  We first pass over the command-line arguments looking for
1774      *  "--mode", etc.  If so, then use the libtool compatibility
1775      *  method for building the software.  Otherwise, auto-detect it
1776      *  via "-o" and the extensions.
1777      */
1778     base = NULL;
1779     if (cmd_data->mode == mUnknown) for (a = 1; a < argc; a++) {
1780         arg = argv[a];
1781
1782         if (strncmp(arg, "--mode=", 7) == 0) {
1783           base = NULL;
1784           break;
1785         }
1786
1787         /*
1788          *      Stop if we get another magic method
1789          */
1790         if ((a == 1) &&
1791             ((strncmp(arg, "LINK", 4) == 0) ||
1792              (strcmp(arg, "CC") == 0) ||
1793              (strcmp(arg, "CXX") == 0))) {
1794           base = NULL;
1795           break;
1796         }
1797
1798         if (strncmp(arg, "-o", 2) == 0) {
1799           base = argv[++a];
1800         }
1801     }
1802
1803     if (base) {
1804             arg = strrchr(base, '.');
1805             if (!arg) {
1806                     cmd_data->mode = mLink;
1807                     push_count_chars(cmd_data->arglist, LINK_c);
1808             }
1809 #ifdef EXE_EXT
1810             else if (strcmp(arg, EXE_EXT) == 0) {
1811                     cmd_data->mode = mLink;
1812                     push_count_chars(cmd_data->arglist, LINK_c);
1813             }
1814 #endif
1815             else if (strcmp(arg + 1, DYNAMIC_LIB_EXT) == 0) {
1816                     cmd_data->mode = mLink;
1817                     push_count_chars(cmd_data->arglist, LINK_c);
1818             }
1819             else if (strcmp(arg + 1, STATIC_LIB_EXT) == 0) {
1820                     cmd_data->mode = mLink;
1821                     push_count_chars(cmd_data->arglist, LINK_c);
1822             }
1823             else if (strcmp(arg + 1, "la") == 0) {
1824                     cmd_data->mode = mLink;
1825                     push_count_chars(cmd_data->arglist, LINK_c);
1826             }
1827             else if ((strcmp(arg + 1, "lo") == 0) ||
1828                      (strcmp(arg + 1, "o") == 0)) {
1829                     cmd_data->mode = mCompile;
1830                     push_count_chars(cmd_data->arglist, CC);
1831             }
1832     }
1833
1834     for (a = 1; a < argc; a++) {
1835         arg = argv[a];
1836         argused = 1;
1837
1838         if (arg[0] == '-') {
1839             if (arg[1] == '-') {
1840                 argused = parse_long_opt(arg + 2, cmd_data);
1841             }
1842             else {
1843                 argused = parse_short_opt(arg + 1, cmd_data);
1844             }
1845
1846             /* We haven't done anything with it yet, try some of the
1847              * more complicated short opts... */
1848             if (argused == 0 && a + 1 < argc) {
1849                 if (arg[1] == 'o' && !arg[2]) {
1850                     arg = argv[++a];
1851                     argused = parse_output_file_name(arg, cmd_data);
1852                 } else if (strcmp(arg+1, "MT") == 0) {
1853                     if (cmd_data->options.debug) {
1854                         printf("Adding: %s\n", arg);
1855                     }
1856                     push_count_chars(cmd_data->arglist, arg);
1857                     arg = argv[++a];
1858                     if (!cmd_data->options.silent) {
1859                         printf(" %s\n", arg);
1860                     }
1861                     push_count_chars(cmd_data->arglist, arg);
1862                     argused = 1;
1863                 } else if (strcmp(arg+1, "rpath") == 0) {
1864                     /* Aha, we should try to link both! */
1865                     cmd_data->install_path = argv[++a];
1866                     argused = 1;
1867                 } else if (strcmp(arg+1, "release") == 0) {
1868                     /* Store for later deciphering */
1869                     cmd_data->version_info = argv[++a];
1870                     argused = 1;
1871                 } else if (strcmp(arg+1, "version-info") == 0) {
1872                     /* Store for later deciphering */
1873                     cmd_data->version_info = argv[++a];
1874                     argused = 1;
1875                 } else if (strcmp(arg+1, "export-symbols-regex") == 0) {
1876                     /* Skip the argument. */
1877                     ++a;
1878                     argused = 1;
1879                 } else if (strcmp(arg+1, "release") == 0) {
1880                     /* Skip the argument. */
1881                     ++a;
1882                     argused = 1;
1883                 } else if (strcmp(arg+1, "undefined") == 0) {
1884                     cmd_data->undefined_flag = argv[++a];
1885                     argused = 1;
1886                 } else if (arg[1] == 'R' && !arg[2]) {
1887                     /* -R dir Add dir to runtime library search path. */
1888                     add_runtimedirlib(argv[++a], cmd_data);
1889                     argused = 1;
1890                 }
1891             }
1892         } else {
1893             argused = parse_input_file_name(arg, cmd_data);
1894         }
1895
1896         if (!argused) {
1897                 /*
1898                  *  If we still don't have a run mode, look for a magic
1899                  *  program name CC, LINK, or whatever.  Then replace that
1900                  *  with the name of the real program we want to run.
1901                  */
1902                 if ((cmd_data->arglist->num == 0) &&
1903                     (cmd_data->mode == mUnknown)) {
1904                         arg = automode(arg, cmd_data);
1905                 }
1906
1907             if (cmd_data->options.debug) {
1908                 printf("Adding: %s\n", arg);
1909             }
1910             push_count_chars(cmd_data->arglist, arg);
1911         }
1912     }
1913
1914 }
1915
1916 #ifdef GEN_EXPORTS
1917 static void generate_def_file(command_t *cmd_data)
1918 {
1919     char def_file[1024];
1920     char implib_file[1024];
1921     char *ext;
1922     FILE *hDef;
1923     char *export_args[1024];
1924     int num_export_args = 0;
1925     char *cmd;
1926     int cmd_size = 0;
1927     int a;
1928
1929     if (cmd_data->output_name) {
1930         strcpy(def_file, cmd_data->output_name);
1931         strcat(def_file, ".def");
1932         hDef = fopen(def_file, "w");
1933
1934         if (hDef != NULL) {
1935             fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
1936             fprintf(hDef, "DATA NONSHARED\n");
1937             fprintf(hDef, "EXPORTS\n");
1938             fclose(hDef);
1939
1940             for (a = 0; a < cmd_data->num_obj_files; a++) {
1941                 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
1942             }
1943
1944             cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
1945             cmd = (char *)malloc(cmd_size);
1946             strcpy(cmd, GEN_EXPORTS);
1947
1948             for (a=0; a < cmd_data->num_obj_files; a++) {
1949                 strcat(cmd, " ");
1950                 strcat(cmd, cmd_data->obj_files[a] );
1951             }
1952
1953             strcat(cmd, ">>");
1954             strcat(cmd, def_file);
1955             puts(cmd);
1956             export_args[num_export_args++] = SHELL_CMD;
1957             export_args[num_export_args++] = "-c";
1958             export_args[num_export_args++] = cmd;
1959             export_args[num_export_args++] = NULL;
1960             external_spawn(cmd_data, export_args[0], (const char**)export_args);
1961             cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
1962
1963             /* Now make an import library for the dll */
1964             num_export_args = 0;
1965             export_args[num_export_args++] = DEF2IMPLIB_CMD;
1966             export_args[num_export_args++] = "-o";
1967
1968             strcpy(implib_file, ".libs/");
1969             strcat(implib_file, cmd_data->basename);
1970             ext = strrchr(implib_file, '.');
1971
1972             if (ext)
1973                 *ext = 0;
1974
1975             strcat(implib_file, ".");
1976             strcat(implib_file, STATIC_LIB_EXT);
1977
1978             export_args[num_export_args++] = implib_file;
1979             export_args[num_export_args++] = def_file;
1980             export_args[num_export_args++] = NULL;
1981             external_spawn(cmd_data, export_args[0], (const char**)export_args);
1982
1983         }
1984     }
1985 }
1986 #endif
1987
1988 #if 0
1989 static const char* expand_path(const char *relpath)
1990 {
1991     char foo[PATH_MAX], *newpath;
1992
1993     getcwd(foo, PATH_MAX-1);
1994     newpath = (char*)malloc(strlen(foo)+strlen(relpath)+2);
1995     strcpy(newpath, foo);
1996     strcat(newpath, "/");
1997     strcat(newpath, relpath);
1998     return newpath;
1999 }
2000 #endif
2001
2002 static void link_fixup(command_t *c)
2003 {
2004     /* If we were passed an -rpath directive, we need to build
2005      * shared objects too.  Otherwise, we should only create static
2006      * libraries.
2007      */
2008     if (!c->install_path && (c->output == otDynamicLibraryOnly ||
2009         c->output == otModule || c->output == otLibrary)) {
2010         if (c->options.shared == share_SHARED) {
2011                 c->install_path = LIBDIR;
2012         }
2013     }
2014
2015     if (c->output == otDynamicLibraryOnly ||
2016         c->output == otModule ||
2017         c->output == otLibrary) {
2018
2019         push_count_chars(c->shared_opts.normal, "-o");
2020         if (c->output == otModule) {
2021             push_count_chars(c->shared_opts.normal, c->module_name.normal);
2022         }
2023         else {
2024             char *tmp;
2025             push_count_chars(c->shared_opts.normal, c->shared_name.normal);
2026 #ifdef DYNAMIC_INSTALL_NAME
2027             push_count_chars(c->shared_opts.normal, DYNAMIC_INSTALL_NAME);
2028
2029             tmp = (char*)malloc(PATH_MAX);
2030             strcpy(tmp, c->install_path);
2031             strcat(tmp, strrchr(c->shared_name.normal, '/'));
2032             push_count_chars(c->shared_opts.normal, tmp);
2033 #endif
2034         }
2035
2036         append_count_chars(c->shared_opts.normal, c->obj_files);
2037         append_count_chars(c->shared_opts.normal, c->shared_opts.dependencies);
2038
2039         if (c->options.export_all) {
2040 #ifdef GEN_EXPORTS
2041             generate_def_file(c);
2042 #endif
2043         }
2044     }
2045
2046     if (c->output == otLibrary || c->output == otStaticLibraryOnly) {
2047         push_count_chars(c->static_opts.normal, "-o");
2048         push_count_chars(c->static_opts.normal, c->output_name);
2049     }
2050
2051     if (c->output == otProgram) {
2052         if (c->output_name) {
2053             push_count_chars(c->arglist, "-o");
2054             push_count_chars(c->arglist, c->output_name);
2055             append_count_chars(c->arglist, c->obj_files);
2056             append_count_chars(c->arglist, c->shared_opts.dependencies);
2057             add_dynamic_link_opts(c, c->arglist);
2058         }
2059     }
2060 }
2061
2062 static void post_parse_fixup(command_t *cmd_data)
2063 {
2064     switch (cmd_data->mode)
2065     {
2066     case mCompile:
2067 #ifdef PIC_FLAG
2068         if (cmd_data->options.pic_mode != pic_AVOID) {
2069             push_count_chars(cmd_data->arglist, PIC_FLAG);
2070         }
2071 #endif
2072         if (cmd_data->output_name) {
2073             push_count_chars(cmd_data->arglist, "-o");
2074             push_count_chars(cmd_data->arglist, cmd_data->output_name);
2075         }
2076         break;
2077     case mLink:
2078         link_fixup(cmd_data);
2079         break;
2080     case mInstall:
2081         if (cmd_data->output == otLibrary) {
2082             link_fixup(cmd_data);
2083         }
2084     default:
2085         break;
2086     }
2087
2088 #ifdef USE_OMF
2089     if (cmd_data->output == otObject ||
2090         cmd_data->output == otProgram ||
2091         cmd_data->output == otLibrary ||
2092         cmd_data->output == otDynamicLibraryOnly) {
2093         push_count_chars(cmd_data->arglist, "-Zomf");
2094     }
2095 #endif
2096
2097     if (cmd_data->options.shared &&
2098             (cmd_data->output == otObject ||
2099              cmd_data->output == otLibrary ||
2100              cmd_data->output == otDynamicLibraryOnly)) {
2101 #ifdef SHARE_SW
2102         push_count_chars(cmd_data->arglist, SHARE_SW);
2103 #endif
2104     }
2105 }
2106
2107 static int run_mode(command_t *cmd_data)
2108 {
2109     int rv;
2110     count_chars *cctemp;
2111
2112     cctemp = (count_chars*)malloc(sizeof(count_chars));
2113     init_count_chars(cctemp);
2114
2115     switch (cmd_data->mode)
2116     {
2117     case mCompile:
2118         rv = run_command(cmd_data, cmd_data->arglist);
2119         if (rv) {
2120             return rv;
2121         }
2122         break;
2123     case mInstall:
2124         /* Well, we'll assume it's a file going to a directory... */
2125         /* For brain-dead install-sh based scripts, we have to repeat
2126          * the command N-times.  install-sh should die.
2127          */
2128         if (!cmd_data->output_name) {
2129             rv = run_command(cmd_data, cmd_data->arglist);
2130             if (rv) {
2131                 return rv;
2132             }
2133         }
2134         if (cmd_data->output_name) {
2135             append_count_chars(cctemp, cmd_data->arglist);
2136             insert_count_chars(cctemp,
2137                                cmd_data->output_name,
2138                                cctemp->num - 1);
2139             rv = run_command(cmd_data, cctemp);
2140             if (rv) {
2141                 return rv;
2142             }
2143             clear_count_chars(cctemp);
2144         }
2145         if (cmd_data->static_name.install) {
2146             append_count_chars(cctemp, cmd_data->arglist);
2147             insert_count_chars(cctemp,
2148                                cmd_data->static_name.install,
2149                                cctemp->num - 1);
2150             rv = run_command(cmd_data, cctemp);
2151             if (rv) {
2152                 return rv;
2153             }
2154 #if defined(__APPLE__) && defined(RANLIB)
2155             /* From the Apple libtool(1) manpage on Tiger/10.4:
2156              * ----
2157              * With  the way libraries used to be created, errors were possible
2158              * if the library was modified with ar(1) and  the  table  of
2159              * contents  was  not updated  by  rerunning ranlib(1).  Thus the
2160              * link editor, ld, warns when the modification date of a library
2161              * is more  recent  than  the  creation date  of its table of
2162              * contents.  Unfortunately, this means that you get the warning
2163              * even if you only copy the library.
2164              * ----
2165              *
2166              * This means that when we install the static archive, we need to
2167              * rerun ranlib afterwards.
2168              */
2169             const char *lib_args[3], *static_lib_name;
2170             char *tmp;
2171             size_t len1, len2;
2172             len1 = strlen(cmd_data->arglist->vals[cmd_data->arglist->num - 1]);
2173
2174             static_lib_name = jlibtool_basename(cmd_data->static_name.install);
2175             len2 = strlen(static_lib_name);
2176
2177             tmp = malloc(len1 + len2 + 2);
2178
2179             snprintf(tmp, len1 + len2 + 2, "%s/%s",
2180                     cmd_data->arglist->vals[cmd_data->arglist->num - 1],
2181                     static_lib_name);
2182
2183             lib_args[0] = RANLIB;
2184             lib_args[1] = tmp;
2185             lib_args[2] = NULL;
2186             external_spawn(cmd_data, RANLIB, lib_args);
2187             free(tmp);
2188 #endif
2189             clear_count_chars(cctemp);
2190         }
2191         if (cmd_data->shared_name.install) {
2192             append_count_chars(cctemp, cmd_data->arglist);
2193             insert_count_chars(cctemp,
2194                                cmd_data->shared_name.install,
2195                                cctemp->num - 1);
2196             rv = run_command(cmd_data, cctemp);
2197             if (rv) {
2198                 return rv;
2199             }
2200             clear_count_chars(cctemp);
2201         }
2202         if (cmd_data->module_name.install) {
2203             append_count_chars(cctemp, cmd_data->arglist);
2204             insert_count_chars(cctemp,
2205                                cmd_data->module_name.install,
2206                                cctemp->num - 1);
2207             rv = run_command(cmd_data, cctemp);
2208             if (rv) {
2209                 return rv;
2210             }
2211             clear_count_chars(cctemp);
2212         }
2213         break;
2214     case mLink:
2215         if (cmd_data->output == otStaticLibraryOnly ||
2216             cmd_data->output == otLibrary) {
2217 #ifdef RANLIB
2218             const char *lib_args[3];
2219 #endif
2220             /* Removes compiler! */
2221             cmd_data->program = LIBRARIAN;
2222             push_count_chars(cmd_data->program_opts, LIBRARIAN_OPTS);
2223             push_count_chars(cmd_data->program_opts,
2224                              cmd_data->static_name.normal);
2225
2226             rv = run_command(cmd_data, cmd_data->obj_files);
2227             if (rv) {
2228                 return rv;
2229             }
2230
2231 #ifdef RANLIB
2232             lib_args[0] = RANLIB;
2233             lib_args[1] = cmd_data->static_name.normal;
2234             lib_args[2] = NULL;
2235             external_spawn(cmd_data, RANLIB, lib_args);
2236 #endif
2237         }
2238
2239         if (cmd_data->output == otDynamicLibraryOnly ||
2240             cmd_data->output == otModule ||
2241             cmd_data->output == otLibrary) {
2242             cmd_data->program = NULL;
2243             clear_count_chars(cmd_data->program_opts);
2244
2245             append_count_chars(cmd_data->program_opts, cmd_data->arglist);
2246             if (cmd_data->output == otModule) {
2247 #ifdef MODULE_OPTS
2248                 push_count_chars(cmd_data->program_opts, MODULE_OPTS);
2249 #endif
2250             } else {
2251 #ifdef SHARED_OPTS
2252                 push_count_chars(cmd_data->program_opts, SHARED_OPTS);
2253 #endif
2254 #ifdef dynamic_link_version_func
2255                 push_count_chars(cmd_data->program_opts,
2256                              dynamic_link_version_func(cmd_data->version_info));
2257 #endif
2258             }
2259             add_dynamic_link_opts(cmd_data, cmd_data->program_opts);
2260
2261             rv = run_command(cmd_data, cmd_data->shared_opts.normal);
2262             if (rv) {
2263                 return rv;
2264             }
2265         }
2266         if (cmd_data->output == otProgram) {
2267             rv = run_command(cmd_data, cmd_data->arglist);
2268             if (rv) {
2269                 return rv;
2270             }
2271         }
2272         break;
2273     case mExecute:
2274     {
2275         char *l, libpath[PATH_MAX];
2276
2277         strcpy(libpath, cmd_data->arglist->vals[0]);
2278         add_dotlibs(libpath);
2279         l = strrchr(libpath, '/');
2280         if (!l) l = strrchr(libpath, '\\');
2281         if (l) {
2282             *l = '\0';
2283             l = libpath;
2284         } else {
2285             l = ".libs/";
2286         }
2287
2288         l = "./build/lib/.libs";
2289         setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
2290         rv = run_command(cmd_data, cmd_data->arglist);
2291         if (rv) {
2292             return rv;
2293         }
2294     }
2295       break;
2296
2297     default:
2298         break;
2299     }
2300
2301     return 0;
2302 }
2303
2304 static void cleanup_tmp_dir(const char *dirname)
2305 {
2306     DIR *dir;
2307     struct dirent *entry;
2308     char fullname[1024];
2309
2310     dir = opendir(dirname);
2311
2312     if (dir == NULL)
2313         return;
2314
2315     while ((entry = readdir(dir)) != NULL) {
2316         if (entry->d_name[0] != '.') {
2317             strcpy(fullname, dirname);
2318             strcat(fullname, "/");
2319             strcat(fullname, entry->d_name);
2320             remove(fullname);
2321         }
2322     }
2323
2324     rmdir(dirname);
2325 }
2326
2327 static void cleanup_tmp_dirs(command_t *cmd_data)
2328 {
2329     int d;
2330
2331     for (d = 0; d < cmd_data->tmp_dirs->num; d++) {
2332         cleanup_tmp_dir(cmd_data->tmp_dirs->vals[d]);
2333     }
2334 }
2335
2336 static int ensure_fake_uptodate(command_t *cmd_data)
2337 {
2338     /* FIXME: could do the stat/touch here, but nah... */
2339     const char *touch_args[3];
2340
2341     if (cmd_data->mode == mInstall) {
2342         return 0;
2343     }
2344     if (!cmd_data->fake_output_name) {
2345         return 0;
2346     }
2347
2348     touch_args[0] = "touch";
2349     touch_args[1] = cmd_data->fake_output_name;
2350     touch_args[2] = NULL;
2351     return external_spawn(cmd_data, "touch", touch_args);
2352 }
2353
2354 /* Store the install path in the *.la file */
2355 static int add_for_runtime(command_t *cmd_data)
2356 {
2357     if (cmd_data->mode == mInstall) {
2358         return 0;
2359     }
2360     if (cmd_data->output == otDynamicLibraryOnly ||
2361         cmd_data->output == otLibrary) {
2362         FILE *f=fopen(cmd_data->fake_output_name,"w");
2363         if (f == NULL) {
2364             return -1;
2365         }
2366         fprintf(f,"%s\n", cmd_data->install_path);
2367         fclose(f);
2368         return(0);
2369     } else {
2370         return(ensure_fake_uptodate(cmd_data));
2371     }
2372 }
2373
2374 int main(int argc, char *argv[])
2375 {
2376     int rc;
2377     command_t cmd_data;
2378
2379     memset(&cmd_data, 0, sizeof(cmd_data));
2380
2381     cmd_data.options.pic_mode = pic_UNKNOWN;
2382
2383     cmd_data.program_opts = (count_chars*)malloc(sizeof(count_chars));
2384     init_count_chars(cmd_data.program_opts);
2385     cmd_data.arglist = (count_chars*)malloc(sizeof(count_chars));
2386     init_count_chars(cmd_data.arglist);
2387     cmd_data.tmp_dirs = (count_chars*)malloc(sizeof(count_chars));
2388     init_count_chars(cmd_data.tmp_dirs);
2389     cmd_data.obj_files = (count_chars*)malloc(sizeof(count_chars));
2390     init_count_chars(cmd_data.obj_files);
2391     cmd_data.dep_rpaths = (count_chars*)malloc(sizeof(count_chars));
2392     init_count_chars(cmd_data.dep_rpaths);
2393     cmd_data.rpaths = (count_chars*)malloc(sizeof(count_chars));
2394     init_count_chars(cmd_data.rpaths);
2395     cmd_data.static_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2396     init_count_chars(cmd_data.static_opts.normal);
2397     cmd_data.shared_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2398     init_count_chars(cmd_data.shared_opts.normal);
2399     cmd_data.shared_opts.dependencies = (count_chars*)malloc(sizeof(count_chars));
2400     init_count_chars(cmd_data.shared_opts.dependencies);
2401
2402     cmd_data.mode = mUnknown;
2403     cmd_data.output = otGeneral;
2404
2405     parse_args(argc, argv, &cmd_data);
2406     post_parse_fixup(&cmd_data);
2407
2408     if (cmd_data.mode == mUnknown) {
2409        usage(1);
2410     }
2411
2412     rc = run_mode(&cmd_data);
2413
2414     if (!rc) {
2415        add_for_runtime(&cmd_data);
2416     }
2417
2418     cleanup_tmp_dirs(&cmd_data);
2419     return rc;
2420 }