#include "../sccshead/sfile.h"
#include "../sccshead/statbuf.h"
#include "../sccshead/sint.h"
# include "../sccshead/had.h"

char prt____[] "~|^`prt.c	3.11";

int	num_files;
char	had[26];
int	release;
int	level;
int	grelease	-1;
int	glevel	-1;

long	cutoff;
int	start, prefix;
int	rofflen 0;
char	newline[] "\n";

main(argc,argv)
int argc;
char *argv[];
{
	register int i;
	register char *p;
	char c;
	extern prt(), fout;

	for(i=1; i<argc; i++)
		if(argv[i][0] == '-' && (c=argv[i][1])) {
			p = &argv[i][2];
			switch (c) {

			case 'c':
				if (*p && dtcvt(p,&cutoff))
					fatal("bad date/time (6)");
				prefix++;
				break;
			case 'y':
				if (*p)
					dor(&grelease,&glevel,p);
				prefix++;
				break;
			case 's':
				if ((start=patoi(p)) == -1)
					fatal("bad starting record (420)");
				break;
			case 'd':
				if (p[0]=='n')
					{
					rofflen=atoi(p+1);
					if(rofflen<=0)
						rofflen=80;
					printf(".pl 1\n.na\n");
					printf(".ll %d\n.in 42\n.ti 0\n",rofflen);
					}
				break;
			case 'a':
			case 'b':
			case 'h':
			case 'p':
			case 'r':
			case 'x':
				break;
			default:
				fatal("unknown key letter (69)");
			}

			had[c - 'a'] = 1;
			argv[i] = 0;
		}
		else num_files++;

	if(num_files == 0) fatal("missing file arg (49)");
	setsig(fatal,fatal,fatal);
	fout = dup(1);
	for (i=1; i<argc; i++)
		if (p=argv[i])
			do_file(p,prt);
	exit(0);
}


int recnum, block, offset;
struct Ibufr ibuf;
long	xtime	441781201L; /* Used by x arg to lie about time */
				/* Value of xtime is Jan 1, 1984 00:00:01 */

/*	`Main' routine.
*/
char	*pfile;

prt(file)
char *file;
{
	register int i;

	pfile = file;
	opnr(&ibuf,pfile);
	if ((HADP || HADH || HADR || HADB) || !(HADY || HADC))
		{
		printf("\n%s:\n\n",pfile);
		if (rofflen>0)
			printf(".ti 0\n");
		}
	recnum = block = offset = 0;
	release = grelease;
	level = glevel;
	if ((HADP|(i=HADS|HADH|HADR|HADD|HADB))==0) HADD = 1;
	else if (i==0) HADS = start = 1;

	if (HADP) doactual();
	else dointerp();

	flush();
	close(ibuf.Ifildes);
}


/*	Routine to read the next record.
*	Computes block, offset, and record number.
*	Handles EOF.
*	Prints block, offset, and record number if required.
*/

nextrec(outyes)
int outyes;
{
	register char *p;

	if ((block+offset)==0) offset = 1;
	else {
		offset =+ ibuf.Ilen + !(ibuf.Ilen&1) + 1;
		block =+ offset>>9;
		offset =& 0777;
	}
	if ((p=getr(&ibuf))==1) fatal("premature eof (58)");
	recnum++;
	if (HADP && outyes)
		out(stringf("RECORD #: %-6d  BLOCK: %-6d  OFFSET: %d\n",
			recnum,block,offset));
	return(p);
}


/*	Prints uninterpreted file.
*	Processes header and release table.
*/

