xref: /freebsd/contrib/bmake/arch.c (revision a8c56be47166295d37600ff81fc1857db87b3a9b)
1*a8c56be4SSimon J. Gerraty /*	$NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
7106b9b3e0SSimon J. Gerraty /*
7206b9b3e0SSimon J. Gerraty  * Manipulate libraries, archives and their members.
733955d011SMarcel Moolenaar  *
74e2eeea75SSimon J. Gerraty  * The first time an archive is referenced, all of its members' headers are
75e2eeea75SSimon J. Gerraty  * read and cached and the archive closed again.  All cached archives are kept
76e2eeea75SSimon J. Gerraty  * on a list which is searched each time an archive member is referenced.
773955d011SMarcel Moolenaar  *
783955d011SMarcel Moolenaar  * The interface to this module is:
79e2eeea75SSimon J. Gerraty  *
80e2eeea75SSimon J. Gerraty  *	Arch_Init	Initialize this module.
81e2eeea75SSimon J. Gerraty  *
82e2eeea75SSimon J. Gerraty  *	Arch_End	Clean up this module.
83e2eeea75SSimon J. Gerraty  *
84956e45f6SSimon J. Gerraty  *	Arch_ParseArchive
85e2eeea75SSimon J. Gerraty  *			Parse an archive specification such as
86e2eeea75SSimon J. Gerraty  *			"archive.a(member1 member2)".
873955d011SMarcel Moolenaar  *
883955d011SMarcel Moolenaar  *	Arch_Touch	Alter the modification time of the archive
893955d011SMarcel Moolenaar  *			member described by the given node to be
90e2eeea75SSimon J. Gerraty  *			the time when make was started.
913955d011SMarcel Moolenaar  *
923955d011SMarcel Moolenaar  *	Arch_TouchLib	Update the modification time of the library
933955d011SMarcel Moolenaar  *			described by the given node. This is special
943955d011SMarcel Moolenaar  *			because it also updates the modification time
953955d011SMarcel Moolenaar  *			of the library's table of contents.
963955d011SMarcel Moolenaar  *
97e2eeea75SSimon J. Gerraty  *	Arch_UpdateMTime
98e2eeea75SSimon J. Gerraty  *			Find the modification time of a member of
99e2eeea75SSimon J. Gerraty  *			an archive *in the archive* and place it in the
100e2eeea75SSimon J. Gerraty  *			member's GNode.
1013955d011SMarcel Moolenaar  *
102e2eeea75SSimon J. Gerraty  *	Arch_UpdateMemberMTime
103e2eeea75SSimon J. Gerraty  *			Find the modification time of a member of
1043955d011SMarcel Moolenaar  *			an archive. Called when the member doesn't
1053955d011SMarcel Moolenaar  *			already exist. Looks in the archive for the
1063955d011SMarcel Moolenaar  *			modification time. Returns the modification
1073955d011SMarcel Moolenaar  *			time.
1083955d011SMarcel Moolenaar  *
1093955d011SMarcel Moolenaar  *	Arch_FindLib	Search for a library along a path. The
1103955d011SMarcel Moolenaar  *			library name in the GNode should be in
1113955d011SMarcel Moolenaar  *			-l<name> format.
1123955d011SMarcel Moolenaar  *
113e2eeea75SSimon J. Gerraty  *	Arch_LibOODate	Decide if a library node is out-of-date.
1143955d011SMarcel Moolenaar  */
1153955d011SMarcel Moolenaar 
1163955d011SMarcel Moolenaar #ifdef HAVE_CONFIG_H
1173955d011SMarcel Moolenaar # include "config.h"
1183955d011SMarcel Moolenaar #endif
1193955d011SMarcel Moolenaar #include <sys/types.h>
1203955d011SMarcel Moolenaar #include <sys/stat.h>
1213955d011SMarcel Moolenaar #include <sys/time.h>
1223955d011SMarcel Moolenaar #include <sys/param.h>
1233955d011SMarcel Moolenaar #ifdef HAVE_AR_H
1243955d011SMarcel Moolenaar #include <ar.h>
1253955d011SMarcel Moolenaar #else
1263955d011SMarcel Moolenaar struct ar_hdr {
1273955d011SMarcel Moolenaar         char ar_name[16];               /* name */
1283955d011SMarcel Moolenaar         char ar_date[12];               /* modification time */
1293955d011SMarcel Moolenaar         char ar_uid[6];                 /* user id */
1303955d011SMarcel Moolenaar         char ar_gid[6];                 /* group id */
1313955d011SMarcel Moolenaar         char ar_mode[8];                /* octal file permissions */
1323955d011SMarcel Moolenaar         char ar_size[10];               /* size in bytes */
1333955d011SMarcel Moolenaar #ifndef ARFMAG
1343955d011SMarcel Moolenaar #define ARFMAG  "`\n"
1353955d011SMarcel Moolenaar #endif
1363955d011SMarcel Moolenaar         char ar_fmag[2];                /* consistency check */
1373955d011SMarcel Moolenaar };
1383955d011SMarcel Moolenaar #endif
1393955d011SMarcel Moolenaar #if defined(HAVE_RANLIB_H) && !(defined(__ELF__) || defined(NO_RANLIB))
1403955d011SMarcel Moolenaar #include <ranlib.h>
1413955d011SMarcel Moolenaar #endif
1423955d011SMarcel Moolenaar #ifdef HAVE_UTIME_H
1433955d011SMarcel Moolenaar #include <utime.h>
1443955d011SMarcel Moolenaar #endif
1453955d011SMarcel Moolenaar 
1463955d011SMarcel Moolenaar #include "make.h"
1473955d011SMarcel Moolenaar #include "dir.h"
1483955d011SMarcel Moolenaar 
149956e45f6SSimon J. Gerraty /*	"@(#)arch.c	8.2 (Berkeley) 1/2/94"	*/
150*a8c56be4SSimon J. Gerraty MAKE_RCSID("$NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $");
1513955d011SMarcel Moolenaar 
152956e45f6SSimon J. Gerraty typedef struct List ArchList;
153956e45f6SSimon J. Gerraty typedef struct ListNode ArchListNode;
154956e45f6SSimon J. Gerraty 
15506b9b3e0SSimon J. Gerraty static ArchList archives;	/* The archives we've already examined */
1563955d011SMarcel Moolenaar 
1573955d011SMarcel Moolenaar typedef struct Arch {
158548bfc56SSimon J. Gerraty 	char *name;
159956e45f6SSimon J. Gerraty 	HashTable members;	/* All the members of the archive described
1603955d011SMarcel Moolenaar 				 * by <name, struct ar_hdr *> key/value pairs */
1613955d011SMarcel Moolenaar 	char *fnametab;		/* Extended name table strings */
1623955d011SMarcel Moolenaar 	size_t fnamesize;	/* Size of the string table */
1633955d011SMarcel Moolenaar } Arch;
1643955d011SMarcel Moolenaar 
1652c3632d1SSimon J. Gerraty static FILE *ArchFindMember(const char *, const char *,
1662c3632d1SSimon J. Gerraty 			    struct ar_hdr *, const char *);
1673955d011SMarcel Moolenaar #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__)
1683955d011SMarcel Moolenaar #define SVR4ARCHIVES
1693955d011SMarcel Moolenaar static int ArchSVR4Entry(Arch *, char *, size_t, FILE *);
1703955d011SMarcel Moolenaar #endif
1713955d011SMarcel Moolenaar 
1723955d011SMarcel Moolenaar 
1733955d011SMarcel Moolenaar #if defined(_AIX)
1743955d011SMarcel Moolenaar # define AR_NAME _ar_name.ar_name
1753955d011SMarcel Moolenaar # define AR_FMAG _ar_name.ar_fmag
1763955d011SMarcel Moolenaar # define SARMAG  SAIAMAG
1773955d011SMarcel Moolenaar # define ARMAG   AIAMAG
1783955d011SMarcel Moolenaar # define ARFMAG  AIAFMAG
1793955d011SMarcel Moolenaar #endif
1803955d011SMarcel Moolenaar #ifndef  AR_NAME
1813955d011SMarcel Moolenaar # define AR_NAME ar_name
1823955d011SMarcel Moolenaar #endif
1833955d011SMarcel Moolenaar #ifndef  AR_DATE
1843955d011SMarcel Moolenaar # define AR_DATE ar_date
1853955d011SMarcel Moolenaar #endif
1863955d011SMarcel Moolenaar #ifndef  AR_SIZE
1873955d011SMarcel Moolenaar # define AR_SIZE ar_size
1883955d011SMarcel Moolenaar #endif
1893955d011SMarcel Moolenaar #ifndef  AR_FMAG
1903955d011SMarcel Moolenaar # define AR_FMAG ar_fmag
1913955d011SMarcel Moolenaar #endif
1923955d011SMarcel Moolenaar #ifndef ARMAG
1933955d011SMarcel Moolenaar # define ARMAG	"!<arch>\n"
1943955d011SMarcel Moolenaar #endif
1953955d011SMarcel Moolenaar #ifndef SARMAG
1963955d011SMarcel Moolenaar # define SARMAG	8
1973955d011SMarcel Moolenaar #endif
1983955d011SMarcel Moolenaar 
1993955d011SMarcel Moolenaar 
2003955d011SMarcel Moolenaar #ifdef CLEANUP
2013955d011SMarcel Moolenaar static void
ArchFree(Arch * a)202548bfc56SSimon J. Gerraty ArchFree(Arch *a)
2033955d011SMarcel Moolenaar {
204956e45f6SSimon J. Gerraty 	HashIter hi;
2053955d011SMarcel Moolenaar 
206956e45f6SSimon J. Gerraty 	HashIter_Init(&hi, &a->members);
2078d5c8e21SSimon J. Gerraty 	while (HashIter_Next(&hi))
208956e45f6SSimon J. Gerraty 		free(hi.entry->value);
2093955d011SMarcel Moolenaar 
2103955d011SMarcel Moolenaar 	free(a->name);
2113955d011SMarcel Moolenaar 	free(a->fnametab);
212956e45f6SSimon J. Gerraty 	HashTable_Done(&a->members);
2133955d011SMarcel Moolenaar 	free(a);
2143955d011SMarcel Moolenaar }
2153955d011SMarcel Moolenaar #endif
2163955d011SMarcel Moolenaar 
217b0c40a00SSimon J. Gerraty /* Return "archive(member)". */
218548bfc56SSimon J. Gerraty MAKE_ATTR_NOINLINE static char *
FullName(const char * archive,const char * member)219b0c40a00SSimon J. Gerraty FullName(const char *archive, const char *member)
220b0c40a00SSimon J. Gerraty {
221548bfc56SSimon J. Gerraty 	Buffer buf;
222548bfc56SSimon J. Gerraty 	Buf_Init(&buf);
223548bfc56SSimon J. Gerraty 	Buf_AddStr(&buf, archive);
224548bfc56SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
225548bfc56SSimon J. Gerraty 	Buf_AddStr(&buf, member);
226548bfc56SSimon J. Gerraty 	Buf_AddStr(&buf, ")");
227548bfc56SSimon J. Gerraty 	return Buf_DoneData(&buf);
228b0c40a00SSimon J. Gerraty }
2293955d011SMarcel Moolenaar 
230e2eeea75SSimon J. Gerraty /*
231e2eeea75SSimon J. Gerraty  * Parse an archive specification such as "archive.a(member1 member2.${EXT})",
232548bfc56SSimon J. Gerraty  * adding nodes for the expanded members to gns.  If successful, advance pp
233548bfc56SSimon J. Gerraty  * beyond the archive specification and any trailing whitespace.
2343955d011SMarcel Moolenaar  */
235b0c40a00SSimon J. Gerraty bool
Arch_ParseArchive(char ** pp,GNodeList * gns,GNode * scope)236dba7b0efSSimon J. Gerraty Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
2373955d011SMarcel Moolenaar {
2389f45a3c8SSimon J. Gerraty 	char *spec;		/* For modifying some bytes of *pp */
2399f45a3c8SSimon J. Gerraty 	const char *cp;		/* Pointer into line */
2403955d011SMarcel Moolenaar 	GNode *gn;		/* New node */
2419f45a3c8SSimon J. Gerraty 	FStr lib;		/* Library-part of specification */
24212904384SSimon J. Gerraty 	FStr mem;		/* Member-part of specification */
2433955d011SMarcel Moolenaar 	char saveChar;		/* Ending delimiter of member-name */
244d5e0a182SSimon J. Gerraty 	bool expandLib;		/* Whether the parsed lib contains
2459f45a3c8SSimon J. Gerraty 				 * expressions that need to be expanded */
2463955d011SMarcel Moolenaar 
2479f45a3c8SSimon J. Gerraty 	spec = *pp;
2489f45a3c8SSimon J. Gerraty 	lib = FStr_InitRefer(spec);
2499f45a3c8SSimon J. Gerraty 	expandLib = false;
2503955d011SMarcel Moolenaar 
2519f45a3c8SSimon J. Gerraty 	for (cp = lib.str; *cp != '(' && *cp != '\0';) {
2523955d011SMarcel Moolenaar 		if (*cp == '$') {
253d5e0a182SSimon J. Gerraty 			/* Expand nested expressions. */
25406b9b3e0SSimon J. Gerraty 			/* XXX: This code can probably be shortened. */
255956e45f6SSimon J. Gerraty 			const char *nested_p = cp;
25606b9b3e0SSimon J. Gerraty 			FStr result;
257b0c40a00SSimon J. Gerraty 			bool isError;
2583955d011SMarcel Moolenaar 
259e2eeea75SSimon J. Gerraty 			/* XXX: is expanded twice: once here and once below */
2608d5c8e21SSimon J. Gerraty 			result = Var_Parse(&nested_p, scope,
2618d5c8e21SSimon J. Gerraty 			    VARE_EVAL_DEFINED);
262956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
26306b9b3e0SSimon J. Gerraty 			isError = result.str == var_Error;
26406b9b3e0SSimon J. Gerraty 			FStr_Done(&result);
2652c3632d1SSimon J. Gerraty 			if (isError)
266b0c40a00SSimon J. Gerraty 				return false;
267be19d90bSSimon J. Gerraty 
2689f45a3c8SSimon J. Gerraty 			expandLib = true;
269956e45f6SSimon J. Gerraty 			cp += nested_p - cp;
270956e45f6SSimon J. Gerraty 		} else
271956e45f6SSimon J. Gerraty 			cp++;
2723955d011SMarcel Moolenaar 	}
2733955d011SMarcel Moolenaar 
2749f45a3c8SSimon J. Gerraty 	spec[cp++ - spec] = '\0';
2759f45a3c8SSimon J. Gerraty 	if (expandLib)
2768d5c8e21SSimon J. Gerraty 		Var_Expand(&lib, scope, VARE_EVAL_DEFINED);
2773955d011SMarcel Moolenaar 
2783955d011SMarcel Moolenaar 	for (;;) {
2793955d011SMarcel Moolenaar 		/*
2803955d011SMarcel Moolenaar 		 * First skip to the start of the member's name, mark that
2813955d011SMarcel Moolenaar 		 * place and skip to the end of it (either white-space or
2823955d011SMarcel Moolenaar 		 * a close paren).
2833955d011SMarcel Moolenaar 		 */
284b0c40a00SSimon J. Gerraty 		bool doSubst = false;
2853955d011SMarcel Moolenaar 
2869f45a3c8SSimon J. Gerraty 		cpp_skip_whitespace(&cp);
287956e45f6SSimon J. Gerraty 
28812904384SSimon J. Gerraty 		mem = FStr_InitRefer(cp);
289956e45f6SSimon J. Gerraty 		while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) {
2903955d011SMarcel Moolenaar 			if (*cp == '$') {
291d5e0a182SSimon J. Gerraty 				/* Expand nested expressions. */
2929f45a3c8SSimon J. Gerraty 				/*
2939f45a3c8SSimon J. Gerraty 				 * XXX: This code can probably be shortened.
2949f45a3c8SSimon J. Gerraty 				 */
29506b9b3e0SSimon J. Gerraty 				FStr result;
296b0c40a00SSimon J. Gerraty 				bool isError;
297956e45f6SSimon J. Gerraty 				const char *nested_p = cp;
2983955d011SMarcel Moolenaar 
2998c973ee2SSimon J. Gerraty 				result = Var_Parse(&nested_p, scope,
3008d5c8e21SSimon J. Gerraty 				    VARE_EVAL_DEFINED);
301956e45f6SSimon J. Gerraty 				/* TODO: handle errors */
30206b9b3e0SSimon J. Gerraty 				isError = result.str == var_Error;
30306b9b3e0SSimon J. Gerraty 				FStr_Done(&result);
304be19d90bSSimon J. Gerraty 
3052c3632d1SSimon J. Gerraty 				if (isError)
306b0c40a00SSimon J. Gerraty 					return false;
3073955d011SMarcel Moolenaar 
308b0c40a00SSimon J. Gerraty 				doSubst = true;
309956e45f6SSimon J. Gerraty 				cp += nested_p - cp;
3103955d011SMarcel Moolenaar 			} else {
3113955d011SMarcel Moolenaar 				cp++;
3123955d011SMarcel Moolenaar 			}
3133955d011SMarcel Moolenaar 		}
3143955d011SMarcel Moolenaar 
3153955d011SMarcel Moolenaar 		if (*cp == '\0') {
31606b9b3e0SSimon J. Gerraty 			Parse_Error(PARSE_FATAL,
317*a8c56be4SSimon J. Gerraty 			    "Missing \")\" in archive specification");
318b0c40a00SSimon J. Gerraty 			return false;
3193955d011SMarcel Moolenaar 		}
3203955d011SMarcel Moolenaar 
32112904384SSimon J. Gerraty 		if (cp == mem.str)
3223955d011SMarcel Moolenaar 			break;
3233955d011SMarcel Moolenaar 
3243955d011SMarcel Moolenaar 		saveChar = *cp;
3259f45a3c8SSimon J. Gerraty 		spec[cp - spec] = '\0';
3263955d011SMarcel Moolenaar 
3273955d011SMarcel Moolenaar 		/*
3283955d011SMarcel Moolenaar 		 * XXX: This should be taken care of intelligently by
32906b9b3e0SSimon J. Gerraty 		 * SuffExpandChildren, both for the archive and the member
33006b9b3e0SSimon J. Gerraty 		 * portions.
3313955d011SMarcel Moolenaar 		 */
3323955d011SMarcel Moolenaar 		/*
3333955d011SMarcel Moolenaar 		 * If member contains variables, try and substitute for them.
3344fde40d9SSimon J. Gerraty 		 * This slows down archive specs with dynamic sources, since
3354fde40d9SSimon J. Gerraty 		 * they are (non-)substituted three times, but we need to do
3364fde40d9SSimon J. Gerraty 		 * this since SuffExpandChildren calls us, otherwise we could
3374fde40d9SSimon J. Gerraty 		 * assume the substitutions would be taken care of later.
3383955d011SMarcel Moolenaar 		 */
3393955d011SMarcel Moolenaar 		if (doSubst) {
34006b9b3e0SSimon J. Gerraty 			char *fullName;
3419f45a3c8SSimon J. Gerraty 			char *p;
34212904384SSimon J. Gerraty 			const char *unexpandedMem = mem.str;
3433955d011SMarcel Moolenaar 
3448d5c8e21SSimon J. Gerraty 			Var_Expand(&mem, scope, VARE_EVAL_DEFINED);
3453955d011SMarcel Moolenaar 
3463955d011SMarcel Moolenaar 			/*
34706b9b3e0SSimon J. Gerraty 			 * Now form an archive spec and recurse to deal with
34806b9b3e0SSimon J. Gerraty 			 * nested variables and multi-word variable values.
3493955d011SMarcel Moolenaar 			 */
3509f45a3c8SSimon J. Gerraty 			fullName = FullName(lib.str, mem.str);
35106b9b3e0SSimon J. Gerraty 			p = fullName;
3523955d011SMarcel Moolenaar 
35312904384SSimon J. Gerraty 			if (strcmp(mem.str, unexpandedMem) == 0) {
3543955d011SMarcel Moolenaar 				/*
35506b9b3e0SSimon J. Gerraty 				 * Must contain dynamic sources, so we can't
35606b9b3e0SSimon J. Gerraty 				 * deal with it now. Just create an ARCHV node
357548bfc56SSimon J. Gerraty 				 * and let SuffExpandChildren handle it.
3583955d011SMarcel Moolenaar 				 */
35906b9b3e0SSimon J. Gerraty 				gn = Targ_GetNode(fullName);
3603955d011SMarcel Moolenaar 				gn->type |= OP_ARCHV;
36106b9b3e0SSimon J. Gerraty 				Lst_Append(gns, gn);
362956e45f6SSimon J. Gerraty 
363dba7b0efSSimon J. Gerraty 			} else if (!Arch_ParseArchive(&p, gns, scope)) {
364956e45f6SSimon J. Gerraty 				/* Error in nested call. */
36506b9b3e0SSimon J. Gerraty 				free(fullName);
36606b9b3e0SSimon J. Gerraty 				/* XXX: does unexpandedMemName leak? */
367b0c40a00SSimon J. Gerraty 				return false;
3683955d011SMarcel Moolenaar 			}
36906b9b3e0SSimon J. Gerraty 			free(fullName);
37006b9b3e0SSimon J. Gerraty 			/* XXX: does unexpandedMemName leak? */
3713955d011SMarcel Moolenaar 
37212904384SSimon J. Gerraty 		} else if (Dir_HasWildcards(mem.str)) {
37306b9b3e0SSimon J. Gerraty 			StringList members = LST_INIT;
37412904384SSimon J. Gerraty 			SearchPath_Expand(&dirSearchPath, mem.str, &members);
375956e45f6SSimon J. Gerraty 
37606b9b3e0SSimon J. Gerraty 			while (!Lst_IsEmpty(&members)) {
37706b9b3e0SSimon J. Gerraty 				char *member = Lst_Dequeue(&members);
3789f45a3c8SSimon J. Gerraty 				char *fullname = FullName(lib.str, member);
3793955d011SMarcel Moolenaar 				free(member);
3802c3632d1SSimon J. Gerraty 
381956e45f6SSimon J. Gerraty 				gn = Targ_GetNode(fullname);
382956e45f6SSimon J. Gerraty 				free(fullname);
383956e45f6SSimon J. Gerraty 
3843955d011SMarcel Moolenaar 				gn->type |= OP_ARCHV;
38506b9b3e0SSimon J. Gerraty 				Lst_Append(gns, gn);
3863955d011SMarcel Moolenaar 			}
38706b9b3e0SSimon J. Gerraty 			Lst_Done(&members);
3882c3632d1SSimon J. Gerraty 
3893955d011SMarcel Moolenaar 		} else {
3909f45a3c8SSimon J. Gerraty 			char *fullname = FullName(lib.str, mem.str);
391956e45f6SSimon J. Gerraty 			gn = Targ_GetNode(fullname);
392956e45f6SSimon J. Gerraty 			free(fullname);
393956e45f6SSimon J. Gerraty 
3943955d011SMarcel Moolenaar 			gn->type |= OP_ARCHV;
39506b9b3e0SSimon J. Gerraty 			Lst_Append(gns, gn);
3963955d011SMarcel Moolenaar 		}
39712904384SSimon J. Gerraty 		FStr_Done(&mem);
3983955d011SMarcel Moolenaar 
3999f45a3c8SSimon J. Gerraty 		spec[cp - spec] = saveChar;
4003955d011SMarcel Moolenaar 	}
4013955d011SMarcel Moolenaar 
4029f45a3c8SSimon J. Gerraty 	FStr_Done(&lib);
4033955d011SMarcel Moolenaar 
404956e45f6SSimon J. Gerraty 	cp++;			/* skip the ')' */
4059f45a3c8SSimon J. Gerraty 	cpp_skip_whitespace(&cp);
4069f45a3c8SSimon J. Gerraty 	*pp += cp - *pp;
407b0c40a00SSimon J. Gerraty 	return true;
4083955d011SMarcel Moolenaar }
4093955d011SMarcel Moolenaar 
41006b9b3e0SSimon J. Gerraty /*
411548bfc56SSimon J. Gerraty  * Locate a member in an archive.
412e2eeea75SSimon J. Gerraty  *
413e2eeea75SSimon J. Gerraty  * See ArchFindMember for an almost identical copy of this code.
4143955d011SMarcel Moolenaar  */
4153955d011SMarcel Moolenaar static struct ar_hdr *
ArchStatMember(const char * archive,const char * member,bool addToCache)416b0c40a00SSimon J. Gerraty ArchStatMember(const char *archive, const char *member, bool addToCache)
4173955d011SMarcel Moolenaar {
4186a7405f5SSimon J. Gerraty #define AR_MAX_NAME_LEN (sizeof arh.AR_NAME - 1)
41906b9b3e0SSimon J. Gerraty 	FILE *arch;
4202c3632d1SSimon J. Gerraty 	size_t size;		/* Size of archive member */
4213955d011SMarcel Moolenaar 	char magic[SARMAG];
422956e45f6SSimon J. Gerraty 	ArchListNode *ln;
423548bfc56SSimon J. Gerraty 	Arch *ar;
424548bfc56SSimon J. Gerraty 	struct ar_hdr arh;
4253955d011SMarcel Moolenaar 	char memName[MAXPATHLEN + 1];
4263955d011SMarcel Moolenaar 	/* Current member name while hashing. */
4273955d011SMarcel Moolenaar 
42806b9b3e0SSimon J. Gerraty 	member = str_basename(member);
429956e45f6SSimon J. Gerraty 
43006b9b3e0SSimon J. Gerraty 	for (ln = archives.first; ln != NULL; ln = ln->next) {
431e2eeea75SSimon J. Gerraty 		const Arch *a = ln->datum;
432e2eeea75SSimon J. Gerraty 		if (strcmp(a->name, archive) == 0)
433956e45f6SSimon J. Gerraty 			break;
4343955d011SMarcel Moolenaar 	}
4353955d011SMarcel Moolenaar 
4363955d011SMarcel Moolenaar 	if (ln != NULL) {
437956e45f6SSimon J. Gerraty 		struct ar_hdr *hdr;
4383955d011SMarcel Moolenaar 
439956e45f6SSimon J. Gerraty 		ar = ln->datum;
440956e45f6SSimon J. Gerraty 		hdr = HashTable_FindValue(&ar->members, member);
441956e45f6SSimon J. Gerraty 		if (hdr != NULL)
442956e45f6SSimon J. Gerraty 			return hdr;
4433955d011SMarcel Moolenaar 
444956e45f6SSimon J. Gerraty 		{
4453955d011SMarcel Moolenaar 			/* Try truncated name */
4463955d011SMarcel Moolenaar 			char copy[AR_MAX_NAME_LEN + 1];
4473955d011SMarcel Moolenaar 			size_t len = strlen(member);
4483955d011SMarcel Moolenaar 
4493955d011SMarcel Moolenaar 			if (len > AR_MAX_NAME_LEN) {
4502c3632d1SSimon J. Gerraty 				snprintf(copy, sizeof copy, "%s", member);
451956e45f6SSimon J. Gerraty 				hdr = HashTable_FindValue(&ar->members, copy);
452e2eeea75SSimon J. Gerraty 			}
453956e45f6SSimon J. Gerraty 			return hdr;
4543955d011SMarcel Moolenaar 		}
4553955d011SMarcel Moolenaar 	}
4563955d011SMarcel Moolenaar 
457e2eeea75SSimon J. Gerraty 	if (!addToCache) {
4583955d011SMarcel Moolenaar 		/*
459548bfc56SSimon J. Gerraty 		 * Since the archive is not to be cached, assume there's no
460548bfc56SSimon J. Gerraty 		 * need to allocate the header, so just declare it static.
4613955d011SMarcel Moolenaar 		 */
4623955d011SMarcel Moolenaar 		static struct ar_hdr sarh;
4633955d011SMarcel Moolenaar 
4643955d011SMarcel Moolenaar 		arch = ArchFindMember(archive, member, &sarh, "r");
465956e45f6SSimon J. Gerraty 		if (arch == NULL)
4663955d011SMarcel Moolenaar 			return NULL;
467956e45f6SSimon J. Gerraty 
4683955d011SMarcel Moolenaar 		fclose(arch);
4693841c287SSimon J. Gerraty 		return &sarh;
4703955d011SMarcel Moolenaar 	}
4713955d011SMarcel Moolenaar 
4723955d011SMarcel Moolenaar 	arch = fopen(archive, "r");
473956e45f6SSimon J. Gerraty 	if (arch == NULL)
4743955d011SMarcel Moolenaar 		return NULL;
4753955d011SMarcel Moolenaar 
476e2eeea75SSimon J. Gerraty 	if (fread(magic, SARMAG, 1, arch) != 1 ||
477e2eeea75SSimon J. Gerraty 	    strncmp(magic, ARMAG, SARMAG) != 0) {
478e2eeea75SSimon J. Gerraty 		(void)fclose(arch);
4793955d011SMarcel Moolenaar 		return NULL;
4803955d011SMarcel Moolenaar 	}
4813955d011SMarcel Moolenaar 
482e2eeea75SSimon J. Gerraty 	ar = bmake_malloc(sizeof *ar);
4833955d011SMarcel Moolenaar 	ar->name = bmake_strdup(archive);
4843955d011SMarcel Moolenaar 	ar->fnametab = NULL;
4853955d011SMarcel Moolenaar 	ar->fnamesize = 0;
486956e45f6SSimon J. Gerraty 	HashTable_Init(&ar->members);
4873955d011SMarcel Moolenaar 	memName[AR_MAX_NAME_LEN] = '\0';
4883955d011SMarcel Moolenaar 
489e2eeea75SSimon J. Gerraty 	while (fread(&arh, sizeof arh, 1, arch) == 1) {
4902c3632d1SSimon J. Gerraty 		char *nameend;
4912c3632d1SSimon J. Gerraty 
492e2eeea75SSimon J. Gerraty 		if (strncmp(arh.AR_FMAG, ARFMAG, sizeof arh.AR_FMAG) != 0)
493548bfc56SSimon J. Gerraty 			goto bad_archive;
494e2eeea75SSimon J. Gerraty 
495e2eeea75SSimon J. Gerraty 		arh.AR_SIZE[sizeof arh.AR_SIZE - 1] = '\0';
496e2eeea75SSimon J. Gerraty 		size = (size_t)strtol(arh.AR_SIZE, NULL, 10);
4973955d011SMarcel Moolenaar 
498e2eeea75SSimon J. Gerraty 		memcpy(memName, arh.AR_NAME, sizeof arh.AR_NAME);
4992c3632d1SSimon J. Gerraty 		nameend = memName + AR_MAX_NAME_LEN;
500e2eeea75SSimon J. Gerraty 		while (nameend > memName && *nameend == ' ')
5012c3632d1SSimon J. Gerraty 			nameend--;
5022c3632d1SSimon J. Gerraty 		nameend[1] = '\0';
5033955d011SMarcel Moolenaar 
5043955d011SMarcel Moolenaar #ifdef SVR4ARCHIVES
5053955d011SMarcel Moolenaar 		/*
50606b9b3e0SSimon J. Gerraty 		 * svr4 names are slash-terminated.
50706b9b3e0SSimon J. Gerraty 		 * Also svr4 extended the AR format.
5083955d011SMarcel Moolenaar 		 */
5093955d011SMarcel Moolenaar 		if (memName[0] == '/') {
51006b9b3e0SSimon J. Gerraty 			/* svr4 magic mode; handle it */
5113955d011SMarcel Moolenaar 			switch (ArchSVR4Entry(ar, memName, size, arch)) {
5123955d011SMarcel Moolenaar 			case -1:	/* Invalid data */
513548bfc56SSimon J. Gerraty 				goto bad_archive;
5143955d011SMarcel Moolenaar 			case 0:		/* List of files entry */
5153955d011SMarcel Moolenaar 				continue;
5163955d011SMarcel Moolenaar 			default:	/* Got the entry */
5173955d011SMarcel Moolenaar 				break;
5183955d011SMarcel Moolenaar 			}
519956e45f6SSimon J. Gerraty 		} else {
5202c3632d1SSimon J. Gerraty 			if (nameend[0] == '/')
5212c3632d1SSimon J. Gerraty 				nameend[0] = '\0';
5223955d011SMarcel Moolenaar 		}
5233955d011SMarcel Moolenaar #endif
5243955d011SMarcel Moolenaar 
5253955d011SMarcel Moolenaar #ifdef AR_EFMT1
5263955d011SMarcel Moolenaar 		/*
5273955d011SMarcel Moolenaar 		 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
5283955d011SMarcel Moolenaar 		 * first <namelen> bytes of the file
5293955d011SMarcel Moolenaar 		 */
530e2eeea75SSimon J. Gerraty 		if (strncmp(memName, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 &&
531e2eeea75SSimon J. Gerraty 		    ch_isdigit(memName[sizeof AR_EFMT1 - 1])) {
5323955d011SMarcel Moolenaar 
5334fde40d9SSimon J. Gerraty 			size_t elen = (size_t)atoi(
5344fde40d9SSimon J. Gerraty 			    memName + sizeof AR_EFMT1 - 1);
5353955d011SMarcel Moolenaar 
53612904384SSimon J. Gerraty 			if (elen > MAXPATHLEN)
537548bfc56SSimon J. Gerraty 				goto bad_archive;
53812904384SSimon J. Gerraty 			if (fread(memName, elen, 1, arch) != 1)
539548bfc56SSimon J. Gerraty 				goto bad_archive;
5403955d011SMarcel Moolenaar 			memName[elen] = '\0';
54112904384SSimon J. Gerraty 			if (fseek(arch, -(long)elen, SEEK_CUR) != 0)
542548bfc56SSimon J. Gerraty 				goto bad_archive;
543e2eeea75SSimon J. Gerraty 			if (DEBUG(ARCH) || DEBUG(MAKE))
54406b9b3e0SSimon J. Gerraty 				debug_printf(
54506b9b3e0SSimon J. Gerraty 				    "ArchStatMember: "
54606b9b3e0SSimon J. Gerraty 				    "Extended format entry for %s\n",
547956e45f6SSimon J. Gerraty 				    memName);
5483955d011SMarcel Moolenaar 		}
5493955d011SMarcel Moolenaar #endif
5503955d011SMarcel Moolenaar 
551956e45f6SSimon J. Gerraty 		{
55206b9b3e0SSimon J. Gerraty 			struct ar_hdr *cached_hdr = bmake_malloc(
55306b9b3e0SSimon J. Gerraty 			    sizeof *cached_hdr);
554e2eeea75SSimon J. Gerraty 			memcpy(cached_hdr, &arh, sizeof arh);
555e2eeea75SSimon J. Gerraty 			HashTable_Set(&ar->members, memName, cached_hdr);
556956e45f6SSimon J. Gerraty 		}
557e2eeea75SSimon J. Gerraty 
558548bfc56SSimon J. Gerraty 		/* Files are padded with newlines to an even-byte boundary. */
5592c3632d1SSimon J. Gerraty 		if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0)
560548bfc56SSimon J. Gerraty 			goto bad_archive;
5613955d011SMarcel Moolenaar 	}
5623955d011SMarcel Moolenaar 
5633955d011SMarcel Moolenaar 	fclose(arch);
5643955d011SMarcel Moolenaar 
56506b9b3e0SSimon J. Gerraty 	Lst_Append(&archives, ar);
5663955d011SMarcel Moolenaar 
567956e45f6SSimon J. Gerraty 	return HashTable_FindValue(&ar->members, member);
5683955d011SMarcel Moolenaar 
569548bfc56SSimon J. Gerraty bad_archive:
5703955d011SMarcel Moolenaar 	fclose(arch);
571956e45f6SSimon J. Gerraty 	HashTable_Done(&ar->members);
5723955d011SMarcel Moolenaar 	free(ar->fnametab);
5733955d011SMarcel Moolenaar 	free(ar);
5743955d011SMarcel Moolenaar 	return NULL;
5753955d011SMarcel Moolenaar }
5763955d011SMarcel Moolenaar 
5773955d011SMarcel Moolenaar #ifdef SVR4ARCHIVES
57806b9b3e0SSimon J. Gerraty /*
5793955d011SMarcel Moolenaar  * Parse an SVR4 style entry that begins with a slash.
58006b9b3e0SSimon J. Gerraty  * If it is "//", then load the table of filenames.
5813955d011SMarcel Moolenaar  * If it is "/<offset>", then try to substitute the long file name
5823955d011SMarcel Moolenaar  * from offset of a table previously read.
58306b9b3e0SSimon J. Gerraty  * If a table is read, the file pointer is moved to the next archive member.
5843955d011SMarcel Moolenaar  *
5853955d011SMarcel Moolenaar  * Results:
5863955d011SMarcel Moolenaar  *	-1: Bad data in archive
5873955d011SMarcel Moolenaar  *	 0: A table was loaded from the file
5883955d011SMarcel Moolenaar  *	 1: Name was successfully substituted from table
5893955d011SMarcel Moolenaar  *	 2: Name was not successfully substituted from table
5903955d011SMarcel Moolenaar  */
5913955d011SMarcel Moolenaar static int
ArchSVR4Entry(Arch * ar,char * inout_name,size_t size,FILE * arch)592e2eeea75SSimon J. Gerraty ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch)
5933955d011SMarcel Moolenaar {
5943955d011SMarcel Moolenaar #define ARLONGNAMES1 "//"
5953955d011SMarcel Moolenaar #define ARLONGNAMES2 "/ARFILENAMES"
5963955d011SMarcel Moolenaar 	size_t entry;
5973955d011SMarcel Moolenaar 	char *ptr, *eptr;
5983955d011SMarcel Moolenaar 
599e2eeea75SSimon J. Gerraty 	if (strncmp(inout_name, ARLONGNAMES1, sizeof ARLONGNAMES1 - 1) == 0 ||
600e2eeea75SSimon J. Gerraty 	    strncmp(inout_name, ARLONGNAMES2, sizeof ARLONGNAMES2 - 1) == 0) {
6013955d011SMarcel Moolenaar 
6023955d011SMarcel Moolenaar 		if (ar->fnametab != NULL) {
60306b9b3e0SSimon J. Gerraty 			DEBUG0(ARCH,
60406b9b3e0SSimon J. Gerraty 			    "Attempted to redefine an SVR4 name table\n");
6053955d011SMarcel Moolenaar 			return -1;
6063955d011SMarcel Moolenaar 		}
6073955d011SMarcel Moolenaar 
6083955d011SMarcel Moolenaar 		/*
6093955d011SMarcel Moolenaar 		 * This is a table of archive names, so we build one for
6103955d011SMarcel Moolenaar 		 * ourselves
6113955d011SMarcel Moolenaar 		 */
6123955d011SMarcel Moolenaar 		ar->fnametab = bmake_malloc(size);
6133955d011SMarcel Moolenaar 		ar->fnamesize = size;
6143955d011SMarcel Moolenaar 
6153955d011SMarcel Moolenaar 		if (fread(ar->fnametab, size, 1, arch) != 1) {
616956e45f6SSimon J. Gerraty 			DEBUG0(ARCH, "Reading an SVR4 name table failed\n");
6173955d011SMarcel Moolenaar 			return -1;
6183955d011SMarcel Moolenaar 		}
6193955d011SMarcel Moolenaar 		eptr = ar->fnametab + size;
6203955d011SMarcel Moolenaar 		for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++)
621956e45f6SSimon J. Gerraty 			if (*ptr == '/') {
6223955d011SMarcel Moolenaar 				entry++;
6233955d011SMarcel Moolenaar 				*ptr = '\0';
6243955d011SMarcel Moolenaar 			}
6259f45a3c8SSimon J. Gerraty 		DEBUG1(ARCH,
6269f45a3c8SSimon J. Gerraty 		    "Found svr4 archive name table with %lu entries\n",
627e48f47ddSSimon J. Gerraty 		    (unsigned long)entry);
6283955d011SMarcel Moolenaar 		return 0;
6293955d011SMarcel Moolenaar 	}
6303955d011SMarcel Moolenaar 
631e2eeea75SSimon J. Gerraty 	if (inout_name[1] == ' ' || inout_name[1] == '\0')
6323955d011SMarcel Moolenaar 		return 2;
6333955d011SMarcel Moolenaar 
634e2eeea75SSimon J. Gerraty 	entry = (size_t)strtol(&inout_name[1], &eptr, 0);
635e2eeea75SSimon J. Gerraty 	if ((*eptr != ' ' && *eptr != '\0') || eptr == &inout_name[1]) {
636e2eeea75SSimon J. Gerraty 		DEBUG1(ARCH, "Could not parse SVR4 name %s\n", inout_name);
6373955d011SMarcel Moolenaar 		return 2;
6383955d011SMarcel Moolenaar 	}
6393955d011SMarcel Moolenaar 	if (entry >= ar->fnamesize) {
640956e45f6SSimon J. Gerraty 		DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n",
641e2eeea75SSimon J. Gerraty 		    inout_name, (unsigned long)ar->fnamesize);
6423955d011SMarcel Moolenaar 		return 2;
6433955d011SMarcel Moolenaar 	}
6443955d011SMarcel Moolenaar 
645e2eeea75SSimon J. Gerraty 	DEBUG2(ARCH, "Replaced %s with %s\n", inout_name, &ar->fnametab[entry]);
6463955d011SMarcel Moolenaar 
647e2eeea75SSimon J. Gerraty 	snprintf(inout_name, MAXPATHLEN + 1, "%s", &ar->fnametab[entry]);
6483955d011SMarcel Moolenaar 	return 1;
6493955d011SMarcel Moolenaar }
6503955d011SMarcel Moolenaar #endif
6513955d011SMarcel Moolenaar 
6523955d011SMarcel Moolenaar 
653b0c40a00SSimon J. Gerraty static bool
ArchiveMember_HasName(const struct ar_hdr * hdr,const char * name,size_t namelen)654e2eeea75SSimon J. Gerraty ArchiveMember_HasName(const struct ar_hdr *hdr,
655e2eeea75SSimon J. Gerraty 		      const char *name, size_t namelen)
656e2eeea75SSimon J. Gerraty {
657e2eeea75SSimon J. Gerraty 	const size_t ar_name_len = sizeof hdr->AR_NAME;
658e2eeea75SSimon J. Gerraty 	const char *ar_name = hdr->AR_NAME;
659e2eeea75SSimon J. Gerraty 
660e2eeea75SSimon J. Gerraty 	if (strncmp(ar_name, name, namelen) != 0)
661b0c40a00SSimon J. Gerraty 		return false;
662e2eeea75SSimon J. Gerraty 
663e2eeea75SSimon J. Gerraty 	if (namelen >= ar_name_len)
664e2eeea75SSimon J. Gerraty 		return namelen == ar_name_len;
665e2eeea75SSimon J. Gerraty 
666e2eeea75SSimon J. Gerraty 	/* hdr->AR_NAME is space-padded to the right. */
667e2eeea75SSimon J. Gerraty 	if (ar_name[namelen] == ' ')
668b0c40a00SSimon J. Gerraty 		return true;
669e2eeea75SSimon J. Gerraty 
6709f45a3c8SSimon J. Gerraty 	/*
6719f45a3c8SSimon J. Gerraty 	 * In archives created by GNU binutils 2.27, the member names end
6729f45a3c8SSimon J. Gerraty 	 * with a slash.
6739f45a3c8SSimon J. Gerraty 	 */
674548bfc56SSimon J. Gerraty 	if (ar_name[namelen] == '/' && ar_name[namelen + 1] == ' ')
675b0c40a00SSimon J. Gerraty 		return true;
676e2eeea75SSimon J. Gerraty 
677b0c40a00SSimon J. Gerraty 	return false;
678e2eeea75SSimon J. Gerraty }
679e2eeea75SSimon J. Gerraty 
68006b9b3e0SSimon J. Gerraty /*
681548bfc56SSimon J. Gerraty  * Load the header of an archive member.  The mode is "r" for read-only
682548bfc56SSimon J. Gerraty  * access, "r+" for read-write access.
6833955d011SMarcel Moolenaar  *
684548bfc56SSimon J. Gerraty  * Upon successful return, the archive file is positioned at the start of the
685548bfc56SSimon J. Gerraty  * member's struct ar_hdr.  In case of a failure or if the member doesn't
686548bfc56SSimon J. Gerraty  * exist, return NULL.
687e2eeea75SSimon J. Gerraty  *
688e2eeea75SSimon J. Gerraty  * See ArchStatMember for an almost identical copy of this code.
6893955d011SMarcel Moolenaar  */
6903955d011SMarcel Moolenaar static FILE *
ArchFindMember(const char * archive,const char * member,struct ar_hdr * out_arh,const char * mode)691548bfc56SSimon J. Gerraty ArchFindMember(const char *archive, const char *member,
692548bfc56SSimon J. Gerraty 	       struct ar_hdr *out_arh, const char *mode)
6933955d011SMarcel Moolenaar {
694548bfc56SSimon J. Gerraty 	FILE *arch;
6953955d011SMarcel Moolenaar 	int size;		/* Size of archive member */
6963955d011SMarcel Moolenaar 	char magic[SARMAG];
69706b9b3e0SSimon J. Gerraty 	size_t len;
6983955d011SMarcel Moolenaar 
6993955d011SMarcel Moolenaar 	arch = fopen(archive, mode);
700956e45f6SSimon J. Gerraty 	if (arch == NULL)
7013955d011SMarcel Moolenaar 		return NULL;
7023955d011SMarcel Moolenaar 
703e2eeea75SSimon J. Gerraty 	if (fread(magic, SARMAG, 1, arch) != 1 ||
704e2eeea75SSimon J. Gerraty 	    strncmp(magic, ARMAG, SARMAG) != 0) {
7053955d011SMarcel Moolenaar 		fclose(arch);
7063955d011SMarcel Moolenaar 		return NULL;
7073955d011SMarcel Moolenaar 	}
7083955d011SMarcel Moolenaar 
709548bfc56SSimon J. Gerraty 	/* Files are archived using their basename, not the entire path. */
71006b9b3e0SSimon J. Gerraty 	member = str_basename(member);
71106b9b3e0SSimon J. Gerraty 	len = strlen(member);
7123955d011SMarcel Moolenaar 
713e2eeea75SSimon J. Gerraty 	while (fread(out_arh, sizeof *out_arh, 1, arch) == 1) {
714956e45f6SSimon J. Gerraty 
71506b9b3e0SSimon J. Gerraty 		if (strncmp(out_arh->AR_FMAG, ARFMAG,
71606b9b3e0SSimon J. Gerraty 			    sizeof out_arh->AR_FMAG) != 0) {
7173955d011SMarcel Moolenaar 			fclose(arch);
7183955d011SMarcel Moolenaar 			return NULL;
719956e45f6SSimon J. Gerraty 		}
720956e45f6SSimon J. Gerraty 
721e2eeea75SSimon J. Gerraty 		DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n",
722e2eeea75SSimon J. Gerraty 		    archive,
723e2eeea75SSimon J. Gerraty 		    (int)sizeof out_arh->AR_NAME, out_arh->AR_NAME,
724e2eeea75SSimon J. Gerraty 		    (int)sizeof out_arh->ar_date, out_arh->ar_date);
725956e45f6SSimon J. Gerraty 
726e2eeea75SSimon J. Gerraty 		if (ArchiveMember_HasName(out_arh, member, len)) {
72706b9b3e0SSimon J. Gerraty 			if (fseek(arch, -(long)sizeof *out_arh, SEEK_CUR) !=
72806b9b3e0SSimon J. Gerraty 			    0) {
729e1cee40dSSimon J. Gerraty 				fclose(arch);
730e1cee40dSSimon J. Gerraty 				return NULL;
731e1cee40dSSimon J. Gerraty 			}
7323841c287SSimon J. Gerraty 			return arch;
7333955d011SMarcel Moolenaar 		}
734956e45f6SSimon J. Gerraty 
7353955d011SMarcel Moolenaar #ifdef AR_EFMT1
7363955d011SMarcel Moolenaar 		/*
7373955d011SMarcel Moolenaar 		 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
7383955d011SMarcel Moolenaar 		 * first <namelen> bytes of the file
7393955d011SMarcel Moolenaar 		 */
74006b9b3e0SSimon J. Gerraty 		if (strncmp(out_arh->AR_NAME, AR_EFMT1, sizeof AR_EFMT1 - 1) ==
74106b9b3e0SSimon J. Gerraty 		    0 &&
74206b9b3e0SSimon J. Gerraty 		    (ch_isdigit(out_arh->AR_NAME[sizeof AR_EFMT1 - 1]))) {
7434fde40d9SSimon J. Gerraty 			size_t elen = (size_t)atoi(
74412904384SSimon J. Gerraty 			    &out_arh->AR_NAME[sizeof AR_EFMT1 - 1]);
7453955d011SMarcel Moolenaar 			char ename[MAXPATHLEN + 1];
7463955d011SMarcel Moolenaar 
74712904384SSimon J. Gerraty 			if (elen > MAXPATHLEN) {
7483955d011SMarcel Moolenaar 				fclose(arch);
7493955d011SMarcel Moolenaar 				return NULL;
7503955d011SMarcel Moolenaar 			}
75112904384SSimon J. Gerraty 			if (fread(ename, elen, 1, arch) != 1) {
7523955d011SMarcel Moolenaar 				fclose(arch);
7533955d011SMarcel Moolenaar 				return NULL;
7543955d011SMarcel Moolenaar 			}
7553955d011SMarcel Moolenaar 			ename[elen] = '\0';
756e2eeea75SSimon J. Gerraty 			if (DEBUG(ARCH) || DEBUG(MAKE))
75706b9b3e0SSimon J. Gerraty 				debug_printf(
75806b9b3e0SSimon J. Gerraty 				    "ArchFindMember: "
75906b9b3e0SSimon J. Gerraty 				    "Extended format entry for %s\n",
760e2eeea75SSimon J. Gerraty 				    ename);
7613955d011SMarcel Moolenaar 			if (strncmp(ename, member, len) == 0) {
7623955d011SMarcel Moolenaar 				/* Found as extended name */
76306b9b3e0SSimon J. Gerraty 				if (fseek(arch,
76412904384SSimon J. Gerraty 				    -(long)(sizeof(struct ar_hdr) - elen),
765e1cee40dSSimon J. Gerraty 				    SEEK_CUR) != 0) {
766e1cee40dSSimon J. Gerraty 					fclose(arch);
767e1cee40dSSimon J. Gerraty 					return NULL;
768e1cee40dSSimon J. Gerraty 				}
7693841c287SSimon J. Gerraty 				return arch;
7703955d011SMarcel Moolenaar 			}
77112904384SSimon J. Gerraty 			if (fseek(arch, -(long)elen, SEEK_CUR) != 0) {
772e1cee40dSSimon J. Gerraty 				fclose(arch);
773e1cee40dSSimon J. Gerraty 				return NULL;
774e1cee40dSSimon J. Gerraty 			}
775956e45f6SSimon J. Gerraty 		}
7763955d011SMarcel Moolenaar #endif
777956e45f6SSimon J. Gerraty 
778548bfc56SSimon J. Gerraty 		/* Advance to the next member. */
779e2eeea75SSimon J. Gerraty 		out_arh->AR_SIZE[sizeof out_arh->AR_SIZE - 1] = '\0';
780e2eeea75SSimon J. Gerraty 		size = (int)strtol(out_arh->AR_SIZE, NULL, 10);
781548bfc56SSimon J. Gerraty 		/* Files are padded with newlines to an even-byte boundary. */
78212904384SSimon J. Gerraty 		if (fseek(arch, (size + 1) & ~1L, SEEK_CUR) != 0) {
783e1cee40dSSimon J. Gerraty 			fclose(arch);
784e1cee40dSSimon J. Gerraty 			return NULL;
785e1cee40dSSimon J. Gerraty 		}
7863955d011SMarcel Moolenaar 	}
7873955d011SMarcel Moolenaar 
7883955d011SMarcel Moolenaar 	fclose(arch);
7893955d011SMarcel Moolenaar 	return NULL;
7903955d011SMarcel Moolenaar }
7913955d011SMarcel Moolenaar 
79206b9b3e0SSimon J. Gerraty /*
793548bfc56SSimon J. Gerraty  * Update the ar_date of the member of an archive, on disk but not in the
794548bfc56SSimon J. Gerraty  * GNode.  Update the st_mtime of the entire archive as well.  For a library,
795548bfc56SSimon J. Gerraty  * it may be required to run ranlib after this.
7963955d011SMarcel Moolenaar  */
7973955d011SMarcel Moolenaar void
Arch_Touch(GNode * gn)7983955d011SMarcel Moolenaar Arch_Touch(GNode *gn)
7993955d011SMarcel Moolenaar {
800e2eeea75SSimon J. Gerraty 	FILE *f;
801e2eeea75SSimon J. Gerraty 	struct ar_hdr arh;
8023955d011SMarcel Moolenaar 
80306b9b3e0SSimon J. Gerraty 	f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh,
80406b9b3e0SSimon J. Gerraty 	    "r+");
805e2eeea75SSimon J. Gerraty 	if (f == NULL)
806e2eeea75SSimon J. Gerraty 		return;
807be19d90bSSimon J. Gerraty 
808e2eeea75SSimon J. Gerraty 	snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now);
809e2eeea75SSimon J. Gerraty 	(void)fwrite(&arh, sizeof arh, 1, f);
810e2eeea75SSimon J. Gerraty 	fclose(f);		/* TODO: handle errors */
8113955d011SMarcel Moolenaar }
8123955d011SMarcel Moolenaar 
81306b9b3e0SSimon J. Gerraty /*
81406b9b3e0SSimon J. Gerraty  * Given a node which represents a library, touch the thing, making sure that
815e2eeea75SSimon J. Gerraty  * the table of contents is also touched.
8162c3632d1SSimon J. Gerraty  *
8172c3632d1SSimon J. Gerraty  * Both the modification time of the library and of the RANLIBMAG member are
81806b9b3e0SSimon J. Gerraty  * set to 'now'.
81906b9b3e0SSimon J. Gerraty  */
8203955d011SMarcel Moolenaar void
Arch_TouchLib(GNode * gn MAKE_ATTR_UNUSED)821e2eeea75SSimon J. Gerraty Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED)
8223955d011SMarcel Moolenaar {
8233955d011SMarcel Moolenaar #ifdef RANLIBMAG
824e2eeea75SSimon J. Gerraty 	FILE *f;
8253955d011SMarcel Moolenaar 	struct ar_hdr arh;	/* Header describing table of contents */
826e2eeea75SSimon J. Gerraty 	struct utimbuf times;
8273955d011SMarcel Moolenaar 
828e2eeea75SSimon J. Gerraty 	f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+");
829e2eeea75SSimon J. Gerraty 	if (f == NULL)
830e2eeea75SSimon J. Gerraty 		return;
8313955d011SMarcel Moolenaar 
832e2eeea75SSimon J. Gerraty 	snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now);
833e2eeea75SSimon J. Gerraty 	(void)fwrite(&arh, sizeof arh, 1, f);
834e2eeea75SSimon J. Gerraty 	fclose(f);		/* TODO: handle errors */
8353955d011SMarcel Moolenaar 
8363955d011SMarcel Moolenaar 	times.actime = times.modtime = now;
837e2eeea75SSimon J. Gerraty 	utime(gn->path, &times);	/* TODO: handle errors */
8383955d011SMarcel Moolenaar #endif
8393955d011SMarcel Moolenaar }
8403955d011SMarcel Moolenaar 
84106b9b3e0SSimon J. Gerraty /*
84206b9b3e0SSimon J. Gerraty  * Update the mtime of the GNode with the mtime from the archive member on
84306b9b3e0SSimon J. Gerraty  * disk (or in the cache).
84406b9b3e0SSimon J. Gerraty  */
845e2eeea75SSimon J. Gerraty void
Arch_UpdateMTime(GNode * gn)846e2eeea75SSimon J. Gerraty Arch_UpdateMTime(GNode *gn)
8473955d011SMarcel Moolenaar {
848e2eeea75SSimon J. Gerraty 	struct ar_hdr *arh;
8493955d011SMarcel Moolenaar 
850b0c40a00SSimon J. Gerraty 	arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), true);
851e2eeea75SSimon J. Gerraty 	if (arh != NULL)
852e2eeea75SSimon J. Gerraty 		gn->mtime = (time_t)strtol(arh->ar_date, NULL, 10);
853e2eeea75SSimon J. Gerraty 	else
854e2eeea75SSimon J. Gerraty 		gn->mtime = 0;
8553955d011SMarcel Moolenaar }
8563955d011SMarcel Moolenaar 
85706b9b3e0SSimon J. Gerraty /*
85806b9b3e0SSimon J. Gerraty  * Given a nonexistent archive member's node, update gn->mtime from its
85906b9b3e0SSimon J. Gerraty  * archived form, if it exists.
86006b9b3e0SSimon J. Gerraty  */
861e2eeea75SSimon J. Gerraty void
Arch_UpdateMemberMTime(GNode * gn)862e2eeea75SSimon J. Gerraty Arch_UpdateMemberMTime(GNode *gn)
8633955d011SMarcel Moolenaar {
864956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
8653955d011SMarcel Moolenaar 
86606b9b3e0SSimon J. Gerraty 	for (ln = gn->parents.first; ln != NULL; ln = ln->next) {
867956e45f6SSimon J. Gerraty 		GNode *pgn = ln->datum;
8683955d011SMarcel Moolenaar 
8693955d011SMarcel Moolenaar 		if (pgn->type & OP_ARCHV) {
8703955d011SMarcel Moolenaar 			/*
87106b9b3e0SSimon J. Gerraty 			 * If the parent is an archive specification and is
87206b9b3e0SSimon J. Gerraty 			 * being made and its member's name matches the name
87306b9b3e0SSimon J. Gerraty 			 * of the node we were given, record the modification
87406b9b3e0SSimon J. Gerraty 			 * time of the parent in the child. We keep searching
87506b9b3e0SSimon J. Gerraty 			 * its parents in case some other parent requires this
87606b9b3e0SSimon J. Gerraty 			 * child to exist.
8773955d011SMarcel Moolenaar 			 */
8782c3632d1SSimon J. Gerraty 			const char *nameStart = strchr(pgn->name, '(') + 1;
8792c3632d1SSimon J. Gerraty 			const char *nameEnd = strchr(nameStart, ')');
8802c3632d1SSimon J. Gerraty 			size_t nameLen = (size_t)(nameEnd - nameStart);
8813955d011SMarcel Moolenaar 
88212904384SSimon J. Gerraty 			if (pgn->flags.remake &&
8832c3632d1SSimon J. Gerraty 			    strncmp(nameStart, gn->name, nameLen) == 0) {
884e2eeea75SSimon J. Gerraty 				Arch_UpdateMTime(pgn);
885e2eeea75SSimon J. Gerraty 				gn->mtime = pgn->mtime;
8863955d011SMarcel Moolenaar 			}
88712904384SSimon J. Gerraty 		} else if (pgn->flags.remake) {
8883955d011SMarcel Moolenaar 			/*
88906b9b3e0SSimon J. Gerraty 			 * Something which isn't a library depends on the
89006b9b3e0SSimon J. Gerraty 			 * existence of this target, so it needs to exist.
8913955d011SMarcel Moolenaar 			 */
8923955d011SMarcel Moolenaar 			gn->mtime = 0;
8933955d011SMarcel Moolenaar 			break;
8943955d011SMarcel Moolenaar 		}
8953955d011SMarcel Moolenaar 	}
8963955d011SMarcel Moolenaar }
8973955d011SMarcel Moolenaar 
89806b9b3e0SSimon J. Gerraty /*
89906b9b3e0SSimon J. Gerraty  * Search for a library along the given search path.
9003955d011SMarcel Moolenaar  *
9013955d011SMarcel Moolenaar  * The node's 'path' field is set to the found path (including the
9023955d011SMarcel Moolenaar  * actual file name, not -l...). If the system can handle the -L
9033955d011SMarcel Moolenaar  * flag when linking (or we cannot find the library), we assume that
9042c3632d1SSimon J. Gerraty  * the user has placed the .LIBS variable in the final linking
9053955d011SMarcel Moolenaar  * command (or the linker will know where to find it) and set the
9063955d011SMarcel Moolenaar  * TARGET variable for this node to be the node's name. Otherwise,
9073955d011SMarcel Moolenaar  * we set the TARGET variable to be the full path of the library,
9083955d011SMarcel Moolenaar  * as returned by Dir_FindFile.
9093955d011SMarcel Moolenaar  */
9103955d011SMarcel Moolenaar void
Arch_FindLib(GNode * gn,SearchPath * path)911956e45f6SSimon J. Gerraty Arch_FindLib(GNode *gn, SearchPath *path)
9123955d011SMarcel Moolenaar {
913956e45f6SSimon J. Gerraty 	char *libName = str_concat3("lib", gn->name + 2, ".a");
9143955d011SMarcel Moolenaar 	gn->path = Dir_FindFile(libName, path);
9153955d011SMarcel Moolenaar 	free(libName);
9163955d011SMarcel Moolenaar 
917dba7b0efSSimon J. Gerraty 	Var_Set(gn, TARGET, gn->name);
9183955d011SMarcel Moolenaar }
9193955d011SMarcel Moolenaar 
92012904384SSimon J. Gerraty static bool
RanlibOODate(const GNode * gn MAKE_ATTR_UNUSED)92112904384SSimon J. Gerraty RanlibOODate(const GNode *gn MAKE_ATTR_UNUSED)
92212904384SSimon J. Gerraty {
92312904384SSimon J. Gerraty #ifdef RANLIBMAG
92412904384SSimon J. Gerraty 	struct ar_hdr *arh;	/* Header for __.SYMDEF */
92512904384SSimon J. Gerraty 	int tocModTime;		/* The table-of-contents' mod time */
92612904384SSimon J. Gerraty 
92712904384SSimon J. Gerraty 	arh = ArchStatMember(gn->path, RANLIBMAG, false);
92812904384SSimon J. Gerraty 
92912904384SSimon J. Gerraty 	if (arh == NULL) {
93012904384SSimon J. Gerraty 		/* A library without a table of contents is out-of-date. */
93112904384SSimon J. Gerraty 		if (DEBUG(ARCH) || DEBUG(MAKE))
93212904384SSimon J. Gerraty 			debug_printf("no toc...");
93312904384SSimon J. Gerraty 		return true;
93412904384SSimon J. Gerraty 	}
93512904384SSimon J. Gerraty 
93612904384SSimon J. Gerraty 	tocModTime = (int)strtol(arh->ar_date, NULL, 10);
93712904384SSimon J. Gerraty 
93812904384SSimon J. Gerraty 	if (DEBUG(ARCH) || DEBUG(MAKE))
93912904384SSimon J. Gerraty 		debug_printf("%s modified %s...",
94012904384SSimon J. Gerraty 		    RANLIBMAG, Targ_FmtTime(tocModTime));
94112904384SSimon J. Gerraty 	return gn->youngestChild == NULL ||
94212904384SSimon J. Gerraty 	       gn->youngestChild->mtime > tocModTime;
94312904384SSimon J. Gerraty #else
94412904384SSimon J. Gerraty 	return false;
94512904384SSimon J. Gerraty #endif
94612904384SSimon J. Gerraty }
94712904384SSimon J. Gerraty 
94806b9b3e0SSimon J. Gerraty /*
949548bfc56SSimon J. Gerraty  * Decide if a node with the OP_LIB attribute is out-of-date.
950e2eeea75SSimon J. Gerraty  * The library is cached if it hasn't been already.
9513955d011SMarcel Moolenaar  *
952548bfc56SSimon J. Gerraty  * There are several ways for a library to be out-of-date that are not
953548bfc56SSimon J. Gerraty  * available to ordinary files.  In addition, there are ways that are open to
954548bfc56SSimon J. Gerraty  * regular files that are not available to libraries.
955e2eeea75SSimon J. Gerraty  *
956548bfc56SSimon J. Gerraty  * A library that is only used as a source is never considered out-of-date by
957548bfc56SSimon J. Gerraty  * itself.  This does not preclude the library's modification time from making
958548bfc56SSimon J. Gerraty  * its parent be out-of-date.  A library will be considered out-of-date for
959548bfc56SSimon J. Gerraty  * any of these reasons, given that it is a target on a dependency line
960548bfc56SSimon J. Gerraty  * somewhere:
9612c3632d1SSimon J. Gerraty  *
9622c3632d1SSimon J. Gerraty  *	Its modification time is less than that of one of its sources
963956e45f6SSimon J. Gerraty  *	(gn->mtime < gn->youngestChild->mtime).
9642c3632d1SSimon J. Gerraty  *
9652c3632d1SSimon J. Gerraty  *	Its modification time is greater than the time at which the make
9662c3632d1SSimon J. Gerraty  *	began (i.e. it's been modified in the course of the make, probably
9672c3632d1SSimon J. Gerraty  *	by archiving).
9682c3632d1SSimon J. Gerraty  *
9692c3632d1SSimon J. Gerraty  *	The modification time of one of its sources is greater than the one
9702c3632d1SSimon J. Gerraty  *	of its RANLIBMAG member (i.e. its table of contents is out-of-date).
971e2eeea75SSimon J. Gerraty  *	We don't compare the archive time vs. TOC time because they can be
9722c3632d1SSimon J. Gerraty  *	too close. In my opinion we should not bother with the TOC at all
9732c3632d1SSimon J. Gerraty  *	since this is used by 'ar' rules that affect the data contents of the
9742c3632d1SSimon J. Gerraty  *	archive, not by ranlib rules, which affect the TOC.
9753955d011SMarcel Moolenaar  */
976b0c40a00SSimon J. Gerraty bool
Arch_LibOODate(GNode * gn)9773955d011SMarcel Moolenaar Arch_LibOODate(GNode *gn)
9783955d011SMarcel Moolenaar {
9793955d011SMarcel Moolenaar 
980548bfc56SSimon J. Gerraty 	if (gn->type & OP_PHONY)
98112904384SSimon J. Gerraty 		return true;
982548bfc56SSimon J. Gerraty 	if (!GNode_IsTarget(gn) && Lst_IsEmpty(&gn->children))
98312904384SSimon J. Gerraty 		return false;
984548bfc56SSimon J. Gerraty 	if ((!Lst_IsEmpty(&gn->children) && gn->youngestChild == NULL) ||
9853955d011SMarcel Moolenaar 		   (gn->mtime > now) ||
986956e45f6SSimon J. Gerraty 		   (gn->youngestChild != NULL &&
987548bfc56SSimon J. Gerraty 		    gn->mtime < gn->youngestChild->mtime))
98812904384SSimon J. Gerraty 		return true;
98912904384SSimon J. Gerraty 	return RanlibOODate(gn);
9903955d011SMarcel Moolenaar }
9913955d011SMarcel Moolenaar 
992956e45f6SSimon J. Gerraty /* Initialize the archives module. */
9933955d011SMarcel Moolenaar void
Arch_Init(void)9943955d011SMarcel Moolenaar Arch_Init(void)
9953955d011SMarcel Moolenaar {
99606b9b3e0SSimon J. Gerraty 	Lst_Init(&archives);
9973955d011SMarcel Moolenaar }
9983955d011SMarcel Moolenaar 
99922619282SSimon J. Gerraty #ifdef CLEANUP
1000956e45f6SSimon J. Gerraty /* Clean up the archives module. */
10013955d011SMarcel Moolenaar void
Arch_End(void)10023955d011SMarcel Moolenaar Arch_End(void)
10033955d011SMarcel Moolenaar {
1004548bfc56SSimon J. Gerraty 	ArchListNode *ln;
1005548bfc56SSimon J. Gerraty 
1006548bfc56SSimon J. Gerraty 	for (ln = archives.first; ln != NULL; ln = ln->next)
1007548bfc56SSimon J. Gerraty 		ArchFree(ln->datum);
1008548bfc56SSimon J. Gerraty 	Lst_Done(&archives);
10093955d011SMarcel Moolenaar }
101022619282SSimon J. Gerraty #endif
10113955d011SMarcel Moolenaar 
1012b0c40a00SSimon J. Gerraty bool
Arch_IsLib(GNode * gn)10133955d011SMarcel Moolenaar Arch_IsLib(GNode *gn)
10143955d011SMarcel Moolenaar {
1015548bfc56SSimon J. Gerraty 	char buf[8];
10163955d011SMarcel Moolenaar 	int fd;
1017548bfc56SSimon J. Gerraty 	bool isLib;
10183955d011SMarcel Moolenaar 
10193955d011SMarcel Moolenaar 	if ((fd = open(gn->path, O_RDONLY)) == -1)
1020b0c40a00SSimon J. Gerraty 		return false;
1021548bfc56SSimon J. Gerraty 	isLib = read(fd, buf, sizeof buf) == sizeof buf
1022548bfc56SSimon J. Gerraty 	    && memcmp(buf, "!<arch>\n", sizeof buf) == 0;
10233955d011SMarcel Moolenaar 	(void)close(fd);
1024548bfc56SSimon J. Gerraty 	return isLib;
10253955d011SMarcel Moolenaar }
1026