xref: /original-bsd/usr.bin/make/arch.c (revision bbd64002)
181df88d0Sbostic /*
233717ddfSbostic  * Copyright (c) 1988, 1989, 1990, 1993
333717ddfSbostic  *	The Regents of the University of California.  All rights reserved.
481df88d0Sbostic  * Copyright (c) 1989 by Berkeley Softworks
581df88d0Sbostic  * All rights reserved.
681df88d0Sbostic  *
781df88d0Sbostic  * This code is derived from software contributed to Berkeley by
881df88d0Sbostic  * Adam de Boor.
981df88d0Sbostic  *
10bc1a3d4aSbostic  * %sccs.include.redist.c%
1181df88d0Sbostic  */
1281df88d0Sbostic 
1381df88d0Sbostic #ifndef lint
14*bbd64002Schristos static char sccsid[] = "@(#)arch.c	8.3 (Berkeley) 04/28/95";
1581df88d0Sbostic #endif /* not lint */
1681df88d0Sbostic 
17c1204029Sbostic /*-
18c1204029Sbostic  * arch.c --
19c1204029Sbostic  *	Functions to manipulate libraries, archives and their members.
20c1204029Sbostic  *
21c1204029Sbostic  *	Once again, cacheing/hashing comes into play in the manipulation
22c1204029Sbostic  * of archives. The first time an archive is referenced, all of its members'
23c1204029Sbostic  * headers are read and hashed and the archive closed again. All hashed
24c1204029Sbostic  * archives are kept on a list which is searched each time an archive member
25c1204029Sbostic  * is referenced.
26c1204029Sbostic  *
27c1204029Sbostic  * The interface to this module is:
28c1204029Sbostic  *	Arch_ParseArchive   	Given an archive specification, return a list
29c1204029Sbostic  *	    	  	    	of GNode's, one for each member in the spec.
30c1204029Sbostic  *	    	  	    	FAILURE is returned if the specification is
31c1204029Sbostic  *	    	  	    	invalid for some reason.
32c1204029Sbostic  *
33c1204029Sbostic  *	Arch_Touch	    	Alter the modification time of the archive
34c1204029Sbostic  *	    	  	    	member described by the given node to be
35c1204029Sbostic  *	    	  	    	the current time.
36c1204029Sbostic  *
37c1204029Sbostic  *	Arch_TouchLib	    	Update the modification time of the library
38c1204029Sbostic  *	    	  	    	described by the given node. This is special
39c1204029Sbostic  *	    	  	    	because it also updates the modification time
40c1204029Sbostic  *	    	  	    	of the library's table of contents.
41c1204029Sbostic  *
42c1204029Sbostic  *	Arch_MTime	    	Find the modification time of a member of
43c1204029Sbostic  *	    	  	    	an archive *in the archive*. The time is also
44c1204029Sbostic  *	    	  	    	placed in the member's GNode. Returns the
45c1204029Sbostic  *	    	  	    	modification time.
46c1204029Sbostic  *
47c1204029Sbostic  *	Arch_MemTime	    	Find the modification time of a member of
48c1204029Sbostic  *	    	  	    	an archive. Called when the member doesn't
49c1204029Sbostic  *	    	  	    	already exist. Looks in the archive for the
50c1204029Sbostic  *	    	  	    	modification time. Returns the modification
51c1204029Sbostic  *	    	  	    	time.
52c1204029Sbostic  *
53c1204029Sbostic  *	Arch_FindLib	    	Search for a library along a path. The
54c1204029Sbostic  *	    	  	    	library name in the GNode should be in
55c1204029Sbostic  *	    	  	    	-l<name> format.
56c1204029Sbostic  *
57c1204029Sbostic  *	Arch_LibOODate	    	Special function to decide if a library node
58c1204029Sbostic  *	    	  	    	is out-of-date.
59c1204029Sbostic  *
60c1204029Sbostic  *	Arch_Init 	    	Initialize this module.
61*bbd64002Schristos  *
62*bbd64002Schristos  *	Arch_End 	    	Cleanup this module.
63c1204029Sbostic  */
64c1204029Sbostic 
65c1204029Sbostic #include    <sys/types.h>
66c1204029Sbostic #include    <sys/stat.h>
67c1204029Sbostic #include    <sys/time.h>
68*bbd64002Schristos #include    <sys/param.h>
69c1204029Sbostic #include    <ctype.h>
70c1204029Sbostic #include    <ar.h>
7115e05a09Sbostic #include    <ranlib.h>
7215e05a09Sbostic #include    <stdio.h>
73*bbd64002Schristos #include    <stdlib.h>
74c1204029Sbostic #include    "make.h"
75c1204029Sbostic #include    "hash.h"
7611d27f68Sbostic #include    "dir.h"
7711d27f68Sbostic #include    "config.h"
78c1204029Sbostic 
79c1204029Sbostic static Lst	  archives;   /* Lst of archives we've already examined */
80c1204029Sbostic 
81c1204029Sbostic typedef struct Arch {
82c1204029Sbostic     char	  *name;      /* Name of archive */
83c1204029Sbostic     Hash_Table	  members;    /* All the members of the archive described
84c1204029Sbostic 			       * by <name, struct ar_hdr *> key/value pairs */
85c1204029Sbostic } Arch;
86c1204029Sbostic 
87*bbd64002Schristos static int ArchFindArchive __P((ClientData, ClientData));
88*bbd64002Schristos static void ArchFree __P((ClientData));
8911d27f68Sbostic static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean));
9011d27f68Sbostic static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *));
91ad10560bSbostic 
92c1204029Sbostic /*-
93c1204029Sbostic  *-----------------------------------------------------------------------
94*bbd64002Schristos  * ArchFree --
95*bbd64002Schristos  *	Free memory used by an archive
96*bbd64002Schristos  *
97*bbd64002Schristos  * Results:
98*bbd64002Schristos  *	None.
99*bbd64002Schristos  *
100*bbd64002Schristos  * Side Effects:
101*bbd64002Schristos  *	None.
102*bbd64002Schristos  *
103*bbd64002Schristos  *-----------------------------------------------------------------------
104*bbd64002Schristos  */
105*bbd64002Schristos static void
ArchFree(ap)106*bbd64002Schristos ArchFree(ap)
107*bbd64002Schristos     ClientData ap;
108*bbd64002Schristos {
109*bbd64002Schristos     Arch *a = (Arch *) ap;
110*bbd64002Schristos     Hash_Search	  search;
111*bbd64002Schristos     Hash_Entry	  *entry;
112*bbd64002Schristos 
113*bbd64002Schristos     /* Free memory from hash entries */
114*bbd64002Schristos     for (entry = Hash_EnumFirst(&a->members, &search);
115*bbd64002Schristos 	 entry != (Hash_Entry *)NULL;
116*bbd64002Schristos 	 entry = Hash_EnumNext(&search))
117*bbd64002Schristos 	free((Address) Hash_GetValue (entry));
118*bbd64002Schristos 
119*bbd64002Schristos     free(a->name);
120*bbd64002Schristos     Hash_DeleteTable(&a->members);
121*bbd64002Schristos     free((Address) a);
122*bbd64002Schristos }
123*bbd64002Schristos 
124*bbd64002Schristos 
125*bbd64002Schristos 
126*bbd64002Schristos /*-
127*bbd64002Schristos  *-----------------------------------------------------------------------
128c1204029Sbostic  * Arch_ParseArchive --
129c1204029Sbostic  *	Parse the archive specification in the given line and find/create
130c1204029Sbostic  *	the nodes for the specified archive members, placing their nodes
131c1204029Sbostic  *	on the given list.
132c1204029Sbostic  *
133c1204029Sbostic  * Results:
134c1204029Sbostic  *	SUCCESS if it was a valid specification. The linePtr is updated
135c1204029Sbostic  *	to point to the first non-space after the archive spec. The
136c1204029Sbostic  *	nodes for the members are placed on the given list.
137c1204029Sbostic  *
138c1204029Sbostic  * Side Effects:
139c1204029Sbostic  *	Some nodes may be created. The given list is extended.
140c1204029Sbostic  *
141c1204029Sbostic  *-----------------------------------------------------------------------
142c1204029Sbostic  */
143c1204029Sbostic ReturnStatus
Arch_ParseArchive(linePtr,nodeLst,ctxt)144c1204029Sbostic Arch_ParseArchive (linePtr, nodeLst, ctxt)
145c1204029Sbostic     char	    **linePtr;      /* Pointer to start of specification */
146c1204029Sbostic     Lst	    	    nodeLst;   	    /* Lst on which to place the nodes */
147c1204029Sbostic     GNode   	    *ctxt;  	    /* Context in which to expand variables */
148c1204029Sbostic {
149c1204029Sbostic     register char   *cp;	    /* Pointer into line */
150c1204029Sbostic     GNode	    *gn;     	    /* New node */
151c1204029Sbostic     char	    *libName;  	    /* Library-part of specification */
152c1204029Sbostic     char	    *memName;  	    /* Member-part of specification */
15311d27f68Sbostic     char	    nameBuf[MAKE_BSIZE]; /* temporary place for node name */
154c1204029Sbostic     char	    saveChar;  	    /* Ending delimiter of member-name */
155c1204029Sbostic     Boolean 	    subLibName;	    /* TRUE if libName should have/had
156c1204029Sbostic 				     * variable substitution performed on it */
157c1204029Sbostic 
158c1204029Sbostic     libName = *linePtr;
159c1204029Sbostic 
160c1204029Sbostic     subLibName = FALSE;
161c1204029Sbostic 
162c1204029Sbostic     for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
163c1204029Sbostic 	if (*cp == '$') {
164c1204029Sbostic 	    /*
165c1204029Sbostic 	     * Variable spec, so call the Var module to parse the puppy
166c1204029Sbostic 	     * so we can safely advance beyond it...
167c1204029Sbostic 	     */
168c1204029Sbostic 	    int 	length;
169c1204029Sbostic 	    Boolean	freeIt;
170c1204029Sbostic 	    char	*result;
171c1204029Sbostic 
172c1204029Sbostic 	    result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
173c1204029Sbostic 	    if (result == var_Error) {
174c1204029Sbostic 		return(FAILURE);
175c1204029Sbostic 	    } else {
176c1204029Sbostic 		subLibName = TRUE;
177c1204029Sbostic 	    }
178c1204029Sbostic 
179c1204029Sbostic 	    if (freeIt) {
180c1204029Sbostic 		free(result);
181c1204029Sbostic 	    }
182c1204029Sbostic 	    cp += length-1;
183c1204029Sbostic 	}
184c1204029Sbostic     }
185c1204029Sbostic 
186c1204029Sbostic     *cp++ = '\0';
187c1204029Sbostic     if (subLibName) {
18811d27f68Sbostic 	libName = Var_Subst(NULL, libName, ctxt, TRUE);
189c1204029Sbostic     }
190c1204029Sbostic 
191c1204029Sbostic 
19211d27f68Sbostic     for (;;) {
193c1204029Sbostic 	/*
194c1204029Sbostic 	 * First skip to the start of the member's name, mark that
195c1204029Sbostic 	 * place and skip to the end of it (either white-space or
196c1204029Sbostic 	 * a close paren).
197c1204029Sbostic 	 */
198c1204029Sbostic 	Boolean	doSubst = FALSE; /* TRUE if need to substitute in memName */
199c1204029Sbostic 
200c1204029Sbostic 	while (*cp != '\0' && *cp != ')' && isspace (*cp)) {
201c1204029Sbostic 	    cp++;
202c1204029Sbostic 	}
203c1204029Sbostic 	memName = cp;
204c1204029Sbostic 	while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {
205c1204029Sbostic 	    if (*cp == '$') {
206c1204029Sbostic 		/*
207c1204029Sbostic 		 * Variable spec, so call the Var module to parse the puppy
208c1204029Sbostic 		 * so we can safely advance beyond it...
209c1204029Sbostic 		 */
210c1204029Sbostic 		int 	length;
211c1204029Sbostic 		Boolean	freeIt;
212c1204029Sbostic 		char	*result;
213c1204029Sbostic 
214c1204029Sbostic 		result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
215c1204029Sbostic 		if (result == var_Error) {
216c1204029Sbostic 		    return(FAILURE);
217c1204029Sbostic 		} else {
218c1204029Sbostic 		    doSubst = TRUE;
219c1204029Sbostic 		}
220c1204029Sbostic 
221c1204029Sbostic 		if (freeIt) {
222c1204029Sbostic 		    free(result);
223c1204029Sbostic 		}
224c1204029Sbostic 		cp += length;
225c1204029Sbostic 	    } else {
226c1204029Sbostic 		cp++;
227c1204029Sbostic 	    }
228c1204029Sbostic 	}
229c1204029Sbostic 
230c1204029Sbostic 	/*
231c1204029Sbostic 	 * If the specification ends without a closing parenthesis,
232c1204029Sbostic 	 * chances are there's something wrong (like a missing backslash),
233c1204029Sbostic 	 * so it's better to return failure than allow such things to happen
234c1204029Sbostic 	 */
235c1204029Sbostic 	if (*cp == '\0') {
236c1204029Sbostic 	    printf("No closing parenthesis in archive specification\n");
237c1204029Sbostic 	    return (FAILURE);
238c1204029Sbostic 	}
239c1204029Sbostic 
240c1204029Sbostic 	/*
241c1204029Sbostic 	 * If we didn't move anywhere, we must be done
242c1204029Sbostic 	 */
243c1204029Sbostic 	if (cp == memName) {
244c1204029Sbostic 	    break;
245c1204029Sbostic 	}
246c1204029Sbostic 
247c1204029Sbostic 	saveChar = *cp;
248c1204029Sbostic 	*cp = '\0';
249c1204029Sbostic 
250c1204029Sbostic 	/*
251c1204029Sbostic 	 * XXX: This should be taken care of intelligently by
252c1204029Sbostic 	 * SuffExpandChildren, both for the archive and the member portions.
253c1204029Sbostic 	 */
254c1204029Sbostic 	/*
255c1204029Sbostic 	 * If member contains variables, try and substitute for them.
256c1204029Sbostic 	 * This will slow down archive specs with dynamic sources, of course,
257c1204029Sbostic 	 * since we'll be (non-)substituting them three times, but them's
258c1204029Sbostic 	 * the breaks -- we need to do this since SuffExpandChildren calls
259c1204029Sbostic 	 * us, otherwise we could assume the thing would be taken care of
260c1204029Sbostic 	 * later.
261c1204029Sbostic 	 */
262c1204029Sbostic 	if (doSubst) {
263c1204029Sbostic 	    char    *buf;
264c1204029Sbostic 	    char    *sacrifice;
265c1204029Sbostic 	    char    *oldMemName = memName;
266c1204029Sbostic 
26711d27f68Sbostic 	    memName = Var_Subst(NULL, memName, ctxt, TRUE);
268c1204029Sbostic 
269c1204029Sbostic 	    /*
270c1204029Sbostic 	     * Now form an archive spec and recurse to deal with nested
271c1204029Sbostic 	     * variables and multi-word variable values.... The results
272c1204029Sbostic 	     * are just placed at the end of the nodeLst we're returning.
273c1204029Sbostic 	     */
2741a771901Sbostic 	    buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);
275c1204029Sbostic 
276c1204029Sbostic 	    sprintf(buf, "%s(%s)", libName, memName);
277c1204029Sbostic 
27811d27f68Sbostic 	    if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
279c1204029Sbostic 		/*
280c1204029Sbostic 		 * Must contain dynamic sources, so we can't deal with it now.
281c1204029Sbostic 		 * Just create an ARCHV node for the thing and let
282c1204029Sbostic 		 * SuffExpandChildren handle it...
283c1204029Sbostic 		 */
284c1204029Sbostic 		gn = Targ_FindNode(buf, TARG_CREATE);
285c1204029Sbostic 
286c1204029Sbostic 		if (gn == NILGNODE) {
287c1204029Sbostic 		    free(buf);
288c1204029Sbostic 		    return(FAILURE);
289c1204029Sbostic 		} else {
290c1204029Sbostic 		    gn->type |= OP_ARCHV;
291c1204029Sbostic 		    (void)Lst_AtEnd(nodeLst, (ClientData)gn);
292c1204029Sbostic 		}
293c1204029Sbostic 	    } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
294c1204029Sbostic 		/*
295c1204029Sbostic 		 * Error in nested call -- free buffer and return FAILURE
296c1204029Sbostic 		 * ourselves.
297c1204029Sbostic 		 */
298c1204029Sbostic 		free(buf);
299c1204029Sbostic 		return(FAILURE);
300c1204029Sbostic 	    }
301c1204029Sbostic 	    /*
302c1204029Sbostic 	     * Free buffer and continue with our work.
303c1204029Sbostic 	     */
304c1204029Sbostic 	    free(buf);
305c1204029Sbostic 	} else if (Dir_HasWildcards(memName)) {
306c1204029Sbostic 	    Lst	  members = Lst_Init(FALSE);
307c1204029Sbostic 	    char  *member;
308c1204029Sbostic 
309c1204029Sbostic 	    Dir_Expand(memName, dirSearchPath, members);
310c1204029Sbostic 	    while (!Lst_IsEmpty(members)) {
311c1204029Sbostic 		member = (char *)Lst_DeQueue(members);
312c1204029Sbostic 
313c1204029Sbostic 		sprintf(nameBuf, "%s(%s)", libName, member);
314c1204029Sbostic 		free(member);
315c1204029Sbostic 		gn = Targ_FindNode (nameBuf, TARG_CREATE);
316c1204029Sbostic 		if (gn == NILGNODE) {
317c1204029Sbostic 		    return (FAILURE);
318c1204029Sbostic 		} else {
319c1204029Sbostic 		    /*
320c1204029Sbostic 		     * We've found the node, but have to make sure the rest of
321c1204029Sbostic 		     * the world knows it's an archive member, without having
322c1204029Sbostic 		     * to constantly check for parentheses, so we type the
323c1204029Sbostic 		     * thing with the OP_ARCHV bit before we place it on the
324c1204029Sbostic 		     * end of the provided list.
325c1204029Sbostic 		     */
326c1204029Sbostic 		    gn->type |= OP_ARCHV;
327c1204029Sbostic 		    (void) Lst_AtEnd (nodeLst, (ClientData)gn);
328c1204029Sbostic 		}
329c1204029Sbostic 	    }
330c1204029Sbostic 	    Lst_Destroy(members, NOFREE);
331c1204029Sbostic 	} else {
332c1204029Sbostic 	    sprintf(nameBuf, "%s(%s)", libName, memName);
333c1204029Sbostic 	    gn = Targ_FindNode (nameBuf, TARG_CREATE);
334c1204029Sbostic 	    if (gn == NILGNODE) {
335c1204029Sbostic 		return (FAILURE);
336c1204029Sbostic 	    } else {
337c1204029Sbostic 		/*
338c1204029Sbostic 		 * We've found the node, but have to make sure the rest of the
339c1204029Sbostic 		 * world knows it's an archive member, without having to
340c1204029Sbostic 		 * constantly check for parentheses, so we type the thing with
341c1204029Sbostic 		 * the OP_ARCHV bit before we place it on the end of the
342c1204029Sbostic 		 * provided list.
343c1204029Sbostic 		 */
344c1204029Sbostic 		gn->type |= OP_ARCHV;
345c1204029Sbostic 		(void) Lst_AtEnd (nodeLst, (ClientData)gn);
346c1204029Sbostic 	    }
347c1204029Sbostic 	}
348c1204029Sbostic 	if (doSubst) {
349c1204029Sbostic 	    free(memName);
350c1204029Sbostic 	}
351c1204029Sbostic 
352c1204029Sbostic 	*cp = saveChar;
353c1204029Sbostic     }
354c1204029Sbostic 
355c1204029Sbostic     /*
356c1204029Sbostic      * If substituted libName, free it now, since we need it no longer.
357c1204029Sbostic      */
358c1204029Sbostic     if (subLibName) {
359c1204029Sbostic 	free(libName);
360c1204029Sbostic     }
361c1204029Sbostic 
362c1204029Sbostic     /*
363c1204029Sbostic      * We promised the pointer would be set up at the next non-space, so
364c1204029Sbostic      * we must advance cp there before setting *linePtr... (note that on
365c1204029Sbostic      * entrance to the loop, cp is guaranteed to point at a ')')
366c1204029Sbostic      */
367c1204029Sbostic     do {
368c1204029Sbostic 	cp++;
369c1204029Sbostic     } while (*cp != '\0' && isspace (*cp));
370c1204029Sbostic 
371c1204029Sbostic     *linePtr = cp;
372c1204029Sbostic     return (SUCCESS);
373c1204029Sbostic }
374ad10560bSbostic 
375c1204029Sbostic /*-
376c1204029Sbostic  *-----------------------------------------------------------------------
377c1204029Sbostic  * ArchFindArchive --
378c1204029Sbostic  *	See if the given archive is the one we are looking for. Called
379c1204029Sbostic  *	From ArchStatMember and ArchFindMember via Lst_Find.
380c1204029Sbostic  *
381c1204029Sbostic  * Results:
382c1204029Sbostic  *	0 if it is, non-zero if it isn't.
383c1204029Sbostic  *
384c1204029Sbostic  * Side Effects:
385c1204029Sbostic  *	None.
386c1204029Sbostic  *
387c1204029Sbostic  *-----------------------------------------------------------------------
388c1204029Sbostic  */
389c1204029Sbostic static int
ArchFindArchive(ar,archName)390c1204029Sbostic ArchFindArchive (ar, archName)
391*bbd64002Schristos     ClientData	  ar;	      	  /* Current list element */
392*bbd64002Schristos     ClientData	  archName;  	  /* Name we want */
393c1204029Sbostic {
394*bbd64002Schristos     return (strcmp ((char *) archName, ((Arch *) ar)->name));
395c1204029Sbostic }
396ad10560bSbostic 
397c1204029Sbostic /*-
398c1204029Sbostic  *-----------------------------------------------------------------------
399c1204029Sbostic  * ArchStatMember --
400c1204029Sbostic  *	Locate a member of an archive, given the path of the archive and
401c1204029Sbostic  *	the path of the desired member.
402c1204029Sbostic  *
403c1204029Sbostic  * Results:
404c1204029Sbostic  *	A pointer to the current struct ar_hdr structure for the member. Note
405c1204029Sbostic  *	That no position is returned, so this is not useful for touching
406c1204029Sbostic  *	archive members. This is mostly because we have no assurances that
407c1204029Sbostic  *	The archive will remain constant after we read all the headers, so
408c1204029Sbostic  *	there's not much point in remembering the position...
409c1204029Sbostic  *
410c1204029Sbostic  * Side Effects:
411c1204029Sbostic  *
412c1204029Sbostic  *-----------------------------------------------------------------------
413c1204029Sbostic  */
414c1204029Sbostic static struct ar_hdr *
ArchStatMember(archive,member,hash)415c1204029Sbostic ArchStatMember (archive, member, hash)
416c1204029Sbostic     char	  *archive;   /* Path to the archive */
417c1204029Sbostic     char	  *member;    /* Name of member. If it is a path, only the
418c1204029Sbostic 			       * last component is used. */
419c1204029Sbostic     Boolean	  hash;	      /* TRUE if archive should be hashed if not
420c1204029Sbostic     			       * already so. */
421c1204029Sbostic {
422c1204029Sbostic #define AR_MAX_NAME_LEN	    (sizeof(arh.ar_name)-1)
423c1204029Sbostic     FILE *	  arch;	      /* Stream to archive */
424c1204029Sbostic     int		  size;       /* Size of archive member */
425c1204029Sbostic     char	  *cp;	      /* Useful character pointer */
426c1204029Sbostic     char	  magic[SARMAG];
427c1204029Sbostic     LstNode	  ln;	      /* Lst member containing archive descriptor */
428c1204029Sbostic     Arch	  *ar;	      /* Archive descriptor */
429c1204029Sbostic     Hash_Entry	  *he;	      /* Entry containing member's description */
430c1204029Sbostic     struct ar_hdr arh;        /* archive-member header for reading archive */
431*bbd64002Schristos     char	  memName[MAXPATHLEN+1];
432*bbd64002Schristos     	    	    	    /* Current member name while hashing. */
433c1204029Sbostic 
434c1204029Sbostic     /*
435c1204029Sbostic      * Because of space constraints and similar things, files are archived
436c1204029Sbostic      * using their final path components, not the entire thing, so we need
437c1204029Sbostic      * to point 'member' to the final component, if there is one, to make
438c1204029Sbostic      * the comparisons easier...
439c1204029Sbostic      */
44011d27f68Sbostic     cp = strrchr (member, '/');
441c1204029Sbostic     if (cp != (char *) NULL) {
442c1204029Sbostic 	member = cp + 1;
443c1204029Sbostic     }
444c1204029Sbostic 
445c1204029Sbostic     ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive);
446c1204029Sbostic     if (ln != NILLNODE) {
447c1204029Sbostic 	ar = (Arch *) Lst_Datum (ln);
448c1204029Sbostic 
449da3f38faSbostic 	he = Hash_FindEntry (&ar->members, member);
450c1204029Sbostic 
451c1204029Sbostic 	if (he != (Hash_Entry *) NULL) {
452c1204029Sbostic 	    return ((struct ar_hdr *) Hash_GetValue (he));
453c1204029Sbostic 	} else {
454*bbd64002Schristos 	    /* Try truncated name */
455*bbd64002Schristos 	    char copy[AR_MAX_NAME_LEN+1];
456*bbd64002Schristos 	    int len = strlen (member);
457*bbd64002Schristos 
458*bbd64002Schristos 	    if (len > AR_MAX_NAME_LEN) {
459*bbd64002Schristos 		len = AR_MAX_NAME_LEN;
460*bbd64002Schristos 		strncpy(copy, member, AR_MAX_NAME_LEN);
461*bbd64002Schristos 		copy[AR_MAX_NAME_LEN] = '\0';
462*bbd64002Schristos 	    }
463*bbd64002Schristos 	    if (he = Hash_FindEntry (&ar->members, copy))
464*bbd64002Schristos 		return ((struct ar_hdr *) Hash_GetValue (he));
465c1204029Sbostic 	    return ((struct ar_hdr *) NULL);
466c1204029Sbostic 	}
467c1204029Sbostic     }
468c1204029Sbostic 
469c1204029Sbostic     if (!hash) {
470c1204029Sbostic 	/*
471c1204029Sbostic 	 * Caller doesn't want the thing hashed, just use ArchFindMember
472c1204029Sbostic 	 * to read the header for the member out and close down the stream
473c1204029Sbostic 	 * again. Since the archive is not to be hashed, we assume there's
474c1204029Sbostic 	 * no need to allocate extra room for the header we're returning,
475c1204029Sbostic 	 * so just declare it static.
476c1204029Sbostic 	 */
477c1204029Sbostic 	 static struct ar_hdr	sarh;
478c1204029Sbostic 
479c1204029Sbostic 	 arch = ArchFindMember(archive, member, &sarh, "r");
480c1204029Sbostic 
481c1204029Sbostic 	 if (arch == (FILE *)NULL) {
482c1204029Sbostic 	    return ((struct ar_hdr *)NULL);
483c1204029Sbostic 	} else {
484c1204029Sbostic 	    fclose(arch);
485c1204029Sbostic 	    return (&sarh);
486c1204029Sbostic 	}
487c1204029Sbostic     }
488c1204029Sbostic 
489c1204029Sbostic     /*
490c1204029Sbostic      * We don't have this archive on the list yet, so we want to find out
491c1204029Sbostic      * everything that's in it and cache it so we can get at it quickly.
492c1204029Sbostic      */
493c1204029Sbostic     arch = fopen (archive, "r");
494c1204029Sbostic     if (arch == (FILE *) NULL) {
495c1204029Sbostic 	return ((struct ar_hdr *) NULL);
496c1204029Sbostic     }
497c1204029Sbostic 
498c1204029Sbostic     /*
499c1204029Sbostic      * We use the ARMAG string to make sure this is an archive we
500c1204029Sbostic      * can handle...
501c1204029Sbostic      */
502c1204029Sbostic     if ((fread (magic, SARMAG, 1, arch) != 1) ||
503c1204029Sbostic     	(strncmp (magic, ARMAG, SARMAG) != 0)) {
504c1204029Sbostic 	    fclose (arch);
505c1204029Sbostic 	    return ((struct ar_hdr *) NULL);
506c1204029Sbostic     }
507c1204029Sbostic 
5081a771901Sbostic     ar = (Arch *)emalloc (sizeof (Arch));
509ad10560bSbostic     ar->name = strdup (archive);
510da3f38faSbostic     Hash_InitTable (&ar->members, -1);
511c1204029Sbostic     memName[AR_MAX_NAME_LEN] = '\0';
512c1204029Sbostic 
513c1204029Sbostic     while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {
514c1204029Sbostic 	if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {
515c1204029Sbostic 				 /*
516c1204029Sbostic 				  * The header is bogus, so the archive is bad
517c1204029Sbostic 				  * and there's no way we can recover...
518c1204029Sbostic 				  */
519c1204029Sbostic 				 fclose (arch);
520c1204029Sbostic 				 Hash_DeleteTable (&ar->members);
521c1204029Sbostic 				 free ((Address)ar);
522c1204029Sbostic 				 return ((struct ar_hdr *) NULL);
523c1204029Sbostic 	} else {
524c1204029Sbostic 	    (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name));
525c1204029Sbostic 	    for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
526c1204029Sbostic 		continue;
527c1204029Sbostic 	    }
528c1204029Sbostic 	    cp[1] = '\0';
529c1204029Sbostic 
530*bbd64002Schristos #ifdef AR_EFMT1
531*bbd64002Schristos 	    /*
532*bbd64002Schristos 	     * BSD 4.4 extended AR format: #1/<namelen>, with name as the
533*bbd64002Schristos 	     * first <namelen> bytes of the file
534*bbd64002Schristos 	     */
535*bbd64002Schristos 	    if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
536*bbd64002Schristos 		isdigit(memName[sizeof(AR_EFMT1) - 1])) {
537*bbd64002Schristos 
538*bbd64002Schristos 		unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);
539*bbd64002Schristos 
540*bbd64002Schristos 		if (elen > MAXPATHLEN) {
541*bbd64002Schristos 			fclose (arch);
542*bbd64002Schristos 			Hash_DeleteTable (&ar->members);
543*bbd64002Schristos 			free ((Address)ar);
544*bbd64002Schristos 			return ((struct ar_hdr *) NULL);
545*bbd64002Schristos 		}
546*bbd64002Schristos 		if (fread (memName, elen, 1, arch) != 1) {
547*bbd64002Schristos 			fclose (arch);
548*bbd64002Schristos 			Hash_DeleteTable (&ar->members);
549*bbd64002Schristos 			free ((Address)ar);
550*bbd64002Schristos 			return ((struct ar_hdr *) NULL);
551*bbd64002Schristos 		}
552*bbd64002Schristos 		memName[elen] = '\0';
553*bbd64002Schristos 		fseek (arch, -elen, 1);
554*bbd64002Schristos 		if (DEBUG(ARCH) || DEBUG(MAKE)) {
555*bbd64002Schristos 		    printf("ArchStat: Extended format entry for %s\n", memName);
556*bbd64002Schristos 		}
557*bbd64002Schristos 	    }
558*bbd64002Schristos #endif
559*bbd64002Schristos 
560*bbd64002Schristos 	    he = Hash_CreateEntry (&ar->members, memName, (Boolean *)NULL);
5611a771901Sbostic 	    Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr)));
56211d27f68Sbostic 	    memcpy ((Address)Hash_GetValue (he), (Address)&arh,
563c1204029Sbostic 		sizeof (struct ar_hdr));
564c1204029Sbostic 	}
565c1204029Sbostic 	/*
566c1204029Sbostic 	 * We need to advance the stream's pointer to the start of the
567c1204029Sbostic 	 * next header. Files are padded with newlines to an even-byte
568c1204029Sbostic 	 * boundary, so we need to extract the size of the file from the
569c1204029Sbostic 	 * 'size' field of the header and round it up during the seek.
570c1204029Sbostic 	 */
571c1204029Sbostic 	arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
572*bbd64002Schristos 	size = (int) strtol(arh.ar_size, NULL, 10);
573c1204029Sbostic 	fseek (arch, (size + 1) & ~1, 1);
574c1204029Sbostic     }
575c1204029Sbostic 
576c1204029Sbostic     fclose (arch);
577c1204029Sbostic 
578c1204029Sbostic     (void) Lst_AtEnd (archives, (ClientData) ar);
579c1204029Sbostic 
580c1204029Sbostic     /*
581c1204029Sbostic      * Now that the archive has been read and cached, we can look into
582c1204029Sbostic      * the hash table to find the desired member's header.
583c1204029Sbostic      */
584da3f38faSbostic     he = Hash_FindEntry (&ar->members, member);
585c1204029Sbostic 
586c1204029Sbostic     if (he != (Hash_Entry *) NULL) {
587c1204029Sbostic 	return ((struct ar_hdr *) Hash_GetValue (he));
588c1204029Sbostic     } else {
589c1204029Sbostic 	return ((struct ar_hdr *) NULL);
590c1204029Sbostic     }
591c1204029Sbostic }
592ad10560bSbostic 
593c1204029Sbostic /*-
594c1204029Sbostic  *-----------------------------------------------------------------------
595c1204029Sbostic  * ArchFindMember --
596c1204029Sbostic  *	Locate a member of an archive, given the path of the archive and
597c1204029Sbostic  *	the path of the desired member. If the archive is to be modified,
598c1204029Sbostic  *	the mode should be "r+", if not, it should be "r".
599c1204029Sbostic  *
600c1204029Sbostic  * Results:
601c1204029Sbostic  *	An FILE *, opened for reading and writing, positioned at the
602c1204029Sbostic  *	start of the member's struct ar_hdr, or NULL if the member was
603c1204029Sbostic  *	nonexistent. The current struct ar_hdr for member.
604c1204029Sbostic  *
605c1204029Sbostic  * Side Effects:
606c1204029Sbostic  *	The passed struct ar_hdr structure is filled in.
607c1204029Sbostic  *
608c1204029Sbostic  *-----------------------------------------------------------------------
609c1204029Sbostic  */
610c1204029Sbostic static FILE *
ArchFindMember(archive,member,arhPtr,mode)611c1204029Sbostic ArchFindMember (archive, member, arhPtr, mode)
612c1204029Sbostic     char	  *archive;   /* Path to the archive */
613c1204029Sbostic     char	  *member;    /* Name of member. If it is a path, only the
614c1204029Sbostic 			       * last component is used. */
615c1204029Sbostic     struct ar_hdr *arhPtr;    /* Pointer to header structure to be filled in */
616c1204029Sbostic     char	  *mode;      /* The mode for opening the stream */
617c1204029Sbostic {
618c1204029Sbostic     FILE *	  arch;	      /* Stream to archive */
619c1204029Sbostic     int		  size;       /* Size of archive member */
620c1204029Sbostic     char	  *cp;	      /* Useful character pointer */
621c1204029Sbostic     char	  magic[SARMAG];
622*bbd64002Schristos     int		  len, tlen;
623c1204029Sbostic 
624c1204029Sbostic     arch = fopen (archive, mode);
625c1204029Sbostic     if (arch == (FILE *) NULL) {
626c1204029Sbostic 	return ((FILE *) NULL);
627c1204029Sbostic     }
628c1204029Sbostic 
629c1204029Sbostic     /*
630c1204029Sbostic      * We use the ARMAG string to make sure this is an archive we
631c1204029Sbostic      * can handle...
632c1204029Sbostic      */
633c1204029Sbostic     if ((fread (magic, SARMAG, 1, arch) != 1) ||
634c1204029Sbostic     	(strncmp (magic, ARMAG, SARMAG) != 0)) {
635c1204029Sbostic 	    fclose (arch);
636c1204029Sbostic 	    return ((FILE *) NULL);
637c1204029Sbostic     }
638c1204029Sbostic 
639c1204029Sbostic     /*
640c1204029Sbostic      * Because of space constraints and similar things, files are archived
641c1204029Sbostic      * using their final path components, not the entire thing, so we need
642c1204029Sbostic      * to point 'member' to the final component, if there is one, to make
643c1204029Sbostic      * the comparisons easier...
644c1204029Sbostic      */
64511d27f68Sbostic     cp = strrchr (member, '/');
646c1204029Sbostic     if (cp != (char *) NULL) {
647c1204029Sbostic 	member = cp + 1;
648c1204029Sbostic     }
649*bbd64002Schristos     len = tlen = strlen (member);
650c1204029Sbostic     if (len > sizeof (arhPtr->ar_name)) {
651*bbd64002Schristos 	tlen = sizeof (arhPtr->ar_name);
652c1204029Sbostic     }
653c1204029Sbostic 
654c1204029Sbostic     while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) {
655c1204029Sbostic 	if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) {
656c1204029Sbostic 	     /*
657c1204029Sbostic 	      * The header is bogus, so the archive is bad
658c1204029Sbostic 	      * and there's no way we can recover...
659c1204029Sbostic 	      */
660c1204029Sbostic 	     fclose (arch);
661c1204029Sbostic 	     return ((FILE *) NULL);
662*bbd64002Schristos 	} else if (strncmp (member, arhPtr->ar_name, tlen) == 0) {
663c1204029Sbostic 	    /*
664c1204029Sbostic 	     * If the member's name doesn't take up the entire 'name' field,
665c1204029Sbostic 	     * we have to be careful of matching prefixes. Names are space-
666c1204029Sbostic 	     * padded to the right, so if the character in 'name' at the end
667c1204029Sbostic 	     * of the matched string is anything but a space, this isn't the
668c1204029Sbostic 	     * member we sought.
669c1204029Sbostic 	     */
670*bbd64002Schristos 	    if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){
671*bbd64002Schristos 		goto skip;
672c1204029Sbostic 	    } else {
673c1204029Sbostic 		/*
674c1204029Sbostic 		 * To make life easier, we reposition the file at the start
675c1204029Sbostic 		 * of the header we just read before we return the stream.
676c1204029Sbostic 		 * In a more general situation, it might be better to leave
677c1204029Sbostic 		 * the file at the actual member, rather than its header, but
678c1204029Sbostic 		 * not here...
679c1204029Sbostic 		 */
680c1204029Sbostic 		fseek (arch, -sizeof(struct ar_hdr), 1);
681c1204029Sbostic 		return (arch);
682c1204029Sbostic 	    }
683*bbd64002Schristos 	} else
684*bbd64002Schristos #ifdef AR_EFMT1
685*bbd64002Schristos 		/*
686*bbd64002Schristos 		 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
687*bbd64002Schristos 		 * first <namelen> bytes of the file
688*bbd64002Schristos 		 */
689*bbd64002Schristos 	    if (strncmp(arhPtr->ar_name, AR_EFMT1,
690*bbd64002Schristos 					sizeof(AR_EFMT1) - 1) == 0 &&
691*bbd64002Schristos 		isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) {
692*bbd64002Schristos 
693*bbd64002Schristos 		unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]);
694*bbd64002Schristos 		char ename[MAXPATHLEN];
695*bbd64002Schristos 
696*bbd64002Schristos 		if (elen > MAXPATHLEN) {
697*bbd64002Schristos 			fclose (arch);
698*bbd64002Schristos 			return NULL;
699*bbd64002Schristos 		}
700*bbd64002Schristos 		if (fread (ename, elen, 1, arch) != 1) {
701*bbd64002Schristos 			fclose (arch);
702*bbd64002Schristos 			return NULL;
703*bbd64002Schristos 		}
704*bbd64002Schristos 		ename[elen] = '\0';
705*bbd64002Schristos 		if (DEBUG(ARCH) || DEBUG(MAKE)) {
706*bbd64002Schristos 		    printf("ArchFind: Extended format entry for %s\n", ename);
707*bbd64002Schristos 		}
708*bbd64002Schristos 		if (strncmp(ename, member, len) == 0) {
709*bbd64002Schristos 			/* Found as extended name */
710*bbd64002Schristos 			fseek (arch, -sizeof(struct ar_hdr) - elen, 1);
711*bbd64002Schristos 			return (arch);
712*bbd64002Schristos 		}
713*bbd64002Schristos 		fseek (arch, -elen, 1);
714*bbd64002Schristos 		goto skip;
715*bbd64002Schristos 	} else
716*bbd64002Schristos #endif
717*bbd64002Schristos 	{
718*bbd64002Schristos skip:
719c1204029Sbostic 	    /*
720c1204029Sbostic 	     * This isn't the member we're after, so we need to advance the
721c1204029Sbostic 	     * stream's pointer to the start of the next header. Files are
722c1204029Sbostic 	     * padded with newlines to an even-byte boundary, so we need to
723c1204029Sbostic 	     * extract the size of the file from the 'size' field of the
724c1204029Sbostic 	     * header and round it up during the seek.
725c1204029Sbostic 	     */
726c1204029Sbostic 	    arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0';
727*bbd64002Schristos 	    size = (int) strtol(arhPtr->ar_size, NULL, 10);
728c1204029Sbostic 	    fseek (arch, (size + 1) & ~1, 1);
729c1204029Sbostic 	}
730c1204029Sbostic     }
731c1204029Sbostic 
732c1204029Sbostic     /*
733c1204029Sbostic      * We've looked everywhere, but the member is not to be found. Close the
734c1204029Sbostic      * archive and return NULL -- an error.
735c1204029Sbostic      */
736c1204029Sbostic     fclose (arch);
737c1204029Sbostic     return ((FILE *) NULL);
738c1204029Sbostic }
739ad10560bSbostic 
740c1204029Sbostic /*-
741c1204029Sbostic  *-----------------------------------------------------------------------
742c1204029Sbostic  * Arch_Touch --
743c1204029Sbostic  *	Touch a member of an archive.
744c1204029Sbostic  *
745c1204029Sbostic  * Results:
746c1204029Sbostic  *	The 'time' field of the member's header is updated.
747c1204029Sbostic  *
748c1204029Sbostic  * Side Effects:
749c1204029Sbostic  *	The modification time of the entire archive is also changed.
750c1204029Sbostic  *	For a library, this could necessitate the re-ranlib'ing of the
751c1204029Sbostic  *	whole thing.
752c1204029Sbostic  *
753c1204029Sbostic  *-----------------------------------------------------------------------
754c1204029Sbostic  */
755c1204029Sbostic void
Arch_Touch(gn)756c1204029Sbostic Arch_Touch (gn)
757c1204029Sbostic     GNode	  *gn;	  /* Node of member to touch */
758c1204029Sbostic {
759c1204029Sbostic     FILE *	  arch;	  /* Stream open to archive, positioned properly */
760c1204029Sbostic     struct ar_hdr arh;	  /* Current header describing member */
761*bbd64002Schristos     char *p1, *p2;
762c1204029Sbostic 
763*bbd64002Schristos     arch = ArchFindMember(Var_Value (ARCHIVE, gn, &p1),
764*bbd64002Schristos 			  Var_Value (TARGET, gn, &p2),
765c1204029Sbostic 			  &arh, "r+");
766*bbd64002Schristos     if (p1)
767*bbd64002Schristos 	free(p1);
768*bbd64002Schristos     if (p2)
769*bbd64002Schristos 	free(p2);
7702aa253f0Sbostic     sprintf(arh.ar_date, "%-12ld", (long) now);
771c1204029Sbostic 
772c1204029Sbostic     if (arch != (FILE *) NULL) {
773c1204029Sbostic 	(void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
774c1204029Sbostic 	fclose (arch);
775c1204029Sbostic     }
776c1204029Sbostic }
777ad10560bSbostic 
778c1204029Sbostic /*-
779c1204029Sbostic  *-----------------------------------------------------------------------
780c1204029Sbostic  * Arch_TouchLib --
781c1204029Sbostic  *	Given a node which represents a library, touch the thing, making
782c1204029Sbostic  *	sure that the table of contents also is touched.
783c1204029Sbostic  *
784c1204029Sbostic  * Results:
785c1204029Sbostic  *	None.
786c1204029Sbostic  *
787c1204029Sbostic  * Side Effects:
78815e05a09Sbostic  *	Both the modification time of the library and of the RANLIBMAG
789c1204029Sbostic  *	member are set to 'now'.
790c1204029Sbostic  *
791c1204029Sbostic  *-----------------------------------------------------------------------
792c1204029Sbostic  */
793c1204029Sbostic void
Arch_TouchLib(gn)794c1204029Sbostic Arch_TouchLib (gn)
795c1204029Sbostic     GNode	    *gn;      	/* The node of the library to touch */
796c1204029Sbostic {
797c1204029Sbostic     FILE *	    arch;	/* Stream open to archive */
798c1204029Sbostic     struct ar_hdr   arh;      	/* Header describing table of contents */
799c1204029Sbostic     struct timeval  times[2];	/* Times for utimes() call */
800c1204029Sbostic 
80115e05a09Sbostic     arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+");
8022aa253f0Sbostic     sprintf(arh.ar_date, "%-12ld", (long) now);
803c1204029Sbostic 
804c1204029Sbostic     if (arch != (FILE *) NULL) {
805c1204029Sbostic 	(void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
806c1204029Sbostic 	fclose (arch);
807c1204029Sbostic 
808c1204029Sbostic 	times[0].tv_sec = times[1].tv_sec = now;
809c1204029Sbostic 	times[0].tv_usec = times[1].tv_usec = 0;
810c1204029Sbostic 	utimes(gn->path, times);
811c1204029Sbostic     }
812c1204029Sbostic }
813ad10560bSbostic 
814c1204029Sbostic /*-
815c1204029Sbostic  *-----------------------------------------------------------------------
816c1204029Sbostic  * Arch_MTime --
817c1204029Sbostic  *	Return the modification time of a member of an archive.
818c1204029Sbostic  *
819c1204029Sbostic  * Results:
820c1204029Sbostic  *	The modification time (seconds).
821c1204029Sbostic  *
822c1204029Sbostic  * Side Effects:
823c1204029Sbostic  *	The mtime field of the given node is filled in with the value
824c1204029Sbostic  *	returned by the function.
825c1204029Sbostic  *
826c1204029Sbostic  *-----------------------------------------------------------------------
827c1204029Sbostic  */
828c1204029Sbostic int
Arch_MTime(gn)829c1204029Sbostic Arch_MTime (gn)
830c1204029Sbostic     GNode	  *gn;	      /* Node describing archive member */
831c1204029Sbostic {
832c1204029Sbostic     struct ar_hdr *arhPtr;    /* Header of desired member */
833c1204029Sbostic     int		  modTime;    /* Modification time as an integer */
834*bbd64002Schristos     char *p1, *p2;
835c1204029Sbostic 
836*bbd64002Schristos     arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn, &p1),
837*bbd64002Schristos 			     Var_Value (TARGET, gn, &p2),
838c1204029Sbostic 			     TRUE);
839*bbd64002Schristos     if (p1)
840*bbd64002Schristos 	free(p1);
841*bbd64002Schristos     if (p2)
842*bbd64002Schristos 	free(p2);
843*bbd64002Schristos 
844c1204029Sbostic     if (arhPtr != (struct ar_hdr *) NULL) {
845*bbd64002Schristos 	modTime = (int) strtol(arhPtr->ar_date, NULL, 10);
846c1204029Sbostic     } else {
847c1204029Sbostic 	modTime = 0;
848c1204029Sbostic     }
849c1204029Sbostic 
850c1204029Sbostic     gn->mtime = modTime;
851c1204029Sbostic     return (modTime);
852c1204029Sbostic }
853ad10560bSbostic 
854c1204029Sbostic /*-
855c1204029Sbostic  *-----------------------------------------------------------------------
856c1204029Sbostic  * Arch_MemMTime --
857c1204029Sbostic  *	Given a non-existent archive member's node, get its modification
858c1204029Sbostic  *	time from its archived form, if it exists.
859c1204029Sbostic  *
860c1204029Sbostic  * Results:
861c1204029Sbostic  *	The modification time.
862c1204029Sbostic  *
863c1204029Sbostic  * Side Effects:
864c1204029Sbostic  *	The mtime field is filled in.
865c1204029Sbostic  *
866c1204029Sbostic  *-----------------------------------------------------------------------
867c1204029Sbostic  */
868c1204029Sbostic int
Arch_MemMTime(gn)869c1204029Sbostic Arch_MemMTime (gn)
870c1204029Sbostic     GNode   	  *gn;
871c1204029Sbostic {
872c1204029Sbostic     LstNode 	  ln;
873c1204029Sbostic     GNode   	  *pgn;
874c1204029Sbostic     char    	  *nameStart,
875c1204029Sbostic 		  *nameEnd;
876c1204029Sbostic 
877c1204029Sbostic     if (Lst_Open (gn->parents) != SUCCESS) {
878c1204029Sbostic 	gn->mtime = 0;
879c1204029Sbostic 	return (0);
880c1204029Sbostic     }
881c1204029Sbostic     while ((ln = Lst_Next (gn->parents)) != NILLNODE) {
882c1204029Sbostic 	pgn = (GNode *) Lst_Datum (ln);
883c1204029Sbostic 
884c1204029Sbostic 	if (pgn->type & OP_ARCHV) {
885c1204029Sbostic 	    /*
886c1204029Sbostic 	     * If the parent is an archive specification and is being made
887c1204029Sbostic 	     * and its member's name matches the name of the node we were
888c1204029Sbostic 	     * given, record the modification time of the parent in the
889c1204029Sbostic 	     * child. We keep searching its parents in case some other
890c1204029Sbostic 	     * parent requires this child to exist...
891c1204029Sbostic 	     */
89211d27f68Sbostic 	    nameStart = strchr (pgn->name, '(') + 1;
89311d27f68Sbostic 	    nameEnd = strchr (nameStart, ')');
894c1204029Sbostic 
895c1204029Sbostic 	    if (pgn->make &&
896c1204029Sbostic 		strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) {
897c1204029Sbostic 				     gn->mtime = Arch_MTime(pgn);
898c1204029Sbostic 	    }
899c1204029Sbostic 	} else if (pgn->make) {
900c1204029Sbostic 	    /*
901c1204029Sbostic 	     * Something which isn't a library depends on the existence of
902c1204029Sbostic 	     * this target, so it needs to exist.
903c1204029Sbostic 	     */
904c1204029Sbostic 	    gn->mtime = 0;
905c1204029Sbostic 	    break;
906c1204029Sbostic 	}
907c1204029Sbostic     }
908c1204029Sbostic 
909c1204029Sbostic     Lst_Close (gn->parents);
910c1204029Sbostic 
911c1204029Sbostic     return (gn->mtime);
912c1204029Sbostic }
913ad10560bSbostic 
914c1204029Sbostic /*-
915c1204029Sbostic  *-----------------------------------------------------------------------
916c1204029Sbostic  * Arch_FindLib --
917c1204029Sbostic  *	Search for a library along the given search path.
918c1204029Sbostic  *
919c1204029Sbostic  * Results:
920c1204029Sbostic  *	None.
921c1204029Sbostic  *
922c1204029Sbostic  * Side Effects:
923c1204029Sbostic  *	The node's 'path' field is set to the found path (including the
924c1204029Sbostic  *	actual file name, not -l...). If the system can handle the -L
925c1204029Sbostic  *	flag when linking (or we cannot find the library), we assume that
926c1204029Sbostic  *	the user has placed the .LIBRARIES variable in the final linking
927c1204029Sbostic  *	command (or the linker will know where to find it) and set the
928c1204029Sbostic  *	TARGET variable for this node to be the node's name. Otherwise,
929c1204029Sbostic  *	we set the TARGET variable to be the full path of the library,
930c1204029Sbostic  *	as returned by Dir_FindFile.
931c1204029Sbostic  *
932c1204029Sbostic  *-----------------------------------------------------------------------
933c1204029Sbostic  */
934c1204029Sbostic void
Arch_FindLib(gn,path)935c1204029Sbostic Arch_FindLib (gn, path)
936c1204029Sbostic     GNode	    *gn;	      /* Node of library to find */
937c1204029Sbostic     Lst	    	    path;	      /* Search path */
938c1204029Sbostic {
939c1204029Sbostic     char	    *libName;   /* file name for archive */
940c1204029Sbostic 
9411a771901Sbostic     libName = (char *)emalloc (strlen (gn->name) + 6 - 2);
942c1204029Sbostic     sprintf(libName, "lib%s.a", &gn->name[2]);
943c1204029Sbostic 
944c1204029Sbostic     gn->path = Dir_FindFile (libName, path);
945c1204029Sbostic 
946c1204029Sbostic     free (libName);
947c1204029Sbostic 
948c1204029Sbostic #ifdef LIBRARIES
949c1204029Sbostic     Var_Set (TARGET, gn->name, gn);
950c1204029Sbostic #else
951c1204029Sbostic     Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn);
952c1204029Sbostic #endif LIBRARIES
953c1204029Sbostic }
954ad10560bSbostic 
955c1204029Sbostic /*-
956c1204029Sbostic  *-----------------------------------------------------------------------
957c1204029Sbostic  * Arch_LibOODate --
958c1204029Sbostic  *	Decide if a node with the OP_LIB attribute is out-of-date. Called
959c1204029Sbostic  *	from Make_OODate to make its life easier.
960c1204029Sbostic  *
961c1204029Sbostic  *	There are several ways for a library to be out-of-date that are
962c1204029Sbostic  *	not available to ordinary files. In addition, there are ways
963c1204029Sbostic  *	that are open to regular files that are not available to
964c1204029Sbostic  *	libraries. A library that is only used as a source is never
965c1204029Sbostic  *	considered out-of-date by itself. This does not preclude the
966c1204029Sbostic  *	library's modification time from making its parent be out-of-date.
967c1204029Sbostic  *	A library will be considered out-of-date for any of these reasons,
968c1204029Sbostic  *	given that it is a target on a dependency line somewhere:
969c1204029Sbostic  *	    Its modification time is less than that of one of its
970c1204029Sbostic  *	    	  sources (gn->mtime < gn->cmtime).
971c1204029Sbostic  *	    Its modification time is greater than the time at which the
972c1204029Sbostic  *	    	  make began (i.e. it's been modified in the course
973c1204029Sbostic  *	    	  of the make, probably by archiving).
974*bbd64002Schristos  *	    The modification time of one of its sources is greater than
975*bbd64002Schristos  *		  the one of its RANLIBMAG member (i.e. its table of contents
976*bbd64002Schristos  *	    	  is out-of-date). We don't compare of the archive time
977*bbd64002Schristos  *		  vs. TOC time because they can be too close. In my
978*bbd64002Schristos  *		  opinion we should not bother with the TOC at all since
979*bbd64002Schristos  *		  this is used by 'ar' rules that affect the data contents
980*bbd64002Schristos  *		  of the archive, not by ranlib rules, which affect the
981*bbd64002Schristos  *		  TOC.
982c1204029Sbostic  *
983c1204029Sbostic  * Results:
984c1204029Sbostic  *	TRUE if the library is out-of-date. FALSE otherwise.
985c1204029Sbostic  *
986c1204029Sbostic  * Side Effects:
987c1204029Sbostic  *	The library will be hashed if it hasn't been already.
988c1204029Sbostic  *
989c1204029Sbostic  *-----------------------------------------------------------------------
990c1204029Sbostic  */
991c1204029Sbostic Boolean
Arch_LibOODate(gn)992c1204029Sbostic Arch_LibOODate (gn)
993c1204029Sbostic     GNode   	  *gn;  	/* The library's graph node */
994c1204029Sbostic {
995c1204029Sbostic     Boolean 	  oodate;
996c1204029Sbostic 
997c1204029Sbostic     if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
998c1204029Sbostic 	oodate = FALSE;
999c1204029Sbostic     } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) {
1000c1204029Sbostic 	oodate = TRUE;
1001c1204029Sbostic     } else {
1002c1204029Sbostic 	struct ar_hdr  	*arhPtr;    /* Header for __.SYMDEF */
1003c1204029Sbostic 	int 	  	modTimeTOC; /* The table-of-contents's mod time */
1004c1204029Sbostic 
100515e05a09Sbostic 	arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE);
1006c1204029Sbostic 
1007c1204029Sbostic 	if (arhPtr != (struct ar_hdr *)NULL) {
1008*bbd64002Schristos 	    modTimeTOC = (int) strtol(arhPtr->ar_date, NULL, 10);
1009c1204029Sbostic 
1010c1204029Sbostic 	    if (DEBUG(ARCH) || DEBUG(MAKE)) {
101115e05a09Sbostic 		printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
1012c1204029Sbostic 	    }
1013*bbd64002Schristos 	    oodate = (gn->cmtime > modTimeTOC);
1014c1204029Sbostic 	} else {
1015c1204029Sbostic 	    /*
1016c1204029Sbostic 	     * A library w/o a table of contents is out-of-date
1017c1204029Sbostic 	     */
1018c1204029Sbostic 	    if (DEBUG(ARCH) || DEBUG(MAKE)) {
1019c1204029Sbostic 		printf("No t.o.c....");
1020c1204029Sbostic 	    }
1021c1204029Sbostic 	    oodate = TRUE;
1022c1204029Sbostic 	}
1023c1204029Sbostic     }
1024c1204029Sbostic     return (oodate);
1025c1204029Sbostic }
1026ad10560bSbostic 
1027c1204029Sbostic /*-
1028c1204029Sbostic  *-----------------------------------------------------------------------
1029c1204029Sbostic  * Arch_Init --
1030c1204029Sbostic  *	Initialize things for this module.
1031c1204029Sbostic  *
1032c1204029Sbostic  * Results:
1033c1204029Sbostic  *	None.
1034c1204029Sbostic  *
1035c1204029Sbostic  * Side Effects:
1036c1204029Sbostic  *	The 'archives' list is initialized.
1037c1204029Sbostic  *
1038c1204029Sbostic  *-----------------------------------------------------------------------
1039c1204029Sbostic  */
1040c1204029Sbostic void
Arch_Init()1041c1204029Sbostic Arch_Init ()
1042c1204029Sbostic {
1043c1204029Sbostic     archives = Lst_Init (FALSE);
1044c1204029Sbostic }
1045*bbd64002Schristos 
1046*bbd64002Schristos 
1047*bbd64002Schristos 
1048*bbd64002Schristos /*-
1049*bbd64002Schristos  *-----------------------------------------------------------------------
1050*bbd64002Schristos  * Arch_End --
1051*bbd64002Schristos  *	Cleanup things for this module.
1052*bbd64002Schristos  *
1053*bbd64002Schristos  * Results:
1054*bbd64002Schristos  *	None.
1055*bbd64002Schristos  *
1056*bbd64002Schristos  * Side Effects:
1057*bbd64002Schristos  *	The 'archives' list is freed
1058*bbd64002Schristos  *
1059*bbd64002Schristos  *-----------------------------------------------------------------------
1060*bbd64002Schristos  */
1061*bbd64002Schristos void
Arch_End()1062*bbd64002Schristos Arch_End ()
1063*bbd64002Schristos {
1064*bbd64002Schristos     Lst_Destroy(archives, ArchFree);
1065*bbd64002Schristos }
1066