[BACK]Return to arch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/arch.c between version 1.43 and 1.44

version 1.43, 2001/03/02 16:57:26 version 1.44, 2001/05/03 13:41:00
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenPackages$ */
   /*      $OpenBSD$ */
 /*      $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $       */  /*      $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $       */
   
 /*  /*
  * Copyright (c) 2000 Marc Espie.   * Copyright (c) 1999,2000 Marc Espie.
  *   *
  * Extensive code changes for the OpenBSD project.   * Extensive code changes for the OpenBSD project.
  *   *
Line 76 
Line 77 
  * is referenced.   * is referenced.
  *   *
  * The interface to this module is:   * The interface to this module is:
  *      Arch_ParseArchive       Given an archive specification, return a list   *      Arch_ParseArchive       Given an archive specification, return a list
  *                              of GNode's, one for each member in the spec.   *                              of GNode's, one for each member in the spec.
  *                              FAILURE is returned if the specification is   *                              FAILURE is returned if the specification is
  *                              invalid for some reason.   *                              invalid for some reason.
  *   *
  *      Arch_Touch              Alter the modification time of the archive   *      Arch_Touch              Alter the modification time of the archive
  *                              member described by the given node to be   *                              member described by the given node to be
  *                              the current time.   *                              the current time.
  *   *
  *      Arch_TouchLib           Update the modification time of the library   *      Arch_TouchLib           Update the modification time of the library
  *                              described by the given node. This is special   *                              described by the given node. This is special
  *                              because it also updates the modification time   *                              because it also updates the modification time
  *                              of the library's table of contents.   *                              of the library's table of contents.
  *   *
  *      Arch_MTime              Find the modification time of a member of   *      Arch_MTime              Find the modification time of a member of
  *                              an archive *in the archive*, return TRUE if   *                              an archive *in the archive*. The time is also
  *                              exists. The time is placed in the member's   *                              placed in the member's GNode. Returns the
  *                              GNode. Returns the modification time.   *                              modification time.
  *   *
  *      Arch_MemMTime           Find the modification time of a member of   *      Arch_MemMTime           Find the modification time of a member of
  *                              an archive. Called when the member doesn't   *                              an archive. Called when the member doesn't
  *                              already exist. Looks in the archive for the   *                              already exist. Looks in the archive for the
  *                              modification time. Returns the modification   *                              modification time. Returns the modification
  *                              time.   *                              time.
  *   *
  *      Arch_FindLib            Search for a library along a path. The   *      Arch_FindLib            Search for a library along a path. The
  *                              library name in the GNode should be in   *                              library name in the GNode should be in
  *                              -l<name> format.   *                              -l<name> format.
  *   *
  *      Arch_LibOODate          Special function to decide if a library node   *      Arch_LibOODate          Special function to decide if a library node
  *                              is out-of-date.   *                              is out-of-date.
  *   *
  *      Arch_Init               Initialize this module.   *      Arch_Init               Initialize this module.
  *   *
  *      Arch_End                Cleanup this module.   *      Arch_End                Cleanup this module.
  */   */
   
 #include    <sys/types.h>  #include    <sys/types.h>
 #include    <sys/stat.h>  #include    <sys/stat.h>
 #include    <sys/time.h>  #include    <sys/time.h>
 #include    <sys/param.h>  #include    <sys/param.h>
 #include    <stddef.h>  #include    <assert.h>
 #include    <ctype.h>  #include    <ctype.h>
 #include    <ar.h>  #include    <ar.h>
 #include    <assert.h>  
 #include    <utime.h>  #include    <utime.h>
 #include    <stdio.h>  #include    <stdio.h>
   #include    <stddef.h>
 #include    <stdlib.h>  #include    <stdlib.h>
 #include    <fcntl.h>  #include    <fcntl.h>
 #include    "make.h"  #include    "make.h"
Line 139 
Line 140 
 #endif  #endif
 #endif /* not lint */  #endif /* not lint */
   
   
 #ifdef TARGET_MACHINE  #ifdef TARGET_MACHINE
 #undef MACHINE  #undef MACHINE
 #define MACHINE TARGET_MACHINE  #define MACHINE TARGET_MACHINE
