home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / DMAKE38C.ZIP / TOS / ARLIB.C next >
C/C++ Source or Header  |  1992-01-23  |  13KB  |  505 lines

  1. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/tos/arlib.c,v 1.1 1992/01/24 03:27:09 dvadura Exp $
  2. -- SYNOPSIS -- Unix archive manipulation code.
  3. -- 
  4. -- DESCRIPTION
  5. --     Originally this code was provided by Eric Gisin of MKS.  I took
  6. --    his code and completely rewrote it adding cacheing of lib members
  7. --    and other various optimizations.  I kept the overal functional
  8. --    idea of the library routines as they are similar to those in GNU
  9. --    make and felt it advantageous to maintain a similar interface.
  10. --
  11. -- AUTHOR
  12. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  13. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  14. --
  15. -- COPYRIGHT
  16. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  17. -- 
  18. --      This program is free software; you can redistribute it and/or
  19. --      modify it under the terms of the GNU General Public License
  20. --      (version 1), as published by the Free Software Foundation, and
  21. --      found in the file 'LICENSE' included with this distribution.
  22. -- 
  23. --      This program is distributed in the hope that it will be useful,
  24. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  25. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26. --      GNU General Public License for more details.
  27. -- 
  28. --      You should have received a copy of the GNU General Public License
  29. --      along with this program;  if not, write to the Free Software
  30. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  31. --
  32. -- LOG
  33. --     $Log: arlib.c,v $
  34.  * Revision 1.1  1992/01/24  03:27:09  dvadura
  35.  * dmake Version 3.8, Initial revision
  36.  *
  37. */
  38.  
  39. #include <ar.h>
  40. #include "extern.h"
  41. #include "sysintf.h"
  42.  
  43. /* By defining the defines below it is possible to configure the library
  44.  * code for library cacheing/non-cacheing, ASCII archive headers, and a full
  45.  * decode of the ar_hdr fields in the scan_ar function. */
  46.  
  47. #define ASCARCH            1    /* ASCII time stored in archive    */
  48. #define LC            1    /* Turn on library cacheing    */
  49. #define DECODE_ALL_AR_FIELDS    0    /* decode only fields make needs*/
  50.  
  51. #if LC
  52. #  define FOUND_MEMBER    FALSE
  53. #else
  54. #  define FOUND_MEMBER    TRUE
  55. #  define _cache_member(a, b, c)
  56. #  define _check_cache(a, b, c, d)    FALSE
  57. #endif
  58.  
  59. #define    MAXFNAME    32    /* Longest file name in archive    */
  60. #define    MAXMNAME    8    /* Max module name < MAXFNAME    */
  61.  
  62.  
  63. /* This struct is used to pass the library and member information about the
  64.  * routines that perform the library seeking/cacheing */
  65. struct ar_args {
  66.    char   *lib;
  67.    char   *member;
  68.    time_t time;
  69. };
  70.  
  71.  
  72. typedef struct AR {
  73.    char    ar_name[MAXFNAME+1];      /* File name */
  74.    long    ar_size;                  /* Size in bytes */
  75.    time_t  ar_time;                  /* Modification time */
  76.  
  77. #ifdef DOS
  78.    char    ar_modname[MAXMNAME+1];   /* DOS module name */
  79. #endif
  80.  
  81. #if DECODE_ALL_AR_FIELDS
  82.    uint16  ar_mode;                  /* File mode */
  83.    uint16  ar_uid;                     /* File owner */
  84.    uint16  ar_gid;                   /* File group owner */
  85. #endif
  86. } AR, *ARPTR;
  87.  
  88.  
  89. static int ar_scan  ANSI((FILE *,
  90.               int (*) ANSI((FILE *, struct AR *, struct ar_args *)),
  91.               struct ar_args *));
  92. static int ar_touch ANSI(( FILE *, time_t ));
  93. static int time_function  ANSI(( FILE *, struct AR *, struct ar_args * ));
  94. static int touch_function ANSI(( FILE *, struct AR *, struct ar_args * ));
  95.  
  96. #if LC
  97. static int _cache_member ANSI((char *, char *, time_t));
  98. static int _check_cache  ANSI((char *, char *, time_t *, int));
  99. #endif
  100.  
  101. /* decoded archive header */
  102. static AR _ar;
  103.  
  104.  
  105. PUBLIC time_t
  106. seek_arch(name, lib)/*
  107. ======================
  108.    Look for module 'name' inside 'lib'.  If compiled with cacheing then first
  109.    check to see if the specified lib is cached.  If so then return that time
  110.    stamp instead of looking into the library. */
  111. char    *name;
  112. char     *lib;
  113. {
  114.    FILE   *f;
  115.    int    rv;
  116.    time_t mtime;
  117.    struct ar_args args;
  118.  
  119.    /* Check the cache first (if there is a cache) */
  120.    if( _check_cache(name, lib, &mtime, FALSE) )  return( mtime );
  121.  
  122.    /* Open the lib file and perform the scan of the members, looking
  123.     * for our particular member.  If cacheing is enabled it will be
  124.     * taken care of automatically during the scan. */
  125.  
  126.    args.lib    = lib;
  127.    args.member = name;
  128.    args.time   = (time_t)0L;
  129.  
  130.    if( (f = fopen(lib, "rb")) == NIL(FILE) ) return( (time_t)0L );
  131.    rv = ar_scan(f, time_function, &args );
  132.    fclose( f );
  133.  
  134.    if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
  135.  
  136.    return( args.time );
  137. }
  138.  
  139.  
  140. PUBLIC int
  141. touch_arch(name, lib)/*
  142. =======================
  143.    Look for module 'name' inside 'lib'.  If compiled with cacheing then first
  144.    check to see if the specified lib is cached.  If so then set that time
  145.    stamp and write it into the library.  Returns 0 on success, non-zero
  146.    on failure. */
  147. char   *name;
  148. char   *lib;
  149. {
  150.    FILE   *f;
  151.    int    rv;
  152.    struct ar_args args;
  153.  
  154.    /* Open the lib file and perform the scan of the members, looking
  155.     * for our particular member.  If cacheing is enabled it will be
  156.     * taken care of automatically during the scan. */
  157.  
  158.    args.lib    = lib;
  159.    args.member = name;
  160.    args.time   = (time_t)0L;
  161.  
  162.    if( (f = fopen(lib, "rb+")) == NIL(FILE) ) return( (time_t)1L );
  163.    rv = ar_scan(f, touch_function, &args );
  164.    fclose( f );
  165.  
  166.    if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
  167.  
  168.    return( 0 );
  169. }
  170.  
  171.  
  172.  
  173. static int
  174. time_function(f, arp, argp)/*
  175. =============================
  176.    get library member's time, if it matches than return it in argp, if
  177.    cacheing is enabled than cache the library members also. */
  178. FILE           *f;      /* library file          */
  179. struct AR      *arp;    /* library member header */
  180. struct ar_args *argp;
  181. {
  182.    int rv = _cache_member( arp->ar_name, argp->lib, arp->ar_time );
  183.  
  184.    if( strcmp(argp->member, arp->ar_name) == 0 ) {
  185.       argp->time = arp->ar_time;
  186.  
  187.       if( arp->ar_time == 0 && !(Glob_attr & A_SILENT) )
  188.          Warning( "(%s): Can't extract library member timestamp; using EPOCH",
  189.               argp->member);
  190.  
  191.       return( rv );  /* 1 => no cacheing, 0 => cacheing */
  192.    }
  193.  
  194.    return( FALSE ); /* continue scan */
  195. }
  196.  
  197.  
  198.  
  199. static int
  200. touch_function(f, arp, argp)/*
  201. ==============================
  202.    Update library member's time stamp, and write new time value into cache
  203.    if required. */
  204. FILE           *f;      /* library file */
  205. struct AR      *arp;    /* library member header */
  206. struct ar_args *argp;
  207. {
  208.    extern time_t time ANSI(( time_t * ));
  209.    time_t now = time((time_t*) NULL);  /* Current time.          */
  210.  
  211.    if( strcmp(argp->member, arp->ar_name) == 0 ) {
  212.       _check_cache( argp->member, argp->lib, &now, TRUE );
  213.       ar_touch(f, now );
  214.  
  215.       return( TRUE );
  216.    }
  217.  
  218.    return( FALSE ); /* continue scan */
  219. }
  220.  
  221.  
  222.  
  223.  
  224. static int
  225. ar_scan(f, function, arg)/*
  226. ===========================
  227.    Scan the opened archive, and call the given function for each member found.
  228.    The function will be called with the file positioned at the beginning of
  229.    the member and it can read up to arp->ar_size bytes of the archive member.
  230.    If the function returns 1, we stop and return 1.  We return 0 at the end
  231.    of the archive, or -1 if the archive has invalid format.  This interface
  232.    is more general than required by "make", but it can be used by other
  233.    utilities.  */
  234. register FILE *f;
  235. int      (*function) ANSI((FILE *, struct AR *, struct ar_args *));
  236. struct ar_args *arg;
  237. {
  238.    extern long atol ANSI((char *));
  239.    register char *p;
  240.    struct ar_hdr arhdr;   /* external archive header */
  241.    off_t         offset;  /* member seek offset      */
  242.  
  243. #if ASCARCH
  244.    char magic[SARMAG];
  245. #else
  246.    unsigned short word;
  247. #endif
  248.  
  249.    fseek( f, 0L, 0 );    /* Start at the beginning of the archive file */
  250.  
  251. #if ASCARCH
  252.    fread( magic, sizeof(magic), 1, f );
  253.    if( strncmp(magic, ARMAG, SARMAG) != 0 ) return( -1 );
  254. #else
  255.    fread( (char*)&word, sizeof(word), 1, f );
  256.    if( word != ARMAG ) return( -1 );
  257. #endif
  258.  
  259.    /* scan the library, calling `function' for each member
  260.     */
  261.    while( 1 ) {
  262.       if( fread((char*) &arhdr, sizeof(arhdr), 1, f) != 1 ) break;
  263.       offset = ftell(f);
  264.       strncpy(_ar.ar_name, arhdr.ar_name, sizeof(arhdr.ar_name));
  265.  
  266.       for( p = &_ar.ar_name[sizeof(arhdr.ar_name)];
  267.            --p >= _ar.ar_name && *p == ' ';);
  268.  
  269.       p[1] = '\0';
  270.       if( *p == '/' ) *p = 0;     /* Only SysV has trailing '/' */
  271.  
  272. #if ASCARCH
  273.       if( strncmp(arhdr.ar_fmag, ARFMAG, sizeof(arhdr.ar_fmag)) != 0 )
  274.          return( -1 );
  275.       _ar.ar_time = atol(arhdr.ar_date);
  276.       _ar.ar_size = atol(arhdr.ar_size);
  277. #else
  278.       _ar.ar_time = arhdr.ar_date;
  279.       _ar.ar_size = arhdr.ar_size;
  280. #endif
  281.  
  282.  
  283. #if DECODE_ALL_AR_FIELDS
  284. #if ASCARCH
  285.       _ar.ar_mode = atoi(arhdr.ar_mode);
  286.       _ar.ar_uid  = atoi(arhdr.ar_uid);
  287.       _ar.ar_gid  = atoi(arhdr.ar_gid);
  288. #else
  289.       _ar.ar_mode = arhdr.ar_mode;
  290.       _ar.ar_size = arhdr.ar_size;
  291.       _ar.ar_uid = arhdr.ar_uid;
  292.       _ar.ar_gid = arhdr.ar_gid;
  293. #endif
  294. #endif
  295.  
  296.       if( (*function)(f, &_ar, arg) ) return( 1 );
  297.       fseek( f, offset + (_ar.ar_size+1 & ~1L), 0 );
  298.    }
  299.  
  300.    if( !feof(f) ) return( -1 );
  301.    return 0;
  302. }
  303.  
  304.  
  305.  
  306. static int
  307. ar_touch( f, now )/*
  308. ====================
  309.    touch module header timestamp. */
  310. FILE   *f;
  311. time_t now;
  312. {
  313.    struct ar_hdr arhdr;                /* external archive header */
  314.  
  315.    fseek(f, - (off_t) (sizeof(arhdr) - sizeof(arhdr.ar_name)), 1);
  316.  
  317. #if ASCARCH
  318.    fprintf(f, "%lu", now);
  319. #else
  320.    fwrite((char *)now, sizeof(now), 1, f);
  321. #endif
  322.  
  323.    return( ferror(f) ? 0 : 1 );
  324. }
  325.  
  326.  
  327. #if LC
  328. typedef struct mem {
  329.    time_t    m_time;        /* modify time of member*/
  330.    struct mem    *m_next;    /* next member in lib    */
  331.    char        m_valid;    /* valid cache entry    */
  332.    char     m_name[1];    /* lib member name    */
  333. } MEM, *MEMPTR;
  334.  
  335. typedef struct lib {
  336.    struct lib    *lb_next;    /* next library in list */
  337.    struct mem    *lb_members;    /* list of lib members    */
  338.    char        lb_valid;    /* valid cache entry    */
  339.    char     *lb_name;    /* library name        */
  340. } LIB, *LIBPTR;
  341.  
  342. static LIBPTR _cache = NIL(LIB);
  343. static MEMPTR _find_member ANSI(( LIBPTR, char * ));
  344.  
  345. static int
  346. _check_cache( name, lib, pmtime, touch )/*
  347. ==========================================
  348.    Check to see if we have cached member in lib, if so return time in pmtime
  349.    and return TRUE, otherwise return FALSE, if touch is TRUE then touch
  350.    the archive member instead. */
  351. char   *name;
  352. char   *lib;
  353. time_t *pmtime;
  354. int    touch;
  355. {
  356.    register MEMPTR mp;
  357.    register LIBPTR lp;
  358.  
  359.    for( lp=_cache; lp != NIL(LIB) && lp->lb_name != lib; lp=lp->lb_next );
  360.    if( lp == NIL(LIB) ) return( FALSE );
  361.  
  362.    mp = _find_member( lp, name );
  363.    if( mp == NIL(MEM) || !mp->m_valid ) return( FALSE );
  364.  
  365.    if( touch == TRUE )
  366.    {
  367.       mp->m_time = *pmtime;
  368.       mp->m_valid = 1;
  369.    }
  370.    else
  371.       *pmtime = mp->m_time;
  372.  
  373.    lp->lb_valid   = 1;
  374.    lp->lb_members = mp;
  375.  
  376.    return( TRUE );
  377. }
  378.  
  379.  
  380.  
  381. static int
  382. _cache_member( name, lib, mtime )/*
  383. ===================================
  384.    Cache name in lib along with it's time */
  385. char   *name;
  386. char   *lib;
  387. time_t mtime;
  388. {
  389.    register MEMPTR mp;
  390.    register LIBPTR lp;
  391.  
  392.    for( lp=_cache;
  393.     lp != NIL(LIB) && lp->lb_name != NIL(char) && lp->lb_name != lib;
  394.     lp=lp->lb_next);
  395.  
  396.    if( lp == NIL(LIB) )
  397.    {
  398.       lp = (LIBPTR) malloc(sizeof(LIB));
  399.       if( lp == NIL(LIB) ) No_ram();
  400.  
  401.       lp->lb_name    = lib;
  402.       lp->lb_members = NIL(MEM);
  403.       lp->lb_next    = _cache;
  404.       lp->lb_valid   = 0;
  405.       _cache = lp;
  406.    }
  407.  
  408.    /* On UNIX ar does not allow multiple copies of the same .o file to live
  409.     * in the same AR file.  If this is not TRUE then use the commented out
  410.     * version to set the value of mp. */
  411.  
  412.    /*mp = _find_member(lp, name);*/
  413.    mp = NIL(MEM);
  414.  
  415.    if( mp == NIL(MEM) )
  416.    {
  417.       mp = (MEMPTR) malloc(sizeof(char)*offsetof(MEM,m_name[strlen(name)+1]));
  418.       if( mp == NIL(MEM) ) No_ram();
  419.  
  420.       strcpy( mp->m_name, name );
  421.       mp->m_time     = mtime;
  422.  
  423.       if( lp->lb_members == NIL(MEM) ) {
  424.      mp->m_next     = mp;
  425.      lp->lb_members = mp;
  426.       }
  427.       else {
  428.      mp->m_next = lp->lb_members->m_next;
  429.      lp->lb_members->m_next = mp;
  430.      lp->lb_members = mp;
  431.       }
  432.    }
  433.    else
  434.       mp->m_time = mtime;
  435.  
  436.    mp->m_valid = 1;
  437.  
  438.    return( lp->lb_valid );
  439. }
  440.  
  441.  
  442. static MEMPTR
  443. _find_member( lp, name )
  444. LIBPTR lp;
  445. char   *name;
  446. {
  447.    register MEMPTR mp = lp->lb_members;
  448.  
  449.    if( mp == NIL(MEM) ) return(mp);
  450.  
  451.    do {
  452.       if( !strcmp(mp->m_name, name ) ) return( mp );
  453.       mp = mp->m_next;
  454.    }
  455.    while( mp != lp->lb_members );
  456.  
  457.    return( NIL(MEM) );
  458. }
  459. #endif
  460.  
  461.  
  462.  
  463. void
  464. void_lcache( lib, member )/*
  465. ============================
  466.    Void the library cache for lib.  If member is NIL(char) then nuke all
  467.    of the members, if member is NOT NIL(char) then invalidate only that
  468.    member. */
  469. char *lib;
  470. char *member;
  471. {
  472. #if LC
  473.    register LIBPTR lp;
  474.    register MEMPTR mp;
  475.    register MEMPTR tmp;
  476.  
  477.    for( lp=_cache; lp != NIL(LIB) && lp->lb_name != lib; lp=lp->lb_next );
  478.    if( lp == NIL(LIB) ) return;
  479.  
  480.    if( member == NIL(char) ) {
  481.       mp = lp->lb_members;
  482.       do {
  483.      tmp = mp->m_next;
  484.      (void) free( mp );
  485.      mp = tmp;
  486.       } while( mp != lp->lb_members );
  487.  
  488.       lp->lb_valid   = 0;
  489.       lp->lb_members = NIL(MEM);
  490.       lp->lb_name    = NIL(char);
  491.    }
  492.    else {
  493.       mp=lp->lb_members;
  494.       do {
  495.      if( strcmp( member, mp->m_name) == 0 ) {
  496.         lp->lb_members = mp->m_next;
  497.         mp->m_valid = 0;
  498.      }
  499.        
  500.      mp=mp->m_next;
  501.       } while( mp != lp->lb_members );
  502.    }
  503. #endif
  504. }
  505.