1 /* arsup.c - Archive support for MRI compatibility
2    Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3    2004 Free Software Foundation, Inc.
4 
5    This file is part of GNU Binutils.
6 
7    This program 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 2 of the License, or
10    (at your option) any later version.
11 
12    This program 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 this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20 
21 
22 /* Contributed by Steve Chamberlain
23    sac@cygnus.com
24 
25    This file looks after requests from arparse.y, to provide the MRI
26    style librarian command syntax + 1 word LIST.  */
27 
28 #include "bfd.h"
29 #include "arsup.h"
30 #include "libiberty.h"
31 #include "bucomm.h"
32 #include "filenames.h"
33 
34 static void map_over_list
35   (bfd *, void (*function) (bfd *, bfd *), struct list *);
36 static void ar_directory_doer (bfd *, bfd *);
37 static void ar_addlib_doer (bfd *, bfd *);
38 
39 extern int verbose;
40 
41 static void
map_over_list(bfd * arch,void (* function)(bfd *,bfd *),struct list * list)42 map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
43 {
44   bfd *head;
45 
46   if (list == NULL)
47     {
48       bfd *next;
49 
50       head = arch->next;
51       while (head != NULL)
52 	{
53 	  next = head->next;
54 	  function (head, (bfd *) NULL);
55 	  head = next;
56 	}
57     }
58   else
59     {
60       struct list *ptr;
61 
62       /* This may appear to be a baroque way of accomplishing what we
63 	 want.  however we have to iterate over the filenames in order
64 	 to notice where a filename is requested but does not exist in
65 	 the archive.  Ditto mapping over each file each time -- we
66 	 want to hack multiple references.  */
67       for (ptr = list; ptr; ptr = ptr->next)
68 	{
69 	  bfd_boolean found = FALSE;
70 	  bfd *prev = arch;
71 
72 	  for (head = arch->next; head; head = head->next)
73 	    {
74 	      if (head->filename != NULL
75 		  && FILENAME_CMP (ptr->name, head->filename) == 0)
76 		{
77 		  found = TRUE;
78 		  function (head, prev);
79 		}
80 	      prev = head;
81 	    }
82 	  if (! found)
83 	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
84 	}
85     }
86 }
87 
88 
89 FILE *outfile;
90 
91 static void
ar_directory_doer(bfd * abfd,bfd * ignore ATTRIBUTE_UNUSED)92 ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
93 {
94   print_arelt_descr(outfile, abfd, verbose);
95 }
96 
97 void
ar_directory(char * ar_name,struct list * list,char * output)98 ar_directory (char *ar_name, struct list *list, char *output)
99 {
100   bfd *arch;
101 
102   arch = open_inarch (ar_name, (char *) NULL);
103   if (output)
104     {
105       outfile = fopen(output,"w");
106       if (outfile == 0)
107 	{
108 	  outfile = stdout;
109 	  fprintf (stderr,_("Can't open file %s\n"), output);
110 	  output = 0;
111 	}
112     }
113   else
114     outfile = stdout;
115 
116   map_over_list (arch, ar_directory_doer, list);
117 
118   bfd_close (arch);
119 
120   if (output)
121    fclose (outfile);
122 }
123 
124 void
prompt(void)125 prompt (void)
126 {
127   extern int interactive;
128 
129   if (interactive)
130     {
131       printf ("AR >");
132       fflush (stdout);
133     }
134 }
135 
136 void
maybequit(void)137 maybequit (void)
138 {
139   if (! interactive)
140     xexit (9);
141 }
142 
143 
144 bfd *obfd;
145 char *real_name;
146 
147 void
ar_open(char * name,int t)148 ar_open (char *name, int t)
149 {
150   char *tname = (char *) xmalloc (strlen (name) + 10);
151   const char *bname = lbasename (name);
152   real_name = name;
153 
154   /* Prepend tmp- to the beginning, to avoid file-name clashes after
155      truncation on filesystems with limited namespaces (DOS).  */
156   sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname);
157   obfd = bfd_openw (tname, NULL);
158 
159   if (!obfd)
160     {
161       fprintf (stderr,
162 	       _("%s: Can't open output archive %s\n"),
163 	       program_name,  tname);
164 
165       maybequit ();
166     }
167   else
168     {
169       if (!t)
170 	{
171 	  bfd **ptr;
172 	  bfd *element;
173 	  bfd *ibfd;
174 
175 	  ibfd = bfd_openr (name, NULL);
176 
177 	  if (!ibfd)
178 	    {
179 	      fprintf (stderr,_("%s: Can't open input archive %s\n"),
180 		       program_name, name);
181 	      maybequit ();
182 	      return;
183 	    }
184 
185 	  if (!bfd_check_format(ibfd, bfd_archive))
186 	    {
187 	      fprintf (stderr,
188 		       _("%s: file %s is not an archive\n"),
189 		       program_name, name);
190 	      maybequit ();
191 	      return;
192 	    }
193 
194 	  ptr = &(obfd->archive_head);
195 	  element = bfd_openr_next_archived_file (ibfd, NULL);
196 
197 	  while (element)
198 	    {
199 	      *ptr = element;
200 	      ptr = &element->next;
201 	      element = bfd_openr_next_archived_file (ibfd, element);
202 	    }
203 	}
204 
205       bfd_set_format (obfd, bfd_archive);
206 
207       obfd->has_armap = 1;
208     }
209 }
210 
211 static void
ar_addlib_doer(bfd * abfd,bfd * prev)212 ar_addlib_doer (bfd *abfd, bfd *prev)
213 {
214   /* Add this module to the output bfd.  */
215   if (prev != NULL)
216     prev->next = abfd->next;
217 
218   abfd->next = obfd->archive_head;
219   obfd->archive_head = abfd;
220 }
221 
222 void
ar_addlib(char * name,struct list * list)223 ar_addlib (char *name, struct list *list)
224 {
225   if (obfd == NULL)
226     {
227       fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
228       maybequit ();
229     }
230   else
231     {
232       bfd *arch;
233 
234       arch = open_inarch (name, (char *) NULL);
235       if (arch != NULL)
236 	map_over_list (arch, ar_addlib_doer, list);
237 
238       /* Don't close the bfd, since it will make the elements disappear.  */
239     }
240 }
241 
242 void
ar_addmod(struct list * list)243 ar_addmod (struct list *list)
244 {
245   if (!obfd)
246     {
247       fprintf (stderr, _("%s: no open output archive\n"), program_name);
248       maybequit ();
249     }
250   else
251     {
252       while (list)
253 	{
254 	  bfd *abfd = bfd_openr (list->name, NULL);
255 
256 	  if (!abfd)
257 	    {
258 	      fprintf (stderr, _("%s: can't open file %s\n"),
259 		       program_name, list->name);
260 	      maybequit ();
261 	    }
262 	  else
263 	    {
264 	      abfd->next = obfd->archive_head;
265 	      obfd->archive_head = abfd;
266 	    }
267 	  list = list->next;
268 	}
269     }
270 }
271 
272 
273 void
ar_clear(void)274 ar_clear (void)
275 {
276   if (obfd)
277     obfd->archive_head = 0;
278 }
279 
280 void
ar_delete(struct list * list)281 ar_delete (struct list *list)
282 {
283   if (!obfd)
284     {
285       fprintf (stderr, _("%s: no open output archive\n"), program_name);
286       maybequit ();
287     }
288   else
289     {
290       while (list)
291 	{
292 	  /* Find this name in the archive.  */
293 	  bfd *member = obfd->archive_head;
294 	  bfd **prev = &(obfd->archive_head);
295 	  int found = 0;
296 
297 	  while (member)
298 	    {
299 	      if (FILENAME_CMP(member->filename, list->name) == 0)
300 		{
301 		  *prev = member->next;
302 		  found = 1;
303 		}
304 	      else
305 		prev = &(member->next);
306 
307 	      member = member->next;
308 	    }
309 
310 	  if (!found)
311 	    {
312 	      fprintf (stderr, _("%s: can't find module file %s\n"),
313 		       program_name, list->name);
314 	      maybequit ();
315 	    }
316 
317 	  list = list->next;
318 	}
319     }
320 }
321 
322 void
ar_save(void)323 ar_save (void)
324 {
325   if (!obfd)
326     {
327       fprintf (stderr, _("%s: no open output archive\n"), program_name);
328       maybequit ();
329     }
330   else
331     {
332       char *ofilename = xstrdup (bfd_get_filename (obfd));
333 
334       bfd_close (obfd);
335 
336       smart_rename (ofilename, real_name, 0);
337       obfd = 0;
338       free (ofilename);
339     }
340 }
341 
342 void
ar_replace(struct list * list)343 ar_replace (struct list *list)
344 {
345   if (!obfd)
346     {
347       fprintf (stderr, _("%s: no open output archive\n"), program_name);
348       maybequit ();
349     }
350   else
351     {
352       while (list)
353 	{
354 	  /* Find this name in the archive.  */
355 	  bfd *member = obfd->archive_head;
356 	  bfd **prev = &(obfd->archive_head);
357 	  int found = 0;
358 
359 	  while (member)
360 	    {
361 	      if (FILENAME_CMP (member->filename, list->name) == 0)
362 		{
363 		  /* Found the one to replace.  */
364 		  bfd *abfd = bfd_openr (list->name, 0);
365 
366 		  if (!abfd)
367 		    {
368 		      fprintf (stderr, _("%s: can't open file %s\n"),
369 			       program_name, list->name);
370 		      maybequit ();
371 		    }
372 		  else
373 		    {
374 		      *prev = abfd;
375 		      abfd->next = member->next;
376 		      found = 1;
377 		    }
378 		}
379 	      else
380 		{
381 		  prev = &(member->next);
382 		}
383 	      member = member->next;
384 	    }
385 
386 	  if (!found)
387 	    {
388 	      bfd *abfd = bfd_openr (list->name, 0);
389 
390 	      fprintf (stderr,_("%s: can't find module file %s\n"),
391 		       program_name, list->name);
392 	      if (!abfd)
393 		{
394 		  fprintf (stderr, _("%s: can't open file %s\n"),
395 			   program_name, list->name);
396 		  maybequit ();
397 		}
398 	      else
399 		*prev = abfd;
400 	    }
401 
402 	  list = list->next;
403 	}
404     }
405 }
406 
407 /* And I added this one.  */
408 void
ar_list(void)409 ar_list (void)
410 {
411   if (!obfd)
412     {
413       fprintf (stderr, _("%s: no open output archive\n"), program_name);
414       maybequit ();
415     }
416   else
417     {
418       bfd *abfd;
419 
420       outfile = stdout;
421       verbose =1 ;
422       printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
423 
424       for (abfd = obfd->archive_head;
425 	   abfd != (bfd *)NULL;
426 	   abfd = abfd->next)
427 	ar_directory_doer (abfd, (bfd *) NULL);
428     }
429 }
430 
431 void
ar_end(void)432 ar_end (void)
433 {
434   if (obfd)
435     {
436       bfd_cache_close (obfd);
437       unlink (bfd_get_filename (obfd));
438     }
439 }
440 
441 void
ar_extract(struct list * list)442 ar_extract (struct list *list)
443 {
444   if (!obfd)
445     {
446       fprintf (stderr, _("%s: no open archive\n"), program_name);
447       maybequit ();
448     }
449   else
450     {
451       while (list)
452 	{
453 	  /* Find this name in the archive.  */
454 	  bfd *member = obfd->archive_head;
455 	  int found = 0;
456 
457 	  while (member && !found)
458 	    {
459 	      if (FILENAME_CMP (member->filename, list->name) == 0)
460 		{
461 		  extract_file (member);
462 		  found = 1;
463 		}
464 
465 	      member = member->next;
466 	    }
467 
468 	  if (!found)
469 	    {
470 	      bfd_openr (list->name, 0);
471 	      fprintf (stderr, _("%s: can't find module file %s\n"),
472 		       program_name, list->name);
473 	    }
474 
475 	  list = list->next;
476 	}
477     }
478 }
479