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