/*--- EDIT # 0061	27 Nov 1981   22:47:40	DB0:[310,105]DIR.C;77  */
/*--- PREVIOUS EDIT	27 Nov 1981   21:41:44	DB0:[310,105]DIR.C;76  */
/*
 * DIR [-1dlptv] [dir ...]
 */
#include <stdio.h>
#include <hdr.h>
#include <cx.h>

#define	FMAX	1000

/*
 * This is the format of an
 * RSX directory entry.
 */
struct	dirent
{
	int	d_fnum;
	int	d_fseq;
	int	d_gok;
	int	d_name[4];
	int	d_ver;
};

/*
 * File table entry.
 * Saves information from the
 * directory.
 */
struct	file
{
	int	f_fnum;
	int	f_fseq;
	char	f_name[12];
	int	f_ver;
};

int	eflag= 0;	/* sort by extent as primary key */
int	dflag= 0;
int	lflag= 0;
int	oflag= 0;
int	pflag= 0;
int	tflag= 0;
int	vflag= 0;
struct	hdr	ib;
int	nfile;
long	talloc= 0;
long	tused= 0;
struct	file	file[FMAX];
extern char $$uic[1];
FILE *dir;

main(argc, argv)
char *argv[];
{
	register char *p;
	register int c, i;
	int nf;
	
	tiatt();	/* attach terminal for CNTL/O */
	nf = argc-1;
	for(i=1; i<argc; ++i) {
		p = argv[i];
		if(*p == '-') {
			++p;
			while(c = *p++)
				switch(c) {

				case 'l':
				case 'L':
					++lflag; ++tflag;
					break;

				case '1':
					++oflag;
					break;

				case 'v':
				case 'V':
					++vflag;
					break;

				case 'd':
				case 'D':
					++dflag;
					break;

				case 'p':
				case 'P':
					++pflag; ++lflag; ++tflag;
					break;

				case 't':
				case 'T':
					++tflag;
					break;


				case 'e':
				case 'E':
					++eflag;
					break;

				default:
					usage();
				}
			argv[i] = 0;
			--nf;
		}
	}
	if(nf == 0)
		list("", 0);
	else
		for(i=1; i<argc; ++i)
			if(p = argv[i])
				list(p, nf!=1);
}

usage()
{
	fprintf(stderr, "Usage: DIR [-1delptv] [dir dir ...]\n");
	exit(1);
}

list(s, b)
char *s;
{
	if(!collect(s) || nfile==0)
		return;
	if(!dflag) {
	    if (nfile > 100) fprintf (stderr,
			"Have patience. I am sorting %d filenames.\n",
			nfile);
		sort();
	    }
	if(b)
		printf("\n%s:\n", s);
	output();
	fclose (dir);
}

collect(s)
char *s;
{
	register struct file *p;
	struct dirent db;
	char dn[40];

	if(!dirname(dn, s)) {
		err(s, "bad format");
		return(0);
	}
	if((dir=fopen(dn, "run")) == NULL) {
		err(s, "cannot list");
		return(0);
	}
	p = file;
	while(fget(&db, sizeof(db), dir) == sizeof(db)) {
		if((db.d_fnum == 0) || (db.d_gok != 0))
			continue;
		if(p >= &file[FMAX]) {
			err(s, "too many files");
			break;
		}
		p->f_fnum = db.d_fnum;
		p->f_fseq = db.d_fseq;
		r50toa(p->f_name, db.d_name, 4);
		p->f_ver = db.d_ver;
		++p;
	}
	nfile = p-file;
	return(1);
}

dirname(db, s)
char *db;
register char *s;
{
	register char *d;
	register int c;
	int uic, dev, u, g;
	char dn[60];

	dev = 0;
	uic = 0;
	u = $$uic[0] & 0377;
	g = $$uic[1] & 0377;
	while(*s) {
		if(*s == '[') {
			if(uic)
				return(0);
			++uic;
			++s;
			g = 0;
			while((c = *s++) && c>='0' && c<='7')
				g = (g<<3) + c - '0';
			if(c != ',')
				return(0);
			u = 0;
			while((c = *s++) && c>='0' && c<='7')
				u = (u<<3) + c - '0';
			if(c != ']')
				return(0);
		} else {
			if(dev)
				return(0);
			++dev;
			d = s;
			while((c = *s++) && c!=':')
				;
			if(c != ':')
				return(0);
		}
	}
	s = db;
	if(dev)
		while((*s++ = *d++) != ':')
			;
	d = "[0,0]";
	while(*s++ = *d++)
		;
	--s;
	sprintf(dn, "%03o%03o.dir", g, u);
	d = dn;
	while(*s++ = *d++)
		;
	return(1);
}

err(s, m)
char *s, *m;
{
	if(*s)
		fprintf(stderr, "%s: %s\n", s, m);
	else
		fprintf(stderr, "%c%s\n", *m&~' ', m+1);
}

