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