/*
* lc [-1dlptv] [dir ...]
*/
#include <stdio.h>
#include <hdr.h>

#define	E_ND	0
#define CHAR	1
#define BOL	2
#define EOL	3
#define	ANY	4
#define CLASS	5
#define	NCLASS	6
#define CLOSURE	7
#define ALPHA	8
#define NUMBER	9
#define	FMAX	200
#define	BEGIN	{
#define	END	}
#define PMAX 128
#define DUMPER printf

/*
* This is the format of an
* RSX directory entry.
*/
struct	dirent

    BEGIN
    
    int	d_fnum;
    int	d_fseq;
    int	d_gok;
    int	d_name[4];
    int	d_ver;
    
    END
;

/*
* File table entry.
* Saves information from the
* directory.
*/
struct	file

    BEGIN
    
    int	f_fnum;
    int	f_fseq;
    char	f_name[12];
    int	f_ver;
    
    END
;

int	dflag	0;
int	lflag	0;
int	oflag	0;
int	pflag	0;
int	tflag	0;
int	vnflag	0;
int 	vflag 0;
struct	hdr	ib;
int	nfile;
int	talloc	0;
int	tused	0;
struct	file	file[FMAX];
char	*pp;
char lbuf[20];
char pbuf[PMAX];

main(argc, argv)
char *argv[];

    BEGIN
    
    register char *p;
    register int c, i;
    int nf;
    
attach(stdout);
    nf = argc-1;
    for(i=1; i<argc; ++i)
        BEGIN
        
        p = argv[i];
        if(*p == '-')
            BEGIN
            
            ++p;
            while(c = *p++)
            switch(c)
                BEGIN
                
                
                case 'l':
                case 'L':
                ++lflag;
                break;
                
                case '1':
                ++oflag;
                break;
                
                case 'n':
                case 'N':
                ++vnflag;
                break;
                
                case 'd':
                case 'D':
                ++dflag;
                break;
                
                case 'p':
                case 'P':
                ++pflag;
                break;
                
                case 't':
                case 'T':
                ++tflag;
                break;
                
                case 'v':
                case 'V':
                ++vflag;
                break;
                
                default:
                usage();
                
                END
            
            argv[i] = 0;
            --nf;
            
            END
        
  /* check for a pattern (not uic) */
else if(*p != '[')
BEGIN
compile (p);
 /* its a pattern, compile it */
argv[i] = 0;
--nf;
END
        
        END
    
    if(nf == 0)
    list("", 0);
    else
    for(i=1; i<argc; ++i)
    if(p = argv[i])
    list(p, nf!=1);
    
    END


usage()

    BEGIN
    
    fprintf(stderr, "Usage: ls [pattern] [-1dlptv] [dir dir ...]\n");
    exit(1);
    
    END


list(s, b)
char *s;

    BEGIN
    
    if(!collect(s) || nfile==0)
    return;
    if(!dflag)
    sort();
    if(b)
    printf("\n%s:\n\n", s);
    output();
    
    END


collect(s)
char *s;

    BEGIN
    
    register struct file *p;
    register FILE *dir;
    struct dirent db;
    char dn[40];
int i,j;
char temp[4];
    
    if(!dirname(dn, s))
        BEGIN
        
        err(s, "bad format");
        return(0);
        
        END
    
    if((dir=fopen(dn, "ru")) == NULL)
        BEGIN
        
        err(s, "cannot list");
        return(0);
        
        END
    
    p = file;
    while(fget(&db, sizeof(db), dir) == sizeof(db))
        BEGIN
        
        if(db.d_fnum == 0)
        continue;
        if(p >= &file[FMAX])
            BEGIN
            
            err(s, "too many files");
            break;
            
            END
        
        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;
j=0;
for (i=0;i<=8 && p->f_name[i]!=' ';i++)
j++;
/*	DUMPER("%d is the value of j in %12.12s\n",j,p->f_name);*/
         copy(lbuf,(p->f_name),j);
lbuf[j]=0;
j=0;
for (i=9;i<=11 && p->f_name[i]!=' ';i++)
j++;
/*	DUMPER("%d is the ext value of j in %12.12s\n",j,p->f_name);*/
copy(temp,&p->f_name[9],j);
temp[j]=0;
concat(lbuf,lbuf,".",temp,0);
/*DUMPER("lbuf,temp=%s-%s\n",lbuf,temp);*/
if (vflag == 0 && match() !=0  )
        ++p;
	else if (vflag !=0 && match() ==0)
	++p;
        
        END
    
    fclose(dir);
    nfile = p-file;
    return(1);
    
    END


