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