home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dmake40.zip / unix / arlib.c next >
C/C++ Source or Header  |  1994-10-23  |  15KB  |  556 lines

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