File:  [MW Coherent from dump] / coherent / d / bin / ar.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * Archive manager.
 * Also manages libraries for the
 * link editor,
 * including ranlib header updates.
 */
#define	RUNRSX	0
#define	FMTRSX	0		/* Achives in COHERENT format */

#include <stdio.h>
#include <ar.h>
#include <canon.h>
#include <sys/types.h>
#if !RUNRSX
#include <sys/stat.h>
#endif

#define	RO	0
#define	RW	1

#define	NONE	0
#define	BEFORE	1
#define	AFTER	2

#define	ALLOK	0
#define	NOTALL	1
#define	ERROR	2

#define	aechk()	{ if(ferror(afp)) ioerr(anp); }
#define	techk()	{ if(ferror(tfp)) ioerr(tnp); }

char	nwork[] = "No work";
char	found[]	= "found";
char	copen[]	= "%s: cannot open";
char	ccrea[] = "%s: cannot create";
char	creop[] = "%s: cannot reopen";

FILE	*afp;
FILE	*tfp;
FILE	*rfp;
struct	ar_hdr ahb;
int	nname;
char	**namep;
char	*ctime();
int	usage();
long	fsize();
long	ftell();
int	cflag;
int	kflag;
int	lflag;
int	sflag;
int	uflag;
int	vflag;
char	*pnp;
char	*anp;
char	*tnp;
char	rnp[] = HDRNAME;
int	xstat	 = ALLOK;
int	pos	 = NONE;
int	(*ffp)() = usage;

#if RUNRSX
struct	header fhb;
time_t	fmdate();
time_t	getmdate();
#else
char	state[] = "%s: stat error";
#endif

main(argc, argv)
char *argv[];
{
	register char *p;
	register i;
	int usage(), rfunc();

	if (argc < 2)
		usage();
	key(argv[1]);
	nname = argc-2;
	namep = &argv[2];
	for (i=2; i<argc; ++i) {
		p = argv[i];
		if (pos!=NONE && pnp==NULL) {
			pnp = p;
			++namep;
			--nname;
		} else if (anp == NULL) {
			anp = p;
			++namep;
			--nname;
		}
	}
	if (anp == NULL)
		usage();
	if (pos != NONE) {
		if (pnp == NULL)
			usage();
		if (ffp == usage)
			ffp = rfunc;
	}
	(*ffp)();
	delexit(xstat);
}

/*
 * Decode key.
 * Save function name in 'ffp'.
 * Set 'c', 'l', 'k' and 'v' flags.
 */
key(p)
register char *p;
{
	register c;
	int dfunc(), rfunc(), qfunc(), tfunc();
	int mfunc(), xfunc(), pfunc();

	while (c = *p++) {
		switch (c) {

		case 'd':	/* Delete */
			ffp = dfunc;
			break;

		case 'r':	/* Replace */
			ffp = rfunc;
			break;

		case 'q':	/* Quick append */
			ffp = qfunc;
			break;

		case 't':	/* Tabulate */
			ffp = tfunc;
			break;

		case 'p':	/* Print */
			ffp = pfunc;
			break;

		case 'm':	/* Move */
			ffp = mfunc;
			break;

		case 'x':	/* Extract */
			ffp = xfunc;
			break;

		case 'c':	/* no create message */
			++cflag;
			break;

		case 'k':	/* keep dates */
			++kflag;
			break;

		case 'l':	/* local temp file */
			++lflag;
			break;

		case 's':	/* ranlib symbol table */
			++sflag;
			break;

		case 'u':	/* update replace */
			++uflag;
			break;

		case 'v':	/* verbose */
			++vflag;
			break;

		case 'a':	/* after position or append */
			pos = AFTER;
			break;

		case 'b':	/* before position */
		case 'i':	/* insert */
			pos = BEFORE;
			break;

		default:
			usage();
		}
	}
}

/*
 * Replace.
 * Eliminate dead stuff if 'u'.
 * Copy up to insert point.
 * Copy in new files.
 * Copy the rest of the file.
 * Copy back.
 */
rfunc()
{
	register char *qfn;
	register i, nef;
	FILE *qfp;

	if (nname == 0)
		diag(1, nwork);
	aopen(RW);
	ropen();
	if (uflag) {
		update();
		fseek(afp, (long)sizeof(int), 0);
		if (rfp != NULL) {
			geth();
			if (eqh(rnp))
				fseek(afp, (long)ahb.ar_size, 1);
			else
				fseek(afp, (long)sizeof(int), 0);
		}
	}
	topen();
	while (nef = geth()) {
		if (pos==BEFORE && eqh(pnp)) {
			fseek(afp, (long)-sizeof(struct ar_hdr), 1);
			break;
		}
		if (pos == NONE) {
			for (i=0; i<nname; ++i) {
				if ((qfn=namep[i])!=NULL && eqh(qfn))
					break;
			}
			if (i != nname) {
				fseek(afp, ahb.ar_size, 1);
				namep[i] = NULL;
				remove(i, qfn);
				if ((qfp = fopen(qfn, "rb")) == NULL)
					diag(1, copen, qfn);
				makeh(qfn, qfp);
				if (vflag)
					printf("%s: in place replace.\n", qfn);
				puth();
				ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn));
				fclose(qfp);
				continue;
			}
		}
		mmove(0);
		if (pos==AFTER &&  eqh(pnp))
			break;
	}
	if (nef==0 && pos!=NONE)
		diag(1, "%s: not in archive", pnp);
	for (i=0; i<nname; ++i) {
		if ((qfn=namep[i]) == NULL)
			continue;
		remove(i, qfn);
		if ((qfp=fopen(qfn, "rb")) == NULL)
			diag(1, copen, qfn);
		makeh(qfn, qfp);
		if (vflag)
			printf("%s: replaced.\n", qfn);
		puth();
		ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn));
		fclose(qfp);
	}
	while (geth())
		mmove(0);
	tacopy();
}

/*
 * Handle the 'u' option.
 * Read through the archive, comparing
 * the dates in the headers to the last
 * modification dates of the files in
 * the command line. Make some files
 * go away.
 */
