]>
Commit | Line | Data |
---|---|---|
18a24fed | 1 | /* VMS archive wrapper. |
7adcbafe | 2 | Copyright (C) 2011-2022 Free Software Foundation, Inc. |
18a24fed TG |
3 | Contributed by AdaCore. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include <errno.h> | |
22 | #include <stdio.h> | |
23 | #include <sys/types.h> | |
24 | #include <sys/stat.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | #include <unistd.h> | |
28 | ||
29 | #include "libiberty.h" | |
30 | ||
31 | #define FATAL_EXIT_CODE (44 | 0x10000000) | |
32 | ||
33 | /* Librarian arguments. */ | |
34 | static int lib_arg_max = 0; | |
35 | static const char **lib_args; | |
36 | static int lib_arg_index = -1; | |
37 | ||
38 | /* Set for r/c/x/v command. */ | |
39 | static int replace_mode = 0; | |
40 | static int create_mode = 0; | |
41 | static int extract_mode = 0; | |
42 | static int verbose_mode = 0; | |
43 | ||
44 | static char modecmd[32]; | |
45 | static char libname[256]; | |
46 | ||
47 | #define TEMP_FILE "arXXXXXX" | |
48 | #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) | |
49 | #define SUFFIX ".com" | |
50 | #define SUFFIX_LEN (sizeof(SUFFIX) - 1) | |
51 | ||
52 | static char *to_host_file_spec (char *filespec); | |
53 | static int is_regular_file (char *name); | |
54 | ||
55 | #ifdef VMS | |
56 | static char new_host_filespec [255]; | |
57 | static char filename_buff [256]; | |
58 | ||
59 | static int | |
60 | translate_unix (char *name, int type) | |
61 | { | |
62 | strcpy (filename_buff, name); | |
63 | return 0; | |
64 | } | |
65 | #endif | |
66 | ||
67 | static char * | |
68 | to_host_file_spec (char *filespec) | |
69 | { | |
70 | #ifdef VMS | |
71 | if (strchr (filespec, ']') || strchr (filespec, ':')) | |
72 | return filespec; | |
73 | else | |
74 | { | |
75 | strcpy (filename_buff, filespec); | |
76 | decc$to_vms (filespec, translate_unix, 1, 1); | |
77 | strcpy (new_host_filespec, filename_buff); | |
78 | return new_host_filespec; | |
79 | } | |
80 | #else | |
81 | return filespec; | |
82 | #endif | |
83 | } | |
84 | ||
85 | /* Check to see if the file named in NAME is a regular file, i.e. not a | |
86 | directory. */ | |
87 | ||
88 | static int | |
89 | is_regular_file (char *name) | |
90 | { | |
91 | int ret; | |
92 | struct stat statbuf; | |
93 | ||
94 | ret = stat (name, &statbuf); | |
95 | return !ret && S_ISREG (statbuf.st_mode); | |
96 | } | |
97 | ||
98 | /* Add the argument contained in STR to the list of arguments to pass to the | |
99 | archiver. */ | |
100 | ||
101 | static void | |
102 | addarg (const char *str) | |
103 | { | |
104 | if (++lib_arg_index >= lib_arg_max) | |
105 | { | |
106 | lib_arg_max += 1000; | |
107 | lib_args = XRESIZEVEC (const char *, lib_args, lib_arg_max); | |
108 | } | |
109 | ||
110 | lib_args[lib_arg_index] = str; | |
111 | } | |
112 | ||
113 | static void | |
114 | usage (void) | |
115 | { | |
116 | printf ("usage: ar -r [-cv] archive file...\n"); | |
117 | printf (" ar -c [-rv] archive file...\n"); | |
118 | printf (" ar -x [-v] archive [module...]\n"); | |
119 | } | |
120 | ||
121 | int | |
122 | main (int argc, char *argv[]) | |
123 | { | |
124 | int i, nexti, iarg; | |
125 | FILE *comfile; | |
126 | int comfd; | |
127 | int outlen, maxoutlen = 4000; | |
18a24fed TG |
128 | char temp_filename[] = TEMP_FILE SUFFIX; |
129 | char command[256]; | |
130 | int status; | |
131 | ||
18a24fed TG |
132 | if (argc < 2) |
133 | { | |
134 | fprintf (stderr, "ar: no command or archive\n"); | |
135 | exit (FATAL_EXIT_CODE); | |
136 | } | |
137 | ||
138 | if (argv[1][0] != '-') | |
139 | { | |
140 | int arglen = strlen (argv[1]); | |
141 | ||
142 | /* Compatibility mode. */ | |
143 | for (i = 0; i < arglen; i++) | |
144 | { | |
145 | if (argv[1][i] == 'r') | |
146 | { | |
147 | replace_mode = 1; | |
148 | } | |
149 | else if (argv[1][i] == 'c') | |
150 | { | |
151 | create_mode = 1; | |
152 | } | |
153 | else if (argv[1][i] == 'x') | |
154 | { | |
155 | extract_mode = 1; | |
156 | } | |
157 | else if (argv[1][i] == 'v') | |
158 | { | |
159 | verbose_mode = 1; | |
160 | } | |
161 | else | |
162 | { | |
163 | fprintf (stderr, "ar: unknown command '%c'\n", argv[1][i]); | |
164 | exit (FATAL_EXIT_CODE); | |
165 | } | |
166 | } | |
167 | nexti = 2; | |
168 | } | |
169 | else | |
170 | { | |
171 | /* Option mode. */ | |
172 | nexti = 1; | |
173 | for (i = 1; i < argc; i++) | |
174 | { | |
175 | if (argv[i][0] != '-') | |
176 | { | |
177 | nexti = i; | |
178 | break; | |
179 | } | |
180 | else if (strcmp (argv[i], "-r") == 0) | |
181 | { | |
182 | replace_mode = 1; | |
183 | } | |
184 | else if (strcmp (argv[i], "-c") == 0) | |
185 | { | |
186 | create_mode = 1; | |
187 | } | |
188 | else if (strcmp (argv[i], "-x") == 0) | |
189 | { | |
190 | extract_mode = 1; | |
191 | } | |
192 | else if (strcmp (argv[i], "-v") == 0) | |
193 | { | |
194 | verbose_mode = 1; | |
195 | } | |
196 | else if (strcmp (argv[i], "--help") == 0) | |
197 | { | |
198 | usage (); | |
199 | exit (EXIT_SUCCESS); | |
200 | } | |
201 | else | |
202 | { | |
203 | fprintf (stderr, "ar: unknown option %s\n", argv[i]); | |
204 | exit (FATAL_EXIT_CODE); | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
209 | if (extract_mode) | |
210 | { | |
211 | do | |
212 | { | |
213 | char *lname = argv[nexti]; | |
214 | int lnamelen; | |
215 | ||
216 | /* Next argument is the archive name. */ | |
217 | if (is_regular_file (lname)) | |
218 | { | |
219 | addarg (xstrdup (to_host_file_spec (lname))); | |
220 | break; | |
221 | } | |
222 | ||
223 | /* If not found, try with .olb instead of .a. */ | |
224 | lnamelen = strlen (lname); | |
225 | ||
226 | if (lnamelen > 2 | |
227 | && strcmp (&lname [lnamelen - 2], ".a") == 0) | |
228 | { | |
229 | char *nlibname; | |
230 | ||
231 | nlibname = (char *)alloca (lnamelen + 3); | |
232 | strcpy (nlibname, lname); | |
233 | strcpy (&nlibname [lnamelen - 2], ".olb"); | |
234 | if (is_regular_file (nlibname)) | |
235 | { | |
236 | addarg (xstrdup (to_host_file_spec (nlibname))); | |
237 | break; | |
238 | } | |
239 | } | |
240 | ||
241 | fprintf (stderr, "ar: file '%s' doesn't exist\n", lname); | |
242 | exit (FATAL_EXIT_CODE); | |
243 | } while (0); | |
244 | } | |
245 | else | |
246 | strcpy (libname, to_host_file_spec (argv[nexti])); | |
247 | ||
248 | nexti++; | |
249 | ||
250 | /* Build command mode. */ | |
251 | if (replace_mode) | |
252 | { | |
253 | strcat (modecmd, "/replace"); | |
254 | ||
255 | if (!is_regular_file (libname) || !replace_mode) | |
256 | { | |
257 | /* Really create if the archive doesn't exist. */ | |
258 | strcat (modecmd, "/create"); | |
259 | } | |
260 | } | |
261 | else if (extract_mode) | |
262 | { | |
263 | if (nexti == argc) | |
264 | { | |
265 | /* Extract all. */ | |
266 | strcat (modecmd, "/extract=(*"); | |
267 | } | |
268 | else | |
269 | strcat (modecmd, "/extract=("); | |
270 | } | |
271 | ||
272 | /* Add files. */ | |
273 | for (i = nexti; i < argc; i++) | |
274 | { | |
275 | if (extract_mode) | |
276 | { | |
277 | /* Convert to module name (remove extension) and quote it. */ | |
278 | char *module = argv[i]; | |
279 | int module_len = strlen (module); | |
280 | char *newarg = (char *)xmalloc (module_len + 3); | |
281 | int l; | |
282 | ||
283 | newarg[0] = '"'; | |
284 | memcpy (newarg + 1, module, module_len); | |
285 | ||
286 | l = 1 + module_len; | |
287 | if (module_len > 4 | |
288 | && strcmp (&module[module_len - 4], ".obj") == 0) | |
289 | l -= 4; | |
290 | ||
291 | newarg[l] = '"'; | |
292 | newarg[l + 1] = 0; | |
293 | ||
294 | addarg (newarg); | |
295 | } | |
296 | else | |
297 | { | |
298 | /* Add the filename. */ | |
299 | addarg (xstrdup (to_host_file_spec (argv[i]))); | |
300 | } | |
301 | } | |
302 | ||
303 | if (extract_mode) | |
304 | addarg (")"); | |
305 | ||
306 | /* Create the command file name. */ | |
307 | strcpy (temp_filename, TEMP_FILE SUFFIX); | |
308 | comfd = mkstemps (temp_filename, SUFFIX_LEN); | |
309 | comfile = fdopen (comfd, "w"); | |
310 | ||
311 | /* Write the command file. | |
312 | We need to split to command into severals ones if it is too long. */ | |
313 | outlen = 0; | |
314 | for (iarg = 0; iarg <= lib_arg_index; iarg++) | |
315 | { | |
316 | if (outlen == 0) | |
317 | { | |
318 | fprintf (comfile, "$ library %s %s -\n", modecmd, libname); | |
319 | if (create_mode && iarg == 0) | |
320 | strcpy (modecmd, "/replace"); | |
321 | } | |
322 | ||
323 | fprintf (comfile, "%s", lib_args [iarg]); | |
324 | outlen += strlen (lib_args [iarg]) + 2; | |
325 | ||
326 | if (outlen > maxoutlen || iarg == lib_arg_index) | |
327 | { | |
328 | /* Will write a new command. */ | |
329 | fprintf (comfile, "\n"); | |
330 | outlen = 0; | |
331 | } | |
332 | else | |
333 | { | |
334 | /* Continuation line. */ | |
335 | fprintf (comfile, ",-\n"); | |
336 | } | |
337 | } | |
338 | ||
339 | fclose (comfile); | |
340 | ||
341 | sprintf (command, "@%s", temp_filename); | |
342 | ||
343 | status = system (command); | |
344 | ||
345 | remove (temp_filename); | |
346 | ||
347 | exit (status); | |
348 | } |