doactual()
{
	register struct Header *hdr;
	register struct Reltab *rt;

	if (HADS) HADH = HADR = HADD = HADB = 1;
	else start = 1;
	hdr = nextrec(HADH);
	if (HADH) {
		out(stringf("Magic number: %d  ",hdr->Hmagicno));
		out(stringf("Default release: %d  ",hdr->Hrdef));
		if (!HADX)
			out(stringf("Hash: %d (0%o)\n",ibuf.Ihtot,ibuf.Ihtot));
		else out(newline);
		dobeg(hdr);
		out(stringf("Floor: %d  Ceiling: %d  Locks: ",
			hdr->Hfloor,hdr->Hceil));
		out(stringf("%5d%5d%5d%5d%5d\n",hdr->Hsw[0],
			hdr->Hsw[1],hdr->Hsw[2],hdr->Hsw[3],hdr->Hsw[4]));
		dowho(hdr);
	}
	if ((HADR|HADD|HADB)==0) return;
	for (rt=nextrec(HADR); rt->Rrel; rt=nextrec(HADR))
		if (HADR) out(stringf("Release %d: %d levels\n",
			rt->Rrel,rt->Rlevs));
	if (HADR) out(stringf("Release 0: %d levels\n",rt->Rlevs));
	if ((HADD|HADB)==0) return;
	dodel();
	if (HADB==0) return;
	dobod();
}


/*	Prints interpreted file.
*	Processes header and release table.
*/

dointerp()
{
	register struct Header *hdr;
	int i, rdef, found;
	register struct Reltab *rt;

	start = 1;
	hdr = nextrec(HADH);
	if (hdr->Hmagicno!=MAGICNO) fatal("not an SCCS file (421)");
	if (HADH) {
		dobeg(hdr);
		if ((i=hdr->Hfloor)==0) i = 1;
		out(stringf("Floor: %d  ",i));
		if ((i=hdr->Hceil)==0) i = 9999;
		out(stringf("Ceiling: %d  ",i));
		found = 0;
		out("Locked releases:");
		for (i=0; i<5; i++) if (hdr->Hsw[i]) {
			out(stringf("%5d",hdr->Hsw[i]));
			found++;
		}
		if (found) out(newline);
		else out(" none\n");
		dowho(hdr);
	}
	rdef = hdr->Hrdef;
	rt = nextrec(HADR);
	if (rdef==0 && (rdef=rt->Rrel)==0) rdef = 1;
	if (HADH)
		out(stringf("Default release: %d\n",rdef));
	if ((HADR|HADD|HADB)==0) return;
	if (HADY && release == -1)
		release = rdef;
	for (; rt->Rrel; rt = nextrec(HADR)) {
		if (HADR) {
			out(stringf("Release %d: %d levels\n",
				rt->Rrel,rt->Rlevs));
		}
		if (level == -1 && rt->Rrel == release)
			level = rt->Rlevs;
	}
	if ((HADD|HADB)==0) return;
	dodel();
	if (HADB==0) return;
	dobod();
}


/*	Print header data.
*	Common to both doactual and dointerp.
*/

dobeg(ahdr)
struct Header *ahdr;
{
	register struct Header *hdr;
	register int found;

	found = 0;
	if (hdr->Htype[0]) {
		found++;
		out(stringf("Type: %-9s  ",hdr->Htype));
	}
	if (hdr->Hpers[0]) {
		found++;
		out(stringf("Person: %-6s  ",hdr->Hpers));
	}
	if (hdr->Hdesc[0]) {
		found++;
		out(stringf("Description: %s",hdr->Hdesc));
	}
	if (found) out(newline);
}


/*	Prints user list (Hulist).
*	Common to both doactual and dointerp.
*/

dowho(ahdr)
struct Header *ahdr;
{
	register struct Header *hdr;
	register int mask, j;
	int i, found, cnt;
	char *p;

	hdr = ahdr;
	found = 0;
	out("Who may add deltas:  ");
	cnt = 3;
	for (i=0; i<32; i++) {
		mask = 1;
		for (j=0; j<8; j++) {
			if (hdr->Hulist[i]&mask) {
				found++;
				if (p=getlnam((i<<3)+j)) out(stringf("%7s",p));
				else out(stringf("%7d",(i<<3)+j));
				if (++cnt==10) {
					cnt = 0;
					out(newline);
				}
			}
			mask =<< 1;
		}
	}
	if (found==0) out("everyone\n");
	else if (cnt) out(newline);
}