Line 148 
Line 150 
 #define MACHINE_ARCH TARGET_MACHINE_ARCH  #define MACHINE_ARCH TARGET_MACHINE_ARCH
 #endif  #endif
   
 static struct ohash     archives;   /* Archives we've already examined */  static struct ohash       archives;   /* Archives we've already examined.  */
   
 typedef struct Arch_ {  typedef struct Arch_ {
     struct ohash  members;    /* All the members of this archive, as      struct ohash   members;    /* All the members of this archive, as
                                * struct arch_member entries.  */                                 * struct arch_member entries.  */
     char          name[1];    /* Archive name */      char          name[1];    /* Archive name.  */
 } Arch;  } Arch;
   
 /* Used to get to ar's field sizes.  */  /* Used to get to ar's field sizes.  */
 static struct ar_hdr *dummy;  static struct ar_hdr *dummy;
 #define AR_NAME_SIZE            (sizeof(dummy->ar_name))  #define AR_NAME_SIZE            (sizeof(dummy->ar_name))
 #define AR_DATE_SIZE            (sizeof(dummy->ar_date))  #define AR_DATE_SIZE            (sizeof(dummy->ar_date))
   
 /* Each archive member is tied to an arch_member structure,  /* Each archive member is tied to an arch_member structure,
  * suitable for hashing.  */   * suitable for hashing.  */
 struct arch_member {  struct arch_member {
     TIMESTAMP     mtime;        /* Member modification date.  */      TIMESTAMP     mtime;        /* Member modification date.  */
     char          date[AR_DATE_SIZE+1];      char          date[AR_DATE_SIZE+1];
                                 /* Same, before conversion to numeric value.  */                                  /* Same, before conversion to numeric value.  */
     char          name[1];      /* Member name.  */      char          name[1];      /* Member name.  */
 };  };
   
 static struct ohash_info members_info = {  static struct ohash_info members_info = {
     offsetof(struct arch_member, name), NULL,      offsetof(struct arch_member, name), NULL,
     hash_alloc, hash_free, element_alloc      hash_alloc, hash_free, element_alloc
 };  };
   
 static struct ohash_info arch_info = {  static struct ohash_info arch_info = {
     offsetof(Arch, name), NULL, hash_alloc, hash_free, element_alloc      offsetof(Arch, name), NULL, hash_alloc, hash_free, element_alloc
 };  };
   
 static struct arch_member *new_arch_member __P((struct ar_hdr *, const char *));  
 static TIMESTAMP mtime_of_member __P((struct arch_member *));  
 static long field2long __P((const char *, size_t));  
 static Arch *read_archive __P((const char *, const char *));  
   
   
   static struct arch_member *new_arch_member(struct ar_hdr *, const char *);
   static TIMESTAMP mtime_of_member(struct arch_member *);
   static long field2long(const char *, size_t);
   static Arch *read_archive(const char *, const char *);
   
 #ifdef CLEANUP  #ifdef CLEANUP
 static void ArchFree __P((Arch *));  static void ArchFree(Arch *);
 #endif  #endif
 static TIMESTAMP ArchMTimeMember __P((const char *, const char *, Boolean));  static TIMESTAMP ArchMTimeMember(const char *, const char *, Boolean);
 static FILE *ArchFindMember __P((const char *, const char *, struct ar_hdr *, const char *));  static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *);
 static void ArchTouch __P((const char *, const char *));  static void ArchTouch(const char *, const char *);
 #if defined(__svr4__) || defined(__SVR4) || \  #if defined(__svr4__) || defined(__SVR4) || \
     (defined(__OpenBSD__) && defined(__mips__)) || \      (defined(__OpenBSD__) && defined(__mips__)) || \
     (defined(__OpenBSD__) && defined(__powerpc))      (defined(__OpenBSD__) && defined(__powerpc))
Line 204 
Line 208 
   
 static const char *svr4list = "Archive list";  static const char *svr4list = "Archive list";
   
 static char *ArchSVR4Entry __P((struct SVR4namelist *, char *, size_t, FILE *));  static char *ArchSVR4Entry(struct SVR4namelist *, char *, size_t, FILE *);
 #endif  #endif
   
 static struct arch_member *  static struct arch_member *
Line 216 
Line 220 
     struct arch_member *n;      struct arch_member *n;
   
     n = ohash_create_entry(&members_info, name, &end);      n = ohash_create_entry(&members_info, name, &end);
     /* XXX ar entries are NOT null terminated.  */      /* XXX ar entries are NOT null terminated.  */
     memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE);      memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE);
     n->date[AR_DATE_SIZE] = '\0';      n->date[AR_DATE_SIZE] = '\0';
     /* Don't compute mtime before it is needed. */      /* Don't compute mtime before it is needed. */
Line 229 
Line 233 
     struct arch_member *m;      struct arch_member *m;
 {  {
     if (is_out_of_date(m->mtime))      if (is_out_of_date(m->mtime))
         grab_date((time_t) strtol(m->date, NULL, 10), m->mtime);          grab_date((time_t) strtol(m->date, NULL, 10), m->mtime);
     return m->mtime;      return m->mtime;
 }  }
   
