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