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