unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);  if (elen > MAXPATHLEN) goto badarch; if (fread (memName, elen, 1, arch) != 1) goto badarch;
int elen = atoi(memName + sizeof(AR_EFMT1)-1);  if (elen <= 0 || elen > MAXPATHLEN) break; memName = buffer; if (fread(memName, elen, 1, arch) != 1) break;
static Arch *read_archive __P((const char *, const char *));#ifdef CLEANUPstatic void ArchFree __P((Arch *));#endifstatic TIMESTAMP ArchMTimeMember __P((const char *, const char *, Boolean));static FILE *ArchFindMember __P((const char *, const char *, struct ar_hdr *, const char *));static void ArchTouch __P((const char *, const char *));#if defined(__svr4__) || defined(__SVR4) || \    (defined(__OpenBSD__) && defined(__mips__)) || \    (defined(__OpenBSD__) && defined(__powerpc))#define SVR4ARCHIVES#endif#ifdef SVR4ARCHIVESstruct SVR4namelist {    char	  *fnametab;  /* Extended name table strings */    size_t	  fnamesize;  /* Size of the string table */};static const char *svr4list = "Archive list";static char *ArchSVR4Entry __P((struct SVR4namelist *, char *, size_t, FILE *));#endifstatic struct arch_member *new_arch_member(hdr, name)    struct ar_hdr *hdr;    const char *name;{    const char *end = NULL;    struct arch_member *n;    n = hash_create_entry(&members_info, name, &end);    /* XXX ar entries are NOT null terminated.  */    memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE);    n->date[AR_DATE_SIZE] = '\0';    /* Don't compute mtime before it is needed. */    set_out_of_date(n->mtime);    return n;}static TIMESTAMPmtime_of_member(m)    struct arch_member *m;{    if (is_out_of_date(m->mtime))    	grab_date((time_t) strtol(m->date, NULL, 10), m->mtime);    return m->mtime;}#ifdef CLEANUP/*- *----------------------------------------------------------------------- * ArchFree -- *	Free memory used by an archive *----------------------------------------------------------------------- */static voidArchFree(ap)    Arch	*a;{    struct arch_member *mem;    unsigned int i;    /* Free memory from hash entries */    for (mem = hash_first(&a->members, &i); mem != NULL;    	mem = hash_next(&a->members, &i))	free(mem);    hash_delete(&a->members);    free(a);}#endif/*- *----------------------------------------------------------------------- * Arch_ParseArchive -- *	Parse the archive specification in the given line and find/create *	the nodes for the specified archive members, placing their nodes *	on the given list. * * Results: *	SUCCESS if it was a valid specification. The linePtr is updated *	to point to the first non-space after the archive spec. The *	nodes for the members are placed on the given list. * * Side Effects: *	Some nodes may be created. The given list is extended. * *----------------------------------------------------------------------- */ReturnStatusArch_ParseArchive(linePtr, nodeLst, ctxt)    char	    **linePtr;      /* Pointer to start of specification */    Lst	    	    nodeLst;   	    /* Lst on which to place the nodes */    SymTable   	    *ctxt;  	    /* Context in which to expand variables */{    register char   *cp;	    /* Pointer into line */    GNode	    *gn;     	    /* New node */    char	    *libName;  	    /* Library-part of specification */    char	    *memName;  	    /* Member-part of specification */    char	    nameBuf[MAKE_BSIZE]; /* temporary place for node name */    char	    saveChar;  	    /* Ending delimiter of member-name */    Boolean 	    subLibName;	    /* TRUE if libName should have/had				     * variable substitution performed on it */    libName = *linePtr;    subLibName = FALSE;    for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {	if (*cp == '$') {	    /*	     * 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);	    if (result == var_Error) {		return(FAILURE);	    } else {		subLibName = TRUE;	    }	    if (freeIt) {		free(result);	    }	    cp += length-1;	}    }    *cp++ = '\0';    if (subLibName) {	libName = Var_Subst(libName, ctxt, TRUE);    }    for (;;) {	/*	 * First skip to the start of the member's name, mark that	 * place and skip to the end of it (either white-space or	 * a close paren).	 */	Boolean	doSubst = FALSE; /* TRUE if need to substitute in memName */	while (*cp != '\0' && *cp != ')' && isspace (*cp)) {	    cp++;	}	memName = cp;	while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {	    if (*cp == '$') {		/*		 * 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);		if (result == var_Error) {		    return(FAILURE);		} else {		    doSubst = TRUE;		}		if (freeIt) {		    free(result);		}		cp += length;	    } else {		cp++;	    }	}	/*	 * If the specification ends without a closing parenthesis,	 * chances are there's something wrong (like a missing backslash),	 * so it's better to return failure than allow such things to happen	 */	if (*cp == '\0') {	    printf("No closing parenthesis in archive specification\n");	    return (FAILURE);	}	/*	 * If we didn't move anywhere, we must be done	 */	if (cp == memName) {	    break;	}	saveChar = *cp;	*cp = '\0';	/*	 * XXX: This should be taken care of intelligently by	 * SuffExpandChildren, both for the archive and the member portions.	 */	/*	 * If member contains variables, try and substitute for them.	 * This will slow down archive specs with dynamic sources, of course,	 * since we'll be (non-)substituting them three times, but them's	 * the breaks -- we need to do this since SuffExpandChildren calls	 * us, otherwise we could assume the thing would be taken care of	 * later.	 */	if (doSubst) {	    char    *buf;	    char    *sacrifice;	    char    *oldMemName = memName;	    memName = Var_Subst(memName, ctxt, TRUE);	    /*	     * Now form an archive spec and recurse to deal with nested	     * variables and multi-word variable values.... The results	     * are just placed at the end of the nodeLst we're returning.	     */	    buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);	    sprintf(buf, "%s(%s)", libName, memName);	    if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {		/*		 * Must contain dynamic sources, so we can't deal with it now.		 * Just create an ARCHV node for the thing and let		 * SuffExpandChildren handle it...		 */		gn = Targ_FindNode(buf, TARG_CREATE);		if (gn == NULL) {		    free(buf);		    return(FAILURE);		} else {		    gn->type |= OP_ARCHV;		    Lst_AtEnd(nodeLst, gn);		}	    } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {		/*		 * Error in nested call -- free buffer and return FAILURE		 * ourselves.		 */		free(buf);		return(FAILURE);	    }	    /*	     * Free buffer and continue with our work.	     */	    free(buf);	} else if (Dir_HasWildcards(memName)) {	    LIST members;	    char  *member;	    Lst_Init(&members);	    Dir_Expand(memName, &dirSearchPath, &members);	    while ((member = (char *)Lst_DeQueue(&members)) != NULL) {		sprintf(nameBuf, "%s(%s)", libName, member);		free(member);		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;		    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;		Lst_AtEnd(nodeLst, gn);	    }	}	if (doSubst) {	    free(memName);	}	*cp = saveChar;    }    /*     * If substituted libName, free it now, since we need it no longer.     */    if (subLibName) {	free(libName);    }    /*     * 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     * entrance to the loop, cp is guaranteed to point at a ')')     */    do {	cp++;    } while (*cp != '\0' && isspace (*cp));    *linePtr = cp;    return (SUCCESS);}static Arch *read_archive(archive, end)    const char *archive;    const char *end;{    FILE 		*arch;	/* Stream to archive */    char		magic[SARMAG];    Arch		*ar;    struct ar_hdr 	arh;	/* archive-member header for reading archive */    char		*cp;#ifdef SVR4ARCHIVES    struct SVR4namelist list;    list.fnametab = NULL;#endif#define AR_MAX_NAME_LEN	    (sizeof(arh.ar_name)-1)    /* When we encounter an archive for the first time, we read its     * whole contents, to place it in the cache.  */    arch = fopen(archive, "r");    if (arch == NULL)	return NULL;    /* 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 = hash_create_entry(&arch_info, archive, &end);    hash_init(&ar->members, 8, &members_info);    while (fread((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {	int		size;	/* Size of archive member */	char		buffer[MAXPATHLEN+1];	char 		*memName;				/* Current member name while hashing. */	memName = buffer;	memName[AR_MAX_NAME_LEN] = '\0';	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.  */		memName = ArchSVR4Entry(&list, memName, size, arch);		if (memName == NULL) 		/* Invalid data */		    break;		else if (memName == svr4list) 	/* List of files entry */		    continue;		/* Got the entry.  */		/* XXX this assumes further processing, such as AR_EFMT1,		 * also applies to SVR4ARCHIVES.  */	    }	    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	    hash_insert(&ar->members,		hash_qlookup(&ar->members, memName),		    new_arch_member(&arh, memName));	}	fseek(arch, (size + 1) & ~1, SEEK_CUR);    }    fclose(arch);    return ar;badarch:    fclose(arch);    hash_delete(&ar->members);#ifdef SVR4ARCHIVES    efree(list.fnametab);#endif    free(ar);    return NULL;}