⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arch.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1988, 1989, 1990, 1993 *	The Regents of the University of California.  All rights reserved. * Copyright (c) 1989 by Berkeley Softworks * All rights reserved. * * This code is derived from software contributed to Berkeley by * Adam de Boor. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)arch.c	8.2 (Berkeley) 1/2/94";#endif /* not lint *//*- * arch.c -- *	Functions to manipulate libraries, archives and their members. * *	Once again, cacheing/hashing comes into play in the manipulation * of archives. The first time an archive is referenced, all of its members' * headers are read and hashed and the archive closed again. All hashed * archives are kept on a list which is searched each time an archive member * is referenced. * * The interface to this module is: *	Arch_ParseArchive   	Given an archive specification, return a list *	    	  	    	of GNode's, one for each member in the spec. *	    	  	    	FAILURE is returned if the specification is *	    	  	    	invalid for some reason. * *	Arch_Touch	    	Alter the modification time of the archive *	    	  	    	member described by the given node to be *	    	  	    	the current time. * *	Arch_TouchLib	    	Update the modification time of the library *	    	  	    	described by the given node. This is special *	    	  	    	because it also updates the modification time *	    	  	    	of the library's table of contents. * *	Arch_MTime	    	Find the modification time of a member of *	    	  	    	an archive *in the archive*. The time is also *	    	  	    	placed in the member's GNode. Returns the *	    	  	    	modification time. * *	Arch_MemTime	    	Find the modification time of a member of *	    	  	    	an archive. Called when the member doesn't *	    	  	    	already exist. Looks in the archive for the *	    	  	    	modification time. Returns the modification *	    	  	    	time. * *	Arch_FindLib	    	Search for a library along a path. The *	    	  	    	library name in the GNode should be in *	    	  	    	-l<name> format. * *	Arch_LibOODate	    	Special function to decide if a library node *	    	  	    	is out-of-date. * *	Arch_Init 	    	Initialize this module. */#include    <sys/types.h>#include    <sys/stat.h>#include    <sys/time.h>#include    <ctype.h>#include    <ar.h>#include    <ranlib.h>#include    <stdio.h>#include    "make.h"#include    "hash.h"#include    "dir.h"#include    "config.h"static Lst	  archives;   /* Lst of archives we've already examined */typedef struct Arch {    char	  *name;      /* Name of archive */    Hash_Table	  members;    /* All the members of the archive described			       * by <name, struct ar_hdr *> key/value pairs */} Arch;static int ArchFindArchive __P((Arch *, char *));static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean));static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *));/*- *----------------------------------------------------------------------- * 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 */    GNode   	    *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...	     */	    int 	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(NULL, 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...		 */		int 	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(NULL, 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 == NILGNODE) {		    free(buf);		    return(FAILURE);		} else {		    gn->type |= OP_ARCHV;		    (void)Lst_AtEnd(nodeLst, (ClientData)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)) {	    Lst	  members = Lst_Init(FALSE);	    char  *member;	    Dir_Expand(memName, dirSearchPath, members);	    while (!Lst_IsEmpty(members)) {		member = (char *)Lst_DeQueue(members);				sprintf(nameBuf, "%s(%s)", libName, member);		free(member);		gn = Targ_FindNode (nameBuf, TARG_CREATE);		if (gn == NILGNODE) {		    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;		    (void) Lst_AtEnd (nodeLst, (ClientData)gn);		}	    }	    Lst_Destroy(members, NOFREE);	} else {	    sprintf(nameBuf, "%s(%s)", libName, memName);	    gn = Targ_FindNode (nameBuf, TARG_CREATE);	    if (gn == NILGNODE) {		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;		(void) Lst_AtEnd (nodeLst, (ClientData)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);}/*- *----------------------------------------------------------------------- * ArchFindArchive -- *	See if the given archive is the one we are looking for. Called *	From ArchStatMember and ArchFindMember via Lst_Find. * * Results: *	0 if it is, non-zero if it isn't. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static intArchFindArchive (ar, archName)    Arch	  *ar;	      	  /* Current list element */    char	  *archName;  	  /* Name we want */{    return (strcmp (archName, ar->name));}/*- *----------------------------------------------------------------------- * ArchStatMember -- *	Locate a member of an archive, given the path of the archive and *	the path of the desired member. * * Results: *	A pointer to the current struct ar_hdr structure for the member. Note *	That no position is returned, so this is not useful for touching *	archive members. This is mostly because we have no assurances that *	The archive will remain constant after we read all the headers, so *	there's not much point in remembering the position... * * Side Effects: * *----------------------------------------------------------------------- */static struct ar_hdr *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];    int		  len;    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[AR_MAX_NAME_LEN+1];    	    	    	    /* Current member name while hashing. The name is			     * truncated to AR_MAX_NAME_LEN bytes, but we need			     * room for the null byte... */    char    	  copy[AR_MAX_NAME_LEN+1];    	    	    	    /* Holds copy of last path element from member, if			     * it has to be truncated, so we don't have to			     * figure it out again once the table is hashed. */    /*     * 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 != (char *) NULL) {	member = cp + 1;    }    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';	member = copy;    }    ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive);    if (ln != NILLNODE) {	ar = (Arch *) Lst_Datum (ln);	he = Hash_FindEntry (&ar->members, member);	if (he != (Hash_Entry *) NULL) {	    return ((struct ar_hdr *) Hash_GetValue (he));	} else {	    return ((struct ar_hdr *) 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 == (FILE *)NULL) {	    return ((struct ar_hdr *)NULL);	} else {	    fclose(arch);	    return (&sarh);	}    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -