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