1131 lines
23 KiB
C
1131 lines
23 KiB
C
#ifndef lint
|
||
static char sccsid[] = "@(#)files.c 1.1 94/10/31 SMI"; /* from S5R2 1.3 03/28/83 */
|
||
#endif
|
||
|
||
#include "defs"
|
||
#include <sys/stat.h>
|
||
#include <pwd.h>
|
||
#include <ar.h>
|
||
#ifdef BSD
|
||
#include <ranlib.h>
|
||
|
||
long sgetl();
|
||
#endif
|
||
/* UNIX DEPENDENT PROCEDURES */
|
||
|
||
#define equaln !strncmp
|
||
|
||
/*
|
||
* For 6.0, create a make which can understand all three archive
|
||
* formats. This is kind of tricky, and <ar.h> isn't any help.
|
||
* Note that there is no sgetl() and sputl() on the pdp11, so
|
||
* make cannot handle anything but the one format there.
|
||
*/
|
||
char archmem[64]; /* archive file member name to search for */
|
||
char archname[64]; /* archive file to be opened */
|
||
|
||
int ar_type; /* to distiguish which archive format we have */
|
||
#define ARpdp 1
|
||
#define AR5 2
|
||
#define ARport 3
|
||
|
||
long first_ar_mem; /* where first archive member header is at */
|
||
long sym_begin; /* where the symbol lookup starts */
|
||
long num_symbols; /* the number of symbols available */
|
||
long sym_size; /* length of symbol directory file */
|
||
|
||
/*
|
||
* Defines for all the different archive formats. See next comment
|
||
* block for justification for not using <ar.h>'s versions.
|
||
*/
|
||
#define ARpdpMAG 0177545 /* old format (short) magic number */
|
||
|
||
#define AR5MAG "<ar>" /* 5.0 format magic string */
|
||
#define SAR5MAG 4 /* 5.0 format magic string length */
|
||
|
||
#define ARportMAG "!<arch>\n" /* Port. (6.0) magic string */
|
||
#define SARportMAG 8 /* Port. (6.0) magic string length */
|
||
#define ARFportMAG "`\n" /* Port. (6.0) end of header string */
|
||
|
||
/*
|
||
* These are the archive file headers for the three formats. Note
|
||
* that it really doesn't matter if these structures are defined
|
||
* here. They are correct as of the respective archive format
|
||
* releases. If the archive format is changed, then since backwards
|
||
* compatability is the desired behavior, a new structure is added
|
||
* to the list.
|
||
*/
|
||
struct /* pdp11 -- old archive format */
|
||
{
|
||
char ar_name[14]; /* '\0' terminated */
|
||
long ar_date; /* native machine bit representation */
|
||
char ar_uid; /* " */
|
||
char ar_gid; /* " */
|
||
int ar_mode; /* " */
|
||
long ar_size; /* " */
|
||
} ar_pdp;
|
||
|
||
struct /* pdp11 a.out header */
|
||
{
|
||
short a_magic;
|
||
unsigned a_text;
|
||
unsigned a_data;
|
||
unsigned a_bss;
|
||
unsigned a_syms; /* length of symbol table */
|
||
unsigned a_entry;
|
||
char a_unused;
|
||
char a_hitext;
|
||
char a_flag;
|
||
char a_stamp;
|
||
} arobj_pdp;
|
||
|
||
struct /* pdp11 a.out symbol table entry */
|
||
{
|
||
char n_name[8]; /* null-terminated name */
|
||
int n_type;
|
||
unsigned n_value;
|
||
} ars_pdp;
|
||
|
||
struct /* UNIX 5.0 archive header format: vax family; 3b family */
|
||
{
|
||
char ar_magic[SAR5MAG]; /* AR5MAG */
|
||
char ar_name[16]; /* ' ' terminated */
|
||
char ar_date[4]; /* sgetl() accessed */
|
||
char ar_syms[4]; /* sgetl() accessed */
|
||
} arh_5;
|
||
|
||
struct /* UNIX 5.0 archive symbol format: vax family; 3b family */
|
||
{
|
||
char sym_name[8]; /* ' ' terminated */
|
||
char sym_ptr[4]; /* sgetl() accessed */
|
||
} ars_5;
|
||
|
||
struct /* UNIX 5.0 archive member format: vax family; 3b family */
|
||
{
|
||
char arf_name[16]; /* ' ' terminated */
|
||
char arf_date[4]; /* sgetl() accessed */
|
||
char arf_uid[4]; /* " */
|
||
char arf_gid[4]; /* " */
|
||
char arf_mode[4]; /* " */
|
||
char arf_size[4]; /* " */
|
||
} arf_5;
|
||
|
||
struct /* Portable (6.0) archive format: vax family; 3b family */
|
||
{
|
||
#ifdef BSD
|
||
char ar_name[16]; /* ' ' terminated */
|
||
#else
|
||
char ar_name[16]; /* '/' terminated */
|
||
#endif
|
||
char ar_date[12]; /* left-adjusted; decimal ascii; blank filled */
|
||
char ar_uid[6]; /* " */
|
||
char ar_gid[6]; /* " */
|
||
char ar_mode[8]; /* left-adjusted; octal ascii; blank filled */
|
||
char ar_size[10]; /* left-adjusted; decimal ascii; blank filled */
|
||
char ar_fmag[2]; /* special end-of-header string (ARFportMAG) */
|
||
} ar_port;
|
||
|
||
|
||
#if 0 /* no longer used! */
|
||
/*
|
||
* New common object version of files.c
|
||
*/
|
||
char archmem[64];
|
||
char archname[64]; /* name of archive library */
|
||
struct ar_hdr head; /* archive file header */
|
||
struct ar_sym symbol; /* archive file symbol table entry */
|
||
struct arf_hdr fhead; /* archive file object file header */
|
||
#endif
|
||
|
||
TIMETYPE afilescan();
|
||
TIMETYPE entryscan();
|
||
TIMETYPE pdpentrys();
|
||
FILE *arfd;
|
||
char BADAR[] = "BAD ARCHIVE";
|
||
|
||
|
||
#include <errno.h>
|
||
|
||
extern int errno;
|
||
|
||
TIMETYPE
|
||
exists(pname)
|
||
NAMEBLOCK pname;
|
||
{
|
||
register CHARSTAR s;
|
||
struct stat buf;
|
||
TIMETYPE lookarch();
|
||
CHARSTAR filename;
|
||
static char fname[MAXPATHLEN+1];
|
||
|
||
filename = pname->namep;
|
||
|
||
if(any(filename, LPAREN))
|
||
return(lookarch(filename));
|
||
|
||
if(stat(filename,&buf) < 0)
|
||
{
|
||
if(errno != ENOENT)
|
||
return(0); /* file exists but is inaccessible */
|
||
s = findfl(filename, &buf);
|
||
if(s != NULL)
|
||
{
|
||
pname->alias = copys(s);
|
||
return(buf.st_mtime);
|
||
}
|
||
return(0);
|
||
}
|
||
else
|
||
return(buf.st_mtime);
|
||
}
|
||
|
||
|
||
TIMETYPE
|
||
prestime()
|
||
{
|
||
extern long time();
|
||
TIMETYPE t;
|
||
(void)time(&t);
|
||
return(t);
|
||
}
|
||
|
||
|
||
|
||
DEPBLOCK
|
||
srchdir(pat, mkchain)
|
||
register CHARSTAR pat; /* pattern to be matched in directory */
|
||
int mkchain; /* nonzero if results to be remembered */
|
||
{
|
||
DIR * dirf;
|
||
CHARSTAR dirname, dirpref, endir, filepat, p;
|
||
char temp[85+MAXNAMLEN];
|
||
char fullname[85+MAXNAMLEN];
|
||
NAMEBLOCK q;
|
||
DEPBLOCK thisdbl = NULL;
|
||
DEPBLOCK nextdbl = NULL;
|
||
OPENDIR od;
|
||
int dirofl = 0;
|
||
static opendirs = 0;
|
||
PATTERN patp;
|
||
VARBLOCK cp;
|
||
CHARSTAR path, strcpy(), strcat();
|
||
char pth[BUFSIZ];
|
||
|
||
struct direct *entry;
|
||
|
||
|
||
if(mkchain == NO && hashpat(pat))
|
||
return (0);
|
||
|
||
endir = 0;
|
||
|
||
for(p=pat; *p!=CNULL; ++p)
|
||
if(*p==SLASH)
|
||
endir = p;
|
||
|
||
if(endir==0)
|
||
{
|
||
dirpref = "";
|
||
filepat = pat;
|
||
cp = varptr("VPATH");
|
||
if(*cp->varval == 0)
|
||
path = ".";
|
||
else
|
||
{
|
||
path = pth;
|
||
*path = CNULL;
|
||
if(strncmp(cp->varval, ".:", 2) != 0)
|
||
(void) strcpy(pth, ".:");
|
||
(void) strcat(pth, cp->varval);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*endir = CNULL;
|
||
path = strcpy(pth, pat);
|
||
dirpref = concat(pat, "/", temp);
|
||
filepat = endir+1;
|
||
}
|
||
|
||
while(*path)
|
||
{
|
||
dirname = path;
|
||
for(; *path; path++)
|
||
if(*path == KOLON)
|
||
{
|
||
*path++ = CNULL;
|
||
break;
|
||
}
|
||
if(mkchain == NO && hashdir(dirname))
|
||
goto out;
|
||
|
||
dirf = NULL;
|
||
|
||
for(od=firstod ; od!=0; od = od->nextopendir)
|
||
if(equal(dirname, od->dirn))
|
||
{
|
||
dirf = od->dirfc;
|
||
rewinddir(dirf); /* start over at the beginning */
|
||
break;
|
||
}
|
||
|
||
if(dirf == NULL)
|
||
{
|
||
dirf = opendir(dirname);
|
||
if(dirf == NULL)
|
||
{
|
||
#ifdef SCCSDIR
|
||
register int dnamlen = strlen(dirname);
|
||
|
||
if ((dnamlen == 4 && strcmp(dirname, "SCCS") == 0)
|
||
|| (dnamlen > 4 && strcmp(dirname + dnamlen - 5, "/SCCS") == 0))
|
||
goto out;
|
||
#endif
|
||
(void)fprintf(stderr, "Directory %s: ", dirname);
|
||
fatal("Cannot open");
|
||
}
|
||
if(++opendirs < MAXODIR)
|
||
{
|
||
od = ALLOC(opendirectory);
|
||
od->nextopendir = firstod;
|
||
firstod = od;
|
||
od->dirfc = dirf;
|
||
od->dirn = copys(dirname);
|
||
}
|
||
else
|
||
dirofl = 1;
|
||
}
|
||
|
||
while ((entry = readdir(dirf)) != NULL)
|
||
{
|
||
(void)concat(dirpref,entry->d_name,fullname);
|
||
if( (q=srchname(fullname)) ==0)
|
||
q = makename(copys(fullname));
|
||
if(mkchain && amatch(entry->d_name,filepat) )
|
||
{
|
||
thisdbl = ALLOC(depblock);
|
||
thisdbl->nextdep = nextdbl;
|
||
thisdbl->depname = q;
|
||
nextdbl = thisdbl;
|
||
}
|
||
}
|
||
|
||
out:
|
||
if(endir != 0)
|
||
*endir = SLASH;
|
||
if(dirofl)
|
||
closedir(dirf);
|
||
}
|
||
|
||
return(thisdbl);
|
||
}
|
||
|
||
#define DIR_HASHSIZE 16
|
||
FSTATIC struct dirtabent {
|
||
struct dirtabent *nextdir;
|
||
CHARSTAR dirval;
|
||
time_t mtime;
|
||
short flush;
|
||
} *dirtab[DIR_HASHSIZE];
|
||
|
||
hashdir(dir)
|
||
CHARSTAR dir;
|
||
{
|
||
register CHARSTAR p;
|
||
register struct dirtabent *dirp;
|
||
unsigned short val;
|
||
struct stat s;
|
||
int ok;
|
||
|
||
for (val=0, p=dir; *p;)
|
||
val += *p++;
|
||
val %= DIR_HASHSIZE;
|
||
dirp = dirtab[val];
|
||
while (dirp) {
|
||
if (equal(dirp->dirval, dir)) {
|
||
if (dirp->flush) {
|
||
dirp->flush = 0;
|
||
s.st_mtime = 0;
|
||
stat(dir, &s);
|
||
ok = (dirp->mtime == s.st_mtime);
|
||
dirp->mtime = s.st_mtime;
|
||
return (ok);
|
||
}
|
||
return (1);
|
||
}
|
||
dirp = dirp->nextdir;
|
||
}
|
||
dirp = ALLOC(dirtabent);
|
||
dirp->nextdir = dirtab[val];
|
||
dirtab[val] = dirp;
|
||
dirp->dirval = copys(dir);
|
||
dirp->flush = 0;
|
||
s.st_mtime = 0;
|
||
stat(dir, &s);
|
||
dirp->mtime = s.st_mtime;
|
||
return (0);
|
||
}
|
||
|
||
dirflush()
|
||
{
|
||
register struct dirtabent *dirp;
|
||
int i;
|
||
|
||
for (i = 0; i < DIR_HASHSIZE; i++) {
|
||
dirp = dirtab[i];
|
||
while (dirp) {
|
||
dirp->flush = 1;
|
||
dirp = dirp->nextdir;
|
||
}
|
||
}
|
||
}
|
||
|
||
#define PAT_HASHSIZE 64
|
||
FSTATIC PATTERN pattab[PAT_HASHSIZE];
|
||
|
||
hashpat(pat)
|
||
CHARSTAR pat;
|
||
{
|
||
register CHARSTAR p;
|
||
register PATTERN patp;
|
||
unsigned short val;
|
||
|
||
for (val=0, p=pat; *p;)
|
||
val += *p++;
|
||
val %= PAT_HASHSIZE;
|
||
patp = pattab[val];
|
||
while (patp) {
|
||
if (equal(patp->patval, pat))
|
||
return (1);
|
||
patp = patp->nextpattern;
|
||
}
|
||
patp = ALLOC(pattern);
|
||
patp->nextpattern = pattab[val];
|
||
pattab[val] = patp;
|
||
patp->patval = copys(pat);
|
||
return (0);
|
||
}
|
||
|
||
/* stolen from glob through find */
|
||
|
||
amatch(s, p)
|
||
register CHARSTAR s, p;
|
||
{
|
||
register int cc, scc, k;
|
||
int c, lc;
|
||
|
||
top:
|
||
scc = *s;
|
||
lc = 077777;
|
||
switch (c = *p)
|
||
{
|
||
|
||
case LSQUAR:
|
||
k = 0;
|
||
while (cc = *++p)
|
||
{
|
||
switch (cc)
|
||
{
|
||
|
||
case RSQUAR:
|
||
if (k)
|
||
return(amatch(++s, ++p));
|
||
else
|
||
return(0);
|
||
|
||
case MINUS:
|
||
k |= lc <= scc && scc <= (cc=p[1]);
|
||
}
|
||
if(scc==(lc=cc))
|
||
k++;
|
||
}
|
||
return(0);
|
||
|
||
case QUESTN:
|
||
caseq:
|
||
if(scc == 0)
|
||
return(0);
|
||
p++, s++;
|
||
goto top;
|
||
|
||
case STAR:
|
||
return(umatch(s, ++p));
|
||
case 0:
|
||
return(!scc);
|
||
}
|
||
if(c!=scc)
|
||
return(0);
|
||
p++, s++;
|
||
goto top;
|
||
}
|
||
|
||
umatch(s, p)
|
||
register CHARSTAR s, p;
|
||
{
|
||
register c;
|
||
|
||
switch (*p) {
|
||
case 0:
|
||
return (1);
|
||
|
||
case LSQUAR:
|
||
case QUESTN:
|
||
case STAR:
|
||
while(*s)
|
||
if(amatch(s++,p))
|
||
return(1);
|
||
break;
|
||
|
||
default:
|
||
c = *p++;
|
||
while(*s)
|
||
if (*s++ == c && amatch(s, p))
|
||
return (1);
|
||
break;
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
|
||
/* look inside archives for notations a(b) and a((b))
|
||
a(b) is file member b in archive a
|
||
a((b)) is entry point b in object archive a
|
||
*/
|
||
|
||
|
||
#ifdef BSD
|
||
#define ARNLEN 15 /* max number of characters in name */
|
||
#else
|
||
#define ARNLEN 14 /* max number of characters in name */
|
||
#endif
|
||
|
||
TIMETYPE
|
||
lookarch(filename)
|
||
register CHARSTAR filename;
|
||
{
|
||
register int i;
|
||
CHARSTAR p, q;
|
||
extern CHARSTAR strncpy();
|
||
char s[ARNLEN+1];
|
||
int objarch;
|
||
TIMETYPE la();
|
||
|
||
for(p = filename; *p!= LPAREN ; ++p);
|
||
i = p - filename;
|
||
(void)strncpy(archname, filename, i);
|
||
archname[i] = CNULL;
|
||
if(archname[0] == CNULL)
|
||
fatal1("Null archive name `%s'", filename);
|
||
p++;
|
||
if(*p == LPAREN)
|
||
{
|
||
objarch = YES;
|
||
++p;
|
||
if((q = strchr(p, RPAREN)) == NULL)
|
||
q = p + strlen(p);
|
||
i = q - p;
|
||
if(i > ARNLEN)
|
||
i = ARNLEN;
|
||
}
|
||
else
|
||
{
|
||
objarch = NO;
|
||
if((q = strchr(p, RPAREN)) == NULL)
|
||
q = p + strlen(p);
|
||
i = q - p;
|
||
(void)strncpy(archmem, p, i);
|
||
archmem[i] = CNULL;
|
||
if(archmem[0] == CNULL)
|
||
fatal1("Null archive member name `%s'", filename);
|
||
if(p = strrchr(archmem, SLASH))
|
||
++p;
|
||
else
|
||
p = archmem;
|
||
i = ARNLEN;
|
||
}
|
||
(void)strncpy(s, p, i);
|
||
s[i] = CNULL;
|
||
return(la(s, objarch));
|
||
}
|
||
TIMETYPE
|
||
la(am,flag)
|
||
register char *am;
|
||
register int flag;
|
||
{
|
||
TIMETYPE date = 0L;
|
||
|
||
if(openarch(archname) == -1)
|
||
return(0L);
|
||
if(flag)
|
||
date = entryscan(am); /* fatals if cannot find entry */
|
||
else
|
||
date = afilescan(am);
|
||
clarch();
|
||
return(date);
|
||
}
|
||
|
||
TIMETYPE
|
||
afilescan(name) /* return date for named archive member file */
|
||
char *name;
|
||
{
|
||
int len = strlen(name);
|
||
long ptr;
|
||
|
||
if (fseek(arfd, first_ar_mem, 0) != 0)
|
||
{
|
||
seek_error:;
|
||
fatal1("Seek error on archive file %s", archname);
|
||
}
|
||
/*
|
||
* Hunt for the named file in each different type of
|
||
* archive format.
|
||
*/
|
||
switch (ar_type)
|
||
{
|
||
case ARpdp:
|
||
for (;;)
|
||
{
|
||
if (fread((char *)&ar_pdp,
|
||
sizeof(ar_pdp), 1, arfd) != 1)
|
||
{
|
||
if (feof(arfd))
|
||
return (0L);
|
||
break;
|
||
}
|
||
if ((len == sizeof (ar_pdp.ar_name) ||
|
||
ar_pdp.ar_name[len] == '\0') &&
|
||
equaln(ar_pdp.ar_name, name, len))
|
||
return (ar_pdp.ar_date);
|
||
ptr = ar_pdp.ar_size;
|
||
ptr += (ptr & 01);
|
||
if (fseek(arfd, ptr, 1) != 0)
|
||
goto seek_error;
|
||
}
|
||
break;
|
||
#ifndef pdp11
|
||
case AR5:
|
||
for (;;)
|
||
{
|
||
if (fread((char *)&arf_5, sizeof(arf_5), 1, arfd) != 1)
|
||
{
|
||
if (feof(arfd))
|
||
return (0L);
|
||
break;
|
||
}
|
||
if ((len == sizeof (arf_5.arf_name) ||
|
||
arf_5.arf_name[len] == ' ' ||
|
||
arf_5.arf_name[len] == '\0') &&
|
||
equaln(arf_5.arf_name, name, len))
|
||
return (sgetl(arf_5.arf_date));
|
||
ptr = sgetl(arf_5.arf_size);
|
||
ptr += (ptr & 01);
|
||
if (fseek(arfd, ptr, 1) != 0)
|
||
goto seek_error;
|
||
}
|
||
break;
|
||
case ARport:
|
||
for (;;)
|
||
{
|
||
if (fread((char *)&ar_port, sizeof(ar_port), 1,
|
||
arfd) != 1 || !equaln(ar_port.ar_fmag,
|
||
ARFportMAG, sizeof(ar_port.ar_fmag)))
|
||
{
|
||
if (feof(arfd))
|
||
return (0L);
|
||
break;
|
||
}
|
||
if ((len == sizeof (ar_port.ar_name) ||
|
||
ar_port.ar_name[len] == ' ' ||
|
||
ar_port.ar_name[len] == '/' ||
|
||
ar_port.ar_name[len] == '\0') &&
|
||
equaln(ar_port.ar_name, name, len))
|
||
{
|
||
long date;
|
||
|
||
if (sscanf(ar_port.ar_date, "%ld", &date) != 1)
|
||
{
|
||
fatal1("Bad date field for %.*s in %s",
|
||
ARNLEN, name, archname);
|
||
}
|
||
return (date);
|
||
}
|
||
if (sscanf(ar_port.ar_size, "%ld", &ptr) != 1)
|
||
{
|
||
fatal1("Bad size field for %.*s in archive %s",
|
||
ARNLEN, name, archname);
|
||
}
|
||
ptr += (ptr & 01);
|
||
if (fseek(arfd, ptr, 1) != 0)
|
||
goto seek_error;
|
||
}
|
||
break;
|
||
#endif
|
||
}
|
||
/*
|
||
* Only here if fread() [or equaln()] failed and not at EOF
|
||
*/
|
||
fatal1("Read error on archive %s", archname);
|
||
/*NOTREACHED*/
|
||
#if 0
|
||
long date;
|
||
long nsyms;
|
||
long ptr;
|
||
|
||
nsyms = sgetl(head.ar_syms);
|
||
if(fseek(arfd, (long)( nsyms*sizeof(symbol)+sizeof(head) ), 0) == -1)
|
||
fatal("Seek error on archive file %s", archname);
|
||
for(;;)
|
||
{
|
||
if(fread(&fhead, sizeof(fhead), 1, arfd) != 1)
|
||
if(feof(arfd))
|
||
break;
|
||
else
|
||
fatal("Read error on archive %s", archname);
|
||
if(equaln(fhead.arf_name, name, 14))
|
||
{
|
||
date = sgetl(fhead.arf_date);
|
||
return(date);
|
||
}
|
||
ptr = sgetl(fhead.arf_size);
|
||
ptr = (ptr+1)&(~1);
|
||
fseek(arfd, ptr, 1);
|
||
}
|
||
return( 0L );
|
||
#endif
|
||
}
|
||
|
||
TIMETYPE
|
||
entryscan(name) /* return date of member containing global var named */
|
||
char *name;
|
||
{
|
||
/*
|
||
* Hunt through each different archive format for the named
|
||
* symbol. Note that the old archive format does not support
|
||
* this convention since there is no symbol directory to
|
||
* scan through for all defined global variables.
|
||
*/
|
||
if (ar_type == ARpdp)
|
||
return (pdpentrys(name));
|
||
if (sym_begin == 0L || num_symbols == 0L)
|
||
{
|
||
no_such_sym:;
|
||
fatal1("Cannot find symbol %s in archive %s", name, archname);
|
||
}
|
||
if (fseek(arfd, sym_begin, 0) != 0)
|
||
{
|
||
seek_error:;
|
||
fatal1("Seek error on archive file %s", archname);
|
||
}
|
||
#ifndef pdp11
|
||
if (ar_type == AR5)
|
||
{
|
||
register int i;
|
||
int len = strlen(name) + 1;
|
||
|
||
if (len > 8)
|
||
len = 8;
|
||
for (i = 0; i < num_symbols; i++)
|
||
{
|
||
if (fread((char *)&ars_5, sizeof(ars_5), 1, arfd) != 1)
|
||
{
|
||
read_error:;
|
||
fatal1("Read error on archive %s", archname);
|
||
}
|
||
if (equaln(ars_5.sym_name, name, len))
|
||
{
|
||
if (fseek(arfd, sgetl(ars_5.sym_ptr), 0) != 0)
|
||
goto seek_error;
|
||
if (fread((char *)&arf_5,
|
||
sizeof(arf_5), 1, arfd) != 1)
|
||
{
|
||
goto read_error;
|
||
}
|
||
/* replace symbol name with member name */
|
||
strncpy(archmem, arf_5.arf_name,
|
||
sizeof (arf_5.arf_name));
|
||
return (sgetl(arf_5.arf_date));
|
||
}
|
||
}
|
||
}
|
||
else /* ar_type == ARport */
|
||
{
|
||
extern char *malloc();
|
||
int strtablen;
|
||
#ifdef BSD
|
||
register struct ranlib *offs;
|
||
#else
|
||
register char *offs; /* offsets table */
|
||
#endif
|
||
register char *syms; /* string table */
|
||
#ifdef BSD
|
||
register struct ranlib *offend; /* end of offsets table */
|
||
#else
|
||
register char *strend; /* end of string table */
|
||
#endif
|
||
char *strbeg;
|
||
|
||
/*
|
||
* Format of the symbol directory for this format is
|
||
#ifdef BSD
|
||
* as follows: [sputl()d number_of_symbols * sizeof(struct ranlib)]
|
||
#else
|
||
* as follows: [sputl()d number_of_symbols]
|
||
#endif
|
||
* [sputl()d first_symbol_offset]
|
||
#ifdef BSD
|
||
* [sputl()d first_string_table_offset]
|
||
#endif
|
||
* ...
|
||
* [sputl()d number_of_symbols'_offset]
|
||
#ifdef BSD
|
||
* [sputl()d last_string_table_offset]
|
||
#endif
|
||
* [null_terminated_string_table_of_symbols]
|
||
*/
|
||
#ifdef BSD
|
||
/* have already read the num_symbols info */
|
||
if ((offs = (struct ranlib *)malloc(num_symbols * sizeof(struct ranlib))) == NULL)
|
||
#else
|
||
if ((offs = malloc(num_symbols * sizeof(long))) == NULL)
|
||
#endif
|
||
{
|
||
fatal1("Cannot alloc offset table for archive %s",
|
||
archname);
|
||
}
|
||
#ifdef BSD
|
||
if (fread(offs, sizeof(struct ranlib), num_symbols, arfd)
|
||
!= num_symbols)
|
||
#else
|
||
if (fread(offs, sizeof(long), num_symbols, arfd) != num_symbols)
|
||
#endif
|
||
goto read_error;
|
||
#ifdef BSD
|
||
if (fread(&strtablen, sizeof(int), 1, arfd) != 1)
|
||
goto read_error;
|
||
#else
|
||
strtablen = sym_size - ((num_symbols + 1) * sizeof(long));
|
||
#endif
|
||
if ((syms = malloc(strtablen)) == NULL)
|
||
{
|
||
fatal1("Cannot alloc string table for archive %s",
|
||
archname);
|
||
}
|
||
if (fread(syms, sizeof(char), strtablen, arfd) != strtablen)
|
||
goto read_error;
|
||
#ifdef BSD
|
||
offend = &offs[num_symbols];
|
||
#else
|
||
strend = &syms[strtablen];
|
||
#endif
|
||
strbeg = syms;
|
||
#ifdef BSD
|
||
while (offs < offend )
|
||
#else
|
||
while (syms < strend)
|
||
#endif
|
||
{
|
||
#ifdef BSD
|
||
if (strcmp(&syms[offs->ran_un.ran_strx], name) == 0)
|
||
#else
|
||
if (equal(syms, name))
|
||
#endif
|
||
{
|
||
long ptr, date;
|
||
register CHARSTAR ap, hp;
|
||
|
||
#ifdef BSD
|
||
ptr = offs->ran_off;
|
||
#else
|
||
ptr = sgetl(offs);
|
||
#endif
|
||
if (fseek(arfd, ptr, 0) != 0)
|
||
goto seek_error;
|
||
if (fread((char *)&ar_port, sizeof(ar_port), 1,
|
||
arfd) != 1 || !equaln(ar_port.ar_fmag,
|
||
ARFportMAG, sizeof(ar_port.ar_fmag)))
|
||
{
|
||
goto read_error;
|
||
}
|
||
if (sscanf(ar_port.ar_date, "%ld", &date) != 1)
|
||
{
|
||
fatal1("Bad date for %.*s, archive %s",
|
||
ARNLEN, ar_port.ar_name, archname);
|
||
}
|
||
/* replace symbol name with member name */
|
||
ap = archmem;
|
||
hp = ar_port.ar_name;
|
||
while (*hp && *hp != '/' &&
|
||
ap < &archmem[sizeof (archmem)])
|
||
{
|
||
*ap++ = *hp++;
|
||
}
|
||
free(strbeg);
|
||
return (date);
|
||
}
|
||
#ifdef BSD
|
||
offs += sizeof(struct ranlib);
|
||
#else
|
||
syms += strlen(syms) + 1;
|
||
offs += sizeof(long);
|
||
#endif
|
||
}
|
||
free(strbeg);
|
||
}
|
||
#endif
|
||
goto no_such_sym;
|
||
#if 0
|
||
register int i;
|
||
long date;
|
||
long ptr;
|
||
long nsyms;
|
||
|
||
nsyms = sgetl(head.ar_syms);
|
||
for(i = 0; i < nsyms; i++)
|
||
{
|
||
if(fread(&symbol, sizeof(symbol), 1, arfd) != 1)
|
||
badread:
|
||
fatal("Read error on archive %s", archname);
|
||
if(equaln(symbol.sym_name, name, 8))
|
||
{
|
||
ptr = sgetl(symbol.sym_ptr);
|
||
if(fseek(arfd, ptr, 0) == -1)
|
||
fatal("Seek error on archive file %s",archname);
|
||
if(fread(fhead, sizeof(fhead), 1, arfd) != 1)
|
||
goto badread;
|
||
date = sgetl(fhead.arf_date);
|
||
return(date);
|
||
}
|
||
}
|
||
fatal("Cannot find symbol %s in archive %s", name, archname);
|
||
#endif
|
||
}
|
||
|
||
TIMETYPE
|
||
pdpentrys(name)
|
||
char *name;
|
||
{
|
||
long skip;
|
||
long last;
|
||
int len;
|
||
register int i;
|
||
|
||
#ifndef pdp11
|
||
fatal("Cannot do global variable search in pdp11 or old object file.");
|
||
/*NOTREACHED*/
|
||
#else
|
||
len = strlen(name);
|
||
if (len > 8)
|
||
len = 8;
|
||
/*
|
||
* Look through archive, an object file entry at a time. For each
|
||
* object file, jump to its symbol table and check each external
|
||
* symbol for a match. If found, return the date of the module
|
||
* containing the symbol.
|
||
*/
|
||
if (fseek(arfd, sizeof(short), 0) != 0)
|
||
{
|
||
seek_error:;
|
||
fatal1("Cannot seek on archive file %s", archname);
|
||
}
|
||
while (fread((char *)&ar_pdp, sizeof(ar_pdp), 1, arfd) == 1)
|
||
{
|
||
last = ftell(arfd);
|
||
if (ar_pdp.ar_size < sizeof(arobj_pdp) ||
|
||
fread((char *)&arobj_pdp, sizeof(arobj_pdp), 1, arfd)
|
||
!= 1 ||
|
||
(arobj_pdp.a_magic != 0401 && /* A_MAGIC0 */
|
||
arobj_pdp.a_magic != 0407 && /* A_MAGIC1 */
|
||
arobj_pdp.a_magic != 0410 && /* A_MAGIC2 */
|
||
arobj_pdp.a_magic != 0411 && /* A_MAGIC3 */
|
||
arobj_pdp.a_magic != 0405 && /* A_MAGIC4 */
|
||
arobj_pdp.a_magic != 0437)) /* A_MAGIC5 */
|
||
{
|
||
fatal1("%s is not an object module", ar_pdp.ar_name);
|
||
}
|
||
skip = arobj_pdp.a_text + arobj_pdp.a_data;
|
||
if (!arobj_pdp.a_flag)
|
||
skip *= 2;
|
||
if (skip >= ar_pdp.ar_size || fseek(arfd, skip, 1) != 0)
|
||
goto seek_error;
|
||
skip = ar_pdp.ar_size;
|
||
skip += (skip & 01) + last;
|
||
i = (arobj_pdp.a_syms / sizeof(ars_pdp)) + 1;
|
||
while (--i > 0) /* look through symbol table */
|
||
{
|
||
if (fread((char *)&ars_pdp, sizeof(ars_pdp), 1, arfd)
|
||
!= 1)
|
||
{
|
||
fatal1("Read error on archive %s", archname);
|
||
}
|
||
if ((ars_pdp.n_type & 040) /* N_EXT for pdp11 */
|
||
&& equaln(ars_pdp.n_name, name, len))
|
||
{
|
||
(void)strncpy(archmem, ar_pdp.ar_name, ARNLEN);
|
||
archmem[ARNLEN] = '\0';
|
||
return (ar_pdp.ar_date);
|
||
}
|
||
}
|
||
if (fseek(arfd, skip, 0) != 0)
|
||
goto seek_error;
|
||
}
|
||
return (0L);
|
||
#endif
|
||
}
|
||
|
||
|
||
openarch(f)
|
||
register CHARSTAR f;
|
||
{
|
||
unsigned short mag_pdp; /* old archive format */
|
||
char mag_5[SAR5MAG]; /* 5.0 archive format */
|
||
char mag_port[SARportMAG]; /* port (6.0) archive format */
|
||
|
||
arfd = fopen(f, "r");
|
||
if(arfd == NULL)
|
||
return(-1);
|
||
/*
|
||
* More code for three archive formats. Read in just enough to
|
||
* distinguish the three types and set ar_type. Then if it is
|
||
* one of the newer archive formats, gather more info.
|
||
*/
|
||
if (fread((char *)&mag_pdp, sizeof(mag_pdp), 1, arfd) != 1)
|
||
return (-1);
|
||
if (mag_pdp == (unsigned short)ARpdpMAG)
|
||
{
|
||
ar_type = ARpdp;
|
||
first_ar_mem = ftell(arfd);
|
||
sym_begin = num_symbols = sym_size = 0L;
|
||
return (0);
|
||
}
|
||
if (fseek(arfd, 0L, 0) != 0 || fread(mag_5, SAR5MAG, 1, arfd) != 1)
|
||
return (-1);
|
||
if (equaln(mag_5, AR5MAG, SAR5MAG))
|
||
{
|
||
ar_type = AR5;
|
||
/*
|
||
* Must read in header to set necessary info
|
||
*/
|
||
if (fseek(arfd, 0L, 0) != 0 ||
|
||
fread((char *)&arh_5, sizeof(arh_5), 1, arfd) != 1)
|
||
{
|
||
return (-1);
|
||
}
|
||
#ifdef pdp11
|
||
fatal1("Cannot handle 5.0 archive format for %s", archname);
|
||
/*NOTREACHED*/
|
||
#else
|
||
sym_begin = ftell(arfd);
|
||
num_symbols = sgetl(arh_5.ar_syms);
|
||
first_ar_mem = sym_begin + sizeof(ars_5) * num_symbols;
|
||
sym_size = 0L;
|
||
return (0);
|
||
#endif
|
||
}
|
||
if (fseek(arfd, 0L, 0) != 0 ||
|
||
fread(mag_port, SARportMAG, 1, arfd) != 1)
|
||
{
|
||
return (-1);
|
||
}
|
||
if (equaln(mag_port, ARportMAG, SARportMAG))
|
||
{
|
||
ar_type = ARport;
|
||
/*
|
||
* Must read in first member header to find out
|
||
* if there is a symbol directory
|
||
*/
|
||
if (fread((char *)&ar_port, sizeof(ar_port), 1, arfd) != 1 ||
|
||
!equaln(ARFportMAG, ar_port.ar_fmag,
|
||
sizeof(ar_port.ar_fmag)))
|
||
{
|
||
return (-1);
|
||
}
|
||
#ifdef pdp11
|
||
fatal1("Cannot handle portable archive format for %s",
|
||
archname);
|
||
/*NOTREACHED*/
|
||
#else
|
||
#ifdef BSD
|
||
if (equaln(ar_port.ar_name,"__.SYMDEF ",16))
|
||
#else
|
||
if (ar_port.ar_name[0] == '/')
|
||
#endif
|
||
{
|
||
char s[4];
|
||
|
||
if (sscanf(ar_port.ar_size, "%ld", &sym_size) != 1)
|
||
return (-1);
|
||
sym_size += (sym_size & 01); /* round up */
|
||
if (fread(s, sizeof(s), 1, arfd) != 1)
|
||
return (-1);
|
||
#ifdef BSD
|
||
num_symbols = sgetl(s) / sizeof(struct ranlib);
|
||
#else
|
||
num_symbols = sgetl(s);
|
||
#endif
|
||
sym_begin = ftell(arfd);
|
||
first_ar_mem = sym_begin + sym_size - sizeof(s);
|
||
}
|
||
else /* there is no symbol directory */
|
||
{
|
||
sym_size = num_symbols = sym_begin = 0L;
|
||
first_ar_mem = ftell(arfd) - sizeof(ar_port);
|
||
}
|
||
return (0);
|
||
#endif
|
||
}
|
||
fatal1("%s is not an archive", f);
|
||
/*NOTREACHED*/
|
||
#if 0
|
||
if(fread(&head, sizeof(head), 1, arfd) != 1)
|
||
return(-1);
|
||
if(!equaln(head.ar_magic, ARMAG, 4))
|
||
fatal1("%s is not an archive", f);
|
||
return(0);
|
||
#endif
|
||
}
|
||
|
||
clarch()
|
||
{
|
||
if(arfd != NULL)
|
||
fclose(arfd);
|
||
}
|
||
|
||
/*
|
||
* Used when unlinking files. If file cannot be stat'ed or it is
|
||
* a directory, then do not remove it.
|
||
*/
|
||
isdir(p)
|
||
char *p;
|
||
{
|
||
struct stat statbuf;
|
||
|
||
if(stat(p, &statbuf) == -1)
|
||
return(1); /* no stat, no remove */
|
||
if((statbuf.st_mode&S_IFMT) == S_IFDIR)
|
||
return(1);
|
||
return(0);
|
||
}
|
||
|
||
#ifdef BSD
|
||
/*
|
||
* The intent here is to provide a means to make the value of
|
||
* bytes in an io-buffer correspond to the value of a long
|
||
* in the memory while doing the io a `long' at a time.
|
||
* Files written and read in this way are machine-independent.
|
||
*
|
||
*/
|
||
#include <values.h>
|
||
|
||
long
|
||
sgetl(buffer)
|
||
register char *buffer;
|
||
{
|
||
register long w = 0;
|
||
register int i = BITSPERBYTE * sizeof(long);
|
||
|
||
while ((i -= BITSPERBYTE) >= 0)
|
||
w |= (long) ((unsigned char) *buffer++) << i;
|
||
return (w);
|
||
}
|
||
#endif
|