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