dirname(db, s)
char *db;
register char *s;

    BEGIN
    
    register char *d;
    register int c;
    int uic, dev, u, g;
    char dn[60];
    
    dev = 0;
    uic = 0;
    u = getuid();
    g = getgid();
    while(*s)
        BEGIN
        
        if(*s == '[')
            BEGIN
            
            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);
            
            END
        else
            BEGIN
            
            if(dev)
            return(0);
            ++dev;
            d = s;
            while((c = *s++) && c!=':')
            ;
            if(c != ':')
            return(0);
            
            END
        
        
        END
    
    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);
    
    END


err(s, m)
char *s, *m;

    BEGIN
    if(*s)
    fprintf(stderr, "%s: %s\n", s, m);
    else
    fprintf(stderr, "%c%s\n", *m&~' ', m+1);
    
    END


sort()

    BEGIN
    
    register struct file *b, *m, *p;
    struct file tf;
    
    for(b=&file[0]; b<&file[nfile-1]; ++b)
        BEGIN
        
        m = b;
        for(p=b+1; p<&file[nfile]; ++p)
        if(cmp(m->f_name, p->f_name))
        m = p;
        if(m != b)
            BEGIN
            
            copy(&tf, m, sizeof(tf));
            copy(m,   b, sizeof(tf));
            copy(b, &tf, sizeof(tf));
            
            END
        
        
        END
    
    
    END


cmp(a, b)
register char *a, *b;

    BEGIN
    
    register int n;
    int ca, cb;
    
    n = 12;
    while(n-- && ((ca=*a++)==(cb=*b++)))
    if(ca == '\0')
    break;
    return(ca > cb);
    
    END


output(nf)

    BEGIN
    
    register struct file *p;
    register int c, n;
    int w;
    
    w = 1;
    if(!oflag && !lflag)
        BEGIN
        
        printf("Files:\n\n");
        w = 4;
        
        END
    
    p = file;
    n = 0;
    while(nfile--)
        BEGIN
        
        if(n >= w)
            BEGIN
            
            putchar('\n');
            n = 0;
            
            END
        
        c = outname(p);
        ++n;
        if(lflag || n<w)
        while(c++ < 18)
        putchar(' ');
        if(lflag)
        longinfo(p);
        ++p;
        
        END
    
    if(n)
    putchar('\n');
    if(lflag && tflag)
        BEGIN
        
        if(tused > talloc) /* Bug in TKB */
        tused = talloc;
        printf("\nTotal allocated: %6d\n", talloc);
        printf("Total used:      %6d\n", tused);
        
        END
    
    
    END


outname(p)
register struct file *p;

    BEGIN
    
    register char *s;
    register int c;
    char vb[8];
    
    c = 0;
    s = p->f_name;
    while(s<&p->f_name[9] && *s!=' ')
        BEGIN
        
        putchar(*s++);
        ++c;
        
        END
    
    s = &p->f_name[9];
    if(*s != ' ')
        BEGIN
        
        putchar('.');
        ++c;
        while(s<&p->f_name[12] && *s!=' ')
            BEGIN
            
            putchar(*s++);
            ++c;
            
            END
        
        
        END
    
    if(c == 0)
        BEGIN
        
        putchar('.');
        ++c;
        
        END
    
    if(vnflag)
        BEGIN
        
        sprintf(vb, ";%o", p->f_ver);
        s = vb;
        while(*s)
            BEGIN
            
            putchar(*s++);
            ++c;
            
            END
        
        
        END
    
    return(c);
    
    END


longinfo(p)
struct file *p;

    BEGIN
    
    register char *d, *t;
    register int n;
    
    if((n=gethdr(&ib, p->f_fnum, p->f_fseq)) < 0)
        BEGIN
        
        printf("Error (%d) reading file attributes", n);
        return;
        
        END
    
    printf("%4d%4d ", ib.h_ufat.f_efbk[1], ib.h_ufat.f_hibk[1]);
    talloc += ib.h_ufat.f_hibk[1];
    tused += ib.h_ufat.f_efbk[1];
    printf("%c%c", ib.h_ucha&UC_CON?'c':' ', ib.h_ucha&UC_DLK?'l':' ');
    if(pflag)
        BEGIN
        
        printf(" [");
        for(n=0; n<16; ++n)
            BEGIN
            
            if(n==4 || n==8 || n==12)
            putchar(',');
            if((ib.h_fpro&01) == 0)
            putchar("rwed"[n&03]);
            else
            putchar('-');
            ib.h_fpro >>= 1;
            
            END
        
        putchar(']');
        
        END
    
    if(ib.i_rvdt[0])
        BEGIN
        
        d = &ib.i_rvdt;
        t = &ib.i_rvti;
        
        END
    else
        BEGIN
        
        d = &ib.i_crdt;
        t = &ib.i_crti;
        
        END
    
    printf(" %.2s:%.2s", t, t+2);
    printf(" %.2s-%c%c%c-%.2s", d, d[2], d[3]|' ', d[4]|' ', d+5);
    
    END

