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