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