Line 241 
Line 245 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  static void
 ArchFree(ap)  ArchFree(a)
     Arch        *a;      Arch          *a;
 {  {
     struct arch_member *mem;      struct arch_member *mem;
     unsigned int i;      unsigned int i;
   
     /* Free memory from hash entries */      /* Free memory from hash entries */
     for (mem = ohash_first(&a->members, &i); mem != NULL;      for (mem = ohash_first(&a->members, &i); mem != NULL;
         mem = ohash_next(&a->members, &i))          mem = ohash_next(&a->members, &i))
         free(mem);          free(mem);
   
     ohash_delete(&a->members);      ohash_delete(&a->members);
Line 273 
Line 277 
  *   *
  * Side Effects:   * Side Effects:
  *      Some nodes may be created. The given list is extended.   *      Some nodes may be created. The given list is extended.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 ReturnStatus  ReturnStatus
 Arch_ParseArchive(linePtr, nodeLst, ctxt)  Arch_ParseArchive(linePtr, nodeLst, ctxt)
     char            **linePtr;      /* Pointer to start of specification */      char            **linePtr;      /* Pointer to start of specification */
     Lst             nodeLst;        /* Lst on which to place the nodes */      Lst             nodeLst;        /* Lst on which to place the nodes */
     SymTable        *ctxt;          /* Context in which to expand variables */      SymTable        *ctxt;          /* Context in which to expand variables */
 {  {
     register char   *cp;            /* Pointer into line */      char            *cp;            /* Pointer into line */
     GNode           *gn;            /* New node */      GNode           *gn;            /* New node */
     char            *libName;       /* Library-part of specification */      char            *libName;       /* Library-part of specification */
     char            *memName;       /* Member-part of specification */      char            *memName;       /* Member-part of specification */
     char            nameBuf[MAKE_BSIZE]; /* temporary place for node name */      char            nameBuf[MAKE_BSIZE]; /* temporary place for node name */
     char            saveChar;       /* Ending delimiter of member-name */      char            saveChar;       /* Ending delimiter of member-name */
     Boolean         subLibName;     /* TRUE if libName should have/had      Boolean         subLibName;     /* TRUE if libName should have/had
                                      * variable substitution performed on it */                                       * variable substitution performed on it */
   
     libName = *linePtr;      libName = *linePtr;
   
     subLibName = FALSE;      subLibName = FALSE;
   
     for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {      for (cp = libName; *cp != '(' && *cp != '\0';) {
         if (*cp == '$') {          if (*cp == '$') {
             /*              ReturnStatus result;
              * Variable spec, so call the Var module to parse the puppy  
              * so we can safely advance beyond it...  
              */  
             size_t      length;  
             Boolean     freeIt;  
             char        *result;  
   
             result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);              cp += Var_ParseSkip(cp, ctxt, &result);
             if (result == var_Error) {              if (result == FAILURE)
                 return(FAILURE);                  return FAILURE;
             } else {              subLibName = TRUE;
                 subLibName = TRUE;          } else
             }              cp++;
   
             if (freeIt) {  
                 free(result);  
             }  
             cp += length-1;  
         }  
     }      }
   
     *cp++ = '\0';      *cp++ = '\0';
     if (subLibName) {      if (subLibName)
         libName = Var_Subst(libName, ctxt, TRUE);          libName = Var_Subst(libName, ctxt, TRUE);
     }  
   
   
     for (;;) {      for (;;) {
         /*          /* First skip to the start of the member's name, mark that
          * First skip to the start of the member's name, mark that  
          * place and skip to the end of it (either white-space or           * place and skip to the end of it (either white-space or
          * a close paren).           * a close paren).  */
          */          Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */
         Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */  
   
         while (*cp != '\0' && *cp != ')' && isspace (*cp)) {          while (*cp != '\0' && *cp != ')' && isspace(*cp))
             cp++;              cp++;
         }  
         memName = cp;          memName = cp;
         while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {          while (*cp != '\0' && *cp != ')' && !isspace(*cp)) {
             if (*cp == '$') {              if (*cp == '$') {
                 /*                  ReturnStatus result;
                  * Variable spec, so call the Var module to parse the puppy                  cp += Var_ParseSkip(cp, ctxt, &result);
                  * so we can safely advance beyond it...                  if (result == FAILURE)
                  */                      return FAILURE;
                 size_t  length;                  doSubst = TRUE;
                 Boolean freeIt;              } else
                 char    *result;  
   
                 result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);  
                 if (result == var_Error) {  
                     return(FAILURE);  
                 } else {  
                     doSubst = TRUE;  
                 }  
   
                 if (freeIt) {  
                     free(result);  
                 }  
                 cp += length;  
             } else {  
                 cp++;                  cp++;
             }  
         }          }
   
         /*          /* If the specification ends without a closing parenthesis,
          * If the specification ends without a closing parenthesis,  
          * chances are there's something wrong (like a missing backslash),           * chances are there's something wrong (like a missing backslash),
          * so it's better to return failure than allow such things to happen           * so it's better to return failure than allow such things to
          */           * happen.  */
         if (*cp == '\0') {          if (*cp == '\0') {
             printf("No closing parenthesis in archive specification\n");              printf("No closing parenthesis in archive specification\n");
             return (FAILURE);              return FAILURE;
         }          }
   
         /*          /* If we didn't move anywhere, we must be done.  */
          * If we didn't move anywhere, we must be done          if (cp == memName)
          */  
         if (cp == memName) {  
             break;              break;
         }  
   
         saveChar = *cp;          saveChar = *cp;
         *cp = '\0';          *cp = '\0';
   
         /*          /* XXX: This should be taken care of intelligently by
          * XXX: This should be taken care of intelligently by           * SuffExpandChildren, both for the archive and the member portions.  */
          * SuffExpandChildren, both for the archive and the member portions.  
          */          /* If member contains variables, try and substitute for them.
         /*  
          * If member contains variables, try and substitute for them.  
          * This will slow down archive specs with dynamic sources, of course,           * This will slow down archive specs with dynamic sources, of course,
          * since we'll be (non-)substituting them three times, but them's           * since we'll be (non-)substituting them three times, but them's
          * the breaks -- we need to do this since SuffExpandChildren calls           * the breaks -- we need to do this since SuffExpandChildren calls
          * us, otherwise we could assume the thing would be taken care of           * us, otherwise we could assume the thing would be taken care of
          * later.           * later.  */
          */  
         if (doSubst) {          if (doSubst) {
             char    *buf;              char    *buf;
             char    *sacrifice;              char    *sacrifice;
Line 402 
Line 366 
   
             memName = Var_Subst(memName, ctxt, TRUE);              memName = Var_Subst(memName, ctxt, TRUE);
   
             /*              /* Now form an archive spec and recurse to deal with nested
              * Now form an archive spec and recurse to deal with nested  
              * variables and multi-word variable values.... The results               * variables and multi-word variable values.... The results
              * are just placed at the end of the nodeLst we're returning.               * are just placed at the end of the nodeLst we're returning.  */
              */  
             buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);              buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);
   
             sprintf(buf, "%s(%s)", libName, memName);              sprintf(buf, "%s(%s)", libName, memName);
   
             if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {              if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
                 /*                  /* Must contain dynamic sources, so we can't deal with it now.
                  * Must contain dynamic sources, so we can't deal with it now.  
                  * Just create an ARCHV node for the thing and let                   * Just create an ARCHV node for the thing and let
                  * SuffExpandChildren handle it...                   * SuffExpandChildren handle it...  */
                  */                  gn = Targ_FindNode(buf, NULL, TARG_CREATE);
                 gn = Targ_FindNode(buf, TARG_CREATE);  
   
                 if (gn == NULL) {                  if (gn == NULL) {
                     free(buf);                      free(buf);
                     return(FAILURE);                      return FAILURE;
                 } else {                  } else {
                     gn->type |= OP_ARCHV;                      gn->type |= OP_ARCHV;
                     Lst_AtEnd(nodeLst, gn);                      Lst_AtEnd(nodeLst, gn);
                 }                  }
             } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {              } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
                 /*                  /* Error in nested call -- free buffer and return FAILURE
                  * Error in nested call -- free buffer and return FAILURE                   * ourselves.  */
                  * ourselves.  
                  */  
                 free(buf);                  free(buf);
                 return(FAILURE);                  return FAILURE;
             }              }
             /*              /* Free buffer and continue with our work.  */
              * Free buffer and continue with our work.  
              */  
             free(buf);              free(buf);
         } else if (Dir_HasWildcards(memName)) {          } else if (Dir_HasWildcards(memName)) {
             LIST members;              LIST  members;
             char  *member;              char  *member;
   
             Lst_Init(&members);              Lst_Init(&members);
   
             Dir_Expand(memName, &dirSearchPath, &members);              Dir_Expand(memName, &dirSearchPath, &members);
             while ((member = (char *)Lst_DeQueue(&members)) != NULL) {              while ((member = (char *)Lst_DeQueue(&members)) != NULL) {
                   snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, member);
                 sprintf(nameBuf, "%s(%s)", libName, member);  
                 free(member);                  free(member);
                 gn = Targ_FindNode(nameBuf, TARG_CREATE);                  gn = Targ_FindNode(nameBuf, NULL, TARG_CREATE);
                 if (gn == NULL)                  /* We've found the node, but have to make sure the rest of
                     return (FAILURE);                   * the world knows it's an archive member, without having
                 else {                   * to constantly check for parentheses, so we type the
                     /*                   * thing with the OP_ARCHV bit before we place it on the
                      * We've found the node, but have to make sure the rest of                   * end of the provided list.  */
                      * the world knows it's an archive member, without having  
                      * to constantly check for parentheses, so we type the  
                      * thing with the OP_ARCHV bit before we place it on the  
                      * end of the provided list.  
                      */  
                     gn->type |= OP_ARCHV;  
                     Lst_AtEnd(nodeLst, gn);  
                 }  
             }  
             Lst_Destroy(&members, NOFREE);  
         } else {  
             sprintf(nameBuf, "%s(%s)", libName, memName);  
             gn = Targ_FindNode (nameBuf, TARG_CREATE);  
             if (gn == NULL) {  
                 return (FAILURE);  
             } else {  
                 /*  
                  * We've found the node, but have to make sure the rest of the  
                  * world knows it's an archive member, without having to  
                  * constantly check for parentheses, so we type the thing with  
                  * the OP_ARCHV bit before we place it on the end of the  
                  * provided list.  
                  */  
                 gn->type |= OP_ARCHV;                  gn->type |= OP_ARCHV;
                 Lst_AtEnd(nodeLst, gn);                  Lst_AtEnd(nodeLst, gn);
             }              }
           } else {
               snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, memName);
               gn = Targ_FindNode(nameBuf, NULL, TARG_CREATE);
               /* We've found the node, but have to make sure the rest of the
                * world knows it's an archive member, without having to
                * constantly check for parentheses, so we type the thing with
                * the OP_ARCHV bit before we place it on the end of the
                * provided list.  */
               gn->type |= OP_ARCHV;
               Lst_AtEnd(nodeLst, gn);
         }          }
         if (doSubst) {          if (doSubst)
             free(memName);              free(memName);
         }  
   
         *cp = saveChar;          *cp = saveChar;
     }      }
   
     /*      /* If substituted libName, free it now, since we need it no longer.  */
      * If substituted libName, free it now, since we need it no longer.      if (subLibName)
      */  
     if (subLibName) {  
         free(libName);          free(libName);
     }  
   
     /*      /* We promised the pointer would be set up at the next non-space, so
      * We promised the pointer would be set up at the next non-space, so  
      * we must advance cp there before setting *linePtr... (note that on       * we must advance cp there before setting *linePtr... (note that on
      * entrance to the loop, cp is guaranteed to point at a ')')       * entrance to the loop, cp is guaranteed to point at a ')') */
      */  
     do {      do {
         cp++;          cp++;
     } while (*cp != '\0' && isspace (*cp));      } while (*cp != '\0' && isspace(*cp));
   
     *linePtr = cp;      *linePtr = cp;
     return (SUCCESS);      return SUCCESS;
 }  }
   
 /* Helper function: ar fields are not null terminated.  */  /* Helper function: ar fields are not null terminated.  */
 static long  static long
 field2long(field, len)  field2long(field, len)
     const char *field;      const char *field;
