home *** CD-ROM | disk | FTP | other *** search
- /*
- * libtouch.c - Update just the datestamp of an archive for the files
- * requested. It's faster than any other way of updating the
- * archive I've been able to find.
- *
- * Chris Olson
- * v1.0
- * 92/02/20
- *
- * Copyright 1993 by Chris Olson
- *
- * Permision is hereby granted to copy, distribute, or otherwise use any
- * part of this package as long as you do not try to make money from it or
- * pretend that you wrote it. This copyright notice must be maintained in
- * any copy made.
- *
- *
- * Why libtouch? It helps to shorten make times and removes the need to
- * have .o's and timestamp files lying around. A personal pet peeve.
- * A large archive (256 objects) could have an object deleted out of it
- * in 10 secs, this gem updates the date of the file (accomplishing the
- * same thing (see makefile)) in less than 3.
- *
- * A portable makefile which takes advantage of libtouch to put off the
- * archive step until just before the end:
- *
- * LibFullName = lib$(LibName).a
- * LibPath = ../lib
- * LibFullPath = $(LibPath)/$(LibFullName)
- *
- * .c.a:
- * $(CC) -c $(CFLAGS) $(CPPFLAGS) $<
- * libtouch $(LibFullName) $%
- *
- * LibName = sample
- * .PRECIOUS: $(LibFullPath)
- *
- * ALL: $(LibFullPath)
- *
- * LibObjects = sample1.o sample2.o sample3.o sample4.o sample5.o\
- * sample6.o
- *
- * $(LibFullPath): $(LibFullPath)(sample1.o)\
- * $(LibFullPath)(sample2.o)\
- * $(LibFullPath)(sample3.o)\
- * $(LibFullPath)(sample4.o)\
- * $(LibFullPath)(sample5.o)
- * ar ruv $@ `ls $(LibObjects) 2>/dev/null`
- * rm -f $(LibObjects)
- * ranlib $@
- *
- * depend:
- * makedepend $(CFLAGS) -fGNUmakefile -- *.c
- * fixdepend -l$(UnLibFullPath) -fGNUmakefile $(LibObjects)
- */
-
- #include <stdio.h>
- #include <ar.h>
- #include <varargs.h>
- #include <errno.h>
-
- extern int errno;
-
- /*
- * Global variables used to keep track of the archive.
- */
- static FILE *Archive; /* Handle used to access the archive. */
- static char *Archive_name; /* Name of the archive. */
- static unsigned long ArchiveDate; /* Date stamp of the archive. */
- static struct ar_hdr Archive_header; /* Archive entry header. */
- static unsigned long Archive_pos; /* Location of current header. */
-
- /* The max length of an archive member name (Is this defined somewhere?) */
- #define MAX_MEMBER_NAME 15
-
- /*
- * Simple error handling routine.
- */
- static void error (va_alist)
- va_dcl
- {
- char *format; /* Format string to print from. */
- va_list ptr; /* Used to step through the function arguments. */
-
- va_start(ptr);
- format = va_arg(ptr, char *);
- vfprintf(stderr, format, ptr);
- va_end(ptr);
- if (Archive)
- fclose(Archive);
- exit(-1);
- } /* error */
-
- /*
- * Open the archive and check for integrety.
- */
- static void open_archive (archive_name)
- char *archive_name; /* Name of the archive. */
- {
- char magic[SARMAG]; /* Archive magic number storage. */
-
- if ((Archive = fopen(archive_name, "r+")) == NULL) {
- if (errno == EACCES ||
- errno == EISDIR ||
- errno == EROFS ||
- errno == ELOOP ||
- errno == ENAMETOOLONG ||
- errno == EPERM) {
- /*
- * It is an error not to be allowed to open the archive...
- */
- error("Unable to open archive, permision denied.\n");
- }
- /*
- * It's not really an error not to find the archive...
- */
- fprintf(stderr, "Archive file is missing.\n");
- exit(0);
- }
- if (fread(magic, SARMAG, 1, Archive) != 1)
- error("Unable to read magic number for '%s'\n", archive_name);
- if (strncmp(magic, ARMAG, SARMAG))
- error("'%s' is not in archive format.\n", archive_name);
- Archive_name = archive_name;
- } /* archive_name */
-
- /*
- * Read in the archive record header and check it's integrety.
- */
- static int read_header ()
- {
- Archive_pos = ftell(Archive);
- if (fread(&Archive_header, sizeof(struct ar_hdr), 1, Archive) != 1) {
- fclose(Archive);
- exit(0);
- }
- if (strncmp(Archive_header.ar_fmag, ARFMAG, 2))
- error("Error in archive member format.\n");
- } /* read_header */
-
- /*
- * Skip over the body of the current archive record, rememeber to make sure
- * we stay aligned on an even boundary!
- */
- static void skip_member ()
- {
- unsigned long size; /* Size of the data to be skipped. */
-
- size = atol(Archive_header.ar_size);
- size += size % 2;
- fseek(Archive, size, 1);
- } /* skip_member */
-
- /*
- * Update just the ar_date field of the record, and the rewrite that
- * record.
- */
- static void touch_member ()
- {
- char buffer[13]; /* Workspace to create new time stamp. */
-
- unsigned long time();
-
- fseek(Archive, Archive_pos, 0);
- sprintf(buffer, "%ld", time(NULL));
- memcpy(Archive_header.ar_date, buffer, strlen(buffer));
- fwrite(&Archive_header, sizeof(struct ar_hdr), 1, Archive);
- } /* touch_member */
-
- /*
- * Usage:
- * libtouch archive-name [lib-members ...]
- */
- int main (argc, argv)
- int argc; /* Number of arguments on the command line. */
- char **argv; /* Each command line argument... */
- {
- int i; /* Simple loop counter. */
-
- if (argc < 2)
- error("Usage: %s archive-name [lib-members]\n", argv[0]);
-
- open_archive(argv[1]);
- do {
- read_header();
- for (i = 2; i < argc; i++) {
- /* Check only the member name length */
- if (!strncmp(argv[i], Archive_header.ar_name,
- (strlen(argv[i]) <= MAX_MEMBER_NAME) ?
- strlen(argv[i]) : MAX_MEMBER_NAME)) {
- /*
- * A little tricky here: touch the current header, copy the
- * last header to here, and reduce the number to search through.
- * This lets us find the correct record with a steadily
- * reducing number of comparisons, does not require any sort
- * order on any of the two lists, and only makes one pass
- * through the archive.
- */
- touch_member();
- argv[i] = argv[argc - 1];
- argc--;
- break;
- }
- }
- skip_member();
- } while (argc != 2);
- fclose(Archive);
- return 0;
- } /* main */
-