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

  1. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/unix/arlib.c,v 1.1 1992/01/24 03:28:06 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:28:06  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. #ifndef ASCARCH
  48. #define ASCARCH            1    /* ASCII time stored in archive    */
  49. #endif
  50.  
  51. #ifndef LC
  52. #define LC            1    /* Turn on library cacheing    */
  53. #endif
  54.  
  55. #ifndef DECODE_ALL_AR_FIELDS
  56. #define DECODE_ALL_AR_FIELDS    0    /* decode only fields make needs*/
  57. #endif
  58.  
  59. #if LC
  60. #  define FOUND_MEMBER    FALSE
  61. #else
  62. #  define FOUND_MEMBER    TRUE
  63. #  define _cache_member(a, b, c)
  64. #  define _check_cache(a, b, c, d)    FALSE
  65. #endif
  66.  
  67. #define MAXFNAME      255       /* Max length of member name    */
  68. #define    MAXMNAME    8    /* Max module name < MAXFNAME    */
  69.  
  70.  
  71. /* This struct is used to pass the library and member inrmation about the
  72.  * routines that perform the library seeking/cacheing */
  73. struct ar_args {
  74.    char   *lib;
  75.    char   *member;
  76.    time_t time;
  77. };
  78.  
  79.  
  80. typedef struct AR {
  81.    char    ar_name[MAXFNAME+1];      /* File name */
  82.    long    ar_size;                  /* Size in bytes */
  83.    time_t  ar_time;                  /* Modification time */
  84.  
  85. #ifdef DOS
  86.    char    ar_modname[MAXMNAME+1];   /* DOS module name */
  87. #endif
  88.  
  89. #if DECODE_ALL_AR_FIELDS
  90.    uint16  ar_mode;                  /* File mode */
  91.    uint16  ar_uid;                     /* File owner */
  92.    uint16  ar_gid;                   /* File group owner */
  93. #endif
  94. } AR, *ARPTR;
  95.  
  96.  
  97. static int ar_scan  ANSI((FILE *,
  98.               int (*) ANSI((FILE *, struct AR *, struct ar_args *)),
  99.               struct ar_args *));
  100. static int ar_touch ANSI(( FILE *, time_t ));
  101. static int time_function  ANSI(( FILE *, struct AR *, struct ar_args * ));
  102. static int touch_function ANSI(( FILE *, struct AR *, struct ar_args * ));
  103.  
  104. #if LC
  105. static int _cache_member ANSI((char *, char *, time_t));
  106. static int _check_cache  ANSI((char *, char *, time_t *, int));
  107. #endif
  108.  
  109. /* decoded archive header */
  110. static AR    _ar;
  111. static off_t arhdroffset;  /* member seek offset */
  112.  
  113.  
  114. PUBLIC time_t
  115. seek_arch(name, lib)/*
  116. ======================
  117.    Look for module 'name' inside 'lib'.  If compiled with cacheing then first
  118.    check to see if the specified lib is cached.  If so then return that time
  119.    stamp instead of looking into the library. */
  120. char    *name;
  121. char     *lib;
  122. {
  123.    FILE   *f;
  124.    int    rv;
  125.    time_t mtime;
  126.    struct ar_args args;
  127.  
  128.    /* Check the cache first (if there is a cache) */
  129.    if( _check_cache(name, lib, &mtime, FALSE) )  return( mtime );
  130.  
  131.    /* Open the lib file and perform the scan of the members, looking
  132.     * for our particular member.  If cacheing is enabled it will be
  133.     * taken care of automatically during the scan. */
  134.  
  135.    args.lib    = lib;
  136.    args.member = name;
  137.    args.time   = (time_t)0L;
  138.  
  139.    if( (f = fopen(lib, "r")) == NIL(FILE) ) return( (time_t)0L );
  140.    rv = ar_scan(f, time_function, &args );
  141.    fclose( f );
  142.  
  143.    if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
  144.  
  145.    return( args.time );
  146. }
  147.  
  148.  
  149. int
  150. touch_arch(name, lib)/*
  151. =======================
  152.    Look for module 'name' inside 'lib'.  If compiled with cacheing then first
  153.    check to see if the specified lib is cached.  If so then set that time
  154.    stamp and write it into the library.  Returns 0 on success, non-zero
  155.    on failure. */
  156. char   *name;
  157. char   *lib;
  158. {
  159.    FILE   *f;
  160.    int    rv;
  161.    struct ar_args args;
  162.  
  163.    /* Open the lib file and perform the scan of the members, looking
  164.     * for our particular member.  If cacheing is enabled it will be
  165.     * taken care of automatically during the scan. */
  166.  
  167.    args.lib    = lib;
  168.    args.member = name;
  169.    args.time   = (time_t)0L;
  170.  
  171.    if( (f = fopen(lib, "r+")) == NIL(FILE) ) return( (time_t)1L );
  172.    rv = ar_scan(f, touch_function, &args );
  173.    fclose( f );
  174.  
  175.    if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
  176.  
  177.    return( 0 );
  178. }
  179.  
  180.  
  181.  
  182. static int
  183. time_function(f, arp, argp)/*
  184. =============================
  185.    get library member's time, if it matches than return it in argp, if
  186.    cacheing is enabled than cache the library members also. */
  187. FILE           *f;      /* library file          */
  188. struct AR      *arp;    /* library member header */
  189. struct ar_args *argp;
  190. {
  191.    int rv = _cache_member( arp->ar_name, argp->lib, arp->ar_time );
  192.  
  193.    if( strcmp(argp->member, arp->ar_name) == 0 ) {
  194.       argp->time = arp->ar_time;
  195.  
  196.       if( arp->ar_time == 0 && !(Glob_attr & A_SILENT) )
  197.          Warning( "(%s): Can't extract library member timestamp; using EPOCH",
  198.               argp->member);
  199.  
  200.       return( rv );  /* 1 => no cacheing, 0 => cacheing */
  201.    }
  202.  
  203.    return( FALSE ); /* continue scan */
  204. }
  205.  
  206.  
  207.  
  208. static int
  209. touch_function(f, arp, argp)/*
  210. ==============================
  211.    Update library member's time stamp, and write new time value into cache
  212.    if required. */
  213. FILE           *f;      /* library file */
  214. struct AR      *arp;    /* library member header */
  215. struct ar_args *argp;
  216. {
  217.    extern time_t time ANSI(( time_t * ));
  218.    time_t now = time((time_t*) NULL);  /* Current time.          */
  219.  
  220.    if( strcmp(argp->member, arp->ar_name) == 0 ) {
  221.       _check_cache( argp->member, argp->lib, &now, TRUE );
  222.       ar_touch(f, now );
  223.  
  224.       return( TRUE );
  225.    }
  226.  
  227.    return( FALSE ); /* continue scan */
  228. }
  229.  
  230.  
  231.  
  232.  
  233. static int
  234. ar_scan(f, function, arg)/*
  235. ===========================
  236.    Scan the opened archive, and call the given function for each member found.
  237.    The function will be called with the file positioned at the beginning of
  238.    the member and it can read up to arp->ar_size bytes of the archive member.
  239.    If the function returns 1, we stop and return 1.  We return 0 at the end
  240.    of the archive, or -1 if the archive has invalid format.  This interface
  241.    is more general than required by "make", but it can be used by other
  242.    utilities.  */
  243. register FILE *f;
  244. int      (*function) ANSI((FILE *, struct AR *, struct ar_args *));
  245. struct   ar_args *arg;
  246. {
  247.    extern long atol ANSI((char *));
  248.    register char *p;
  249.    struct ar_hdr arhdr;   /* archive member header   */
  250.    int         nsize;   /* size of member name     */
  251. #if defined(_AIX)
  252.    struct fl_hdr flhdr;   /* archive file header     */
  253.    char   magic[SAIAMAG]; /* size of magic string    */
  254. #else
  255. #if ASCARCH
  256.    char magic[SARMAG];
  257. #else
  258.    unsigned short word;
  259. #endif
  260. #endif
  261.  
  262.    fseek( f, 0L, 0 );    /* Start at the beginning of the archive file */
  263.  
  264. #if ASCARCH
  265. #if defined(_AIX)
  266.    fread( (char *)&flhdr, sizeof(flhdr), 1, f );
  267.    if( strncmp(flhdr.fl_magic,AIAMAG, SAIAMAG) != 0 ) return(-1);
  268.    fseek(f, atol(flhdr.fl_fstmoff), 0 ); /* postition to first member */
  269. #else
  270.    fread( magic, sizeof(magic), 1, f );
  271.    if( strncmp(magic, ARMAG, SARMAG) != 0 ) return( -1 );
  272. #endif
  273. #else
  274.    fread( (char*)&word, sizeof(word), 1, f );
  275.    if( word != ARMAG ) return( -1 );
  276. #endif
  277.  
  278.    /* scan the library, calling `function' for each member
  279.     */
  280.    while( 1 ) {
  281.       arhdroffset = ftell(f);
  282. #if defined(_AIX)
  283.       if( fread((char*)&arhdr,sizeof(arhdr)-sizeof(arhdr._ar_name),1,f)!=1)
  284.          break;
  285.       nsize = atoi(arhdr.ar_namlen);
  286.       fseek(f, arhdroffset+(unsigned long)(((struct ar_hdr *)0)->_ar_name.ar_name), 0);
  287.       if( fread((char*)_ar.ar_name,nsize,1,f)!=1)
  288.          break;
  289.       _ar.ar_name[nsize]='\0';
  290. #else
  291.       if( fread((char*) &arhdr, sizeof(arhdr), 1, f) != 1 ) break;
  292.       strncpy(_ar.ar_name, arhdr.ar_name, nsize = sizeof(arhdr.ar_name));
  293. #endif
  294.  
  295.       for( p = &_ar.ar_name[nsize];
  296.            --p >= _ar.ar_name && *p == ' ';);
  297.  
  298.       p[1] = '\0';
  299.       if( *p == '/' ) *p = 0;     /* SysV has trailing '/' */
  300.  
  301. #if !defined(_AIX)
  302. #if ASCARCH
  303.       if( strncmp(arhdr.ar_fmag, ARFMAG, sizeof(arhdr.ar_fmag)) != 0 )
  304.          return( -1 );
  305.       _ar.ar_time = atol(arhdr.ar_date);
  306.       _ar.ar_size = atol(arhdr.ar_size);
  307. #else
  308.       _ar.ar_time = arhdr.ar_date;
  309.       _ar.ar_size = arhdr.ar_size;
  310. #endif
  311. #else
  312. #if ASCARCH
  313.       _ar.ar_time = atol(arhdr.ar_date);
  314.       _ar.ar_size = atol(arhdr.ar_nxtmem);
  315. #else
  316.       _ar.ar_time = arhdr.ar_date;
  317.       _ar.ar_size = arhdr.ar_nxtmem;
  318. #endif
  319. #endif
  320.  
  321.  
  322. #if DECODE_ALL_AR_FIELDS
  323. #if ASCARCH
  324.       _ar.ar_mode = atoi(arhdr.ar_mode);
  325.       _ar.ar_uid  = atoi(arhdr.ar_uid);
  326.       _ar.ar_gid  = atoi(arhdr.ar_gid);
  327. #else
  328.       _ar.ar_mode = arhdr.ar_mode;
  329.       _ar.ar_uid = arhdr.ar_uid;
  330.       _ar.ar_gid = arhdr.ar_gid;
  331. #endif
  332. #endif
  333.  
  334.       if( (*function)(f, &_ar, arg) ) return( 1 );
  335. #if defined(_AIX)
  336.       if( _ar.ar_size == 0L ) break;
  337.       fseek( f, (long) _ar.ar_size, 0 );
  338. #else
  339.       fseek( f, arhdroffset + sizeof(arhdr) + (_ar.ar_size+1 & ~1L), 0 );
  340. #endif
  341.    }
  342.  
  343. #if !defined(_AIX)
  344.    if( !feof(f) ) return( -1 );
  345. #endif
  346.    return 0;
  347. }
  348.  
  349.  
  350.  
  351. static int
  352. ar_touch( f, now )/*
  353. ====================
  354.    touch module header timestamp. */
  355. FILE   *f;
  356. time_t now;
  357. {
  358.    struct ar_hdr arhdr;                /* external archive header */
  359.  
  360.    fseek(f, arhdroffset + (unsigned long)(((struct ar_hdr *)0)->ar_date), 0);
  361.  
  362. #if ASCARCH
  363.    fprintf(f, "%lu", now);
  364. #else
  365.    fwrite((char *)now, sizeof(now), 1, f);
  366. #endif
  367.  
  368.    return( ferror(f) ? 0 : 1 );
  369. }
  370.  
  371.  
  372. #if LC
  373. typedef struct mem {
  374.    time_t    m_time;        /* modify time of member*/
  375.    struct mem    *m_next;    /* next member in lib    */
  376.    char        m_valid;    /* valid cache entry    */
  377.    char     m_name[1];    /* lib member name    */
  378. } MEM, *MEMPTR;
  379.  
  380. typedef struct lib {
  381.    struct lib    *lb_next;    /* next library in list */
  382.    struct mem    *lb_members;    /* list of lib members    */
  383.    char        lb_valid;    /* valid cache entry    */
  384.    char     *lb_name;    /* library name        */
  385. } LIB, *LIBPTR;
  386.  
  387. static LIBPTR _cache = NIL(LIB);
  388. static MEMPTR _find_member ANSI(( LIBPTR, char * ));
  389.  
  390. static int
  391. _check_cache( name, lib, pmtime, touch )/*
  392. ==========================================
  393.    Check to see if we have cached member in lib, if so return time in pmtime
  394.    and return TRUE, otherwise return FALSE, if touch is TRUE then touch
  395.    the archive member instead. */
  396. char   *name;
  397. char   *lib;
  398. time_t *pmtime;
  399. int    touch;
  400. {
  401.    register MEMPTR mp;
  402.    register LIBPTR lp;
  403.  
  404.    for( lp=_cache; lp != NIL(LIB) && lp->lb_name != lib; lp=lp->lb_next );
  405.    if( lp == NIL(LIB) ) return( FALSE );
  406.  
  407.    mp = _find_member( lp, name );
  408.    if( mp == NIL(MEM) || !mp->m_valid ) return( FALSE );
  409.  
  410.    if( touch == TRUE )
  411.    {
  412.       mp->m_time = *pmtime;
  413.       mp->m_valid = 1;
  414.    }
  415.    else
  416.       *pmtime = mp->m_time;
  417.  
  418.    lp->lb_valid   = 1;
  419.    lp->lb_members = mp;
  420.  
  421.    return( TRUE );
  422. }
  423.  
  424.  
  425.  
  426. static int
  427. _cache_member( name, lib, mtime )/*
  428. ===================================
  429.    Cache name in lib along with it's time */
  430. char   *name;
  431. char   *lib;
  432. time_t mtime;
  433. {
  434.    register MEMPTR mp;
  435.    register LIBPTR lp;
  436.  
  437.    for( lp=_cache;
  438.     lp != NIL(LIB) && lp->lb_name != NIL(char) && lp->lb_name != lib;
  439.     lp=lp->lb_next);
  440.  
  441.    if( lp == NIL(LIB) )
  442.    {
  443.       lp = (LIBPTR) malloc(sizeof(LIB));
  444.       if( lp == NIL(LIB) ) No_ram();
  445.  
  446.       lp->lb_name    = lib;
  447.       lp->lb_members = NIL(MEM);
  448.       lp->lb_next    = _cache;
  449.       lp->lb_valid   = 0;
  450.       _cache = lp;
  451.    }
  452.  
  453.    /* On UNIX ar does not allow multiple copies of the same .o file to live
  454.     * in the same AR file.  If this is not TRUE then use the commented out
  455.     * version to set the value of mp. */
  456.  
  457.    /*mp = _find_member(lp, name);*/
  458.    mp = NIL(MEM);
  459.  
  460.    if( mp == NIL(MEM) )
  461.    {
  462.       mp = (MEMPTR) malloc(sizeof(char)*offsetof(MEM,m_name[strlen(name)+1]));
  463.       if( mp == NIL(MEM) ) No_ram();
  464.  
  465.       strcpy( mp->m_name, name );
  466.       mp->m_time     = mtime;
  467.  
  468.       if( lp->lb_members == NIL(MEM) ) {
  469.      mp->m_next     = mp;
  470.      lp->lb_members = mp;
  471.       }
  472.       else {
  473.      mp->m_next = lp->lb_members->m_next;
  474.      lp->lb_members->m_next = mp;
  475.      lp->lb_members = mp;
  476.       }
  477.    }
  478.    else
  479.       mp->m_time = mtime;
  480.  
  481.    mp->m_valid = 1;
  482.  
  483.    return( lp->lb_valid );
  484. }
  485.  
  486.  
  487. static MEMPTR
  488. _find_member( lp, name )
  489. LIBPTR lp;
  490. char   *name;
  491. {
  492.    register MEMPTR mp = lp->lb_members;
  493.  
  494.    if( mp == NIL(MEM) ) return(mp);
  495.  
  496.    do {
  497.       if( !strcmp(mp->m_name, name ) ) return( mp );
  498.       mp = mp->m_next;
  499.    }
  500.    while( mp != lp->lb_members );
  501.  
  502.    return( NIL(MEM) );
  503. }
  504. #endif
  505.  
  506.  
  507.  
  508. void
  509. void_lcache( lib, member )/*
  510. ============================
  511.    Void the library cache for lib.  If member is NIL(char) then nuke all
  512.    of the members, if member is NOT NIL(char) then invalidate only that
  513.    member. */
  514. char *lib;
  515. char *member;
  516. {
  517. #if LC
  518.    register LIBPTR lp;
  519.    register MEMPTR mp;
  520.    register MEMPTR tmp;
  521.  
  522.    for( lp=_cache; lp != NIL(LIB) && lp->lb_name != lib; lp=lp->lb_next );
  523.    if( lp == NIL(LIB) ) return;
  524.  
  525.    if( member == NIL(char) ) {
  526.       mp = lp->lb_members;
  527.       do {
  528.      tmp = mp->m_next;
  529.      (void) free( mp );
  530.      mp = tmp;
  531.       } while( mp != lp->lb_members );
  532.  
  533.       lp->lb_valid   = 0;
  534.       lp->lb_members = NIL(MEM);
  535.       lp->lb_name    = NIL(char);
  536.    }
  537.    else {
  538.       mp=lp->lb_members;
  539.       do {
  540.      if( strcmp( member, mp->m_name) == 0 ) {
  541.         lp->lb_members = mp->m_next;
  542.         mp->m_valid = 0;
  543.      }
  544.        
  545.      mp=mp->m_next;
  546.       } while( mp != lp->lb_members );
  547.    }
  548. #endif
  549. }
  550.