home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / libtouch / part01 / libtouch.c next >
Encoding:
C/C++ Source or Header  |  1993-04-18  |  5.8 KB  |  210 lines

  1. /*
  2.  *  libtouch.c - Update just the datestamp of an archive for the files
  3.  *         requested.  It's faster than any other way of updating the
  4.  *         archive I've been able to find.
  5.  *
  6.  *  Chris Olson
  7.  *  v1.0
  8.  *  92/02/20
  9.  *
  10.  *  Copyright 1993 by Chris Olson
  11.  *
  12.  *  Permision is hereby granted to copy, distribute, or otherwise use any
  13.  *  part of this package as long as you do not try to make money from it or
  14.  *  pretend that you wrote it.  This copyright notice must be maintained in
  15.  *  any copy made.
  16.  *
  17.  *
  18.  *  Why libtouch?  It helps to shorten make times and removes the need to
  19.  *  have .o's and timestamp files lying around.     A personal pet peeve.
  20.  *  A large archive (256 objects) could have an object deleted out of it
  21.  *  in 10 secs, this gem updates the date of the file (accomplishing the
  22.  *  same thing (see makefile)) in less than 3.
  23.  *
  24.  *  A portable makefile which takes advantage of libtouch to put off the
  25.  *  archive step until just before the end:
  26.  *
  27.  *  LibFullName = lib$(LibName).a
  28.  *  LibPath = ../lib
  29.  *  LibFullPath = $(LibPath)/$(LibFullName)
  30.  *
  31.  *  .c.a:
  32.  *        $(CC) -c $(CFLAGS) $(CPPFLAGS) $<
  33.  *        libtouch $(LibFullName) $%
  34.  *
  35.  *  LibName = sample
  36.  *  .PRECIOUS: $(LibFullPath)
  37.  *
  38.  *  ALL: $(LibFullPath)
  39.  *
  40.  *  LibObjects = sample1.o sample2.o sample3.o sample4.o sample5.o\
  41.  *        sample6.o
  42.  *
  43.  *  $(LibFullPath): $(LibFullPath)(sample1.o)\
  44.  *        $(LibFullPath)(sample2.o)\
  45.  *        $(LibFullPath)(sample3.o)\
  46.  *        $(LibFullPath)(sample4.o)\
  47.  *        $(LibFullPath)(sample5.o)
  48.  *        ar ruv $@ `ls $(LibObjects) 2>/dev/null`
  49.  *        rm -f $(LibObjects)
  50.  *        ranlib $@
  51.  *
  52.  *  depend:
  53.  *      makedepend $(CFLAGS) -fGNUmakefile -- *.c
  54.  *      fixdepend -l$(UnLibFullPath) -fGNUmakefile $(LibObjects)
  55.  */
  56.  
  57. #include <stdio.h>
  58. #include <ar.h>
  59. #include <varargs.h>
  60. #include <errno.h>
  61.  
  62. extern int errno;
  63.  
  64. /*
  65.  *  Global variables used to keep track of the archive.
  66.  */
  67. static FILE *Archive;              /* Handle used to access the archive. */
  68. static char *Archive_name;          /* Name of the archive.            */
  69. static unsigned long ArchiveDate;     /* Date stamp of the archive.        */
  70. static struct ar_hdr Archive_header;  /* Archive entry header.            */
  71. static unsigned long Archive_pos;     /* Location of current header.        */
  72.  
  73. /* The max length of an archive member name (Is this defined somewhere?) */
  74. #define MAX_MEMBER_NAME 15
  75.  
  76. /*
  77.  *  Simple error handling routine.
  78.  */
  79. static void error (va_alist)
  80.    va_dcl
  81. {
  82.    char *format;  /* Format string to print from.          */
  83.    va_list ptr;      /* Used to step through the function arguments. */
  84.  
  85.    va_start(ptr);
  86.    format = va_arg(ptr, char *);
  87.    vfprintf(stderr, format, ptr);
  88.    va_end(ptr);
  89.    if (Archive)
  90.       fclose(Archive);
  91.    exit(-1);
  92. } /* error */
  93.  
  94. /*
  95.  *  Open the archive and check for integrety.
  96.  */
  97. static void open_archive (archive_name)
  98.    char *archive_name;    /* Name of the archive. */
  99. {
  100.    char magic[SARMAG];    /* Archive magic number storage. */
  101.  
  102.    if ((Archive = fopen(archive_name, "r+")) == NULL) {
  103.       if (errno == EACCES ||
  104.       errno == EISDIR ||
  105.       errno == EROFS ||
  106.       errno == ELOOP ||
  107.       errno == ENAMETOOLONG ||
  108.       errno == EPERM) {
  109.      /*
  110.       *  It is an error not to be allowed to open the archive...
  111.       */
  112.      error("Unable to open archive, permision denied.\n");
  113.       }
  114.       /*
  115.        *  It's not really an error not to find the archive...
  116.        */
  117.       fprintf(stderr, "Archive file is missing.\n");
  118.       exit(0);
  119.    }
  120.    if (fread(magic, SARMAG, 1, Archive) != 1)
  121.       error("Unable to read magic number for '%s'\n", archive_name);
  122.    if (strncmp(magic, ARMAG, SARMAG))
  123.       error("'%s' is not in archive format.\n", archive_name);
  124.    Archive_name = archive_name;
  125. } /* archive_name */
  126.  
  127. /*
  128.  *  Read in the archive record header and check it's integrety.
  129.  */
  130. static int read_header ()
  131. {
  132.    Archive_pos = ftell(Archive);
  133.    if (fread(&Archive_header, sizeof(struct ar_hdr), 1, Archive) != 1) {
  134.       fclose(Archive);
  135.       exit(0);
  136.    }
  137.    if (strncmp(Archive_header.ar_fmag, ARFMAG, 2))
  138.       error("Error in archive member format.\n");
  139. } /* read_header */
  140.  
  141. /*
  142.  *  Skip over the body of the current archive record, rememeber to make sure
  143.  *  we stay aligned on an even boundary!
  144.  */
  145. static void skip_member ()
  146. {
  147.    unsigned long size;    /* Size of the data to be skipped. */
  148.  
  149.    size = atol(Archive_header.ar_size);
  150.    size += size % 2;
  151.    fseek(Archive, size, 1);
  152. } /* skip_member */
  153.  
  154. /*
  155.  *  Update just the ar_date field of the record, and the rewrite that
  156.  *  record.
  157.  */
  158. static void touch_member ()
  159. {
  160.    char buffer[13];  /* Workspace to create new time stamp. */
  161.    
  162.    unsigned long time();
  163.    
  164.    fseek(Archive, Archive_pos, 0);
  165.    sprintf(buffer, "%ld", time(NULL));
  166.    memcpy(Archive_header.ar_date, buffer, strlen(buffer));
  167.    fwrite(&Archive_header, sizeof(struct ar_hdr), 1, Archive);
  168. } /* touch_member */
  169.  
  170. /*
  171.  *  Usage:
  172.  *    libtouch archive-name [lib-members ...]
  173.  */
  174. int main (argc, argv)
  175.    int argc;      /* Number of arguments on the command line. */
  176.    char **argv;      /* Each command line argument...          */
  177. {
  178.    int i;  /* Simple loop counter. */
  179.    
  180.    if (argc < 2)
  181.       error("Usage: %s archive-name [lib-members]\n", argv[0]);
  182.  
  183.    open_archive(argv[1]);
  184.    do {
  185.       read_header();
  186.       for (i = 2; i < argc; i++) {
  187.      /* Check only the member name length */
  188.      if (!strncmp(argv[i], Archive_header.ar_name, 
  189.         (strlen(argv[i]) <= MAX_MEMBER_NAME) ? 
  190.             strlen(argv[i]) : MAX_MEMBER_NAME)) {
  191.         /*
  192.          *    A little tricky here: touch the current header, copy the
  193.          *    last header to here, and reduce the number to search through.
  194.          *    This lets us find the correct record with a steadily
  195.          *    reducing number of comparisons, does not require any sort
  196.          *    order on any of the two lists, and only makes one pass
  197.          *    through the archive.
  198.          */
  199.         touch_member();
  200.         argv[i] = argv[argc - 1];
  201.         argc--;
  202.         break;
  203.      }
  204.       }
  205.       skip_member();
  206.    } while (argc != 2);
  207.    fclose(Archive);
  208.    return 0;
  209. } /* main */
  210.