|
|
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.