/*	Prints delta table.
*	Processes both actual and interpreted and x arg.
*/

dodel()
{
	register struct Deltab *dt;
	register char c;

	for (dt=nextrec(HADD); dt->Drel; dt=nextrec(HADD)) {
		if (dt->Ddatetime < cutoff)
			HADD = 0;
		if (HADD)
			if (!doadel(dt)) continue;
		if (dt->Drel == release && dt->Dlev == level)
			HADD = 0;
	}
	if (HADD) {
		if (HADP) {
			out(deltastr(0,0,dt->Dtype,dt->Drel,dt->Dlev,
				HADX?(&xtime):(&dt->Ddatetime),
				dt->Dpgmr,dt->Dhist));
			out(newline);
		}
		else {
			if (prefix) out(stringf("%s:\t",pfile));
			if (HADC) {
				out(datetime(&dt->Ddatetime));
				out("created by ");
				out(dt->Dpgmr);
				out(newline);
			}
			else
				out(stringf("File created by %s on %s",
				dt->Dpgmr,ctime(HADX?&xtime:&dt->Ddatetime)));
		}
	}
}


doadel(dt)
register struct Deltab *dt;
{
	register char c;
	register int rc;

	rc = (c=dt->Dtype) != 'R' && c != 'H' && c != 'C';
	if (HADA || rc) {
		if (prefix) out(stringf("%s:\t",pfile));
		if (HADC) {
			out(datetime(&dt->Ddatetime));
			out(stringf("%c%4d.%-4d%-6s ",dt->Dtype,
				dt->Drel,dt->Dlev,dt->Dpgmr));
			out(dt->Dhist);
		}
		else {
			out(deltastr(0,0,dt->Dtype,dt->Drel,dt->Dlev,
				HADX?&xtime:&dt->Ddatetime,
				dt->Dpgmr,dt->Dhist));
		}
		out(newline);
	}
	return(rc);
}


/*	Prints body.
*	Processes both actual and interpreted.
*/

dobod()
{
	register struct Control *ctl;
	register struct Line *lp;
	char c;

	for (ctl=nextrec(HADB); !(ctlrec(ctl,ibuf.Ilen) && ctl->Crel==0);
		ctl=nextrec(HADB)) {
			if (ctlrec(ctl,ibuf.Ilen)) out(stringf("*** %c  %d.%d\n",
				"EDI"[ctl->Cctl-END],ctl->Crel,ctl->Clev));
			else if (ibuf.Ilen) {
				c = (lp=ctl)->Lline[ibuf.Ilen];
				lp->Lline[ibuf.Ilen] = '\0';
				out(stringf("\t%s\n",lp->Lline));
				lp->Lline[ibuf.Ilen] = c;
			}
			else
				out(newline);
	}
	if (HADP) out(stringf("*** %c  %d.%d\n","EDI"[ctl->Cctl+13],
			ctl->Crel,ctl->Clev));
}


/*	Print string (via putchar).
*	Handles starting record number.
*/

out(s)
char *s;
{
	register char *p;

	if (start>recnum) return;
	for (p=s; *p; p++)
		{
		putchar(*p);
		if (*p== '\n' && rofflen>0)
			{
			out(".ti 0");
			putchar('\n');
			}
		}
}


datetime(tvec)
long *tvec;
{
	register struct Time *lcltm;

	lcltm = localtime(tvec);
	prtime(lcltm->Tyear,'/');
	prtime(lcltm->Tmonth+1,'/');
	prtime(lcltm->Tday_month,' ');
	prtime(lcltm->Thours,':');
	prtime(lcltm->Tminutes,':');
	prtime(lcltm->Tseconds,'\t');
}


prtime(n,c)
register int n,c;
{
	char s[4];

	s[0] = n/10 + '0';
	s[1] = n%10 + '0';
	s[2] = c;
	s[3] = 0;
	out(s);
}
