ln = Lst_Find(archives, ArchFindArchive, archive);
ln = Lst_Find(&archives, ArchFindArchive, archive);
ArchStatMember (archive, member, hash)    char	  *archive;   /* Path to the archive */    char	  *member;    /* Name of member. If it is a path, only the			       * last component is used. */    Boolean	  hash;	      /* TRUE if archive should be hashed if not    			       * already so. */{#define AR_MAX_NAME_LEN	    (sizeof(arh.ar_name)-1)    FILE *	  arch;	      /* Stream to archive */    int		  size;       /* Size of archive member */    char	  *cp;	      /* Useful character pointer */    char	  magic[SARMAG];    LstNode	  ln;	      /* Lst member containing archive descriptor */    Arch	  *ar;	      /* Archive descriptor */    Hash_Entry	  *he;	      /* Entry containing member's description */    struct ar_hdr arh;        /* archive-member header for reading archive */    char	  memName[MAXPATHLEN+1];    	    	    	    /* Current member name while hashing. */    /*     * Because of space constraints and similar things, files are archived     * using their final path components, not the entire thing, so we need     * to point 'member' to the final component, if there is one, to make     * the comparisons easier...     */    cp = strrchr (member, '/');    if (cp != NULL)	member = cp + 1;    ln = Lst_Find(archives, ArchFindArchive, archive);    if (ln != NULL) {	ar = (Arch *) Lst_Datum (ln);	he = Hash_FindEntry (&ar->members, member);	if (he != NULL) {	    return ((struct ar_hdr *) Hash_GetValue (he));	} else {	    /* Try truncated name */	    char copy[AR_MAX_NAME_LEN+1];	    int len = strlen (member);	    if (len > AR_MAX_NAME_LEN) {		len = AR_MAX_NAME_LEN;		strncpy(copy, member, AR_MAX_NAME_LEN);		copy[AR_MAX_NAME_LEN] = '\0';	    }	    if ((he = Hash_FindEntry (&ar->members, copy)) != NULL)		return ((struct ar_hdr *) Hash_GetValue (he));	    return (NULL);	}    }    if (!hash) {	/*	 * Caller doesn't want the thing hashed, just use ArchFindMember	 * to read the header for the member out and close down the stream	 * again. Since the archive is not to be hashed, we assume there's	 * no need to allocate extra room for the header we're returning,	 * so just declare it static.	 */	 static struct ar_hdr	sarh;	 arch = ArchFindMember(archive, member, &sarh, "r");	if (arch == NULL) {	    return (NULL);	} else {	    fclose(arch);	    return (&sarh);	}    }    /*     * We don't have this archive on the list yet, so we want to find out     * everything that's in it and cache it so we can get at it quickly.     */    arch = fopen (archive, "r");    if (arch == NULL) {	return (NULL);    }    /*     * We use the ARMAG string to make sure this is an archive we     * can handle...     */    if ((fread (magic, SARMAG, 1, arch) != 1) ||    	(strncmp (magic, ARMAG, SARMAG) != 0)) {	    fclose (arch);	    return (NULL);    }    ar = (Arch *)emalloc (sizeof (Arch));    ar->name = estrdup (archive);    ar->fnametab = NULL;    ar->fnamesize = 0;    Hash_InitTable (&ar->members, -1);    memName[AR_MAX_NAME_LEN] = '\0';    while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {	if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {	    /*	     * The header is bogus, so the archive is bad	     * and there's no way we can recover...	     */	    goto badarch;	} else {	    /*	     * We need to advance the stream's pointer to the start of the	     * next header. Files are padded with newlines to an even-byte	     * boundary, so we need to extract the size of the file from the	     * 'size' field of the header and round it up during the seek.	     */	    arh.ar_size[sizeof(arh.ar_size)-1] = '\0';	    size = (int) strtol(arh.ar_size, NULL, 10);	    (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name));	    for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {		continue;	    }	    cp[1] = '\0';#ifdef SVR4ARCHIVES	    /*	     * svr4 names are slash terminated. Also svr4 extended AR format.	     */	    if (memName[0] == '/') {		/*		 * svr4 magic mode; handle it		 */		switch (ArchSVR4Entry(ar, memName, size, arch)) {		case -1:  /* Invalid data */		    goto badarch;		case 0:	  /* List of files entry */		    continue;		default:  /* Got the entry */		    break;		}	    }	    else {		if (cp[0] == '/')		    cp[0] = '\0';	    }#endif#ifdef AR_EFMT1	    /*	     * BSD 4.4 extended AR format: #1/<namelen>, with name as the	     * first <namelen> bytes of the file	     */	    if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&		isdigit(memName[sizeof(AR_EFMT1) - 1])) {		unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);		if (elen > MAXPATHLEN)			goto badarch;		if (fread (memName, elen, 1, arch) != 1)			goto badarch;		memName[elen] = '\0';		fseek (arch, -elen, SEEK_CUR);		if (DEBUG(ARCH) || DEBUG(MAKE)) {		    printf("ArchStat: Extended format entry for %s\n", memName);		}	    }#endif	    he = Hash_CreateEntry(&ar->members, memName, NULL);	    Hash_SetValue(he, emalloc(sizeof(struct ar_hdr)));	    memcpy(Hash_GetValue(he), &arh, sizeof(struct ar_hdr));	}	fseek (arch, (size + 1) & ~1, SEEK_CUR);    }    fclose (arch);    Lst_AtEnd(archives, ar);    /*     * Now that the archive has been read and cached, we can look into     * the hash table to find the desired member's header.     */    he = Hash_FindEntry (&ar->members, member);    if (he != NULL) {	return ((struct ar_hdr *) Hash_GetValue (he));    } else {	return (NULL);    }badarch:    fclose(arch);    Hash_DeleteTable(&ar->members);    efree(ar->fnametab);    free(ar);    return NULL;}