sort()
{
	register struct file *b, *m, *p;
	struct file tf;

	for(b=&file[0]; b<&file[nfile-1]; ++b) {
		m = b;
		for(p=b+1; p<&file[nfile]; ++p)
			if((vflag && equals(m->f_name, p->f_name, 12) &&
				(m->f_ver > p->f_ver))
				||  cmp(m->f_name, p->f_name))
				m = p;
		if(m != b) {
			copy(&tf, m, sizeof(tf));
			copy(m,   b, sizeof(tf));
			copy(b, &tf, sizeof(tf));
		}
	}
}

/** test for string equality, up to max */
equals (a, b, maxsize)
register char *a, *b;
register int maxsize;
{
	while (maxsize--) {
		if (*a++ != *b++) return (0);
		}
	return (1);
}

cmp(a, b)
register char *a, *b;
{
	register int n;
	int ca, cb;
	char ea[12], eb[12];
	if (eflag) { /* compare extents first */
	  copy (ea, a+9, 3); copy (&ea[3], a, 9);
	  copy (eb, b+9, 3); copy (&eb[3], b, 9);
	  a=&ea; b = &eb;
	  }

	n = 12;
	while(n-- && ((ca=*a++)==(cb=*b++)))
		if(ca == '\0')
			break;
	return(ca > cb);
}

output(nf)
{
	register struct file *p;
	register int c, n;
	int w;

	w = 1;
	if(!oflag && !lflag) {
		w = 4;
	}
	p = file;
	n = 0;
	while(nfile--) {
		if(n >= w) {
			putchar('\n');
			n = 0;
		}
		c = outname(p);
		if (c) {
		++n;
		if(lflag || n<w)
			while(c++ < (lflag?  14:18))
				putchar(' ');
		if(lflag)
			longinfo(p);
		}
		++p;
	}
	if(n)
		putchar('\n');
	if(lflag && tflag) {
		printf("\nTotal used:      %6ld\n", tused);
		printf("Total allocated: %6ld\n", talloc);
	}
}

outname(p)
register struct file *p;
{
	register char *s;
	register int c;
	char vb[8];
	struct file *temp;

	c = 0;
	s = p->f_name;
/* IF we are not printing version numbers but are sorting, only print the
highest version file. They are in ascending order, so only print this one
if the next one has a different name */
	temp = p;
	temp++;
	if ((!dflag) && (!vflag) && equals (p->f_name, temp->f_name, 12)) {
/*  printf ("%06o  %06o \n",p,temp); */
		return (0);
		}
	while(s<&p->f_name[9] && *s!=' ') {
		putchar(*s++);
		++c;
	}
	s = &p->f_name[9];
	if(*s != ' ') {
		putchar('.');
		++c;
		while(s<&p->f_name[12] && *s!=' ') {
			putchar(*s++);
			++c;
		}
	}
	if(c == 0) {
		putchar('.');
		++c;
	}
	if(vflag) {
		sprintf(vb, ";%o", p->f_ver);
		s = vb;
		while(*s) {
			putchar(*s++);
			++c;
		}
	}
	return(c);
}

longinfo(p)
struct file *p;
{
	register char *d, *t;
	register int n;

	if((n=gethdr(&ib, p->f_fnum, p->f_fseq, dir)) < 0) {
		printf("Error (%d) reading file attributes", n);
		return;
	}
	if ((ib.h_ufat.f_ffby == 0) && (ib.h_ufat.f_efbk !=0 ))
		ib.h_ufat.f_efbk -= 1;
	printf("%6ld%6ld ", ib.h_ufat.f_efbk, ib.h_ufat.f_hibk);
	talloc += ib.h_ufat.f_hibk;
	tused += ib.h_ufat.f_efbk;
	printf("%c%c", ib.h_ucha&UC_CON?'C':' ', ib.h_ucha&UC_DLK?'L':' ');
	if(pflag) {
		printf(" [");
		for(n=0; n<16; ++n) {
			if(n==4 || n==8 || n==12)
				putchar(',');
			if((ib.h_fpro&01) == 0)
				putchar("RWED"[n&03]);
			else
				putchar('-');
			ib.h_fpro >>= 1;
		}
		putchar(']');
	}
	d = &ib.i_crdt;
	t = &ib.i_crti;
	printf(" %.2s:%.2s", t, t+2);
	printf(" %.2s-%c%c%c-%.2s", d, d[2], d[3]|' ', d[4]|' ', d+5);
	if(ib.i_rvdt[0]) {
		if ( !(tflag && pflag)) printf("   ");		
		d = &ib.i_rvdt;
		t = &ib.i_rvti;
		printf(" %.2s:%.2s", t, t+2);
		printf(" %.2s-%c%c%c-%.2s", d, d[2], d[3]|' ', d[4]|' ', d+5);
	}
}