Line 527 
Line 464 
     const char *archive;      const char *archive;
     const char *end;      const char *end;
 {  {
     FILE        *arch;  /* Stream to archive */      FILE *        arch;       /* Stream to archive */
     char        magic[SARMAG];      char          magic[SARMAG];
     Arch        *ar;      Arch          *ar;
   
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
     struct SVR4namelist list;      struct SVR4namelist list;
   
Line 554 
Line 490 
     ohash_init(&ar->members, 8, &members_info);      ohash_init(&ar->members, 8, &members_info);
   
     for (;;) {      for (;;) {
         size_t          n;          size_t          n;
         struct ar_hdr   arh;    /* Archive-member header for reading archive */          struct ar_hdr   arh;    /* Archive-member header for reading archive */
         off_t           size;   /* Size of archive member */          off_t           size;   /* Size of archive member */
         char            buffer[MAXPATHLEN+1];          char            buffer[MAXPATHLEN+1];
         char            *memName;          char            *memName;
                                 /* Current member name while hashing. */                                  /* Current member name while hashing. */
         char            *cp;    /* Useful character pointer */          char            *cp;    /* Useful character pointer */
   
         memName = buffer;          memName = buffer;
         n = fread(&arh, 1, sizeof(struct ar_hdr), arch);          n = fread(&arh, 1, sizeof(struct ar_hdr), arch);
   
         /*  Whole archive read ok.  */          /*  Whole archive read ok.  */
         if (n == 0 && feof(arch)) {          if (n == 0 && feof(arch)) {
Line 582 
Line 518 
         } else {          } else {
             /* We need to advance the stream's pointer to the start of the              /* We need to advance the stream's pointer to the start of the
              * next header.  Records are padded with newlines to an even-byte               * next header.  Records are padded with newlines to an even-byte
              * boundary, so we need to extract the size of the record and               * boundary, so we need to extract the size of the record and
              * round it up during the seek.  */               * round it up during the seek.  */
             size = (off_t) field2long(arh.ar_size, sizeof(arh.ar_size));              size = (off_t) field2long(arh.ar_size, sizeof(arh.ar_size));
   
             (void)memcpy(memName, arh.ar_name, AR_NAME_SIZE);              (void)memcpy(memName, arh.ar_name, AR_NAME_SIZE);
             /* Find real end of name (strip extranous ' ')  */              /* Find real end of name (strip extranous ' ')  */
             for (cp = memName + AR_NAME_SIZE - 1; *cp == ' ';)              for (cp = memName + AR_NAME_SIZE - 1; *cp == ' ';)
                 cp--;                  cp--;
             cp[1] = '\0';              cp[1] = '\0';
   
Line 598 
Line 534 
             if (memName[0] == '/') {              if (memName[0] == '/') {
                 /* SVR4 magic mode.  */                  /* SVR4 magic mode.  */
                 memName = ArchSVR4Entry(&list, memName, size, arch);                  memName = ArchSVR4Entry(&list, memName, size, arch);
                 if (memName == NULL)            /* Invalid data */                  if (memName == NULL)            /* Invalid data */
                     break;                      break;
                 else if (memName == svr4list)   /* List of files entry */                  else if (memName == svr4list)   /* List of files entry */
                     continue;                      continue;
                 /* Got the entry.  */                  /* Got the entry.  */
                 /* XXX this assumes further processing, such as AR_EFMT1,                  /* XXX this assumes further processing, such as AR_EFMT1,
Line 619 
Line 555 
                 isdigit(memName[sizeof(AR_EFMT1) - 1])) {                  isdigit(memName[sizeof(AR_EFMT1) - 1])) {
   
                 int elen = atoi(memName + sizeof(AR_EFMT1)-1);                  int elen = atoi(memName + sizeof(AR_EFMT1)-1);
   
                 if (elen <= 0 || elen > MAXPATHLEN)                  if (elen <= 0 || elen > MAXPATHLEN)
                         break;                          break;
                 memName = buffer;                  memName = buffer;
Line 657 
Line 593 
  *      path to the archive and the path to the desired member.   *      path to the archive and the path to the desired member.
  *   *
  * Results:   * Results:
  *      The archive member's modification time, or OUT_OF_DATE if member   *      The archive member's modification time, or OUT_OF_DATE if member
  *      was not found (convenient, so that missing members are always   *      was not found (convenient, so that missing members are always
  *      out of date).   *      out of date).
  *   *
  * Side Effects:   * Side Effects:
  *      Cache the whole archive contents if hash is TRUE.   *      Cache the whole archive contents if hash is TRUE.
  *      Locate a member of an archive, given the path of the archive and  
  *      the path of the desired member.  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static TIMESTAMP  static TIMESTAMP
Line 672 
Line 606 
     const char    *archive;   /* Path to the archive */      const char    *archive;   /* Path to the archive */
     const char    *member;    /* Name of member. If it is a path, only the      const char    *member;    /* Name of member. If it is a path, only the
                                * last component is used. */                                 * last component is used. */
     Boolean       hash;       /* TRUE if archive should be hashed if not      Boolean       hash;       /* TRUE if archive should be hashed if not
                                * already so. */                                 * already so. */
 {  {
 #define AR_MAX_NAME_LEN     (sizeof(arh.ar_name)-1)      FILE *        arch;       /* Stream to archive */
     FILE *        arch;       /* Stream to archive */  
     Arch          *ar;        /* Archive descriptor */      Arch          *ar;        /* Archive descriptor */
     unsigned int  slot;       /* Place of archive in the archives hash */      unsigned int  slot;       /* Place of archive in the archives hash */
     const char    *end = NULL;      const char    *end = NULL;
     const char    *cp;      const char    *cp;
     TIMESTAMP     result;      TIMESTAMP     result;
   
Line 716 
Line 649 
         if (ar != NULL)          if (ar != NULL)
             ohash_insert(&archives, slot, ar);              ohash_insert(&archives, slot, ar);
     }      }
   
     /* If archive was found, get entry we seek.  */      /* If archive was found, get entry we seek.  */
     if (ar != NULL) {      if (ar != NULL) {
         struct arch_member *he;          struct arch_member *he;
         end = NULL;          end = NULL;
   
         he = ohash_find(&ar->members, ohash_qlookupi(&ar->members, member, &end));          he = ohash_find(&ar->members, ohash_qlookupi(&ar->members, member, &end));
Line 726 
Line 660 
             return mtime_of_member(he);              return mtime_of_member(he);
         else {          else {
             if (end - member > AR_NAME_SIZE) {              if (end - member > AR_NAME_SIZE) {
                 /* Try truncated name */                  /* Try truncated name.  */
                 end = member + AR_NAME_SIZE;                  end = member + AR_NAME_SIZE;
                 he = ohash_find(&ar->members,                  he = ohash_find(&ar->members,
                     ohash_qlookupi(&ar->members, member, &end));                      ohash_qlookupi(&ar->members, member, &end));
                 if (he != NULL)                  if (he != NULL)
Line 738 
Line 672 
     return result;      return result;
 }  }
   
   
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
Line 750 
Line 683 
  *   *
  * Results:   * Results:
  *      svr4list: just read a list of names   *      svr4list: just read a list of names
  *      NULL:     error occured   *      NULL:     error occured
  *      extended name   *      extended name
  *   *
  * Side-effect:   * Side-effect:
  *      For a list of names, store the list in l.   *      For a list of names, store the list in l.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
   
 static char *  static char *
 ArchSVR4Entry(l, name, size, arch)  ArchSVR4Entry(l, name, size, arch)
         struct SVR4namelist *l;          struct SVR4namelist *l;
Line 771 
Line 705 
   
     assert(name[0] == '/');      assert(name[0] == '/');
     name++;      name++;
   
     /* First comes a table of archive names, to be used by subsequent calls.  */      /* First comes a table of archive names, to be used by subsequent calls.  */
     if (memcmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 ||      if (memcmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 ||
         memcmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) {          memcmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) {
Line 790 
Line 723 
                 printf("Reading an SVR4 name table failed\n");                  printf("Reading an SVR4 name table failed\n");
             return NULL;              return NULL;
         }          }
   
         eptr = l->fnametab + size;          eptr = l->fnametab + size;
         for (entry = 0, ptr = l->fnametab; ptr < eptr; ptr++)          for (entry = 0, ptr = l->fnametab; ptr < eptr; ptr++)
             switch (*ptr) {              switch (*ptr) {
Line 805 
Line 739 
                 break;                  break;
             }              }
         if (DEBUG(ARCH))          if (DEBUG(ARCH))
             printf("Found svr4 archive name table with %lu entries\n",              printf("Found svr4 archive name table with %lu entries\n",
                         (u_long)entry);                          (u_long)entry);
         return (char *)svr4list;          return (char *)svr4list;
     }      }
   
     /* Then the names themselves are given as offsets in this table.  */      /* Then the names themselves are given as offsets in this table.  */
     if (*name == ' ' || *name == '\0')      if (*name == ' ' || *name == '\0')
         return NULL;          return NULL;
Line 817 
Line 750 
     entry = (size_t) strtol(name, &eptr, 0);      entry = (size_t) strtol(name, &eptr, 0);
     if ((*eptr != ' ' && *eptr != '\0') || eptr == name) {      if ((*eptr != ' ' && *eptr != '\0') || eptr == name) {
         if (DEBUG(ARCH))          if (DEBUG(ARCH))
             printf("Could not parse SVR4 name %s\n", name);              printf("Could not parse SVR4 name /%s\n", name);
         return NULL;          return NULL;
     }      }
     if (entry >= l->fnamesize) {      if (entry >= l->fnamesize) {
         if (DEBUG(ARCH))          if (DEBUG(ARCH))
             printf("SVR4 entry offset %s is greater than %lu\n",              printf("SVR4 entry offset /%s is greater than %lu\n",
                    name, (u_long)l->fnamesize);                     name, (u_long)l->fnamesize);
         return NULL;          return NULL;
     }      }
   
     if (DEBUG(ARCH))      if (DEBUG(ARCH))
         printf("Replaced %s with %s\n", name, l->fnametab + entry);          printf("Replaced /%s with %s\n", name, l->fnametab + entry);
   
     return l->fnametab + entry;      return l->fnametab + entry;
 }  }
Line 844 
Line 777 
  *   *
  * Results:   * Results:
  *      A FILE *, opened for reading and writing, positioned right after   *      A FILE *, opened for reading and writing, positioned right after
  *      the member's header, or NULL if the member was nonexistent.   *      the member's header, or NULL if the member was nonexistent.
  *   *
  * Side Effects:   * Side Effects:
  *      Fill the struct ar_hdr pointed by arhPtr.   *      Fill the struct ar_hdr pointed by arhPtr.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static FILE *  static FILE *
Line 859 
Line 791 
     struct ar_hdr *arhPtr;    /* Pointer to header structure to be filled in */      struct ar_hdr *arhPtr;    /* Pointer to header structure to be filled in */
     const char    *mode;      /* The mode for opening the stream */      const char    *mode;      /* The mode for opening the stream */
 {  {
     FILE *        arch;       /* Stream to archive */      FILE *        arch;       /* Stream to archive */
     char          *cp;        /* Useful character pointer */      char          *cp;        /* Useful character pointer */
     char          magic[SARMAG];      char          magic[SARMAG];
     size_t        len;      size_t        len;
   
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
     struct SVR4namelist list;      struct SVR4namelist list;
   
Line 879 
Line 810 
         strncmp(magic, ARMAG, SARMAG) != 0) {          strncmp(magic, ARMAG, SARMAG) != 0) {
             fclose(arch);              fclose(arch);
             return NULL;              return NULL;
      }      }
   
     /* Because of space constraints and similar things, files are archived      /* Because of space constraints and similar things, files are archived
      * using their final path components, not the entire thing, so we need       * using their final path components, not the entire thing, so we need
Line 888 
Line 819 
     cp = strrchr(member, '/');      cp = strrchr(member, '/');
     if (cp != NULL)      if (cp != NULL)
         member = cp + 1;          member = cp + 1;
   
     len = strlen(member);      len = strlen(member);
     if (len >= AR_NAME_SIZE)      if (len >= AR_NAME_SIZE)
         len = AR_NAME_SIZE;          len = AR_NAME_SIZE;
   
     /* Error handling is simpler than for read_archive, since we just      /* Error handling is simpler than for read_archive, since we just
      * look for a given member.  */       * look for a given member.  */
     while (fread(arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) {      while (fread(arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) {
         off_t             size;       /* Size of archive member */          off_t             size;       /* Size of archive member */
         char              *memName;          char              *memName;
   
         if (memcmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0)          if (memcmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0)
              /* The header is bogus, so the archive is bad.  */               /* The header is bogus, so the archive is bad.  */
              break;               break;
   
         memName = arhPtr->ar_name;          memName = arhPtr->ar_name;
         if (memcmp(member, memName, len) == 0) {          if (memcmp(member, memName, len) == 0) {
             /* If the member's name doesn't take up the entire 'name' field,              /* If the member's name doesn't take up the entire 'name' field,
              * we have to be careful of matching prefixes. Names are space-               * we have to be careful of matching prefixes. Names are space-
              * padded to the right, so if the character in 'name' at the end               * padded to the right, so if the character in 'name' at the end
              * of the matched string is anything but a space, this isn't the               * of the matched string is anything but a space, this isn't the
              * member we sought.  */               * member we sought.  */
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
             if (len < sizeof(arhPtr->ar_name) && memName[len] == '/')              if (len < sizeof(arhPtr->ar_name) && memName[len] == '/')
                 len++;                  len++;
 #endif  #endif
             if (len == sizeof(arhPtr->ar_name) ||              if (len == sizeof(arhPtr->ar_name) ||
                 memName[len] == ' ') {                  memName[len] == ' ') {
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
                 efree(list.fnametab);                  efree(list.fnametab);
 #endif  #endif
Line 925 
Line 858 
   
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
             /* svr4 names are slash terminated. Also svr4 extended AR format.              /* svr4 names are slash terminated. Also svr4 extended AR format.
              */               */
             if (memName[0] == '/') {              if (memName[0] == '/') {
                 /* svr4 magic mode.  */                  /* svr4 magic mode.  */
                 memName = ArchSVR4Entry(&list, arhPtr->ar_name, size, arch);                  memName = ArchSVR4Entry(&list, arhPtr->ar_name, size, arch);
                 if (memName == NULL)            /* Invalid data */                  if (memName == NULL)            /* Invalid data */
                     break;                      break;
                 else if (memName == svr4list)   /* List of files entry */                  else if (memName == svr4list)   /* List of files entry */
                     continue;                      continue;
Line 950 
Line 883 
   
             int elen = atoi(memName + sizeof(AR_EFMT1)-1);              int elen = atoi(memName + sizeof(AR_EFMT1)-1);
   
             if (elen <= 0 || elen > MAXPATHLEN)              if (elen <= 0 || elen > MAXPATHLEN)
                 break;                  break;
             if (fread(ename, elen, 1, arch) != 1)              if (fread(ename, elen, 1, arch) != 1)
                 break;                  break;
             if (fseek(arch, -elen, SEEK_CUR) != 0)              if (fseek(arch, -elen, SEEK_CUR) != 0)
                 break;                  break;
             ename[elen] = '\0';              ename[elen] = '\0';
             if (DEBUG(ARCH) || DEBUG(MAKE))              if (DEBUG(ARCH) || DEBUG(MAKE))
                 printf("ArchFind: Extended format entry for %s\n", ename);                  printf("ArchFind: Extended format entry for %s\n", ename);
             /* Found as extended name.  */              /* Found as extended name.  */
             if (strcmp(ename, member) == 0) {              if (strcmp(ename, member) == 0) {
 #ifdef SVR4ARCHIVES  #ifdef SVR4ARCHIVES
                 efree(list.fnametab);                  efree(list.fnametab);
Line 1011 
Line 944 
  *      The modification time of the entire archive is also changed.   *      The modification time of the entire archive is also changed.
  *      For a library, this could necessitate the re-ranlib'ing of the   *      For a library, this could necessitate the re-ranlib'ing of the
  *      whole thing.   *      whole thing.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
Line 1030 
Line 962 
  * Side Effects:   * Side Effects:
  *      The modification time of the library and of the RANLIBMAG   *      The modification time of the library and of the RANLIBMAG
  *      member are set to 'now'.   *      member are set to 'now'.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Arch_TouchLib(gn)  Arch_TouchLib(gn)
     GNode           *gn;        /* The node of the library to touch */      GNode           *gn;        /* The node of the library to touch */
 {  {
 #ifdef RANLIBMAG  #ifdef RANLIBMAG
     if (gn->path != NULL) {      if (gn->path != NULL) {
         ArchTouch(gn->path, RANLIBMAG);          ArchTouch(gn->path, RANLIBMAG);
         set_times(gn->path);          set_times(gn->path);
     }      }
 #endif  #endif
Line 1063 
Line 994 
     GNode         *gn;        /* Node describing archive member */      GNode         *gn;        /* Node describing archive member */
 {  {
     gn->mtime = ArchMTimeMember(Varq_Value(ARCHIVE_INDEX, gn),      gn->mtime = ArchMTimeMember(Varq_Value(ARCHIVE_INDEX, gn),
         Varq_Value(MEMBER_INDEX, gn),               Varq_Value(MEMBER_INDEX, gn),
         TRUE);               TRUE);
   
     return gn->mtime;      return gn->mtime;
 }  }
Line 1075 
Line 1006 
  *      Given a non-existent archive member's node, get its modification   *      Given a non-existent archive member's node, get its modification
  *      time from its archived form, if it exists.   *      time from its archived form, if it exists.
  *   *
    * Results:
    *      The modification time.
    *
    * Side Effects:
    *      The mtime field is filled in.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 TIMESTAMP  TIMESTAMP
 Arch_MemMTime (gn)  Arch_MemMTime(gn)
     GNode         *gn;      GNode         *gn;
 {  {
     LstNode       ln;      LstNode       ln;
   
     for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) {      for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) {
         GNode   *pgn;          GNode   *pgn;
Line 1097 
Line 1033 
              * child. We keep searching its parents in case some other               * child. We keep searching its parents in case some other
              * parent requires this child to exist...  */               * parent requires this child to exist...  */
             if ((nameStart = strchr(pgn->name, '(') ) != NULL) {              if ((nameStart = strchr(pgn->name, '(') ) != NULL) {
                 nameStart++;                  nameStart++;
                 nameEnd = strchr(nameStart, ')');                  nameEnd = strchr(nameStart, ')');
             } else              } else
                 nameEnd = NULL;                  nameEnd = NULL;
   
             if (pgn->make && nameEnd != NULL &&              if (pgn->make && nameEnd != NULL &&
                 strncmp(nameStart, gn->name, nameEnd - nameStart) == 0 &&                  strncmp(nameStart, gn->name, nameEnd - nameStart) == 0 &&
Line 1109 
Line 1045 
         } else if (pgn->make) {          } else if (pgn->make) {
             /* Something which isn't a library depends on the existence of              /* Something which isn't a library depends on the existence of
              * this target, so it needs to exist.  */               * this target, so it needs to exist.  */
             set_out_of_date(gn->mtime);              set_out_of_date(gn->mtime);
             break;              break;
         }          }
     }      }
Line 1121 
Line 1057 
  * Arch_FindLib --   * Arch_FindLib --
  *      Search for a library along the given search path.   *      Search for a library along the given search path.
  *   *
  * Results:  
  *      None.  
  *  
  * Side Effects:   * Side Effects:
  *      The node's 'path' field is set to the found path (including the   *      The node's 'path' field is set to the found path (including the
  *      actual file name, not -l...). If the system can handle the -L   *      actual file name, not -l...). If the system can handle the -L
Line 1133 
Line 1066 
  *      TARGET variable for this node to be the node's name. Otherwise,   *      TARGET variable for this node to be the node's name. Otherwise,
  *      we set the TARGET variable to be the full path of the library,   *      we set the TARGET variable to be the full path of the library,
  *      as returned by Dir_FindFile.   *      as returned by Dir_FindFile.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Arch_FindLib (gn, path)  Arch_FindLib(gn, path)
     GNode           *gn;              /* Node of library to find */      GNode           *gn;        /* Node of library to find */
     Lst             path;             /* Search path */      Lst             path;       /* Search path */
 {  {
     char            *libName;   /* file name for archive */      char            *libName;   /* file name for archive */
   
     libName = (char *)emalloc (strlen (gn->name) + 6 - 2);      libName = emalloc(strlen(gn->name) + 6 - 2);
     sprintf(libName, "lib%s.a", &gn->name[2]);      sprintf(libName, "lib%s.a", &gn->name[2]);
   
     gn->path = Dir_FindFile (libName, path);      gn->path = Dir_FindFile(libName, path);
   
     free (libName);      free(libName);
   
 #ifdef LIBRARIES  #ifdef LIBRARIES
     Varq_Set(TARGET_INDEX, gn->name, gn);      Varq_Set(TARGET_INDEX, gn->name, gn);
Line 1172 
Line 1104 
  *      A library will be considered out-of-date for any of these reasons,   *      A library will be considered out-of-date for any of these reasons,
  *      given that it is a target on a dependency line somewhere:   *      given that it is a target on a dependency line somewhere:
  *          Its modification time is less than that of one of its   *          Its modification time is less than that of one of its
  *                sources (gn->mtime < gn->cmtime).   *                sources (gn->mtime < gn->cmtime).
  *          Its modification time is greater than the time at which the   *          Its modification time is greater than the time at which the
  *                make began (i.e. it's been modified in the course   *                make began (i.e. it's been modified in the course
  *                of the make, probably by archiving).   *                of the make, probably by archiving).
  *          The modification time of one of its sources is greater than   *          The modification time of one of its sources is greater than
  *                the one of its RANLIBMAG member (i.e. its table of contents   *                the one of its RANLIBMAG member (i.e. its table of contents
  *                is out-of-date). We don't compare of the archive time   *                is out-of-date). We don't compare of the archive time
  *                vs. TOC time because they can be too close. In my   *                vs. TOC time because they can be too close. In my
  *                opinion we should not bother with the TOC at all since   *                opinion we should not bother with the TOC at all since
  *                this is used by 'ar' rules that affect the data contents   *                this is used by 'ar' rules that affect the data contents
Line 1190 
Line 1122 
  *   *
  * Side Effects:   * Side Effects:
  *      The library will be hashed if it hasn't been already.   *      The library will be hashed if it hasn't been already.
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 Boolean  Boolean
 Arch_LibOODate (gn)  Arch_LibOODate(gn)
     GNode         *gn;          /* The library's graph node */      GNode         *gn;          /* The library's graph node */
 {  {
     TIMESTAMP   modTimeTOC;     /* mod time of __.SYMDEF */      TIMESTAMP     modTimeTOC;   /* mod time of __.SYMDEF */
   
     if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children))      if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children))
         return FALSE;          return FALSE;
     if (is_before(now, gn->mtime) || is_before(gn->mtime, gn->cmtime) ||      if (is_before(now, gn->mtime) || is_before(gn->mtime, gn->cmtime) ||
         is_out_of_date(gn->mtime))          is_out_of_date(gn->mtime))
         return TRUE;          return TRUE;
 #ifdef RANLIBMAG  #ifdef RANLIBMAG
     /* non existent libraries are always out-of-date.  */      /* non existent libraries are always out-of-date.  */
     if (gn->path == NULL)      if (gn->path == NULL)
         return TRUE;          return TRUE;
   
     modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, FALSE);      modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, FALSE);
   
     if (!is_out_of_date(modTimeTOC)) {      if (!is_out_of_date(modTimeTOC)) {
Line 1216 
Line 1146 
             printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));              printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
         return is_before(modTimeTOC, gn->cmtime);          return is_before(modTimeTOC, gn->cmtime);
     }      }
     /* A library w/o a table of contents is out-of-date */      /* A library w/o a table of contents is out-of-date.  */
     if (DEBUG(ARCH) || DEBUG(MAKE))      if (DEBUG(ARCH) || DEBUG(MAKE))
         printf("No t.o.c....");          printf("No t.o.c....");
     return TRUE;      return TRUE;
Line 1252 
Line 1182 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Arch_End ()  Arch_End()
 {  {
 #ifdef CLEANUP  #ifdef CLEANUP
     Arch *e;      Arch *e;
     unsigned int i;      unsigned int i;
   
     for (e = ohash_first(&archives, &i); e != NULL;      for (e = ohash_first(&archives, &i); e != NULL;
         e = ohash_next(&archives, &i))          e = ohash_next(&archives, &i))
             ArchFree(e);              ArchFree(e);
     ohash_delete(&archives);      ohash_delete(&archives);
 #endif  #endif
Line 1272 
Line 1202 
  *   *
  * Results:   * Results:
  *      True or False.   *      True or False.
  *  
  * Side Effects:  
  *      None.  
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 int  Boolean
 Arch_IsLib(gn)  Arch_IsLib(gn)
     GNode *gn;      GNode *gn;
 {  {
     static const char armag[] = "!<arch>\n";      char buf[SARMAG];
     char buf[sizeof(armag)-1];  
     int fd;      int fd;
   
     if ((fd = open(gn->path, O_RDONLY)) == -1)      if (gn->path == NULL || (fd = open(gn->path, O_RDONLY)) == -1)
         return FALSE;          return FALSE;
   
     if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {      if (read(fd, buf, SARMAG) != SARMAG) {
         (void) close(fd);          (void)close(fd);
         return FALSE;          return FALSE;
     }      }
   
     (void) close(fd);      (void)close(fd);
   
     return memcmp(buf, armag, sizeof(buf)) == 0;      return memcmp(buf, ARMAG, SARMAG) == 0;
 }  }

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.44