1 /* VMS archive wrapper. 2 Copyright (C) 2011-2015 Free Software Foundation, Inc. 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; 128 char temp_filename[] = TEMP_FILE SUFFIX; 129 char command[256]; 130 int status; 131 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 } 349