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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 bfd *obfd;
42 static char *real_name;
43 static FILE *outfile;
44 
45 static void
map_over_list(bfd * arch,void (* function)(bfd *,bfd *),struct list * list)46 map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
47 {
48   bfd *head;
49 
50   if (list == NULL)
51     {
52       bfd *next;
53 
54       head = arch->next;
55       while (head != NULL)
56 	{
57 	  next = head->next;
58 	  function (head, (bfd *) NULL);
59 	  head = next;
60 	}
61     }
62   else
63     {
64       struct list *ptr;
65 
66       /* This may appear to be a baroque way of accomplishing what we
67 	 want.  however we have to iterate over the filenames in order
68 	 to notice where a filename is requested but does not exist in
69 	 the archive.  Ditto mapping over each file each time -- we
70 	 want to hack multiple references.  */
71       for (ptr = list; ptr; ptr = ptr->next)
72 	{
73 	  bfd_boolean found = FALSE;
74 	  bfd *prev = arch;
75 
76 	  for (head = arch->next; head; head = head->next)
77 	    {
78 	      if (head->filename != NULL
79 		  && FILENAME_CMP (ptr->name, head->filename) == 0)
80 		{
81 		  found = TRUE;
82 		  function (head, prev);
83 		}
84 	      prev = head;
85 	    }
86 	  if (! found)
87 	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
88 	}
89     }
90 }
91 
92 
93 
94 static void
ar_directory_doer(bfd * abfd,bfd * ignore ATTRIBUTE_UNUSED)95 ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
96 {
97   print_arelt_descr(outfile, abfd, verbose);
98 }
99 
100 void
ar_directory(char * ar_name,struct list * list,char * output)101 ar_directory (char *ar_name, struct list *list, char *output)
102 {
103   bfd *arch;
104 
105   arch = open_inarch (ar_name, (char *) NULL);
106   if (output)
107     {
108       outfile = fopen(output,"w");
109       if (outfile == 0)
110 	{
111 	  outfile = stdout;
112 	  fprintf (stderr,_("Can't open file %s\n"), output);
113 	  output = 0;
114 	}
115     }
116   else
117     outfile = stdout;
118 
119   map_over_list (arch, ar_directory_doer, list);
120 
121   bfd_close (arch);
122 
123   if (output)
124    fclose (outfile);
125 }
126 
127 void
prompt(void)128 prompt (void)
129 {
130   extern int interactive;
131 
132   if (interactive)
133     {
134       printf ("AR >");
135       fflush (stdout);
136     }
137 }
138 
139 void
maybequit(void)140 maybequit (void)
141 {
142   if (! interactive)
143     xexit (9);
144 }
145 
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