update()
{
	register char *p;
	register i;
#if !RUNRSX
	struct stat sb;
#endif

	while (geth()) {
		for (i=0; i<nname; ++i) {
			p = namep[i];
			if (p!=NULL && eqh(p)) {
#if RUNRSX
				if (ahb.ar_date >= fmdate(p)) {
#else
				if (stat(p, &sb) < 0)
					diag(1, state, p);
				if (ahb.ar_date >= sb.st_mtime) {
#endif
					if (vflag)
						printf("%s: no update.\n", p);
					namep[i] = NULL;
					remove(i, p);
				}
			}
		}
		fseek(afp, ahb.ar_size, 1);
	}
	for (i=0; i<nname && namep[i]==NULL; ++i)
		;
	if (i >= nname) {
		if (vflag)
			fprintf(stderr, "%s.\n", nwork);
		delexit(ALLOK);
	}
}

/*
 * Move.
 * Copy stuff before insert.
 * Copy moved stuff.
 * Copy remainder.
 * Copy back to archive.
 */
mfunc()
{
	register nef;
	long s;

	aopen(RW);
	ropen();
	topen();
	while (nef = geth()) {
		if (pos==BEFORE && eqh(pnp))
			break;
		mmove(0);
		if (pos==AFTER &&  eqh(pnp))
			break;
	}
	if (nef==0 && pos!=NONE)
		diag(1, "%s: not in archive", pnp);
	s = ftell(afp);
	if (pos == BEFORE)
		s -= sizeof(struct ar_hdr);
	fseek(afp, (long)sizeof(int), 0);
	while (geth())
		mmove(1);
	if (nef) {
		fseek(afp, s, 0);
		while (geth())
			mmove(0);
	}
	tacopy();
}

/*
 * Conditional move to the
 * temp file from the archive
 * file. Used by move and replace
 */
mmove(f1)
register f1;
{
	register f2, i;
	register long size;

	f2 = 0;
	for (i=0; i<nname; ++i) {
		if (eqh(namep[i])) {
			++f2;
			break;
		}
	}
	if (f1 == f2) {
		if (vflag)
			amsg("copied");
		size = ahb.ar_size;
		puth();
		ffcopy(tfp, tnp, afp, anp, size);
	} else {
		if (vflag)
			amsg("skipped");
		fseek(afp, ahb.ar_size, 1);
	}
}

/*
 * Print.
 */
pfunc()
{
	aopen(RO);
	while (geth()) {
		if (nname==0 || match())
			pfile();
		else
			fseek(afp, ahb.ar_size, 1);
	}
	if (nname != 0)
		notdone(found);
}

pfile()
{
#if FMTRSX
	register char *rb;
	register i;
	long s;
	int n;

	if (vflag)
		amsg(NULL);
	if ((rb = malloc(ahb.ar_ufat.f_rsiz)) == NULL)
		diag(1, "Out of space");
	s = ahb.ar_size;
	while (s != 0) {
		if (ahb.ar_ufat.f_rtyp == R_FIX)
			n = ahb.ar_ufat.f_rsiz;
		else {
			fread(&n, sizeof(int), 1, afp);
			s -= sizeof(int);
		}
		fread(rb, sizeof(char), n, afp);
		for (i=0; i<n; ++i)
			putchar(rb[i]);
		if ((ahb.ar_ufat.f_ratt&FD_CR) != 0)
			putchar('\n');
		if ((n&01) != 0) {
			++n;
			fseek(afp, (long)1, 1);
		}
		s -= n;
	}
	free(rb);
#else
	if (vflag)
		amsg(NULL);
	ffcopy(stdout, "Stdout", afp, anp, ahb.ar_size);
#endif
}

/*
 * Delete.
 * Copy archive to temp, deleting
 * members along the way. If all of
 * the files have been deleted then
 * copy back.
 */
dfunc()
{
	register long size;

	if (nname == 0)
		diag(1, nwork);
	aopen(RW);
	ropen();
	topen();
	while (geth()) {
		if (match()) {
			if (vflag)
				amsg("deleted");
			fseek(afp, ahb.ar_size, 1);
			continue;
		}
		if (vflag)
			amsg("copied");
		size = ahb.ar_size;
		puth();
		ffcopy(tfp, tnp, afp, anp, size);
	}
	if (notdone("deleted"))
		delexit(ERROR);
	tacopy();
}

/*
 * Quick insert.
 * Copy archive to temp file.
 * Tack new files onto the end.
 * If no errors, copy back.
 */
qfunc()
{
	register char *qfn;
	register FILE *qfp;
	register i;

	if (nname == 0)
		diag(1, nwork);
	aopen(RW);
	if (geth() != 0 && eqh(rnp)) {
		fseek(afp, (long)-sizeof(ahb), 1);
		ahb.ar_date = 0;
		aputh();
	}
	fseek(afp, (long)0, 2);
	for (i=0; i<nname; ++i) {
		if ((qfn=namep[i]) == NULL)
			continue;
		remove(i, qfn);
		if ((qfp=fopen(qfn, "rb")) == NULL)
			diag(1, copen, qfn);
		makeh(qfn, qfp);
		if (vflag)
			printf("%s: quick insert.\n", qfn);
		aputh();
		ffcopy(afp, anp, qfp, qfn, fsize(qfp, qfn));
		fclose(qfp);
	}
}

/*
 * Table.
 * Read through archive.
 * If good member print its name.
 * If verbose, print extra stuff.
 */
tfunc()
{
	register char *p;
	register c, n;

	aopen(RO);
	while (geth()) {
		if (nname==0 || match()) {
			n = 0;
			p = ahb.ar_name;
			while (n<DIRSIZ && (c=*p++)) {
				putchar(c);
				++n;
			}
			if (vflag) {
				while (n++ < DIRSIZ+1)
					putchar(' ');
#if FMTRSX
				printf("[%03o,%03o] ", ahb.ar_gid, ahb.ar_uid);
				printf("%06o ", ahb.ar_mode);
#else
				printf("%5d %5d ", ahb.ar_gid, ahb.ar_uid);
				printf("%03o ",  ahb.ar_mode);
#endif
				printf("%10ld ", ahb.ar_size);
				printf("%s", ctime(&ahb.ar_date));
			} else
				putchar('\n');
		}
		fseek(afp, ahb.ar_size, 1);
	}
	if (nname != 0)
		notdone(found);
}

/*
 * Extract.
 * Read through archive.
 * Extract any files you find.
 * At end, mutter about files
 * that were not there.
 */
xfunc()
{
	register char *p1, *p2;
	register c;
	char fnb[DIRSIZ+1];
	FILE *xfp;

	aopen(RO);
	while (geth()) {
		if (nname==0 || match()) {
			p1 = ahb.ar_name;
			p2 = fnb;
			while (p1<&ahb.ar_name[DIRSIZ] && (c=*p1++))
				*p2++ = c;
			*p2 = 0;
			if ((xfp=fopen(fnb, "wb")) == NULL) {
				diag(0, ccrea, fnb);
				fseek(afp, ahb.ar_size, 1);
				continue;
			}
			if (vflag)
				amsg("extracting");
			ffcopy(xfp, fnb, afp, anp, ahb.ar_size);
#if RUNRSX && FMTRSX
			fseek(xfp, (long)0, 0);
			xfp->v_rtyp = ahb.ar_ufat.f_rtyp;
			xfp->v_ratt = ahb.ar_ufat.f_ratt;
			xfp->v_rsiz = ahb.ar_ufat.f_rsiz;
			xfp->v_hibk = ahb.ar_ufat.f_hibk;
			xfp->v_efbk = ahb.ar_ufat.f_efbk;
			xfp->v_ffby = ahb.ar_ufat.f_ffby;
#endif
#if !RUNRSX && !FMTRSX
			chmod(fnb, ahb.ar_mode);
#endif
			fclose(xfp);
			if (kflag) {
#if !RUNRSX && !FMTRSX
				time_t	times[2];
				time_t	time();

				time(times+0);
				times[1] = ahb.ar_date;
				if (utime(fnb, times) < 0)
					diag(0, "Unable to set time for %s",
					 fnb);
#endif
			}
		} else
			fseek(afp, ahb.ar_size, 1);
	}
	if (nname != 0)
		notdone(found);
}

/*
 * Make an archive header.
 * Put it in the external archive
 * header buffer 'ahb'. The arg.
 * 'fn' is the file name. The file
 * is open on 'fp'.
 */
makeh(fn, fp)
char *fn;
FILE *fp;
{
	register char *p1, *p2;
	register c;
#if !RUNRSX
	struct stat sb;
#endif

	for (p1=fn; *p1++; )
		;
	while (p1 > fn) {
		c = p1[-1];
#if RUNRSX
		if (c==':' || c==']')
			break;
#endif
#if COHERENT
		if (c == '/')
			break;
#endif
#if GEMDOS
		if (c == '\\')
			break;
#endif
		--p1;
	}
	p2 = ahb.ar_name;
	while (c = *p1++) {
		if (p2 < &ahb.ar_name[DIRSIZ])
			*p2++ = c;
	}
	while (p2 < &ahb.ar_name[DIRSIZ])
		*p2++ = 0;
#if RUNRSX
	if (ratt(fp, &fhb) == 0)
		diag(1, "%s: ratt failed", fn);
	ahb.ar_date = getmdate(&fhb);
	ahb.ar_size = fsize(fp, fn);
#if FMTRSX
	ahb.ar_uid  = fhb.h_prog;
	ahb.ar_gid  = fhb.h_proj;
	ahb.ar_mode = fhb.h_fpro;
	ahb.ar_ufat.f_rtyp = fp->v_rtyp;
	ahb.ar_ufat.f_ratt = fp->v_ratt;
	ahb.ar_ufat.f_rsiz = fp->v_rsiz;
	ahb.ar_ufat.f_hibk = fp->v_hibk;
	ahb.ar_ufat.f_efbk = fp->v_efbk;
	ahb.ar_ufat.f_ffby = fp->v_ffby;
#else
	ahb.ar_uid  = 0;
	ahb.ar_gid  = 0;
	ahb.ar_mode = 0644;
#endif
#else
#if GEMDOS
	if (stat(fn, &sb) < 0)
#else
	if (fstat(fileno(fp), &sb) < 0)
#endif
		diag(1, state, fn);
	if (kflag)
		ahb.ar_date = sb.st_mtime;
	else
		time(&ahb.ar_date);
	ahb.ar_uid  = sb.st_uid;
	ahb.ar_gid  = sb.st_gid;
	ahb.ar_mode = sb.st_mode&0777;
	ahb.ar_size = sb.st_size;
#endif
}

/*
 * Test if the member whose
 * header is held in the archive
 * header buffer is mentioned in
 * the user's list of members.
 * Return the number of matches.
 * All matches are NULLed.
 */
match()
{
	register char *p;
	register i, n;

	n = 0;
	for (i=0; i<nname; ++i) {
		if ((p=namep[i]) == NULL)
			continue;
		if (eqh(p)) {
			++n;
			namep[i] = NULL;
		}
	}
	return (n);
}

/*
 * Remove all instances of name
 * 'fn' from the list of names that
 * is described by 'namep' and
 * 'nname'.
 * Start at index 'i+1'.
 */
remove(i, fn)
register i;
register char *fn;
{
	register char *p;

	for (++i; i<nname; ++i) {
		if ((p=namep[i]) == NULL)
			continue;
		if (strcmp(fn, p) == 0)
			namep[i] = NULL;
	}
}

/*
 * This routine digs through the
 * list of names described by 'namep'
 * and 'nname' looking for names that
 * have not been NULLed out. If any
 * are found it prints a title and 
 * the names. The number of names that
 * were found is returned.
 */
notdone(s)
char *s;
{
	register char *p;
	register i, n;

	n = 0;
	for (i=0; i<nname; ++i) {
		p = namep[i];
		if (p != NULL) {
			if (n++ == 0)
				fprintf(stderr, "Not %s:\n", s);
			fprintf(stderr, "%s\n", p);
		}
	}
	return (n);
}

/*
 * File to file copy.
 * With ranlib construction.
 */
ffcopy(tfp, tfn, ffp, ffn, s)
FILE *tfp, *ffp;
char *tfn, *ffn;
long s;
{
	register n;
	static char fb[BUFSIZ];

	if (rfp != NULL) raddmod(tfp, ffp);
	while (s != 0) {
		n = (s>BUFSIZ) ? BUFSIZ : s;
		if (fread (fb, sizeof(char), n, ffp) != n)
			ioerr(ffn);
		if (fwrite(fb, sizeof(char), n, tfp) != n)
			ioerr(tfn);
		s -= n;
	}
}

/*
 * Get the next archive header
 * into 'ahb'. Check for any I/O
 * errors. Return true if a header
 * was read and false on EOF.
 */
geth()
{
	if (fread(&ahb, sizeof(ahb), 1, afp) != 1) {
		aechk();
		return (0);
	}
	cantime(ahb.ar_date);
	canshort(ahb.ar_gid);
	canshort(ahb.ar_uid);
	canshort(ahb.ar_mode);
	cansize(ahb.ar_size);
	return (1);
}

/*
 * Write the header in 'ahb' to
 * the temp file.
 */
puth()
{
	cantime(ahb.ar_date);
	canshort(ahb.ar_gid);
	canshort(ahb.ar_uid);
	canshort(ahb.ar_mode);
	cansize(ahb.ar_size);
	fwrite(&ahb, sizeof(ahb), 1, tfp);
	techk();
}

/*
 * Write the header in 'ahb' to
 * the archive file.  from qfunc.
 */
aputh()
{
	cantime(ahb.ar_date);
	canshort(ahb.ar_gid);
	canshort(ahb.ar_uid);
	canshort(ahb.ar_mode);
	cansize(ahb.ar_size);
	fwrite(&ahb, sizeof(ahb), 1, afp);
	aechk();
}

/*
 * Compare a string to the name
 * of the member in the archive header
 * buffer. True return if same.
 */
eqh(p)
char *p;
{
	register char *p1, *p2;
	register c;

	if ((p1 = p) == NULL)
		return (0);
	while (*p1++)
		;
	while (p1 > p) {
		c = p1[-1];
#if RUNRSX
		if (c==':' || c==']')
			break;
#endif
#if COHERENT
		if (c == '/')
			break;
#endif
#if GEMDOS
		if (c == '\\')
			break;
#endif
		--p1;
	}
	p2 = ahb.ar_name;
	c  = DIRSIZ;
	while (c && *p1 == *p2++) {
		if (*p1++ == 0)
			return (1);
		--c;
	}
	if (c == 0)
		return (1);
	return (0);
}

/*
 * Open archive.
 * The argument 'aam' is the
 * access mode (RO or RW).
 */
aopen(aam)
{
	int i;

	if ((afp=fopen(anp, "rb")) == NULL) {
		if (aam == RO)
			diag(1, copen, anp);
		if ((afp=fopen(anp, "wb"))==NULL
		 || (afp=freopen(anp, "wrb", afp))==NULL)
			diag(1, ccrea, anp);
		if (cflag == 0)
			printf("%s: new archive.\n", anp);
		i = ARMAG;
		canint(i);
		fwrite(&i, sizeof(i), 1, afp);
		aechk();
		return;
	}
	if (aam != RO) {
		fclose(afp);
		if ((afp=fopen(anp, "rwb"))==NULL)
			diag(1, copen, anp);
	}
	fread(&i, sizeof(i), 1, afp);
	aechk();
	canint(i);
	if (i != ARMAG)
		diag(1, "%s: not an archive", anp);
}

/*
 * Open tempfile.
 * Stash the name in 'tnp' for
 * the benefit of 'delexit'.
 * Honour the 'l' option w.r.t.
 * file placement.
 */
topen()
{
	int i;

#if COHERENT || GEMDOS
	extern char *tempnam();
	tnp = tempnam((lflag ? "." : NULL), "v");
#endif
#if RUNRSX
	tnp = "ar.tmp";
#endif
	if ((tfp=fopen(tnp, "wb")) == NULL) 
		diag(1, ccrea, tnp);
	i = ARMAG;
	canint(i);
	fwrite(&i, sizeof(i), 1, tfp);
	techk();
}

/*
 * Copy tempfile back to the
 * archive.
 */
tacopy()
{
	register FILE *xtp;
	int i;

	fclose(tfp);
	tfp = NULL;  /* Scare off delexit */
	fclose(afp);
	if ((xtp=fopen(tnp, "rb")) == NULL)
		diag(1, creop, tnp);
	if ((afp=fopen(anp, "wb")) == NULL)
		diag(1, creop, anp);
	if (vflag)
		printf("%s: copy back.\n", anp);
	if (fread(&i, sizeof(i), 1, xtp) != 1)
		ioerr(tnp);
	if (fwrite(&i, sizeof(i), 1, afp) != 1)
		ioerr(anp);
	if (rfp != NULL) rcopy();
	ffcopy(afp, anp, xtp, tnp, fsize(xtp, tnp)-sizeof(int));
	tfp = xtp;   /* Delete */
}

/*
 * Write diagnostic.
 * The flag 'f' marks fatal errors.
 */
diag(f, a)
{
	fprintf(stderr, "%r", &a);
	fprintf(stderr, ".\n");
	if (f)
		delexit(ERROR);
	xstat = NOTALL;
}

/*
 * Print a message for a
 * given archive member. The header
 * is in the header buffer. 
 */
amsg(s)
char *s;
{
	register char *p;
	register c;

	p = ahb.ar_name;
	while (p<&ahb.ar_name[DIRSIZ] && (c=*p++)!=0)
		putchar(c);
	putchar(':');
	if (s != NULL)
		printf(" %s.", s);
	putchar('\n');
}

/*
 * Exit.
 * Delete the tempfile if
 * present.
 */
delexit(s)
{
#if RUNRSX
	if (tfp != NULL)
		fmkdl(tfp);
#else
	if (tfp != NULL)
		unlink(tnp);
#endif
#ifdef DEBUG
	if (s)
		abort();
#endif
	exit(s);
}

/*
 * Mutter about an I/O error
 * on file 's'.
 */
ioerr(s)
char *s;
{
	diag(1, "%s: I/O error", s);
}

/*
 * Print usage message.
 */
usage()
{
	fprintf(stderr, "Usage: ar options [posname] afile [name ...].\n");
	delexit(ERROR);
}

/*
 * Compute the size of a file.
 * In bytes.
 * The file must not be seeked.
 */
long
fsize(fp, fn)
register FILE *fp;
char *fn;
{
#if RUNRSX
	return (((fp->v_efbk-1)<<9) + fp->v_ffby);
#else
	struct stat sb;

#if GEMDOS
	if (stat(fn, &sb) < 0)
#endif
#if COHERENT
	if (fstat(fileno(fp), &sb) < 0)
#endif
		diag(1, state, fn);
	return (sb.st_size);
#endif
}

#if RUNRSX
/*
 * The following routines simulate
 * some aspects of Coherent under the
 * dreaded RSX.
 */
#define	DAY	(24L*60L*60L)

time_t
fmdate(fn)
char *fn;
{
	register FILE *fp;
	register s;

	if ((fp=fopen(fn, "rb")) == NULL)
		diag(1, copen, fn);
	s = ratt(fp, &fhb);
	fclose(fp);
	if (s == 0)
		diag(1, "%s: ratt failed", fn);
	return (getmdate(&fhb));
}

time_t
getmdate(fhp)
register struct header *fhp;
{
	register i;
	time_t date;
	int rsxdate[8];
	static	char *mtab[] = {
		"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
		"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
	};

	rsxdate[0] = (fhp->i_rvdt[5]-'0')*10+fhp->i_rvdt[6]-'0';
	for (i=0; i<12; ++i) {
		if (cmp3(&fhp->i_rvdt[2], mtab[i])) {
			rsxdate[1] = i+1;
			break;
		}
	}
	rsxdate[2] = (fhp->i_rvdt[0]-'0')*10+fhp->i_rvdt[1]-'0';
	rsxdate[3] = (fhp->i_rvti[0]-'0')*10+fhp->i_rvti[1]-'0';
	rsxdate[4] = (fhp->i_rvti[2]-'0')*10+fhp->i_rvti[3]-'0';
	rsxdate[5] = (fhp->i_rvti[4]-'0')*10+fhp->i_rvti[5]-'0';
	cvttime(&date, rsxdate);
	return (date);
}

cmp3(p1, p2)
register char *p1, *p2;
{
	if (*p1++==*p2++ && *p1++==*p2++ && *p1++==*p2++)
		return (1);
	return (0);
}

/*
 * Convert rsx date to Coherent
 * format. This routine assumes that
 * the timezone is CST.
 * Courtesy of Tom Duff.
 */
cvttime(date, rsxdate)
register long *date;
int rsxdate[8];
{
	register i;

	*date = 0;
	for (i=70; i!=rsxdate[0]; i++) {
		if (i%4==0)
			*date += 366L*DAY; else
			*date += 365L*DAY;
	}
	for (i=1; i!=rsxdate[1]; i++)
		switch (i){
		case 9:  /* Sep */
		case 4:  /* Apr */
		case 6:  /* Jun */
		case 11: /* Nov */
			*date += 30L*DAY;
			break;

		case 2:  /* Feb */
			if (rsxdate[0]%4 == 0)
				*date += 29L*DAY; else
				*date += 28L*DAY;
			break;

		default:
			*date += 31L*DAY;
		}
	*date += (rsxdate[2]-1)*DAY;
	*date += rsxdate[3]*60L*60L;
	*date += rsxdate[4]*60L;
	*date += rsxdate[5];
	*date += 6L*60L*60L;	/* adjust cst to gmt */
}
#endif

/*
 * Ranlib stuff.
 * If the current archive has HDRNAME as first module,
 * then skip it and open rfp for creation of new ranlib header,
 * otherwise backup and make a vanilla archive.
 * Unless sflag was set as an option,
 * in which case make rfp anyway.
 * Unless HDRNAME matches the name list and ffp == dfunc,
 * in which case make rfp only if sflag was set.
 */
ropen()
{
	extern int dfunc();

	if (geth() != 0) {	/* Must not be end of file */
		if (eqh(rnp)) {
			fseek(afp, (long)ahb.ar_size, 1);
			if (ffp == dfunc && match()) {
				if (vflag)
					amsg("deleted");
			} else
				++sflag;
		} else {
			fseek(afp, (long)-sizeof(ahb), 1);
			if (sflag && ffp == dfunc) {
				strcpy(ahb.ar_name, rnp);
				match();
			}
		}
	}
	if (sflag && (rfp = fopen(rnp, "wb")) == NULL)
		diag(1, ccrea, rnp);
}

/*
 * Add the symbols in mfp to the ranlib header,
 * and seek mfp back to where it began.
 * The postion of this module in the archive
 * is -sizeof(arhdr) from current position of afp.
 */
struct ldheader ldh;
struct ldsym lds;
struct ar_sym ars;

xwrite()
{
	if (fwrite(lds.ls_id, sizeof(lds.ls_id), 1, rfp) != 1
	 || fwrite(&ars.ar_off, sizeof(ars.ar_off), 1, rfp) != 1)
		ioerr(rnp);
}

xread(fp) register FILE *fp;
{
	register int r;
	union { long l; unsigned u[2]; } u;

	if ((ldh.l_flag & LF_32) == 0) {
		r = fread(&lds, sizeof(lds)-sizeof(short), 1, fp);
		u.l = lds.ls_addr;
		canshort(u.u[0]);
		lds.ls_addr = u.u[0];
	} else {
		r = fread(&lds, sizeof(lds), 1, fp);
		canlong(lds.ls_addr);
	}
	canshort(lds.ls_type);
	return (r);
}

raddmod(afp, mfp) FILE *afp, *mfp;
{
	fsize_t	off, offset;
	int	seg, nsym;

	ars.ar_off = ftell(afp) - sizeof(ahb) - sizeof(int);
	cansize(ars.ar_off);
	off = ftell(mfp);
	ldh.l_magic = 0;	/* in case fread fails */
	if (fread(&ldh, sizeof ldh, 1, mfp) != 1)
		goto done;
	canshort(ldh.l_magic);
	if (ldh.l_magic != L_MAGIC)
		goto done;
	canshort(ldh.l_flag);
	if ((ldh.l_flag & LF_32) == 0)
		ldh.l_tbase = sizeof(ldh) - 2*sizeof(short);
	else
		canshort(ldh.l_tbase);
	offset = ldh.l_tbase - (fsize_t)sizeof(ldh);
	for (seg=0; seg<L_SYM; seg++) {
		if (seg==L_BSSI || seg==L_BSSD)
			continue;
		cansize(ldh.l_ssize[seg]);
		offset += ldh.l_ssize[seg];
	}
	fseek(mfp, offset, 1);
	cansize(ldh.l_ssize[L_SYM]);
	if ((ldh.l_flag & LF_32) == 0)
		nsym = ldh.l_ssize[L_SYM]
		    / (sizeof(struct ldsym) - sizeof(short));
	else
		nsym = ldh.l_ssize[L_SYM]/sizeof(struct ldsym);
	while (nsym--) {
		if (xread(mfp) == 0)
			diag(1, "truncated module %.*s", DIRSIZ, ahb.ar_name);
		if ((lds.ls_type&L_GLOBAL) == 0)
			continue;
		if ((lds.ls_type&LR_SEG) != L_REF)
			xwrite();
	}
done:
	fseek(mfp, off, 0);	/* back to beginning of module */
}

/*
 * Copy the ranlib header to the output archive
 * close and null the ranlib file pointer.
 */
rcopy()
{
	register FILE *fp;
	fclose(rfp);
	rfp = NULL;
	if ((fp = fopen(rnp, "rb")) == NULL)
		diag(1, creop, rnp);
	makeh(rnp, fp);
	time(&ahb.ar_date);
	ahb.ar_date += (long)(10*365+3)*24*60*60;
	tfp = afp;
	puth();
	tfp = NULL;
	ffcopy(afp, anp, fp, rnp, fsize(fp, rnp));
	fclose(fp);
	unlink(rnp);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.