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