📄 arch.c
字号:
/* * We don't have this archive on the list yet, so we want to find out * everything that's in it and cache it so we can get at it quickly. */ arch = fopen (archive, "r"); if (arch == (FILE *) NULL) { return ((struct ar_hdr *) NULL); } /* * We use the ARMAG string to make sure this is an archive we * can handle... */ if ((fread (magic, SARMAG, 1, arch) != 1) || (strncmp (magic, ARMAG, SARMAG) != 0)) { fclose (arch); return ((struct ar_hdr *) NULL); } ar = (Arch *)emalloc (sizeof (Arch)); ar->name = strdup (archive); Hash_InitTable (&ar->members, -1); memName[AR_MAX_NAME_LEN] = '\0'; while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) { if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) { /* * The header is bogus, so the archive is bad * and there's no way we can recover... */ fclose (arch); Hash_DeleteTable (&ar->members); free ((Address)ar); return ((struct ar_hdr *) NULL); } else { (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { continue; } cp[1] = '\0'; he = Hash_CreateEntry (&ar->members, strdup (memName), (Boolean *)NULL); Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr))); memcpy ((Address)Hash_GetValue (he), (Address)&arh, sizeof (struct ar_hdr)); } /* * We need to advance the stream's pointer to the start of the * next header. Files are padded with newlines to an even-byte * boundary, so we need to extract the size of the file from the * 'size' field of the header and round it up during the seek. */ arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; (void) sscanf (arh.ar_size, "%10d", &size); fseek (arch, (size + 1) & ~1, 1); } fclose (arch); (void) Lst_AtEnd (archives, (ClientData) ar); /* * Now that the archive has been read and cached, we can look into * the hash table to find the desired member's header. */ he = Hash_FindEntry (&ar->members, member); if (he != (Hash_Entry *) NULL) { return ((struct ar_hdr *) Hash_GetValue (he)); } else { return ((struct ar_hdr *) NULL); }}/*- *----------------------------------------------------------------------- * ArchFindMember -- * Locate a member of an archive, given the path of the archive and * the path of the desired member. If the archive is to be modified, * the mode should be "r+", if not, it should be "r". * * Results: * An FILE *, opened for reading and writing, positioned at the * start of the member's struct ar_hdr, or NULL if the member was * nonexistent. The current struct ar_hdr for member. * * Side Effects: * The passed struct ar_hdr structure is filled in. * *----------------------------------------------------------------------- */static FILE *ArchFindMember (archive, member, arhPtr, mode) char *archive; /* Path to the archive */ char *member; /* Name of member. If it is a path, only the * last component is used. */ struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */ char *mode; /* The mode for opening the stream */{ FILE * arch; /* Stream to archive */ int size; /* Size of archive member */ char *cp; /* Useful character pointer */ char magic[SARMAG]; int len; arch = fopen (archive, mode); if (arch == (FILE *) NULL) { return ((FILE *) NULL); } /* * We use the ARMAG string to make sure this is an archive we * can handle... */ if ((fread (magic, SARMAG, 1, arch) != 1) || (strncmp (magic, ARMAG, SARMAG) != 0)) { fclose (arch); return ((FILE *) NULL); } /* * Because of space constraints and similar things, files are archived * using their final path components, not the entire thing, so we need * to point 'member' to the final component, if there is one, to make * the comparisons easier... */ cp = strrchr (member, '/'); if (cp != (char *) NULL) { member = cp + 1; } len = strlen (member); if (len > sizeof (arhPtr->ar_name)) { len = sizeof (arhPtr->ar_name); } while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) { if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) { /* * The header is bogus, so the archive is bad * and there's no way we can recover... */ fclose (arch); return ((FILE *) NULL); } else if (strncmp (member, arhPtr->ar_name, len) == 0) { /* * If the member's name doesn't take up the entire 'name' field, * we have to be careful of matching prefixes. Names are space- * padded to the right, so if the character in 'name' at the end * of the matched string is anything but a space, this isn't the * member we sought. */ if (len != sizeof(arhPtr->ar_name) && arhPtr->ar_name[len] != ' '){ continue; } else { /* * To make life easier, we reposition the file at the start * of the header we just read before we return the stream. * In a more general situation, it might be better to leave * the file at the actual member, rather than its header, but * not here... */ fseek (arch, -sizeof(struct ar_hdr), 1); return (arch); } } else { /* * This isn't the member we're after, so we need to advance the * stream's pointer to the start of the next header. Files are * padded with newlines to an even-byte boundary, so we need to * extract the size of the file from the 'size' field of the * header and round it up during the seek. */ arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0'; (void)sscanf (arhPtr->ar_size, "%10d", &size); fseek (arch, (size + 1) & ~1, 1); } } /* * We've looked everywhere, but the member is not to be found. Close the * archive and return NULL -- an error. */ fclose (arch); return ((FILE *) NULL);}/*- *----------------------------------------------------------------------- * Arch_Touch -- * Touch a member of an archive. * * Results: * The 'time' field of the member's header is updated. * * Side Effects: * The modification time of the entire archive is also changed. * For a library, this could necessitate the re-ranlib'ing of the * whole thing. * *----------------------------------------------------------------------- */voidArch_Touch (gn) GNode *gn; /* Node of member to touch */{ FILE * arch; /* Stream open to archive, positioned properly */ struct ar_hdr arh; /* Current header describing member */ arch = ArchFindMember(Var_Value (ARCHIVE, gn), Var_Value (TARGET, gn), &arh, "r+"); sprintf(arh.ar_date, "%-12ld", (long) now); if (arch != (FILE *) NULL) { (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); fclose (arch); }}/*- *----------------------------------------------------------------------- * Arch_TouchLib -- * Given a node which represents a library, touch the thing, making * sure that the table of contents also is touched. * * Results: * None. * * Side Effects: * Both the modification time of the library and of the RANLIBMAG * member are set to 'now'. * *----------------------------------------------------------------------- */voidArch_TouchLib (gn) GNode *gn; /* The node of the library to touch */{ FILE * arch; /* Stream open to archive */ struct ar_hdr arh; /* Header describing table of contents */ struct timeval times[2]; /* Times for utimes() call */ arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); sprintf(arh.ar_date, "%-12ld", (long) now); if (arch != (FILE *) NULL) { (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); fclose (arch); times[0].tv_sec = times[1].tv_sec = now; times[0].tv_usec = times[1].tv_usec = 0; utimes(gn->path, times); }}/*- *----------------------------------------------------------------------- * Arch_MTime -- * Return the modification time of a member of an archive. * * Results: * The modification time (seconds). * * Side Effects: * The mtime field of the given node is filled in with the value * returned by the function. * *----------------------------------------------------------------------- */intArch_MTime (gn) GNode *gn; /* Node describing archive member */{ struct ar_hdr *arhPtr; /* Header of desired member */ int modTime; /* Modification time as an integer */ arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn), Var_Value (TARGET, gn), TRUE); if (arhPtr != (struct ar_hdr *) NULL) { (void)sscanf (arhPtr->ar_date, "%12d", &modTime); } else { modTime = 0; } gn->mtime = modTime; return (modTime);}/*- *----------------------------------------------------------------------- * Arch_MemMTime -- * Given a non-existent archive member's node, get its modification * time from its archived form, if it exists. * * Results: * The modification time. * * Side Effects: * The mtime field is filled in. * *----------------------------------------------------------------------- */intArch_MemMTime (gn) GNode *gn;{ LstNode ln; GNode *pgn; char *nameStart, *nameEnd; if (Lst_Open (gn->parents) != SUCCESS) { gn->mtime = 0; return (0); } while ((ln = Lst_Next (gn->parents)) != NILLNODE) { pgn = (GNode *) Lst_Datum (ln); if (pgn->type & OP_ARCHV) { /* * If the parent is an archive specification and is being made * and its member's name matches the name of the node we were * given, record the modification time of the parent in the * child. We keep searching its parents in case some other * parent requires this child to exist... */ nameStart = strchr (pgn->name, '(') + 1; nameEnd = strchr (nameStart, ')'); if (pgn->make && strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { gn->mtime = Arch_MTime(pgn); } } else if (pgn->make) { /* * Something which isn't a library depends on the existence of * this target, so it needs to exist. */ gn->mtime = 0; break; } } Lst_Close (gn->parents); return (gn->mtime);}/*- *----------------------------------------------------------------------- * Arch_FindLib -- * Search for a library along the given search path. * * Results: * None. * * Side Effects: * The node's 'path' field is set to the found path (including the * actual file name, not -l...). If the system can handle the -L * flag when linking (or we cannot find the library), we assume that * the user has placed the .LIBRARIES variable in the final linking * command (or the linker will know where to find it) and set the * TARGET variable for this node to be the node's name. Otherwise, * we set the TARGET variable to be the full path of the library, * as returned by Dir_FindFile. * *----------------------------------------------------------------------- */voidArch_FindLib (gn, path) GNode *gn; /* Node of library to find */ Lst path; /* Search path */{ char *libName; /* file name for archive */ libName = (char *)emalloc (strlen (gn->name) + 6 - 2); sprintf(libName, "lib%s.a", &gn->name[2]); gn->path = Dir_FindFile (libName, path); free (libName);#ifdef LIBRARIES Var_Set (TARGET, gn->name, gn);#else Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn);#endif LIBRARIES}/*- *----------------------------------------------------------------------- * Arch_LibOODate -- * Decide if a node with the OP_LIB attribute is out-of-date. Called * from Make_OODate to make its life easier. * * There are several ways for a library to be out-of-date that are * not available to ordinary files. In addition, there are ways * that are open to regular files that are not available to * libraries. A library that is only used as a source is never * considered out-of-date by itself. This does not preclude the * library's modification time from making its parent be out-of-date. * A library will be considered out-of-date for any of these reasons, * given that it is a target on a dependency line somewhere: * Its modification time is less than that of one of its * sources (gn->mtime < gn->cmtime). * Its modification time is greater than the time at which the * make began (i.e. it's been modified in the course * of the make, probably by archiving). * Its modification time doesn't agree with the modification * time of its RANLIBMAG member (i.e. its table of contents * is out-of-date). * * * Results: * TRUE if the library is out-of-date. FALSE otherwise. * * Side Effects: * The library will be hashed if it hasn't been already. * *----------------------------------------------------------------------- */BooleanArch_LibOODate (gn) GNode *gn; /* The library's graph node */{ Boolean oodate; if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) { oodate = FALSE; } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { oodate = TRUE; } else { struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ int modTimeTOC; /* The table-of-contents's mod time */ arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE); if (arhPtr != (struct ar_hdr *)NULL) { (void)sscanf (arhPtr->ar_date, "%12d", &modTimeTOC); if (DEBUG(ARCH) || DEBUG(MAKE)) { printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); } oodate = (gn->mtime > modTimeTOC); } else { /* * A library w/o a table of contents is out-of-date */ if (DEBUG(ARCH) || DEBUG(MAKE)) { printf("No t.o.c...."); } oodate = TRUE; } } return (oodate);}/*- *----------------------------------------------------------------------- * Arch_Init -- * Initialize things for this module. * * Results: * None. * * Side Effects: * The 'archives' list is initialized. * *----------------------------------------------------------------------- */voidArch_Init (){ archives = Lst_Init (FALSE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -