Fix for coverity (fix cleanup_tmp_dir so it doesn't leak directory handles)
[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, "quiet") == 0) {
652         cmd_data->options.silent = 1;
653     } else if (strcmp(var, "debug") == 0) {
654         cmd_data->options.debug = 1;
655     } else if (strcmp(var, "mode") == 0) {
656         if (cmd_data->mode != mUnknown) {
657                 fprintf(stderr, "Cannot set --mode twice\n");
658                 exit(1);
659         }
660
661         if (strcmp(value, "compile") == 0) {
662             cmd_data->mode = mCompile;
663             cmd_data->output = otObject;
664
665         } else if (strcmp(value, "link") == 0) {
666             cmd_data->mode = mLink;
667             cmd_data->output = otLibrary;
668
669         } else if (strcmp(value, "install") == 0) {
670             cmd_data->mode = mInstall;
671
672         } else if (strcmp(value, "execute") == 0) {
673             cmd_data->mode = mExecute;
674
675         } else {
676             printf("Unknown mode \"%s\"\n", value);
677         }
678     } else if (strcmp(var, "shared") == 0) {
679       if ((cmd_data->mode == mLink) &&
680           (cmd_data->output == otGeneral)) {
681             cmd_data->output = otDynamicLibraryOnly;
682         }
683         cmd_data->options.shared = share_SHARED;
684     } else if (strcmp(var, "export-all") == 0) {
685         cmd_data->options.export_all = 1;
686     } else if (strcmp(var, "dry-run") == 0) {
687         printf("Dry-run mode on!\n");
688         cmd_data->options.dry_run = 1;
689     } else if (strcmp(var, "version") == 0) {
690         printf("Version " VERSION "\n");
691     } else if (strcmp(var, "help") == 0) {
692         usage(0);
693     } else if (strcmp(var, "config") == 0) {
694         print_config(value);
695         exit(0);
696     } else if (strcmp(var, "tag") == 0) {
697         if (strcmp(value, "CC") == 0) {
698             /* Do nothing. */
699         }
700         if (strcmp(value, "CXX") == 0) {
701             /* Do nothing. */
702         }
703     } else {
704         return 0;
705     }
706
707     return 1;
708 }
709
710 /* Return 1 if we eat it. */
711 static int parse_short_opt(char *arg, command_t *cmd_data)
712 {
713     if (strcmp(arg, "export-dynamic") == 0) {
714         cmd_data->options.export_dynamic = 1;
715         return 1;
716     }
717
718     if (strcmp(arg, "module") == 0) {
719         cmd_data->output = otModule;
720         return 1;
721     }
722
723     if (strcmp(arg, "shared") == 0) {
724         if (cmd_data->mode == mLink) {
725             cmd_data->output = otDynamicLibraryOnly;
726         }
727         cmd_data->options.shared = share_SHARED;
728         return 1;
729     }
730
731     if (strcmp(arg, "Zexe") == 0) {
732         return 1;
733     }
734
735     if (strcmp(arg, "avoid-version") == 0) {
736         return 1;
737     }
738
739     if (strcmp(arg, "prefer-pic") == 0) {
740         cmd_data->options.pic_mode = pic_PREFER;
741         return 1;
742     }
743
744     if (strcmp(arg, "prefer-non-pic") == 0) {
745         cmd_data->options.pic_mode = pic_AVOID;
746         return 1;
747     }
748
749     if (strcmp(arg, "static") == 0) {
750        if ((cmd_data->mode == mLink) &&
751           (cmd_data->output == otLibrary)) {
752             cmd_data->output = otStaticLibraryOnly;
753         }
754         cmd_data->options.shared = share_STATIC;
755         return 1;
756     }
757
758     if (cmd_data->mode == mLink) {
759         if (strcmp(arg, "no-install") == 0) {
760             cmd_data->options.no_install = 1;
761             return 1;
762         }
763         if (arg[0] == 'L' || arg[0] == 'l') {
764             /* Hack... */
765             arg--;
766             push_count_chars(cmd_data->shared_opts.dependencies, arg);
767             return 1;
768         } else if (arg[0] == 'R' && arg[1]) {
769             /* -Rdir Add dir to runtime library search path. */
770             add_runtimedirlib(&arg[1], cmd_data);
771             return 1;
772         }
773     }
774     return 0;
775 }
776
777 #ifdef TRUNCATE_DLL_NAME
778 static char *truncate_dll_name(char *path)
779 {
780     /* Cut DLL name down to 8 characters after removing any mod_ prefix */
781     char *tmppath = strdup(path);
782     char *newname = strrchr(tmppath, '/') + 1;
783     char *ext = strrchr(newname, '.');
784     int len;
785
786     if (ext == NULL)
787         return tmppath;
788
789     len = ext - newname;
790
791     if (strncmp(newname, "mod_", 4) == 0) {
792         strcpy(newname, newname + 4);
793         len -= 4;
794     }
795
796     if (len > 8) {
797         strcpy(newname + 8, strchr(newname, '.'));
798     }
799
800     return tmppath;
801 }
802 #endif
803
804 static long safe_strtol(const char *nptr, const char **endptr, int base)
805 {
806     long rv;
807
808     errno = 0;
809
810     rv = strtol(nptr, (char**)endptr, 10);
811
812     if (errno == ERANGE) {
813         return 0;
814     }
815
816     return rv;
817 }
818
819 static void safe_mkdir(const char *path)
820 {
821     int status;
822     mode_t old_umask;
823
824     old_umask = umask(0);
825     umask(old_umask);
826
827 #ifdef MKDIR_NO_UMASK
828     status = mkdir(path);
829 #else
830     status = mkdir(path, ~old_umask);
831 #endif
832     if ((status < 0) && (errno != EEXIST)) {
833         printf("Warning: mkdir of %s failed\n", path);
834     }
835 }
836
837 /* returns just a file's name without the path */
838 static const char *jlibtool_basename(const char *fullpath)
839 {
840     const char *name = strrchr(fullpath, '/');
841
842     if (name == NULL) {
843         name = strrchr(fullpath, '\\');
844     }
845
846     if (name == NULL) {
847         name = fullpath;
848     } else {
849         name++;
850     }
851
852     return name;
853 }
854
855 #ifdef GEN_EXPORTS
856 /* returns just a file's name without path or extension */
857 static const char *nameof(const char *fullpath)
858 {
859     const char *name;
860     const char *ext;
861
862     name = jlibtool_basename(fullpath);
863     ext = strrchr(name, '.');
864
865     if (ext) {
866         char *trimmed;
867         trimmed = malloc(ext - name + 1);
868         strncpy(trimmed, name, ext - name);
869         trimmed[ext-name] = 0;
870         return trimmed;
871     }
872
873     return name;
874 }
875 #endif
876
877 /* version_info is in the form of MAJOR:MINOR:PATCH */
878 static const char *darwin_dynamic_link_function(const char *version_info)
879 {
880     char *newarg;
881     long major, minor, patch;
882
883     major = 0;
884     minor = 0;
885     patch = 0;
886
887     if (version_info) {
888         major = safe_strtol(version_info, &version_info, 10);
889
890         if (version_info) {
891             if (version_info[0] == ':') {
892                 version_info++;
893             }
894
895             minor = safe_strtol(version_info, &version_info, 10);
896
897             if (version_info) {
898                 if (version_info[0] == ':') {
899                     version_info++;
900                 }
901
902                 patch = safe_strtol(version_info, &version_info, 10);
903
904             }
905         }
906     }
907
908     /* Avoid -dylib_compatibility_version must be greater than zero errors. */
909     if (major == 0) {
910         major = 1;
911     }
912     newarg = (char*)malloc(100);
913     snprintf(newarg, 99,
914              "-compatibility_version %ld -current_version %ld.%ld",
915              major, major, minor);
916
917     return newarg;
918 }
919
920
921 /*
922  *      Add a '.libs/' to the buffer.  The caller ensures that
923  *      The buffer is large enough to handle 6 extra characters.
924  */
925 static void add_dotlibs(char *buffer)
926 {
927         char *name = strrchr(buffer, '/');
928
929         if (!name) {
930                 if (!buffer[0]) {
931                         strcpy(buffer, ".libs/");
932                         return;
933                 }
934                 name = buffer;
935         } else {
936                 name++;
937         }
938         memmove(name + 6, name, strlen(name));
939         memcpy(name, ".libs/", 6);
940 }
941
942 static char *gen_library_name(const char *name, enum lib_type genlib)
943 {
944     char *newarg, *newext;
945
946     newarg = (char *)calloc(strlen(name) + 11, 1);
947
948     if (genlib == type_MODULE_LIB && strncmp(name, "lib", 3) == 0) {
949         name += 3;
950     }
951
952     if (genlib == type_MODULE_LIB) {
953         strcpy(newarg, jlibtool_basename(name));
954     }
955     else {
956         strcpy(newarg, name);
957     }
958
959     newext = strrchr(newarg, '.') + 1;
960     if (!newext) {
961         free(newarg);
962         return NULL;
963     }
964
965     switch (genlib) {
966     case type_STATIC_LIB:
967         strcpy(newext, STATIC_LIB_EXT);
968         break;
969     case type_DYNAMIC_LIB:
970         strcpy(newext, DYNAMIC_LIB_EXT);
971         break;
972     case type_MODULE_LIB:
973         strcpy(newext, MODULE_LIB_EXT);
974         break;
975
976     default:
977         break;
978     }
979
980     add_dotlibs(newarg);
981
982     return newarg;
983 }
984
985 static char *gen_install_name(const char *name, enum lib_type genlib)
986 {
987     char *newname;
988     int rv;
989     struct stat sb;
990
991     newname = gen_library_name(name, genlib);
992     if (!newname) return NULL;
993
994     /* Check if it exists. If not, return NULL.  */
995     rv = stat(newname, &sb);
996
997     if (rv) {
998         free(newname);
999         return NULL;
1000     }
1001
1002     return newname;
1003 }
1004
1005 static const char *check_object_exists(command_t *cmd, const char *arg, int arglen)
1006 {
1007     char *newarg, *ext;
1008     int pass, rv;
1009
1010     newarg = (char *)malloc(arglen + 10);
1011     memcpy(newarg, arg, arglen);
1012     newarg[arglen] = 0;
1013     ext = newarg + arglen;
1014
1015     pass = 0;
1016
1017     do {
1018         struct stat sb;
1019
1020         switch (pass) {
1021         case 0:
1022             strcpy(ext, OBJECT_EXT);
1023             break;
1024 /*
1025         case 1:
1026             strcpy(ext, NO_PIC_EXT);
1027             break;
1028 */
1029         default:
1030             break;
1031         }
1032
1033         if (cmd->options.debug) {
1034             printf("Checking (obj): %s\n", newarg);
1035         }
1036         rv = stat(newarg, &sb);
1037     }
1038     while (rv != 0 && ++pass < 1);
1039
1040     if (rv == 0) {
1041         if (pass == 1) {
1042             cmd->options.pic_mode = pic_AVOID;
1043         }
1044         return newarg;
1045     }
1046     
1047     free(newarg);
1048
1049     return NULL;
1050 }
1051
1052 /* libdircheck values:
1053  * 0 - no .libs suffix
1054  * 1 - .libs suffix
1055  */
1056 static char *check_library_exists(command_t *cmd, const char *arg, int pathlen,
1057                            int libdircheck, enum lib_type *libtype)
1058 {
1059     char *newarg, *ext;
1060     int pass, rv, newpathlen;
1061
1062     newarg = (char *)malloc(strlen(arg) + 10);
1063     strcpy(newarg, arg);
1064     newarg[pathlen] = '\0';
1065
1066     newpathlen = pathlen;
1067     if (libdircheck) {
1068         add_dotlibs(newarg);
1069         newpathlen += sizeof(".libs/") - 1;
1070     }
1071
1072     strcpy(newarg + newpathlen, arg + pathlen);
1073     ext = strrchr(newarg, '.') + 1;
1074     if (!ext) {
1075         printf("Error: Library path does not have an extension");
1076         free(newarg);
1077         
1078         return NULL;
1079     }
1080
1081     pass = 0;
1082
1083     do {
1084         struct stat sb;
1085
1086         switch (pass) {
1087         case 0:
1088             if (cmd->options.pic_mode != pic_AVOID &&
1089                 cmd->options.shared != share_STATIC) {
1090                 strcpy(ext, DYNAMIC_LIB_EXT);
1091                 *libtype = type_DYNAMIC_LIB;
1092                 break;
1093             }
1094             pass = 1;
1095             /* Fall through */
1096         case 1:
1097             strcpy(ext, STATIC_LIB_EXT);
1098             *libtype = type_STATIC_LIB;
1099             break;
1100         case 2:
1101             strcpy(ext, MODULE_LIB_EXT);
1102             *libtype = type_MODULE_LIB;
1103             break;
1104         case 3:
1105             strcpy(ext, OBJECT_EXT);
1106             *libtype = type_OBJECT;
1107             break;
1108         default:
1109             *libtype = type_UNKNOWN;
1110             break;
1111         }
1112
1113         if (cmd->options.debug) {
1114             printf("Checking (lib): %s\n", newarg);
1115         }
1116         rv = stat(newarg, &sb);
1117     }
1118     while (rv != 0 && ++pass < 4);
1119
1120     if (rv == 0) {
1121         return newarg;
1122     }
1123     
1124     free(newarg);
1125
1126     return NULL;
1127 }
1128
1129 static char * load_install_path(const char *arg)
1130 {
1131     FILE *f;
1132     char *path;
1133
1134     path = malloc(PATH_MAX);
1135
1136     f = fopen(arg,"r");
1137     if (f == NULL) {
1138         return NULL;
1139     }
1140     fgets(path, PATH_MAX, f);
1141     fclose(f);
1142     if (path[strlen(path)-1] == '\n') {
1143         path[strlen(path)-1] = '\0';
1144     }
1145     /* Check that we have an absolute path.
1146      * Otherwise the file could be a GNU libtool file.
1147      */
1148     if (path[0] != '/') {
1149         return NULL;
1150     }
1151     return path;
1152 }
1153
1154 static char * load_noinstall_path(const char *arg, int pathlen)
1155 {
1156     char *newarg, *expanded_path;
1157     int newpathlen;
1158
1159     newarg = (char *)malloc(strlen(arg) + 10);
1160     strcpy(newarg, arg);
1161     newarg[pathlen] = 0;
1162
1163     newpathlen = pathlen;
1164     strcat(newarg, ".libs");
1165     newpathlen += sizeof(".libs") - 1;
1166     newarg[newpathlen] = 0;
1167
1168 #ifdef HAS_REALPATH
1169     expanded_path = malloc(PATH_MAX);
1170     expanded_path = realpath(newarg, expanded_path);
1171     /* Uh, oh.  There was an error.  Fall back on our first guess. */
1172     if (!expanded_path) {
1173         expanded_path = newarg;
1174     }
1175 #else
1176     /* We might get ../ or something goofy.  Oh, well. */
1177     expanded_path = newarg;
1178 #endif
1179
1180     return expanded_path;
1181 }
1182
1183 static void add_dynamic_link_opts(command_t *cmd_data, count_chars *args)
1184 {
1185 #ifdef DYNAMIC_LINK_OPTS
1186     if (cmd_data->options.pic_mode != pic_AVOID) {
1187         if (cmd_data->options.debug) {
1188            printf("Adding: %s\n", DYNAMIC_LINK_OPTS);
1189         }
1190         push_count_chars(args, DYNAMIC_LINK_OPTS);
1191         if (cmd_data->undefined_flag) {
1192             push_count_chars(args, "-undefined");
1193 #if defined(__APPLE__)
1194             /* -undefined dynamic_lookup is used by the bundled Python in
1195              * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
1196              * we'll get a linker error if we pass this flag.
1197              */
1198             if (strcasecmp(cmd_data->undefined_flag,
1199                            "dynamic_lookup") == 0) {
1200                 insert_count_chars(cmd_data->program_opts,
1201                                    "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
1202             }
1203 #endif
1204             push_count_chars(args, cmd_data->undefined_flag);
1205         }
1206         else {
1207 #ifdef DYNAMIC_LINK_UNDEFINED
1208             if (cmd_data->options.debug) {
1209                 printf("Adding: %s\n", DYNAMIC_LINK_UNDEFINED);
1210             }
1211             push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
1212 #endif
1213         }
1214     }
1215 #endif
1216 }
1217
1218 /* Read the final install location and add it to runtime library search path. */
1219 #ifdef RPATH
1220 static void add_rpath(count_chars *cc, const char *path)
1221 {
1222     int size = 0;
1223     char *tmp;
1224
1225 #ifdef LINKER_FLAG_PREFIX
1226     size = strlen(LINKER_FLAG_PREFIX);
1227 #endif
1228     size = size + strlen(path) + strlen(RPATH) + 2;
1229     tmp = malloc(size);
1230     if (tmp == NULL) {
1231         return;
1232     }
1233 #ifdef LINKER_FLAG_PREFIX
1234     strcpy(tmp, LINKER_FLAG_PREFIX);
1235     strcat(tmp, RPATH);
1236 #else
1237     strcpy(tmp, RPATH);
1238 #endif
1239 #ifndef LINKER_FLAG_NO_EQUALS
1240     strcat(tmp, "=");
1241 #endif
1242     strcat(tmp, path);
1243
1244     push_count_chars(cc, tmp);
1245 }
1246
1247 static void add_rpath_file(count_chars *cc, const char *arg)
1248 {
1249     const char *path;
1250
1251     path = load_install_path(arg);
1252     if (path) {
1253         add_rpath(cc, path);
1254     }
1255 }
1256
1257 static void add_rpath_noinstall(count_chars *cc, const char *arg, int pathlen)
1258 {
1259     const char *path;
1260
1261     path = load_noinstall_path(arg, pathlen);
1262     if (path) {
1263         add_rpath(cc, path);
1264         free(path);
1265     }
1266 }
1267 #endif
1268
1269 #ifdef DYNAMIC_LINK_NO_INSTALL
1270 static void add_dylink_noinstall(count_chars *cc, const char *arg, int pathlen,
1271                           int extlen)
1272 {
1273     const char *install_path, *current_path, *name;
1274     char *exp_argument;
1275     int i_p_len, c_p_len, name_len, dyext_len, cur_len;
1276
1277     install_path = load_install_path(arg);
1278     current_path = load_noinstall_path(arg, pathlen);
1279
1280     if (!install_path || !current_path) {
1281         return;
1282     }
1283
1284     push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
1285
1286     i_p_len = strlen(install_path);
1287     c_p_len = strlen(current_path);
1288
1289     name = arg+pathlen;
1290     name_len = extlen-pathlen;
1291     dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
1292
1293     /* No, we need to replace the extension. */
1294     exp_argument = (char *)malloc(i_p_len + c_p_len + (name_len*2) +
1295                                   (dyext_len*2) + 2);
1296
1297     cur_len = 0;
1298     strcpy(exp_argument, install_path);
1299     cur_len += i_p_len;
1300     exp_argument[cur_len++] = '/';
1301     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1302     cur_len += name_len;
1303     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1304     cur_len += dyext_len;
1305     exp_argument[cur_len++] = ':';
1306     strcpy(exp_argument+cur_len, current_path);
1307     cur_len += c_p_len;
1308     exp_argument[cur_len++] = '/';
1309     strncpy(exp_argument+cur_len, name, extlen-pathlen);
1310     cur_len += name_len;
1311     strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1312     cur_len += dyext_len;
1313
1314     push_count_chars(cc, exp_argument);
1315 }
1316 #endif
1317
1318 #ifdef ADD_MINUS_L
1319 /* use -L -llibname to allow to use installed libraries */
1320 static void add_minus_l(count_chars *cc, const char *arg)
1321 {
1322     char *newarg;
1323     char *name = strrchr(arg, '/');
1324     char *file = strrchr(arg, '.');
1325
1326     if ((name != NULL) && (file != NULL) &&
1327         (strstr(name, "lib") == (name + 1))) {
1328         *name = '\0';
1329         *file = '\0';
1330         file = name;
1331         file = file+4;
1332         push_count_chars(cc, "-L");
1333         push_count_chars(cc, arg);
1334         /* we need one argument like -lapr-1 */
1335         newarg = malloc(strlen(file) + 3);
1336         strcpy(newarg, "-l");
1337         strcat(newarg, file);
1338         push_count_chars(cc, newarg);
1339     } else {
1340         push_count_chars(cc, arg);
1341     }
1342 }
1343 #endif
1344
1345 #if 0
1346 static void add_linker_flag_prefix(count_chars *cc, const char *arg)
1347 {
1348 #ifndef LINKER_FLAG_PREFIX
1349     push_count_chars(cc, arg);
1350 #else
1351     char *newarg;
1352     newarg = (char*)malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
1353     strcpy(newarg, LINKER_FLAG_PREFIX);
1354     strcat(newarg, arg);
1355     push_count_chars(cc, newarg);
1356 #endif
1357 }
1358 #endif
1359
1360 static int explode_static_lib(command_t *cmd_data, const char *lib)
1361 {
1362     count_chars tmpdir_cc, libname_cc;
1363     const char *tmpdir, *libname;
1364     char savewd[PATH_MAX];
1365     const char *name;
1366     DIR *dir;
1367     struct dirent *entry;
1368     const char *lib_args[4];
1369
1370     /* Bah! */
1371     if (cmd_data->options.dry_run) {
1372         return 0;
1373     }
1374
1375     name = jlibtool_basename(lib);
1376
1377     init_count_chars(&tmpdir_cc);
1378     push_count_chars(&tmpdir_cc, ".libs/");
1379     push_count_chars(&tmpdir_cc, name);
1380     push_count_chars(&tmpdir_cc, ".exploded/");
1381     tmpdir = flatten_count_chars(&tmpdir_cc, 0);
1382
1383     if (!cmd_data->options.silent) {
1384         printf("Making: %s\n", tmpdir);
1385     }
1386     safe_mkdir(tmpdir);
1387
1388     push_count_chars(cmd_data->tmp_dirs, tmpdir);
1389
1390     getcwd(savewd, sizeof(savewd));
1391
1392     if (chdir(tmpdir) != 0) {
1393         if (!cmd_data->options.silent) {
1394             printf("Warning: could not explode %s\n", lib);
1395         }
1396         return 1;
1397     }
1398
1399     if (lib[0] == '/') {
1400         libname = lib;
1401     }
1402     else {
1403         init_count_chars(&libname_cc);
1404         push_count_chars(&libname_cc, "../../");
1405         push_count_chars(&libname_cc, lib);
1406         libname = flatten_count_chars(&libname_cc, 0);
1407     }
1408
1409     lib_args[0] = LIBRARIAN;
1410     lib_args[1] = "x";
1411     lib_args[2] = libname;
1412     lib_args[3] = NULL;
1413
1414     external_spawn(cmd_data, LIBRARIAN, lib_args);
1415
1416     chdir(savewd);
1417     dir = opendir(tmpdir);
1418
1419     while ((entry = readdir(dir)) != NULL) {
1420 #if defined(__APPLE__) && defined(RANLIB)
1421         /* Apple inserts __.SYMDEF which isn't needed.
1422          * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
1423          * much fun either.  Just skip them.
1424          */
1425         if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
1426             continue;
1427         }
1428 #endif
1429         if (entry->d_name[0] != '.') {
1430             push_count_chars(&tmpdir_cc, entry->d_name);
1431             name = flatten_count_chars(&tmpdir_cc, 0);
1432             if (cmd_data->options.debug) {
1433                 printf("Adding: %s\n", name);
1434             }
1435             push_count_chars(cmd_data->obj_files, name);
1436             pop_count_chars(&tmpdir_cc);
1437         }
1438     }
1439
1440     closedir(dir);
1441     return 0;
1442 }
1443
1444 static int parse_input_file_name(char *arg, command_t *cmd_data)
1445 {
1446     const char *ext = strrchr(arg, '.');
1447     const char *name;
1448     int pathlen;
1449     enum lib_type libtype;
1450     const char *newarg;
1451
1452     if (!ext) {
1453         return 0;
1454     }
1455
1456     ext++;
1457     name = jlibtool_basename(arg);
1458
1459     pathlen = name - arg;
1460
1461     if (strcmp(ext, "lo") == 0) {
1462         newarg = check_object_exists(cmd_data, arg, ext - arg);
1463         if (!newarg) {
1464             fprintf(stderr, "Can not find suitable object file for %s\n", arg);
1465             exit(1);
1466         }
1467         if (cmd_data->mode != mLink) {
1468             push_count_chars(cmd_data->arglist, newarg);
1469         }
1470         else {
1471             push_count_chars(cmd_data->obj_files, newarg);
1472         }
1473         return 1;
1474     }
1475
1476     if (strcmp(ext, "la") == 0) {
1477         switch (cmd_data->mode) {
1478         case mLink:
1479             /* Try the .libs dir first! */
1480             newarg = check_library_exists(cmd_data, arg, pathlen, 1, &libtype);
1481             if (!newarg) {
1482                 /* Try the normal dir next. */
1483                 newarg = check_library_exists(cmd_data, arg, pathlen, 0, &libtype);
1484                 if (!newarg) {
1485                     fprintf(stderr, "Can not find suitable library for %s\n", arg);
1486                     exit(1);
1487                 }
1488             }
1489
1490             /* It is not ok to just add the file: a library may added with:
1491                1 - -L path library_name. (For *.so in Linux).
1492                2 - library_name.
1493              */
1494 #ifdef ADD_MINUS_L
1495             if (libtype == type_DYNAMIC_LIB) {
1496                  add_minus_l(cmd_data->shared_opts.dependencies, newarg);
1497             } else if (cmd_data->output == otLibrary &&
1498                        libtype == type_STATIC_LIB) {
1499                 explode_static_lib(cmd_data, newarg);
1500             } else {
1501                  push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1502             }
1503 #else
1504             if (cmd_data->output == otLibrary && libtype == type_STATIC_LIB) {
1505                 explode_static_lib(cmd_data, newarg);
1506             }
1507             else {
1508                 push_count_chars(cmd_data->shared_opts.dependencies, newarg);
1509             }
1510 #endif
1511             if (libtype == type_DYNAMIC_LIB) {
1512                 if (cmd_data->options.no_install) {
1513 #ifdef RPATH
1514                     add_rpath_noinstall(cmd_data->shared_opts.dependencies,
1515                                         arg, pathlen);
1516 #endif
1517 #ifdef DYNAMIC_LINK_NO_INSTALL
1518                     /*
1519                      * This doesn't work as Darwin's linker has no way to
1520                      * override at link-time the search paths for a
1521                      * non-installed library.
1522                      */
1523                     /*
1524                     add_dylink_noinstall(cmd_data->shared_opts.dependencies,
1525                                          arg, pathlen, ext - arg);
1526                     */
1527 #endif
1528                 }
1529                 else {
1530 #ifdef RPATH
1531                     add_rpath_file(cmd_data->shared_opts.dependencies, arg);
1532 #endif
1533                 }
1534             }
1535             break;
1536         case mInstall:
1537             /* If we've already recorded a library to install, we're most
1538              * likely getting the .la file that we want to install as.
1539              * The problem is that we need to add it as the directory,
1540              * not the .la file itself.  Otherwise, we'll do odd things.
1541              */
1542             if (cmd_data->output == otLibrary) {
1543                 arg[pathlen] = '\0';
1544                 push_count_chars(cmd_data->arglist, arg);
1545             }
1546             else {
1547                 cmd_data->output = otLibrary;
1548                 cmd_data->output_name = arg;
1549                 cmd_data->static_name.install = gen_install_name(arg, 0);
1550                 cmd_data->shared_name.install = gen_install_name(arg, 1);
1551                 cmd_data->module_name.install = gen_install_name(arg, 2);
1552
1553                 if (!cmd_data->static_name.install &&
1554                     !cmd_data->shared_name.install &&
1555                     !cmd_data->module_name.install) {
1556                   fprintf(stderr, "Files to install do not exist\n");
1557                   exit(1);
1558                 }
1559
1560             }
1561             break;
1562         default:
1563             break;
1564         }
1565         return 1;
1566     }
1567
1568     if (strcmp(ext, "c") == 0) {
1569         /* If we don't already have an idea what our output name will be. */
1570         if (cmd_data->basename == NULL) {
1571             cmd_data->basename = (char *)malloc(strlen(arg) + 4);
1572             strcpy(cmd_data->basename, arg);
1573             strcpy(strrchr(cmd_data->basename, '.') + 1, "lo");
1574
1575             cmd_data->fake_output_name = strrchr(cmd_data->basename, '/');
1576             if (cmd_data->fake_output_name) {
1577                 cmd_data->fake_output_name++;
1578             }
1579             else {
1580                 cmd_data->fake_output_name = cmd_data->basename;
1581             }
1582         }
1583     }
1584
1585     return 0;
1586 }
1587
1588 static int parse_output_file_name(char *arg, command_t *cmd_data)
1589 {
1590     const char *name;
1591     const char *ext;
1592     char *newarg = NULL;
1593     int pathlen;
1594
1595     cmd_data->fake_output_name = arg;
1596
1597     name = jlibtool_basename(arg);
1598     ext = strrchr(name, '.');
1599
1600 #ifdef EXE_EXT
1601     if (!ext || strcmp(ext, EXE_EXT) == 0) {
1602 #else
1603     if (!ext) {
1604 #endif
1605         cmd_data->basename = arg;
1606         cmd_data->output = otProgram;
1607 #if defined(_OSD_POSIX)
1608         cmd_data->options.pic_mode = pic_AVOID;
1609 #endif
1610         newarg = (char *)malloc(strlen(arg) + 5);
1611         strcpy(newarg, arg);
1612 #ifdef EXE_EXT
1613         if (!ext) {
1614           strcat(newarg, EXE_EXT);
1615         }
1616 #endif
1617         cmd_data->output_name = newarg;
1618         return 1;
1619     }
1620
1621     ext++;
1622     pathlen = name - arg;
1623
1624     if (strcmp(ext, "la") == 0) {
1625         assert(cmd_data->mode == mLink);
1626
1627         cmd_data->basename = arg;
1628         cmd_data->static_name.normal = gen_library_name(arg, type_STATIC_LIB);
1629         cmd_data->shared_name.normal = gen_library_name(arg, type_DYNAMIC_LIB);
1630         cmd_data->module_name.normal = gen_library_name(arg, type_MODULE_LIB);
1631         cmd_data->static_name.install = gen_install_name(arg, type_STATIC_LIB);
1632         cmd_data->shared_name.install = gen_install_name(arg, type_DYNAMIC_LIB);
1633         cmd_data->module_name.install = gen_install_name(arg, type_MODULE_LIB);
1634
1635         if (!cmd_data->options.dry_run) {
1636                 char *newname;
1637                 char *newext;
1638                 newname = malloc(strlen(cmd_data->static_name.normal) + 1);
1639
1640                 strcpy(newname, cmd_data->static_name.normal);
1641                 newext = strrchr(newname, '/');
1642                 if (!newext) {
1643                         /* Check first to see if the dir already exists! */
1644                         safe_mkdir(".libs");
1645                 } else {
1646                         *newext = '\0';
1647                         safe_mkdir(newname);
1648                 }
1649                 free(newname);
1650         }
1651
1652 #ifdef TRUNCATE_DLL_NAME
1653         if (shared) {
1654           arg = truncate_dll_name(arg);
1655         }
1656 #endif
1657
1658         cmd_data->output_name = arg;
1659         return 1;
1660     }
1661
1662     if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1663         assert(cmd_data->mode == mLink);
1664
1665         cmd_data->basename = arg;
1666         cmd_data->options.shared = share_STATIC;
1667         cmd_data->output = otStaticLibraryOnly;
1668         cmd_data->static_name.normal = gen_library_name(arg, type_STATIC_LIB);
1669         cmd_data->static_name.install = gen_install_name(arg, type_STATIC_LIB);
1670
1671         if (!cmd_data->options.dry_run) {
1672                 char *newname;
1673                 char *newext;
1674                 newname = malloc(strlen(cmd_data->static_name.normal) + 1);
1675
1676                 strcpy(newname, cmd_data->static_name.normal);
1677                 newext = strrchr(newname, '/');
1678                 if (!newext) {
1679                         /* Check first to see if the dir already exists! */
1680                         safe_mkdir(".libs");
1681                 } else {
1682                         *newext = '\0';
1683                         safe_mkdir(newname);
1684                 }
1685                 free(newname);
1686         }
1687
1688         cmd_data->output_name = arg;
1689         return 1;
1690     }
1691
1692     if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1693         assert(cmd_data->mode == mLink);
1694
1695         cmd_data->basename = arg;
1696         cmd_data->options.shared = share_SHARED;
1697         cmd_data->output = otDynamicLibraryOnly;
1698         cmd_data->shared_name.normal = gen_library_name(arg, type_DYNAMIC_LIB);
1699         cmd_data->module_name.normal = gen_library_name(arg, type_MODULE_LIB);
1700         cmd_data->shared_name.install = gen_install_name(arg, type_DYNAMIC_LIB);
1701         cmd_data->module_name.install = gen_install_name(arg, type_MODULE_LIB);
1702
1703         if (!cmd_data->options.dry_run) {
1704                 char *newname;
1705                 char *newext;
1706                 newname = malloc(strlen(cmd_data->shared_name.normal) + 1);
1707
1708                 strcpy(newname, cmd_data->shared_name.normal);
1709                 newext = strrchr(newname, '/');
1710                 if (!newext) {
1711                         /* Check first to see if the dir already exists! */
1712                         safe_mkdir(".libs");
1713                 } else {
1714                         *newext = '\0';
1715                         safe_mkdir(newname);
1716                 }
1717                 free(newname);
1718         }
1719
1720         cmd_data->output_name = arg;
1721         return 1;
1722     }
1723
1724     if (strcmp(ext, "lo") == 0) {
1725         char *newext;
1726         cmd_data->basename = arg;
1727         cmd_data->output = otObject;
1728         newarg = (char *)malloc(strlen(arg) + 2);
1729         strcpy(newarg, arg);
1730         newext = strrchr(newarg, '.') + 1;
1731         strcpy(newext, OBJECT_EXT);
1732         cmd_data->output_name = newarg;
1733         return 1;
1734     }
1735
1736     if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1737       fprintf(stderr, "Please build libraries with .la target, not ."
1738               DYNAMIC_LIB_EXT "\n");
1739       exit(1);
1740     }
1741
1742     if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1743       fprintf(stderr, "Please build libraries with .la target, not ."
1744               STATIC_LIB_EXT "\n");
1745       exit(1);
1746     }
1747
1748     return 0;
1749 }
1750
1751 static char *automode(char *arg, command_t *cmd_data)
1752 {
1753         if (cmd_data->mode != mUnknown) return arg;
1754
1755         if (strcmp(arg, "CC") == 0) {
1756                 arg = CC;
1757                 cmd_data->mode = mCompile;
1758
1759         } else if (strcmp(arg, "CXX") == 0) {
1760                 arg = CXX;
1761                 cmd_data->mode = mCompile;
1762
1763         } else if (strcmp(arg, "LINK") == 0) {
1764                 arg = LINK_c;
1765                 cmd_data->mode = mLink;
1766
1767         } else if (strcmp(arg, "LINK.c") == 0) {
1768                 arg = LINK_c;
1769                 cmd_data->mode = mLink;
1770
1771         } else if (strcmp(arg, "LINK.cxx") == 0) {
1772                 arg = LINK_cxx;
1773                 cmd_data->mode = mLink;
1774         }
1775         
1776         return arg;
1777 }
1778
1779 static void parse_args(int argc, char *argv[], command_t *cmd_data)
1780 {
1781     int a;
1782     char *arg, *base;
1783     int argused;
1784
1785     /*
1786      *  We now take a major step past libtool.
1787      *
1788      *  IF there's no "--mode=...", AND we recognise
1789      *  the binary as a "special" name, THEN replace it
1790      *  with the correct one, and set the correct mode.
1791      */
1792     base = jlibtool_basename(argv[0]);
1793     arg = automode(base, cmd_data);
1794     
1795     if (arg != base) {
1796             if (cmd_data->options.debug) {
1797                     printf("Adding: %s\n", arg);
1798             }
1799             push_count_chars(cmd_data->arglist, arg);
1800             assert(cmd_data->mode != mUnknown);
1801     }
1802
1803     /*
1804      *  We first pass over the command-line arguments looking for
1805      *  "--mode", etc.  If so, then use the libtool compatibility
1806      *  method for building the software.  Otherwise, auto-detect it
1807      *  via "-o" and the extensions.
1808      */
1809     base = NULL;
1810     if (cmd_data->mode == mUnknown) for (a = 1; a < argc; a++) {
1811         arg = argv[a];
1812
1813         if (strncmp(arg, "--mode=", 7) == 0) {
1814           base = NULL;
1815           break;
1816         }
1817
1818         /*
1819          *      Stop if we get another magic method
1820          */
1821         if ((a == 1) &&
1822             ((strncmp(arg, "LINK", 4) == 0) ||
1823              (strcmp(arg, "CC") == 0) ||
1824              (strcmp(arg, "CXX") == 0))) {
1825           base = NULL;
1826           break;
1827         }
1828
1829         if (strncmp(arg, "-o", 2) == 0) {
1830           base = argv[++a];
1831         }
1832     }
1833
1834     if (base) {
1835             arg = strrchr(base, '.');
1836             if (!arg) {
1837                     cmd_data->mode = mLink;
1838                     push_count_chars(cmd_data->arglist, LINK_c);
1839             }
1840 #ifdef EXE_EXT
1841             else if (strcmp(arg, EXE_EXT) == 0) {
1842                     cmd_data->mode = mLink;
1843                     push_count_chars(cmd_data->arglist, LINK_c);
1844             }
1845 #endif
1846             else if (strcmp(arg + 1, DYNAMIC_LIB_EXT) == 0) {
1847                     cmd_data->mode = mLink;
1848                     push_count_chars(cmd_data->arglist, LINK_c);
1849             }
1850             else if (strcmp(arg + 1, STATIC_LIB_EXT) == 0) {
1851                     cmd_data->mode = mLink;
1852                     push_count_chars(cmd_data->arglist, LINK_c);
1853             }
1854             else if (strcmp(arg + 1, "la") == 0) {
1855                     cmd_data->mode = mLink;
1856                     push_count_chars(cmd_data->arglist, LINK_c);
1857             }
1858             else if ((strcmp(arg + 1, "lo") == 0) ||
1859                      (strcmp(arg + 1, "o") == 0)) {
1860                     cmd_data->mode = mCompile;
1861                     push_count_chars(cmd_data->arglist, CC);
1862             }
1863     }
1864
1865     for (a = 1; a < argc; a++) {
1866         arg = argv[a];
1867         argused = 1;
1868
1869         if (arg[0] == '-') {
1870             if (arg[1] == '-') {
1871                 argused = parse_long_opt(arg + 2, cmd_data);
1872             }
1873             else {
1874                 argused = parse_short_opt(arg + 1, cmd_data);
1875             }
1876
1877             /* We haven't done anything with it yet, try some of the
1878              * more complicated short opts... */
1879             if (argused == 0 && a + 1 < argc) {
1880                 if (arg[1] == 'o' && !arg[2]) {
1881                     arg = argv[++a];
1882                     argused = parse_output_file_name(arg, cmd_data);
1883                 } else if (strcmp(arg+1, "MT") == 0) {
1884                     if (cmd_data->options.debug) {
1885                         printf("Adding: %s\n", arg);
1886                     }
1887                     push_count_chars(cmd_data->arglist, arg);
1888                     arg = argv[++a];
1889                     if (!cmd_data->options.silent) {
1890                         printf(" %s\n", arg);
1891                     }
1892                     push_count_chars(cmd_data->arglist, arg);
1893                     argused = 1;
1894                 } else if (strcmp(arg+1, "rpath") == 0) {
1895                     /* Aha, we should try to link both! */
1896                     cmd_data->install_path = argv[++a];
1897                     argused = 1;
1898                 } else if (strcmp(arg+1, "release") == 0) {
1899                     /* Store for later deciphering */
1900                     cmd_data->version_info = argv[++a];
1901                     argused = 1;
1902                 } else if (strcmp(arg+1, "version-info") == 0) {
1903                     /* Store for later deciphering */
1904                     cmd_data->version_info = argv[++a];
1905                     argused = 1;
1906                 } else if (strcmp(arg+1, "export-symbols-regex") == 0) {
1907                     /* Skip the argument. */
1908                     ++a;
1909                     argused = 1;
1910                 } else if (strcmp(arg+1, "release") == 0) {
1911                     /* Skip the argument. */
1912                     ++a;
1913                     argused = 1;
1914                 } else if (strcmp(arg+1, "undefined") == 0) {
1915                     cmd_data->undefined_flag = argv[++a];
1916                     argused = 1;
1917                 } else if (arg[1] == 'R' && !arg[2]) {
1918                     /* -R dir Add dir to runtime library search path. */
1919                     add_runtimedirlib(argv[++a], cmd_data);
1920                     argused = 1;
1921                 }
1922             }
1923         } else {
1924             argused = parse_input_file_name(arg, cmd_data);
1925         }
1926
1927         if (!argused) {
1928                 /*
1929                  *  If we still don't have a run mode, look for a magic
1930                  *  program name CC, LINK, or whatever.  Then replace that
1931                  *  with the name of the real program we want to run.
1932                  */
1933                 if ((cmd_data->arglist->num == 0) &&
1934                     (cmd_data->mode == mUnknown)) {
1935                         arg = automode(arg, cmd_data);
1936                 }
1937
1938             if (cmd_data->options.debug) {
1939                 printf("Adding: %s\n", arg);
1940             }
1941             push_count_chars(cmd_data->arglist, arg);
1942         }
1943     }
1944
1945 }
1946
1947 #ifdef GEN_EXPORTS
1948 static void generate_def_file(command_t *cmd_data)
1949 {
1950     char def_file[1024];
1951     char implib_file[1024];
1952     char *ext;
1953     FILE *hDef;
1954     char *export_args[1024];
1955     int num_export_args = 0;
1956     char *cmd;
1957     int cmd_size = 0;
1958     int a;
1959
1960     if (cmd_data->output_name) {
1961         strcpy(def_file, cmd_data->output_name);
1962         strcat(def_file, ".def");
1963         hDef = fopen(def_file, "w");
1964
1965         if (hDef != NULL) {
1966             fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
1967             fprintf(hDef, "DATA NONSHARED\n");
1968             fprintf(hDef, "EXPORTS\n");
1969             fclose(hDef);
1970
1971             for (a = 0; a < cmd_data->num_obj_files; a++) {
1972                 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
1973             }
1974
1975             cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
1976             cmd = (char *)malloc(cmd_size);
1977             strcpy(cmd, GEN_EXPORTS);
1978
1979             for (a=0; a < cmd_data->num_obj_files; a++) {
1980                 strcat(cmd, " ");
1981                 strcat(cmd, cmd_data->obj_files[a] );
1982             }
1983
1984             strcat(cmd, ">>");
1985             strcat(cmd, def_file);
1986             puts(cmd);
1987             export_args[num_export_args++] = SHELL_CMD;
1988             export_args[num_export_args++] = "-c";
1989             export_args[num_export_args++] = cmd;
1990             export_args[num_export_args++] = NULL;
1991             external_spawn(cmd_data, export_args[0], (const char**)export_args);
1992             cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
1993
1994             /* Now make an import library for the dll */
1995             num_export_args = 0;
1996             export_args[num_export_args++] = DEF2IMPLIB_CMD;
1997             export_args[num_export_args++] = "-o";
1998
1999             strcpy(implib_file, ".libs/");
2000             strcat(implib_file, cmd_data->basename);
2001             ext = strrchr(implib_file, '.');
2002
2003             if (ext)
2004                 *ext = 0;
2005
2006             strcat(implib_file, ".");
2007             strcat(implib_file, STATIC_LIB_EXT);
2008
2009             export_args[num_export_args++] = implib_file;
2010             export_args[num_export_args++] = def_file;
2011             export_args[num_export_args++] = NULL;
2012             external_spawn(cmd_data, export_args[0], (const char**)export_args);
2013
2014         }
2015     }
2016 }
2017 #endif
2018
2019 #if 0
2020 static const char* expand_path(const char *relpath)
2021 {
2022     char foo[PATH_MAX], *newpath;
2023
2024     getcwd(foo, PATH_MAX-1);
2025     newpath = (char*)malloc(strlen(foo)+strlen(relpath)+2);
2026     strcpy(newpath, foo);
2027     strcat(newpath, "/");
2028     strcat(newpath, relpath);
2029     return newpath;
2030 }
2031 #endif
2032
2033 static void link_fixup(command_t *c)
2034 {
2035     /* If we were passed an -rpath directive, we need to build
2036      * shared objects too.  Otherwise, we should only create static
2037      * libraries.
2038      */
2039     if (!c->install_path && (c->output == otDynamicLibraryOnly ||
2040         c->output == otModule || c->output == otLibrary)) {
2041         if (c->options.shared == share_SHARED) {
2042                 c->install_path = LIBDIR;
2043         }
2044     }
2045
2046     if (c->output == otDynamicLibraryOnly ||
2047         c->output == otModule ||
2048         c->output == otLibrary) {
2049
2050         push_count_chars(c->shared_opts.normal, "-o");
2051         if (c->output == otModule) {
2052             push_count_chars(c->shared_opts.normal, c->module_name.normal);
2053         }
2054         else {
2055             char *tmp;
2056             push_count_chars(c->shared_opts.normal, c->shared_name.normal);
2057 #ifdef DYNAMIC_INSTALL_NAME
2058             push_count_chars(c->shared_opts.normal, DYNAMIC_INSTALL_NAME);
2059
2060             if (!c->install_path) {
2061                     fprintf(stderr, "Installation mode requires -rpath\n");
2062                     exit(1);
2063             }
2064
2065             tmp = (char*)malloc(PATH_MAX);
2066             strcpy(tmp, c->install_path);
2067             if (c->shared_name.install) {
2068                     strcat(tmp, strrchr(c->shared_name.install, '/'));
2069             } else {
2070                     strcat(tmp, strrchr(c->shared_name.normal, '/'));
2071             }
2072             push_count_chars(c->shared_opts.normal, tmp);
2073 #endif
2074         }
2075
2076         append_count_chars(c->shared_opts.normal, c->obj_files);
2077         append_count_chars(c->shared_opts.normal, c->shared_opts.dependencies);
2078
2079         if (c->options.export_all) {
2080 #ifdef GEN_EXPORTS
2081             generate_def_file(c);
2082 #endif
2083         }
2084     }
2085
2086     if (c->output == otLibrary || c->output == otStaticLibraryOnly) {
2087         push_count_chars(c->static_opts.normal, "-o");
2088         push_count_chars(c->static_opts.normal, c->output_name);
2089     }
2090
2091     if (c->output == otProgram) {
2092         if (c->output_name) {
2093             push_count_chars(c->arglist, "-o");
2094             push_count_chars(c->arglist, c->output_name);
2095             append_count_chars(c->arglist, c->obj_files);
2096             append_count_chars(c->arglist, c->shared_opts.dependencies);
2097             add_dynamic_link_opts(c, c->arglist);
2098         }
2099     }
2100 }
2101
2102 static void post_parse_fixup(command_t *cmd_data)
2103 {
2104     switch (cmd_data->mode)
2105     {
2106     case mCompile:
2107 #ifdef PIC_FLAG
2108         if (cmd_data->options.pic_mode != pic_AVOID) {
2109             push_count_chars(cmd_data->arglist, PIC_FLAG);
2110         }
2111 #endif
2112         if (cmd_data->output_name) {
2113             push_count_chars(cmd_data->arglist, "-o");
2114             push_count_chars(cmd_data->arglist, cmd_data->output_name);
2115         }
2116         break;
2117     case mLink:
2118         link_fixup(cmd_data);
2119         break;
2120     case mInstall:
2121         if (cmd_data->output == otLibrary) {
2122             link_fixup(cmd_data);
2123         }
2124     default:
2125         break;
2126     }
2127
2128 #ifdef USE_OMF
2129     if (cmd_data->output == otObject ||
2130         cmd_data->output == otProgram ||
2131         cmd_data->output == otLibrary ||
2132         cmd_data->output == otDynamicLibraryOnly) {
2133         push_count_chars(cmd_data->arglist, "-Zomf");
2134     }
2135 #endif
2136
2137     if (cmd_data->options.shared &&
2138             (cmd_data->output == otObject ||
2139              cmd_data->output == otLibrary ||
2140              cmd_data->output == otDynamicLibraryOnly)) {
2141 #ifdef SHARE_SW
2142         push_count_chars(cmd_data->arglist, SHARE_SW);
2143 #endif
2144     }
2145 }
2146
2147 static int run_mode(command_t *cmd_data)
2148 {
2149     int rv;
2150     count_chars *cctemp;
2151
2152     cctemp = (count_chars*)malloc(sizeof(count_chars));
2153     init_count_chars(cctemp);
2154
2155     switch (cmd_data->mode)
2156     {
2157     case mCompile:
2158         rv = run_command(cmd_data, cmd_data->arglist);
2159         if (rv) {
2160             return rv;
2161         }
2162         break;
2163     case mInstall:
2164         /* Well, we'll assume it's a file going to a directory... */
2165         /* For brain-dead install-sh based scripts, we have to repeat
2166          * the command N-times.  install-sh should die.
2167          */
2168         if (!cmd_data->output_name) {
2169             rv = run_command(cmd_data, cmd_data->arglist);
2170             if (rv) {
2171                 return rv;
2172             }
2173         }
2174         if (cmd_data->output_name) {
2175             append_count_chars(cctemp, cmd_data->arglist);
2176             insert_count_chars(cctemp,
2177                                cmd_data->output_name,
2178                                cctemp->num - 1);
2179             rv = run_command(cmd_data, cctemp);
2180             if (rv) {
2181                 return rv;
2182             }
2183             clear_count_chars(cctemp);
2184         }
2185         if (cmd_data->static_name.install) {
2186             append_count_chars(cctemp, cmd_data->arglist);
2187             insert_count_chars(cctemp,
2188                                cmd_data->static_name.install,
2189                                cctemp->num - 1);
2190             rv = run_command(cmd_data, cctemp);
2191             if (rv) {
2192                 return rv;
2193             }
2194 #if defined(__APPLE__) && defined(RANLIB)
2195             /* From the Apple libtool(1) manpage on Tiger/10.4:
2196              * ----
2197              * With  the way libraries used to be created, errors were possible
2198              * if the library was modified with ar(1) and  the  table  of
2199              * contents  was  not updated  by  rerunning ranlib(1).  Thus the
2200              * link editor, ld, warns when the modification date of a library
2201              * is more  recent  than  the  creation date  of its table of
2202              * contents.  Unfortunately, this means that you get the warning
2203              * even if you only copy the library.
2204              * ----
2205              *
2206              * This means that when we install the static archive, we need to
2207              * rerun ranlib afterwards.
2208              */
2209             const char *lib_args[3], *static_lib_name;
2210             char *tmp;
2211             size_t len1, len2;
2212             len1 = strlen(cmd_data->arglist->vals[cmd_data->arglist->num - 1]);
2213
2214             static_lib_name = jlibtool_basename(cmd_data->static_name.install);
2215             len2 = strlen(static_lib_name);
2216
2217             tmp = malloc(len1 + len2 + 2);
2218
2219             snprintf(tmp, len1 + len2 + 2, "%s/%s",
2220                     cmd_data->arglist->vals[cmd_data->arglist->num - 1],
2221                     static_lib_name);
2222
2223             lib_args[0] = RANLIB;
2224             lib_args[1] = tmp;
2225             lib_args[2] = NULL;
2226             external_spawn(cmd_data, RANLIB, lib_args);
2227             free(tmp);
2228 #endif
2229             clear_count_chars(cctemp);
2230         }
2231         if (cmd_data->shared_name.install) {
2232             append_count_chars(cctemp, cmd_data->arglist);
2233             insert_count_chars(cctemp,
2234                                cmd_data->shared_name.install,
2235                                cctemp->num - 1);
2236             rv = run_command(cmd_data, cctemp);
2237             if (rv) {
2238                 return rv;
2239             }
2240             clear_count_chars(cctemp);
2241         }
2242         if (cmd_data->module_name.install) {
2243             append_count_chars(cctemp, cmd_data->arglist);
2244             insert_count_chars(cctemp,
2245                                cmd_data->module_name.install,
2246                                cctemp->num - 1);
2247             rv = run_command(cmd_data, cctemp);
2248             if (rv) {
2249                 return rv;
2250             }
2251             clear_count_chars(cctemp);
2252         }
2253         break;
2254     case mLink:
2255         if (cmd_data->output == otStaticLibraryOnly ||
2256             cmd_data->output == otLibrary) {
2257 #ifdef RANLIB
2258             const char *lib_args[3];
2259 #endif
2260             /* Removes compiler! */
2261             cmd_data->program = LIBRARIAN;
2262             push_count_chars(cmd_data->program_opts, LIBRARIAN_OPTS);
2263             push_count_chars(cmd_data->program_opts,
2264                              cmd_data->static_name.normal);
2265
2266             rv = run_command(cmd_data, cmd_data->obj_files);
2267             if (rv) {
2268                 return rv;
2269             }
2270
2271 #ifdef RANLIB
2272             lib_args[0] = RANLIB;
2273             lib_args[1] = cmd_data->static_name.normal;
2274             lib_args[2] = NULL;
2275             external_spawn(cmd_data, RANLIB, lib_args);
2276 #endif
2277         }
2278
2279         if (cmd_data->output == otDynamicLibraryOnly ||
2280             cmd_data->output == otModule ||
2281             cmd_data->output == otLibrary) {
2282             cmd_data->program = NULL;
2283             clear_count_chars(cmd_data->program_opts);
2284
2285             append_count_chars(cmd_data->program_opts, cmd_data->arglist);
2286             if (cmd_data->output == otModule) {
2287 #ifdef MODULE_OPTS
2288                 push_count_chars(cmd_data->program_opts, MODULE_OPTS);
2289 #endif
2290             } else {
2291 #ifdef SHARED_OPTS
2292                 push_count_chars(cmd_data->program_opts, SHARED_OPTS);
2293 #endif
2294 #ifdef dynamic_link_version_func
2295                 push_count_chars(cmd_data->program_opts,
2296                              dynamic_link_version_func(cmd_data->version_info));
2297 #endif
2298             }
2299             add_dynamic_link_opts(cmd_data, cmd_data->program_opts);
2300
2301             rv = run_command(cmd_data, cmd_data->shared_opts.normal);
2302             if (rv) {
2303                 return rv;
2304             }
2305         }
2306         if (cmd_data->output == otProgram) {
2307             rv = run_command(cmd_data, cmd_data->arglist);
2308             if (rv) {
2309                 return rv;
2310             }
2311         }
2312         break;
2313     case mExecute:
2314     {
2315         char *l, libpath[PATH_MAX];
2316
2317         strcpy(libpath, cmd_data->arglist->vals[0]);
2318         add_dotlibs(libpath);
2319         l = strrchr(libpath, '/');
2320         if (!l) l = strrchr(libpath, '\\');
2321         if (l) {
2322             *l = '\0';
2323             l = libpath;
2324         } else {
2325             l = ".libs/";
2326         }
2327
2328         l = "./build/lib/.libs";
2329         setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
2330         rv = run_command(cmd_data, cmd_data->arglist);
2331         if (rv) {
2332             return rv;
2333         }
2334     }
2335       break;
2336
2337     default:
2338         break;
2339     }
2340
2341     return 0;
2342 }
2343
2344 static void cleanup_tmp_dir(const char *dirname)
2345 {
2346     DIR *dir;
2347     struct dirent *entry;
2348     char fullname[1024];
2349
2350     dir = opendir(dirname);
2351
2352     if (dir == NULL)
2353         return;
2354
2355     while ((entry = readdir(dir)) != NULL) {
2356         if (entry->d_name[0] != '.') {
2357             strcpy(fullname, dirname);
2358             strcat(fullname, "/");
2359             strcat(fullname, entry->d_name);
2360             (void) remove(fullname);
2361         }
2362     }
2363
2364     rmdir(dirname);
2365     
2366     (void) closedir(dir);
2367 }
2368
2369 static void cleanup_tmp_dirs(command_t *cmd_data)
2370 {
2371     int d;
2372
2373     for (d = 0; d < cmd_data->tmp_dirs->num; d++) {
2374         cleanup_tmp_dir(cmd_data->tmp_dirs->vals[d]);
2375     }
2376 }
2377
2378 static int ensure_fake_uptodate(command_t *cmd_data)
2379 {
2380     /* FIXME: could do the stat/touch here, but nah... */
2381     const char *touch_args[3];
2382
2383     if (cmd_data->mode == mInstall) {
2384         return 0;
2385     }
2386     if (!cmd_data->fake_output_name) {
2387         return 0;
2388     }
2389
2390     touch_args[0] = "touch";
2391     touch_args[1] = cmd_data->fake_output_name;
2392     touch_args[2] = NULL;
2393     return external_spawn(cmd_data, "touch", touch_args);
2394 }
2395
2396 /* Store the install path in the *.la file */
2397 static int add_for_runtime(command_t *cmd_data)
2398 {
2399     if (cmd_data->mode == mInstall) {
2400         return 0;
2401     }
2402     if (cmd_data->output == otDynamicLibraryOnly ||
2403         cmd_data->output == otLibrary) {
2404         FILE *f=fopen(cmd_data->fake_output_name,"w");
2405         if (f == NULL) {
2406             return -1;
2407         }
2408         fprintf(f,"%s\n", cmd_data->install_path);
2409         fclose(f);
2410         return(0);
2411     } else {
2412         return(ensure_fake_uptodate(cmd_data));
2413     }
2414 }
2415
2416 int main(int argc, char *argv[])
2417 {
2418     int rc;
2419     command_t cmd_data;
2420
2421     memset(&cmd_data, 0, sizeof(cmd_data));
2422
2423     cmd_data.options.pic_mode = pic_UNKNOWN;
2424
2425     cmd_data.program_opts = (count_chars*)malloc(sizeof(count_chars));
2426     init_count_chars(cmd_data.program_opts);
2427     cmd_data.arglist = (count_chars*)malloc(sizeof(count_chars));
2428     init_count_chars(cmd_data.arglist);
2429     cmd_data.tmp_dirs = (count_chars*)malloc(sizeof(count_chars));
2430     init_count_chars(cmd_data.tmp_dirs);
2431     cmd_data.obj_files = (count_chars*)malloc(sizeof(count_chars));
2432     init_count_chars(cmd_data.obj_files);
2433     cmd_data.dep_rpaths = (count_chars*)malloc(sizeof(count_chars));
2434     init_count_chars(cmd_data.dep_rpaths);
2435     cmd_data.rpaths = (count_chars*)malloc(sizeof(count_chars));
2436     init_count_chars(cmd_data.rpaths);
2437     cmd_data.static_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2438     init_count_chars(cmd_data.static_opts.normal);
2439     cmd_data.shared_opts.normal = (count_chars*)malloc(sizeof(count_chars));
2440     init_count_chars(cmd_data.shared_opts.normal);
2441     cmd_data.shared_opts.dependencies = (count_chars*)malloc(sizeof(count_chars));
2442     init_count_chars(cmd_data.shared_opts.dependencies);
2443
2444     cmd_data.mode = mUnknown;
2445     cmd_data.output = otGeneral;
2446
2447     parse_args(argc, argv, &cmd_data);
2448     post_parse_fixup(&cmd_data);
2449
2450     if (cmd_data.mode == mUnknown) {
2451        usage(1);
2452     }
2453
2454     rc = run_mode(&cmd_data);
2455
2456     if (!rc) {
2457        add_for_runtime(&cmd_data);
2458     }
2459
2460     cleanup_tmp_dirs(&cmd_data);
2461     return rc;
2462 }