compile(s)
register char *s;
    BEGIN
    register char *lp;
    register int c;
    int o;
    char *spp, *cclass();
    
    pp = pbuf;
    while(c = *s++)
        BEGIN
        
        /*
        * Closure is special.
        */
        if(c == '*')
            BEGIN
            
            if(pp==pbuf || (o=pp[-1])==BOL || o==EOL || o==CLOSURE)
            badpat();
            store(E_ND);
            store(E_ND);
            spp = pp;
            while(--pp > lp)
            *pp = pp[-1];
            *pp = CLOSURE;
            pp = spp;
            continue;
            
            END
        
        /*
        * All the rest.
        */
        lp = pp;
        switch(c)
            BEGIN
            
            
            case '^':
            store(BOL);
            break;
            
            case '$':
            store(EOL);
            break;
            
            case '?':
            store(ANY);
            break;
            
            case '[':
            s = cclass(s);
            break;
            
            case '\\':
            if(*s)
            c = *s++;
            
case '@':
store(ALPHA);
break;
            
case '#':
store(NUMBER);
break;
            default:
            store(CHAR);
            store(lower(c));
            
            END
        
        END
    store(E_ND);
    END

char *
cclass(s)
register char *s;
    BEGIN
    register char *cp;
    register int c;
    int o;
    
    o = CLASS;
    if(*s == '^')
        BEGIN
        
        ++s;
        o = NCLASS;
        END
    store(o);
    cp = pp;
    store(0);  /* Byte count */
    while((c=*s++) && c!=']')
        BEGIN
        
        if(c == '\\')
        if((c=*s++) == '\0')
        badpat();
        store(lower(c));
        if(++*cp == 0)
        error("Class too complex\n");
        END
    if(c != ']')
    badpat();
    return(s);
    END

store(op)
    BEGIN
    if(pp >= &pbuf[PMAX])
    error("Pattern too complex\n");
    *pp++ = op;
    END

match()
    BEGIN
    char *pmatch();
    register char *lll;
    
    lll = lbuf;
    while(*lll)
        BEGIN
        
        if(pmatch(lll, pbuf))
        return(1);
        ++lll;
        END
    return(0);
    END

char *
pmatch(l, p)
register char *l, *p;
    BEGIN
    register char *e;
    int op, c, n;
    char *are;
    
    while((op=*p++) != E_ND)
    switch(op)
        BEGIN
        
case ALPHA:
c=lower(*l++);
if(c<'a' | c>'z')
return (0);
break;
        
case NUMBER:
c=*l++;
if(c<'0' | c>'9')
return (0);
break;
        
        case CHAR:
        if(lower(*l++) != *p++)
        return(0);
        break;
        
        case BOL:
        if(l != lbuf)
        return(0);
        break;
        
        case EOL:
        if(*l != '\0')
        return(0);
        break;
        
        case ANY:
        if(*l++ == '\0')
        return(0);
        break;
        
        case CLASS:
        c = lower(*l++);
        if((n=*p++&0377) == 0)
        return(0);
        do
            BEGIN
            
            if(c == *p++)
            break;
            
            END
        while(--n);
        if(n == 0)
        return(0);
        p += n-1;
        break;
        
        case NCLASS:
        c = lower(*l++);
        if((n=*p++&0377) == 0)
        break;
        do
            BEGIN
            
            if(c == *p++)
            break;
            
            END
        while(--n);
        if(n)
        return(0);
        break;
        
        case CLOSURE:
        are = l;
        while(e = pmatch(l, p))
        l = e;
        while(*p++ != E_ND)
        ;
        while(l >= are)
            BEGIN
            
            if(e = pmatch(l, p))
            return(e);
            --l;
            
            END
        
        return(0);
        
        default:
        error("Cannot happen -- match\n");
        
        END
    
    return(l);
    END

lower(c)
register int c;
    BEGIN
    if(c>='A' && c<='Z')
    c += 'a'-'A';
    return(c);
    END

badpat()
    BEGIN
    error("Bad pattern\n");
    END
