home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / gnu / djgpp / src / binutils.2 / binutils / ar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-20  |  24.8 KB  |  1,018 lines

  1. /* ar.c - Archive modify and extract.
  2.    Copyright 1991, 1992 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Binutils.
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.    Bugs: should use getopt the way tar does (complete w/optional -) and
  22.    should have long options too. GNU ar used to check file against filesystem
  23.    in quick_update and replace operations (would check mtime). Doesn't warn
  24.    when name truncated. No way to specify pos_end. Error messages should be
  25.    more consistant.
  26. */
  27. #include "bfd.h"
  28. #include "sysdep.h"
  29. #include "bucomm.h"
  30. #include "aout/ar.h"
  31. #include "../bfd/libbfd.h"
  32. #include "arsup.h"
  33. #include <stdio.h>
  34. #ifdef POSIX_UTIME
  35. #include <utime.h>
  36. #else /* ! POSIX_UTIME */
  37. #ifdef    USE_UTIME
  38. #include <time.h>
  39. #else /* ! USE_UTIME */
  40. #include <sys/time.h>
  41. #endif /* ! USE_UTIME */
  42. #endif /* ! POSIX_UTIME */
  43. #include <errno.h>
  44. #ifndef errno
  45. extern int errno;
  46. #endif
  47. #define BUFSIZE 8192
  48.  
  49. /* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
  50.  
  51. struct ar_hdr *
  52. bfd_special_undocumented_glue PARAMS ((bfd *abfd, char *filename));
  53.  
  54. /* Forward declarations */
  55.  
  56. static void
  57. print_contents PARAMS ((bfd * member));
  58.  
  59. static void
  60. delete_members PARAMS ((char **files_to_delete));
  61.  
  62. static void
  63. do_quick_append PARAMS ((char *archive_filename, char **files_to_append));
  64.  
  65. static void
  66. move_members PARAMS ((char **files_to_move));
  67.  
  68. static void
  69. replace_members PARAMS ((char **files_to_replace));
  70.  
  71. static void
  72. print_descr PARAMS ((bfd * abfd));
  73.  
  74. static void
  75. ranlib_only PARAMS ((char *archname));
  76.  
  77. /** Globals and flags */
  78.  
  79. char           *program_name = NULL;
  80. bfd            *inarch;        /* The input arch we're manipulating */
  81.  
  82. int mri_mode;
  83. /* This flag distinguishes between ar and ranlib:
  84.    1 means this is 'ranlib'; 0 means this is 'ar'.
  85.    -1 means if we should use argv[0] to decide. */
  86. extern int is_ranlib;
  87. /* Nonzero means don't warn about creating the archive file if necessary.  */
  88. int             silent_create = 0;
  89. /* Nonzero means describe each action performed.  */
  90. int             verbose = 0;
  91. /* Nonzero means preserve dates of members when extracting them.  */
  92. int             preserve_dates = 0;
  93. /*
  94.    Nonzero means don't replace existing members whose dates are more recent
  95.    than the corresponding files.
  96. */
  97. int             newer_only = 0;
  98.  
  99. /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
  100.    member).  -1 means we've been explicitly asked to not write a symbol table;
  101.    +1 means we've been explictly asked to write it;
  102.    0 is the default.
  103.    Traditionally, the default in BSD has been to not write the table.
  104.    However, for Posix.2 compliance the default is now to write a symbol table
  105.    if any of the members are object files. */
  106. int write_armap = 0;
  107.  
  108. /*
  109.    Nonzero means it's the name of an existing member; position new or moved
  110.    files with respect to this one.
  111. */
  112. char           *posname = NULL;
  113. /*
  114.    Sez how to use `posname': pos_before means position before that member.
  115.    pos_after means position after that member. pos_end means always at end.
  116.    pos_default means default appropriately. For the latter two, `posname'
  117.    should also be zero.
  118. */
  119. enum pos {
  120.     pos_default, pos_before, pos_after, pos_end
  121. }               postype = pos_default;
  122.  
  123. #ifdef GNU960
  124.     char *default_target;
  125.  
  126.     void
  127.     gnu960_verify_target(abfd)
  128.     bfd *abfd;
  129.     {
  130.         if ( abfd->format == bfd_unknown ){
  131.         bfd_check_format(abfd, bfd_object);
  132.         /* Don't really care if it's an object --
  133.          * just want to get the correct xvec.
  134.          */
  135.         }
  136.         if ( !BFD_COFF_FILE_P(abfd) ){
  137.         fatal( "'%s' not a COFF file -- operation aborted",
  138.                             abfd->filename );
  139.         }
  140.     }
  141. #endif
  142.  
  143. int interactive = 0;
  144. void
  145. DEFUN_VOID(mri_emul)
  146. {
  147.   interactive = isatty(fileno(stdin)) ;
  148.   yyparse();
  149. }
  150.  
  151. /*
  152.    If count is 0, then function is called once on each entry. if nonzero,
  153.    count is the length of the files chain; function is called on each entry
  154.    whose name matches one in files
  155. */
  156. void
  157. DEFUN(map_over_members,(function, files, count),
  158.       void            (*function) () AND
  159.       char          **files AND
  160.       int             count)
  161. {
  162.   bfd            *head;
  163.  
  164.   if (count == 0) {
  165.     for (head = inarch->next; head; head = head->next)
  166.      function(head);
  167.     return;
  168.   }
  169.   /*
  170.     This may appear to be a baroque way of accomplishing what we want.
  171.     however we have to iterate over the filenames in order to notice where
  172.     a filename is requested but does not exist in the archive.  Ditto
  173.     mapping over each file each time -- we want to hack multiple
  174.     references.
  175.     */
  176.  
  177.   for (; count > 0; files++, count--) {
  178.     boolean         found = false;
  179.     for (head = inarch->next; head; head = head->next)
  180.     {
  181.       if (head->filename == NULL)
  182.       {
  183.     /* Some archive formats don't get the filenames filled in
  184.        'till the elements are opened */
  185.     struct stat buf;
  186.     bfd_stat_arch_elt(head, &buf);
  187.       }
  188.       if ((head->filename != NULL) &&
  189.       (!strcmp(*files, head->filename))) {
  190.     found = true;
  191.     function(head);
  192.       }
  193.     }
  194.     if (!found)
  195.      fprintf(stderr, "No entry %s in archive.\n", *files);
  196.   }
  197. }
  198.  
  199.  
  200. boolean operation_alters_arch = false;
  201.  
  202. extern char *program_version;
  203.  
  204. void
  205. do_show_version ()
  206. {
  207.   printf ("%s version %s\n", program_name, program_version);
  208. }
  209.  
  210. void
  211. usage ()
  212. {
  213.   if (is_ranlib == 0)
  214.     fprintf(stderr, "\
  215. Usage: %s [-]{dmpqrtx}[abcilosuvV] [member-name] archive-file file...\n\
  216.        %s -M [<mri-script]\n",
  217.         program_name, program_name);
  218.   else
  219.     fprintf(stderr, "\
  220. Usage: %s [-vV] archive\n", program_name);
  221.   exit(1);
  222. }
  223.  
  224. /*
  225.    The option parsing should be in its own function.  It will be when I have
  226.    getopt working.
  227. */
  228. int
  229. main(argc, argv)
  230.     int             argc;
  231.     char          **argv;
  232. {
  233.   char           *arg_ptr;
  234.   char            c;
  235.   enum {
  236.     none = 0, delete, replace, print_table,
  237.     print_files, extract, move, quick_append
  238.   }               operation = none;
  239.   int             arg_index;
  240.   char          **files;
  241.   char           *inarch_filename;
  242.   char           *temp;
  243.   int         show_version;
  244.  
  245.   bfd_init();
  246.   show_version = 0;
  247. #ifdef GNU960
  248.   check_v960( argc, argv );
  249.   default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
  250. #endif
  251.  
  252.   program_name = argv[0];
  253.  
  254.   temp = strrchr(program_name, '/');
  255.   if (temp == (char *) NULL)
  256.    temp = program_name;        /* shouldn't happen, but... */
  257.   else
  258.    ++temp;
  259.   if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
  260.     is_ranlib = 1;
  261.     if (argc < 2 || argc > 3)
  262.       usage ();
  263.     arg_ptr = argv[1];
  264.     if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "-v") == 0) {
  265.       do_show_version();
  266.       if (argc == 2)
  267.     exit(0);
  268.       arg_ptr = argv[2];
  269.     }
  270.     ranlib_only(arg_ptr);
  271.   }
  272.   else
  273.     is_ranlib = 0;
  274.  
  275.   if (argc == 2 && strcmp(argv[1],"-M") == 0) {
  276.     mri_emul();
  277.     exit(0);
  278.   }
  279.  
  280.   if (argc < 2)
  281.     usage ();
  282.  
  283.   arg_ptr = argv[1];
  284.  
  285.   if (*arg_ptr == '-')
  286.    ++arg_ptr;            /* compatibility */
  287.  
  288.   while (c = *arg_ptr++) {
  289.     switch (c) {
  290.      case 'd':
  291.      case 'm':
  292.      case 'p':
  293.      case 'q':
  294.      case 'r':
  295.      case 't':
  296.      case 'x':
  297.       if (operation != none)
  298.        fatal("two different operation switches specified");
  299.       switch (c) {
  300.        case 'd':
  301.     operation = delete;
  302.     operation_alters_arch = true;
  303.     break;
  304.        case 'm':
  305.     operation = move;
  306.     operation_alters_arch = true;
  307.     break;
  308.        case 'p':
  309.     operation = print_files;
  310.     break;
  311.        case 'q':
  312.     operation = quick_append;
  313.     operation_alters_arch = true;
  314.     break;
  315.        case 'r':
  316.     operation = replace;
  317.     operation_alters_arch = true;
  318.     break;
  319.        case 't':
  320.     operation = print_table;
  321.     break;
  322.        case 'x':
  323.     operation = extract;
  324.     break;
  325.       }
  326.      case 'l':
  327.       break;
  328.      case 'c':
  329.       silent_create = 1;
  330.       break;
  331.      case 'o':
  332.       preserve_dates = 1;
  333.       break;
  334.      case 'V':
  335.       show_version = true;
  336.       break;
  337.      case 's':
  338.       write_armap = 1;
  339.       break;
  340.      case 'u':
  341.       newer_only = 1;
  342.       break;
  343.      case 'v':
  344.       verbose = 1;
  345.       break;
  346.      case 'a':
  347.       postype = pos_after;
  348.       break;
  349.      case 'b':
  350.       postype = pos_before;
  351.       break;
  352.      case 'i':
  353.       postype = pos_before;
  354.       break;
  355.      case 'M':
  356.  
  357.       mri_mode = 1;
  358.       break;
  359.      default:
  360.       fatal("invalid option %c", c);
  361.     }
  362.   }
  363.  
  364.   if (show_version)
  365.      do_show_version();
  366.  
  367.   if (argc < 3)
  368.     if (show_version)
  369.        exit(0);
  370.     else
  371.       usage ();
  372.  
  373.   if (mri_mode) {
  374.     mri_emul();
  375.   }
  376.   else {
  377.     if ((operation == none || operation == print_table) 
  378.     && write_armap == 1)
  379.      ranlib_only(argv[2]);
  380.  
  381.     if (operation == none)
  382.      fatal("no operation specified");
  383.  
  384.     if (newer_only && operation != replace)
  385.      fatal("'u' only meaningful with 'r' option.");
  386.  
  387.     arg_index = 2;
  388.  
  389.     if (postype != pos_default)
  390.      posname = argv[arg_index++];
  391.  
  392.     inarch_filename = argv[arg_index++];
  393.  
  394.     files = arg_index < argc ? argv + arg_index : NULL;
  395.  
  396.     if (operation == quick_append) {
  397.       if (files != NULL)
  398.        do_quick_append(inarch_filename, files);
  399.       exit(0);
  400.     }
  401.  
  402.  
  403.     open_inarch(inarch_filename);
  404.  
  405.     switch (operation) {
  406.  
  407.      case print_table:
  408.       map_over_members(print_descr, files, argc - 3);
  409.       break;
  410.  
  411.      case print_files:
  412.       map_over_members(print_contents, files, argc - 3);
  413.       break;
  414.  
  415.      case extract:
  416.       map_over_members(extract_file, files, argc - 3);
  417.       break;
  418.  
  419.      case delete:
  420.       if (files != NULL)
  421.        delete_members(files);
  422.       break;
  423.  
  424.      case move:
  425.       if (files != NULL)
  426.        move_members(files);
  427.       break;
  428.  
  429.      case replace:
  430.       if (files != NULL || write_armap > 0)
  431.        replace_members(files);
  432.       break;
  433.  
  434.       /* Shouldn't happen! */
  435.      default:
  436.       fprintf(stderr, "Sorry; this option not implemented.\n");
  437.     }
  438.   }
  439.   return (0);
  440. }                /* main() */
  441.  
  442. static
  443. char *normalize(file)
  444. char *file;
  445. {
  446.     char *    filename = strrchr(file, '/');
  447.     if (filename != (char *)NULL) {
  448.     filename ++;
  449.     }
  450.     else {
  451.     filename = file;
  452.     }
  453.     return filename;
  454. }
  455.  
  456. int 
  457. open_inarch(archive_filename)
  458.     char           *archive_filename;
  459. {
  460.     bfd           **last_one;
  461.     bfd            *next_one;
  462.     struct stat     sbuf;
  463.     bfd_error = no_error;
  464.     if (stat(archive_filename, &sbuf) != 0) {
  465.     if (errno != ENOENT)
  466.         bfd_fatal(archive_filename);
  467.     if (!operation_alters_arch) {
  468.       fprintf (stderr, "%s: %s not found.\n", program_name,
  469.            archive_filename);
  470.       maybequit();
  471.       return 0;
  472.     }    
  473.  
  474.     /* This routine is one way to forcibly create the archive. */
  475.     do_quick_append(archive_filename, 0);
  476.     }
  477.  
  478. #ifdef GNU960
  479.     inarch = bfd_openr(archive_filename, default_target);
  480. #else
  481.     inarch = bfd_openr(archive_filename, NULL);
  482. #endif
  483.     if (inarch == NULL) {
  484.       bloser:
  485.         fprintf (stderr, "%s: ", program_name);
  486.     bfd_perror(archive_filename);
  487.     exit(1);
  488.     }
  489.  
  490.     if (bfd_check_format(inarch, bfd_archive) != true)
  491.     fatal("File %s is not an archive.", archive_filename);
  492. #ifdef GNU960
  493.     gnu960_verify_target(inarch);    /* Exits on failure */
  494. #endif
  495.     last_one = &(inarch->next);
  496.     /* Read all the contents right away, regardless. */
  497.     for (next_one = bfd_openr_next_archived_file(inarch, NULL);
  498.      next_one;
  499.      next_one = bfd_openr_next_archived_file(inarch, next_one)) {
  500.     *last_one = next_one;
  501.     last_one = &next_one->next;
  502.     }
  503.     *last_one = (bfd *) NULL;
  504.     if (bfd_error != no_more_archived_files)
  505.     goto bloser;
  506.     return 1;
  507. }
  508.  
  509.  
  510.  
  511.  
  512.  
  513. static void
  514. print_contents(abfd)
  515.     bfd            *abfd;
  516. {
  517.     int             ncopied = 0;
  518.     struct stat     buf;
  519.     long            size;
  520.     if (bfd_stat_arch_elt(abfd, &buf) != 0)
  521.     fatal("Internal stat error on %s", abfd->filename);
  522.  
  523.     if (verbose)
  524.     printf("\n<member %s>\n\n", abfd->filename);
  525.  
  526.     bfd_seek(abfd, 0, SEEK_SET);
  527.  
  528.     size = buf.st_size;
  529.     while (ncopied < size) {
  530.     char            cbuf[BUFSIZE];
  531.     int             nread;
  532.     int             tocopy = size - ncopied;
  533.     if (tocopy > BUFSIZE)
  534.         tocopy = BUFSIZE;
  535.  
  536.     nread = bfd_read(cbuf, 1, tocopy, abfd);    /* oops -- broke
  537.                                abstraction!  */
  538.  
  539.     if (nread != tocopy)
  540.         fatal("file %s not a valid archive", abfd->my_archive->filename);
  541.     fwrite(cbuf, 1, nread, stdout);
  542.     ncopied += tocopy;
  543.     }
  544. }
  545.  
  546.  
  547. /*
  548.    Extract a member of the archive into its own file.
  549.  
  550. We defer opening the new file until after we have read a BUFSIZ chunk of the
  551.    old one, since we know we have just read the archive header for the old
  552.    one.  Since most members are shorter than BUFSIZ, this means we will read
  553.    the old header, read the old data, write a new inode for the new file, and
  554.    write the new data, and be done. This 'optimization' is what comes from
  555.    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
  556.    Gilmore
  557. */
  558.  
  559. void
  560. extract_file(abfd)
  561.     bfd            *abfd;
  562. {
  563.     FILE           *ostream;
  564.     char            cbuf[BUFSIZE];
  565.     int             nread,
  566.                     tocopy;
  567.     int             ncopied = 0;
  568.     long            size;
  569.     struct stat     buf;
  570.     if (bfd_stat_arch_elt(abfd, &buf) != 0)
  571.     fatal("Internal stat error on %s", abfd->filename);
  572.     size = buf.st_size;
  573.  
  574.     if (verbose)
  575.     printf("x - %s\n", abfd->filename);
  576.  
  577.     bfd_seek(abfd, 0, SEEK_SET);
  578.  
  579.     ostream = 0;
  580.     if (size == 0) {
  581.       /* Seems like an abstraction violation, eh?  Well it's OK! */
  582.       ostream = fopen(abfd->filename, FOPEN_WB);
  583.       if (!ostream) {
  584.     perror(abfd->filename);
  585.     exit(1);
  586.       }
  587.     } else
  588.     while (ncopied < size) {
  589.     tocopy = size - ncopied;
  590.     if (tocopy > BUFSIZE)
  591.         tocopy = BUFSIZE;
  592.  
  593.     nread = bfd_read(cbuf, 1, tocopy, abfd);
  594.     if (nread != tocopy)
  595.         fatal("file %s not a valid archive", abfd->my_archive->filename);
  596.  
  597.     /* See comment above; this saves disk arm motion */
  598.     if (!ostream) {
  599.         /* Seems like an abstraction violation, eh?  Well it's OK! */
  600.         ostream = fopen(abfd->filename, FOPEN_WB);
  601.         if (!ostream) {
  602.         perror(abfd->filename);
  603.         exit(1);
  604.         }
  605.     }
  606.     fwrite(cbuf, 1, nread, ostream);
  607.     ncopied += tocopy;
  608.     }
  609.  
  610.     fclose(ostream);
  611.     chmod(abfd->filename, buf.st_mode);
  612.  
  613.     if (preserve_dates) {
  614. #ifdef POSIX_UTIME
  615.         struct utimbuf    tb;
  616.     tb.actime = buf.st_mtime;
  617.     tb.modtime = buf.st_mtime;
  618.     utime(abfd->filename, &tb);    /* FIXME check result */
  619. #else /* ! POSIX_UTIME */
  620. #ifdef USE_UTIME
  621.     long            tb[2];
  622.     tb[0] = buf.st_mtime;
  623.     tb[1] = buf.st_mtime;
  624.     utime(abfd->filename, tb);    /* FIXME check result */
  625. #else /* ! USE_UTIME */
  626.     struct timeval  tv[2];
  627.     tv[0].tv_sec = buf.st_mtime;
  628.     tv[0].tv_usec = 0;
  629.     tv[1].tv_sec = buf.st_mtime;
  630.     tv[1].tv_usec = 0;
  631.     utimes(abfd->filename, tv);    /* FIXME check result */
  632. #endif /* ! USE_UTIME */
  633. #endif /* ! POSIX_UTIME */
  634.     }
  635. }
  636.  
  637.  
  638. /* Just do it quickly; don't worry about dups, armap, or anything like that */
  639.  
  640. static void
  641. do_quick_append(archive_filename, files_to_append)
  642.     char           *archive_filename;
  643.     char          **files_to_append;
  644.  
  645. {
  646.     FILE           *ofile,
  647.                    *ifile;
  648.     char            buf[BUFSIZE];
  649.     long            tocopy,
  650.                     thistime;
  651.     bfd            *temp;
  652.     struct stat     sbuf;
  653.     boolean         newfile = false;
  654.     bfd_error = no_error;
  655.  
  656.     if (stat(archive_filename, &sbuf) != 0) {
  657.     if (errno != ENOENT)
  658.         bfd_fatal(archive_filename);
  659.     newfile = true;
  660.     }
  661.  
  662.  
  663.     ofile = fopen(archive_filename, FOPEN_AUB);
  664.     if (ofile == NULL) {
  665.     perror(program_name);
  666.     exit(1);
  667.     }
  668.  
  669.     /* bletch */
  670. #ifdef GNU960
  671.     temp = bfd_openr(archive_filename, default_target);
  672. #else
  673.     temp = bfd_openr(archive_filename, NULL);
  674. #endif
  675.     if (temp == NULL) {
  676.         fprintf (stderr, "%s: ", program_name);
  677.     bfd_perror(archive_filename);
  678.     exit(1);
  679.     }
  680.     if (newfile == false) {
  681.     if (bfd_check_format(temp, bfd_archive) != true)
  682.         fatal("File %s is not an archive.", archive_filename);
  683. #ifdef GNU960
  684.     gnu960_verify_target(temp);    /* Exits on failure */
  685. #endif
  686.     }
  687.     else {
  688.     fwrite(ARMAG, 1, SARMAG, ofile);
  689.     if (!silent_create)
  690.         fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
  691.     }
  692.  
  693.     /* assume it's an achive, go straight to the end, sans $200 */
  694.     fseek(ofile, 0, 2);
  695.  
  696.     for (; files_to_append && *files_to_append; ++files_to_append) {
  697.     struct ar_hdr  *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
  698.     if (hdr == NULL) {
  699.         fprintf (stderr, "%s: ", program_name);
  700.         bfd_perror(*files_to_append);
  701.         exit(1);
  702.     }
  703.  
  704.     BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
  705.  
  706.     ifile = fopen(*files_to_append, FOPEN_RB);
  707.     if (ifile == NULL)
  708.       {
  709.         bfd_perror(program_name);
  710.       }
  711.  
  712.     if (stat(*files_to_append, &sbuf) != 0)
  713.       {
  714.         fprintf (stderr, "%s: ", program_name);
  715.         bfd_perror(*files_to_append);
  716.       }
  717.  
  718.     tocopy = sbuf.st_size;
  719.  
  720.     /* XXX should do error-checking! */
  721.     fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
  722.  
  723.  
  724.     while (tocopy > 0) {
  725.         thistime = tocopy;
  726.         if (thistime > BUFSIZE)
  727.         thistime = BUFSIZE;
  728.         fread(buf, 1, thistime, ifile);
  729.         fwrite(buf, 1, thistime, ofile);
  730.         tocopy -= thistime;
  731.     }
  732.     fclose(ifile);
  733.     if ((sbuf.st_size % 2) == 1)
  734.         putc('\n', ofile);
  735.     }
  736.     fclose(ofile);
  737.     bfd_close(temp);
  738. }
  739.  
  740.  
  741. void
  742. write_archive()
  743. {
  744.     bfd            *obfd;
  745.     int             namelen = strlen(inarch->filename);
  746.     char           *new_name = xmalloc(namelen + 6);
  747.     bfd            *contents_head = inarch->next;
  748.  
  749.     strcpy(new_name, inarch->filename);
  750.     strcpy(new_name + namelen, "-art");
  751.     obfd = bfd_openw(new_name,
  752.          /* FIXME: violates abstraction; need a better protocol */
  753.              (inarch->xvec ? bfd_get_target(inarch) : NULL));
  754.  
  755.     if (obfd == NULL)
  756.         bfd_fatal(inarch->filename);
  757.  
  758.     bfd_set_format(obfd, bfd_archive);
  759.  
  760.     /* Request writing the archive symbol table unless we've
  761.        been explicitly requested not to. */
  762.     obfd->has_armap = write_armap >= 0;
  763.  
  764.     if (bfd_set_archive_head(obfd, contents_head) != true)
  765.         bfd_fatal(inarch->filename);
  766.  
  767.     if (!bfd_close(obfd))
  768.         bfd_fatal(inarch->filename);
  769.  
  770.     /* We don't care if this fails, we might be creating the
  771.        archive */
  772.     (void) unlink(inarch->filename);
  773.  
  774.     if (rename(new_name, inarch->filename) != 0)
  775.         bfd_fatal(inarch->filename);
  776. }
  777.  
  778.  
  779.  
  780. /*
  781.    returns a pointer to the pointer to the entry which should be rplacd'd
  782.    into when altering.  default_pos should be how to interpret pos_default,
  783.    and should be a pos value.
  784. */
  785.  
  786. bfd **
  787. get_pos_bfd(contents, default_pos)
  788.     bfd           **contents;
  789.     enum pos        default_pos;
  790. {
  791.     bfd           **after_bfd = contents;
  792.     enum pos        realpos = (postype == pos_default ? default_pos : postype);
  793.  
  794.     if (realpos == pos_end) {
  795.     while (*after_bfd)
  796.         after_bfd = &((*after_bfd)->next);
  797.     }
  798.     else {
  799.     for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
  800.         if (!strcmp((*after_bfd)->filename, posname)) {
  801.         if (realpos == pos_after)
  802.             after_bfd = &(*after_bfd)->next;
  803.         break;
  804.     }
  805.     }
  806.     return after_bfd;
  807. }
  808.  
  809.  
  810. static void
  811. delete_members(files_to_delete)
  812.     char          **files_to_delete;
  813. {
  814.     bfd           **current_ptr_ptr;
  815.     boolean         found;
  816.     boolean         something_changed = false;
  817.     for (; *files_to_delete != NULL; ++files_to_delete) {
  818.     /*
  819.        In a.out systems, the armap is optional.  It's also called
  820.        __.SYMDEF.  So if the user asked to delete it, we should remember
  821.        that fact. This isn't quite right for COFF systems (where
  822.        __.SYMDEF might be regular member), but it's very unlikely
  823.        to be a problem.  FIXME */
  824.  
  825.     if (!strcmp(*files_to_delete, "__.SYMDEF")) {
  826.         inarch->has_armap = false;
  827.         write_armap = -1;
  828.         continue;
  829.     }
  830.  
  831.     found = false;
  832.     current_ptr_ptr = &(inarch->next);
  833.     while (*current_ptr_ptr) {
  834.         if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
  835.         found = true;
  836.         something_changed = true;
  837.         if (verbose)
  838.             printf("d - %s\n",
  839.                *files_to_delete);
  840.         *current_ptr_ptr = ((*current_ptr_ptr)->next);
  841.         goto next_file;
  842.  
  843.         }
  844.         else {
  845.         current_ptr_ptr = &((*current_ptr_ptr)->next);
  846.         }
  847.     }
  848.  
  849.     if (verbose && found == false) {
  850.         printf("No member named `%s'\n", *files_to_delete);
  851.     }
  852. next_file:;
  853.  
  854.     }
  855.  
  856.     if (something_changed == true) {
  857.     write_archive();
  858.     }
  859. }
  860.  
  861.  
  862. /* Reposition existing members within an archive */
  863.  
  864. static void
  865. move_members(files_to_move)
  866.     char          **files_to_move;
  867. {
  868.     bfd           **after_bfd;    /* New entries go after this one */
  869.     bfd           **current_ptr_ptr;    /* cdr pointer into contents */
  870.  
  871.  
  872.  
  873.  
  874.     for (; *files_to_move; ++files_to_move) {
  875.     current_ptr_ptr = &(inarch->next);
  876.     while (*current_ptr_ptr) {
  877.         bfd            *current_ptr = *current_ptr_ptr;
  878.         if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
  879.         /*
  880.            Move this file to the end of the list - first cut from
  881.            where it is.
  882.         */
  883.         *current_ptr_ptr = current_ptr->next;
  884.  
  885.         /* Now glue to end */
  886.         after_bfd = get_pos_bfd(&inarch->next, pos_end);
  887.         *after_bfd = current_ptr;
  888.         current_ptr->next = (bfd *) NULL;
  889.  
  890.         if (verbose)
  891.             printf("m - %s\n", *files_to_move);
  892.  
  893.         goto next_file;
  894.         }
  895.         current_ptr_ptr = &((*current_ptr_ptr)->next);
  896.     }
  897.     fprintf(stderr, "No entry %s in archive %s!\n",
  898.         *files_to_move, inarch->filename);
  899.     exit(1);
  900. next_file:;
  901.     }
  902.  
  903.     write_archive();
  904. }
  905.  
  906.  
  907. /* Ought to default to replacing in place, but this is existing practice! */
  908.  
  909. static void
  910. replace_members(files_to_move)
  911.     char          **files_to_move;
  912. {
  913.     bfd           **after_bfd;    /* New entries go after this one */
  914.     bfd            *current;
  915.     bfd           **current_ptr;
  916.     bfd            *temp;
  917.  
  918.     while (files_to_move && *files_to_move) {
  919.     current_ptr = &inarch->next;
  920.     while (*current_ptr) {
  921.         current = *current_ptr;
  922.         
  923.         if (!strcmp(normalize(*files_to_move), current->filename)) {
  924.         if (newer_only) {
  925.             struct stat     fsbuf,
  926.                             asbuf;
  927.  
  928.             if (current->arelt_data == NULL) {
  929.               /* This can only happen if you specify a file on the
  930.              command line more than once. */
  931.               fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
  932.               goto next_file;
  933.             }
  934.  
  935.             if (stat(*files_to_move, &fsbuf) != 0) {
  936.             if (errno != ENOENT)
  937.                 bfd_fatal(*files_to_move);
  938.             goto next_file;
  939.             }
  940.             if (bfd_stat_arch_elt(current, &asbuf) != 0)
  941.             fatal("Internal stat error on %s", current->filename);
  942.  
  943.             if (fsbuf.st_mtime <= asbuf.st_mtime)
  944.             goto next_file;
  945.         }
  946.  
  947.         /* snip out this entry from the chain */
  948.         *current_ptr = current->next;
  949.  
  950.         after_bfd = get_pos_bfd(&inarch->next, pos_end);
  951.         temp = *after_bfd;
  952.         *after_bfd = bfd_openr(*files_to_move, NULL);
  953.         if (*after_bfd == (bfd *) NULL) {
  954.             fprintf(stderr, "Can't open file %s\n", *files_to_move);
  955.             exit(1);
  956.         }
  957. #ifdef GNU960
  958.         gnu960_verify_target(*after_bfd);    /* Exits on failure */
  959. #endif
  960.         (*after_bfd)->next = temp;
  961.  
  962.         if (verbose) {
  963.             printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
  964.                *files_to_move);
  965.         }
  966.         goto next_file;
  967.         }
  968.         current_ptr = &(current->next);
  969.     }
  970.  
  971.     /* It isn't in there, so add to end */
  972.  
  973.     after_bfd = get_pos_bfd(&inarch->next, pos_end);
  974.     temp = *after_bfd;
  975.     *after_bfd = bfd_openr(*files_to_move, NULL);
  976.     if (*after_bfd == (bfd *) NULL) {
  977.         fprintf(stderr, "Can't open file %s\n", *files_to_move);
  978.         exit(1);
  979.     }
  980. #ifdef GNU960
  981.     gnu960_verify_target(*after_bfd);    /* Exits on failure */
  982. #endif
  983.     if (verbose) {
  984.         printf("c - %s\n", *files_to_move);
  985.     }
  986.  
  987.     (*after_bfd)->next = temp;
  988.  
  989. next_file:;
  990.  
  991.     files_to_move++;
  992.     }
  993.  
  994.  
  995.     write_archive();
  996. }
  997.  
  998. static void
  999. ranlib_only(archname)
  1000.     char           *archname;
  1001. {
  1002.     write_armap = 1;
  1003.     open_inarch(archname);
  1004.     write_archive();
  1005.     exit(0);
  1006. }
  1007.  
  1008.  
  1009.  
  1010. /* Things which are interesting to map over all or some of the files: */
  1011.  
  1012. static void
  1013. print_descr(abfd)
  1014.     bfd            *abfd;
  1015. {
  1016.     print_arelt_descr(stdout,abfd, verbose);
  1017. }
  1018.