Research V6 development
authorKen Thompson <ken@research.uucp>
Wed, 14 May 1975 00:50:01 +0000 (19:50 -0500)
committerKen Thompson <ken@research.uucp>
Wed, 14 May 1975 00:50:01 +0000 (19:50 -0500)
Work on file usr/source/s2/usort.c
Work on file usr/source/s2/tp3.s
Work on file usr/source/s2/units.c

Co-Authored-By: Dennis Ritchie <dmr@research.uucp>
Synthesized-from: v6

usr/source/s2/tp3.s [new file with mode: 0644]
usr/source/s2/units.c [new file with mode: 0644]
usr/source/s2/usort.c [new file with mode: 0644]

diff --git a/usr/source/s2/tp3.s b/usr/source/s2/tp3.s
new file mode 100644 (file)
index 0000000..d500ff3
--- /dev/null
@@ -0,0 +1,522 @@
+/ tap3 -- dec-tape lod/dmp
+
+gettape:
+       mov     $dir,r1
+       clr     -(sp)
+1:
+       tst     (r1)
+       beq     2f
+       jsr     r5,decode; name
+       cmp     rnarg,$2
+       ble     4f
+       mov     $name,r2
+       mov     *parg,r3
+3:
+       tstb    (r3)
+       beq     3f
+       cmpb    (r2)+,(r3)+
+       beq     3b
+       br      2f
+3:
+       tstb    (r2)
+       beq     4f
+       cmpb    (r2),$'/
+       bne     2f
+4:
+       mov     r1,-(sp)
+       jsr     pc,*(r5)
+       mov     (sp)+,r1
+       inc     (sp)
+2:
+       add     $dirsiz,r1
+       cmp     r1,edir
+       blo     1b
+       tst     (sp)+
+       bne     2f
+       cmp     rnarg,$2
+       ble     2f
+       mov     *parg,r1
+       jsr     pc,pstr
+       jsr     r5,mesg
+               < not found\n\0>; .even
+2:
+       dec     narg
+       add     $2,parg
+       cmp     narg,$2
+       bgt     gettape
+       tst     (r5)+
+       rts     r5
+
+delete:
+       jsr     r5,verify; 'd
+               rts pc
+       jsr     pc,clrent
+       rts     pc
+
+numb:
+       mov     r1,-(sp)
+       mov     r0,-(sp)
+       clr     r0
+       br      1f
+
+numbx:
+       mov     r1,-(sp)
+       mov     r0,-(sp)
+       movb    size0(r1),r0
+1:
+       mov     $catlb,r2
+1:
+       mov     $"  ,(r2)+
+       cmp     r2,$catlb+12.
+       blo     1b
+       cmp     (r5),$2
+       bne     1f
+       mov     $"00,-2(r2)
+1:
+       mov     (sp)+,r1
+       jsr     pc,numb2
+       mov     (r5)+,r0
+       sub     r0,r2
+       mov     r2,0f
+       mov     r0,0f+2
+       mov     $1,r0
+       sys     0; 9f
+.data
+9:
+       sys     write; 0:..; ..
+.text
+       mov     (sp)+,r1
+       rts     r5
+
+numb1:
+       clr     r0
+numb2:
+       div     $10.,r0
+       mov     r1,-(sp)
+       mov     r0,r1
+       beq     1f
+       jsr     pc,numb1
+1:
+       mov     (sp)+,r0
+       add     $'0,r0
+       movb    r0,(r2)+
+       rts     pc
+
+update:
+       jsr     pc,bitmap
+       mov     $dir,r1
+1:
+       tst     (r1)
+       beq     2f
+       bit     $100000,mode(r1)
+       beq     2f
+       tstb    size0(r1)
+       bne     9f
+       tst     size1(r1)
+       beq     2f
+9:
+       mov     ndentd8,-(sp)
+       inc     (sp)
+       movb    size0(r1),r2
+       mov     size1(r1),r3
+       add     $511.,r3
+       adc     r2
+       ashc    $-9,r2
+       mov     r3,size
+3:
+       mov     (sp),r2
+       mov     size,r3
+4:
+       jsr     pc,bitcalc
+       inc     r2
+       bitb    (sp)+,map(r0)
+       bne     4f
+       sob     r3,4b
+       mov     (sp)+,tapea(r1)
+       jsr     pc,setmap
+       br      2f
+4:
+       inc     (sp)
+       br      3b
+2:
+       add     $dirsiz,r1
+       cmp     r1,edir
+       blo     1b
+       jsr     pc,wrdir
+
+update1:
+       mov     $dir,r1
+       clr     -(sp)
+       mov     $-1,-(sp)
+1:
+       tst     (r1)
+       beq     2f
+       bit     $100000,mode(r1)
+       beq     2f
+       cmp     tapea(r1),(sp)
+       bhis    2f
+       mov     tapea(r1),(sp)
+       mov     r1,2(sp)
+2:
+       add     $dirsiz,r1
+       cmp     r1,edir
+       blo     1b
+       tst     (sp)+
+       mov     (sp)+,r1
+       bne     1f
+       rts     pc
+1:
+       bic     $100000,mode(r1)
+       movb    size0(r1),mss
+       mov     size1(r1),r2
+       bne     4f
+       tst     mss
+       beq     update1
+4:
+       jsr     r5,decode; name
+       mov     tapea(r1),r0
+       jsr     pc,wseek
+       clr     r3
+       sys     open; name; 0
+       bes     phserr
+       mov     r0,r3
+3:
+       tst     mss
+       bne     4f
+       cmp     r2,$512.
+       blo     3f
+4:
+       mov     r3,r0
+       sys     read; tapeb; 512.
+       bes     phserr
+       cmp     r0,$512.
+       bne     phserr
+       jsr     pc,twrite
+       sub     $512.,r2
+       sbc     mss
+       br      3b
+3:
+       mov     r2,0f
+       beq     3f
+       mov     r3,r0
+       sys     0; 9f
+.data
+9:
+       sys     read; tapeb; 0:..
+.text
+       bes     phserr
+       cmp     r0,0b
+       bne     phserr
+       jsr     pc,twrite
+3:
+       mov     r3,r0
+       sys     read; tapeb; 512.
+       bes     phserr
+       tst     r0
+       bne     phserr
+       mov     r3,r0
+       sys     close
+2:
+       jmp     update1
+
+phserr:
+       mov     r1,-(sp)
+       mov     $name,r1
+       jsr     pc,pstr
+       jsr     r5,mesg
+               < -- Phase error\n\0>; .even
+       mov     (sp)+,r1
+       clr     time0(r1) / time
+       beq     2b
+       sys     close
+       br      2b
+
+bitmap:
+       mov     $map,r0
+1:
+       clr     (r0)+
+       cmp     r0,$emap
+       blo     1b
+       mov     $dir,r1
+1:
+       tst     (r1)
+       beq     2f
+       bit     $100000,mode(r1)
+       bne     2f
+       tst     size1(r1)
+       bne     3f
+       tstb    size0(r1)
+       beq     2f
+3:
+       jsr     pc,setmap
+2:
+       add     $dirsiz,r1
+       cmp     r1,edir
+       blo     1b
+       rts     pc
+
+setmap:
+       movb    size0(r1),r2
+       mov     size1(r1),r3
+       add     $511.,r3
+       adc     r2
+       ashc    $-9.,r2
+       mov     tapea(r1),r2
+1:
+       jsr     pc,bitcalc
+       bitb    (sp),map(r0)
+       bne     maperr
+       bisb    (sp)+,map(r0)
+       inc     r2
+       sob     r3,1b
+       rts     pc
+
+bitcalc:
+       mov     (sp),-(sp)
+       cmp     r2,tapsiz
+       bhis    maperr
+       mov     r2,r0
+       bic     $!7,r0
+       mov     r0,-(sp)
+       mov     $1,r0
+       als     (sp)+,r0
+       mov     r0,2(sp)
+       mov     r2,r0
+       ash     $-3,r0
+       bic     $160000,r0
+       rts     pc
+
+maperr:
+       jsr     r5,mesg
+               <Tape overflow\n\0>; .even
+       jmp     done
+
+usage:
+       jsr     pc,bitmap
+       mov     $dir,r2
+1:
+       tst     (r2)
+       beq     2f
+       inc     nentr
+2:
+       add     $dirsiz,r2
+       cmp     r2,edir
+       blo     1b
+       mov     ndentd8,r2
+       inc     r2
+       mov     tapsiz,r3
+       dec     r3
+       sub     ndentd8,r3
+1:
+       jsr     pc,bitcalc
+       bitb    (sp)+,map(r0)
+       beq     2f
+       inc     nused
+       mov     r2,lused
+       br      3f
+2:
+       inc     nfree
+       tstb    flm
+       bne     1f
+3:
+       inc     r2
+       sob     r3,1b
+1:
+       mov     nentr,r0
+       jsr     r5,numb; 4
+       jsr     r5,mesg
+               < entries\n\0>; .even
+       mov     nused,r0
+       jsr     r5,numb; 4
+       jsr     r5,mesg
+               < used\n\0>; .even
+       tstb    flm
+       bne     1f
+       mov     nfree,r0
+       jsr     r5,numb; 4
+       jsr     r5,mesg
+               < free\n\0>; .even
+1:
+       mov     lused,r0
+       jsr     r5,numb; 4
+       jsr     r5,mesg
+               < last\n\0>; .even
+       rts     pc
+
+taboc:
+       tstb    flv
+       beq     4f
+       mov     mode(r1),r0
+       mov     r0,-(sp)
+       ash     $-6,r0
+       bit     $40,r0
+       jsr     pc,pmod
+       mov     (sp),r0
+       ash     $-3,r0
+       bit     $200,r0
+       jsr     pc,pmod
+       mov     (sp)+,r0
+       bit     $1000,r0
+       jsr     pc,pmod
+       clr     r0
+       bisb    uid(r1),r0
+       jsr     r5,numb; 4
+       clr     r0
+       bisb    gid(r1),r0
+       jsr     r5,numb; 4
+       mov     tapea(r1),r0
+       jsr     r5,numb; 5
+       mov     size1(r1),r0
+       jsr     r5,numbx; 9.
+       mov     r1,-(sp)
+       add     $time0,(sp)
+       jsr     pc,_localtime
+       mov     r0,(sp)
+       mov     10.(r0),r0
+       jsr     r5,numb; 3
+       mov     $'/,r0
+       jsr     pc,putc
+       mov     (sp),r0
+       mov     8.(r0),r0
+       inc     r0
+       jsr     r5,numb; 2
+       mov     $'/,r0
+       jsr     pc,putc
+       mov     (sp),r0
+       mov     6(r0),r0
+       jsr     r5,numb; 2
+       mov     (sp),r0
+       mov     4(r0),r0
+       jsr     r5,numb; 3
+       mov     $':,r0
+       jsr     pc,putc
+       mov     (sp)+,r0
+       mov     2(r0),r0
+       jsr     r5,numb; 2
+       mov     $' ,r0
+       jsr     pc,putc
+4:
+       mov     $name,r1
+       jsr     pc,pstr
+       jsr     r5,mesg
+               <\n\0>
+       rts     pc
+
+pmod:
+       beq     1f
+       mov     $'s,-(sp)
+       br      2f
+1:
+       bit     $1,r0
+       beq     1f
+       mov     $'x,-(sp)
+       br      2f
+1:
+       mov     $'-,-(sp)
+2:
+       bit     $2,r0
+       beq     1f
+       mov     $'w,-(sp)
+       br      2f
+1:
+       mov     $'-,-(sp)
+2:
+       bit     $4,r0
+       beq     1f
+       mov     $'r,r0
+       br      2f
+1:
+       mov     $'-,r0
+2:
+       jsr     pc,putc
+       mov     (sp)+,r0
+       jsr     pc,putc
+       mov     (sp)+,r0
+       jsr     pc,putc
+       rts     pc
+
+xtract:
+       movb    size0(r1),mss
+       bne     2f
+       tst     size1(r1)
+       beq     1f
+2:
+       jsr     r5,verify; 'x
+               rts pc
+       mov     size1(r1),r3
+       mov     tapea(r1),r0
+       jsr     pc,rseek
+       sys     unlink; name
+       mov     mode(r1),0f
+       sys     0; 9f
+.data
+9:
+       sys     creat; name; 0:..
+.text
+       bes     crterr
+       mov     r0,r2
+2:
+       tst     mss
+       bne     3f
+       cmp     r3,$512.
+       blo     2f
+3:
+       jsr     pc,tread
+       mov     r2,r0
+       sys     write; tapeb; 512.
+       bes     crterr1
+       cmp     r0,$512.
+       bne     crterr1
+       sub     r0,r3
+       sbc     mss
+       br      2b
+2:
+       mov     r3,0f
+       beq     2f
+       jsr     pc,tread
+       mov     r2,r0
+       sys     0; 9f
+.data
+9:
+       sys     write; tapeb; 0:..
+.text
+       bes     crterr1
+       cmp     r0,0b
+       bne     crterr1
+2:
+       mov     r2,r0
+       sys     close
+       movb    gid(r1),0f+1
+       movb    uid(r1),0f
+       sys     0; 9f
+.data
+9:
+       sys     chown; name; 0:..
+.text
+       mov     time0(r1),r0
+       mov     r1,-(sp)
+       mov     time1(r1),r1
+/      sys     0; 9f
+.data
+9:
+       sys     smdate; name
+.text
+       mov     (sp)+,r1
+1:
+       rts     pc
+
+crterr1:
+       clr     r0
+       mov     r1,-(sp)
+       clr     r1
+/      sys     smdate; name
+       mov     (sp)+,r1
+       mov     r2,r0
+       sys     close
+
+crterr:
+       mov     $name,r1
+       jsr     pc,pstr
+       jsr     r5,mesg
+               < -- create error\n\0>; .even
+       rts     pc
diff --git a/usr/source/s2/units.c b/usr/source/s2/units.c
new file mode 100644 (file)
index 0000000..060d1e6
--- /dev/null
@@ -0,0 +1,456 @@
+#define        NDIM    10
+#define        NTAB    601
+char   *dfile  "/usr/lib/units";
+char   *unames[NDIM];
+double getflt();
+int    fperr();
+struct unit
+{
+       double  factor;
+       char    dim[NDIM];
+};
+
+struct table
+{
+       double  factor;
+       char    dim[NDIM];
+       char    *name;
+} table[NTAB];
+char   names[NTAB*10];
+struct prefix
+{
+       double  factor;
+       char    *pname;
+} prefix[]
+{
+       1e-18,  "atto",
+       1e-15,  "femto",
+       1e-12,  "pico",
+       1e-9,   "nano",
+       1e-6,   "micro",
+       1e-3,   "milli",
+       1e-2,   "centi",
+       1e-1,   "deci",
+       1e1,    "deka",
+       1e2,    "hecta",
+       1e2,    "hecto",
+       1e3,    "kilo",
+       1e6,    "mega",
+       1e6,    "meg",
+       1e9,    "giga",
+       1e12,   "tera",
+       0.0,    0
+};
+int    ibuf[259];
+int    fperrc;
+int    peekc;
+int    dumpflg;
+
+main(argc, argv)
+char *argv[];
+{
+       register i;
+       register char *file;
+       struct unit u1, u2;
+       double f;
+
+       if(argc>1 && *argv[1]=='-') {
+               argc--;
+               argv++;
+               dumpflg++;
+       }
+       file = dfile;
+       if(argc > 1)
+               file = argv[1];
+       if(fopen(file, ibuf) < 0) {
+               printf("no table\n");
+               exit();
+       }
+       ldfps(07600); /* interrupt on fp errors */
+       signal(8, fperr);
+       init();
+       close(ibuf[0]);
+       ibuf[0] = 0;
+
+loop:
+       fperrc = 0;
+       printf("you have: ");
+       if(convr(&u1))
+               goto loop;
+       if(fperrc)
+               goto fp;
+loop1:
+       printf("you want: ");
+       if(convr(&u2))
+               goto loop1;
+       for(i=0; i<NDIM; i++)
+               if(u1.dim[i] != u2.dim[i])
+                       goto conform;
+       f = u1.factor/u2.factor;
+       if(fperrc)
+               goto fp;
+       printf("\t* %e\n", f);
+       printf("\t/ %e\n", 1./f);
+       goto loop;
+
+conform:
+       if(fperrc)
+               goto fp;
+       printf("conformability\n");
+       units(&u1);
+       units(&u2);
+       goto loop;
+
+fp:
+       printf("underflow or overflow\n");
+       goto loop;
+}
+
+units(up)
+struct unit *up;
+{
+       register struct unit *p;
+       register f, i;
+
+       p = up;
+       printf("\t%e ", p->factor);
+       f = 0;
+       for(i=0; i<NDIM; i++)
+               f =| pu(p->dim[i], i, f);
+       if(f&1) {
+               putchar('/');
+               f = 0;
+               for(i=0; i<NDIM; i++)
+                       f =| pu(-p->dim[i], i, f);
+       }
+       putchar('\n');
+}
+
+pu(u, i, f)
+{
+
+       if(u > 0) {
+               if(f&2)
+                       putchar('-');
+               if(unames[i])
+                       printf("%s", unames[i]); else
+                       printf("*%c*", i+'a');
+               if(u > 1)
+                       putchar(u+'0');
+                       return(2);
+       }
+       if(u < 0)
+               return(1);
+       return(0);
+}
+
+convr(up)
+struct unit *up;
+{
+       register struct unit *p;
+       register c;
+       register char *cp;
+       char name[20];
+       int den, err;
+
+       p = up;
+       for(c=0; c<NDIM; c++)
+               p->dim[c] = 0;
+       p->factor = getflt();
+       if(p->factor == 0.)
+               p->factor = 1.0;
+       err = 0;
+       den = 0;
+       cp = name;
+
+loop:
+       switch(c=get()) {
+
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '-':
+       case '/':
+       case ' ':
+       case '\t':
+       case '\n':
+               if(cp != name) {
+                       *cp++ = 0;
+                       cp = name;
+                       err =| lookup(cp, p, den, c);
+               }
+               if(c == '/')
+                       den++;
+               if(c == '\n')
+                       return(err);
+               goto loop;
+       }
+       *cp++ = c;
+       goto loop;
+}
+
+lookup(name, up, den, c)
+char *name;
+struct unit *up;
+{
+       register struct unit *p;
+       register struct table *q;
+       register i;
+       char *cp1, *cp2;
+       double e;
+
+       p = up;
+       e = 1.0;
+
+loop:
+       q = hash(name);
+       if(q->name) {
+               l1:
+               if(den) {
+                       p->factor =/ q->factor*e;
+                       for(i=0; i<NDIM; i++)
+                               p->dim[i] =- q->dim[i];
+               } else {
+                       p->factor =* q->factor*e;
+                       for(i=0; i<NDIM; i++)
+                               p->dim[i] =+ q->dim[i];
+               }
+               if(c >= '2' && c <= '9') {
+                       c--;
+                       goto l1;
+               }
+               return(0);
+       }
+       for(i=0; cp1 = prefix[i].pname; i++) {
+               cp2 = name;
+               while(*cp1 == *cp2++)
+                       if(*cp1++ == 0) {
+                               cp1--;
+                               break;
+                       }
+               if(*cp1 == 0) {
+                       e =* prefix[i].factor;
+                       name = cp2-1;
+                       goto loop;
+               }
+       }
+       for(cp1 = name; *cp1; cp1++);
+       if(cp1 > name+1 && *--cp1 == 's') {
+               *cp1 = 0;
+               goto loop;
+       }
+       printf("cannot recognize %s\n", name);
+       return(1);
+}
+
+equal(s1, s2)
+char *s1, *s2;
+{
+       register char *c1, *c2;
+
+       c1 = s1;
+       c2 = s2;
+       while(*c1++ == *c2)
+               if(*c2++ == 0)
+                       return(1);
+       return(0);
+}
+
+init()
+{
+       register char *cp;
+       register struct table *tp, *lp;
+       int c, i, f, t;
+       char *np;
+
+       cp = names;
+       for(i=0; i<NDIM; i++) {
+               np = cp;
+               *cp++ = '*';
+               *cp++ = i+'a';
+               *cp++ = '*';
+               *cp++ = 0;
+               lp = hash(np);
+               lp->name = np;
+               lp->factor = 1.0;
+               lp->dim[i] = 1;
+       }
+       lp = hash("");
+       lp->name = cp-1;
+       lp->factor = 1.0;
+
+l0:
+       c = get();
+       if(c == 0) {
+               printf("%l units; %l bytes\n\n", i, cp-names);
+               if(dumpflg)
+               for(tp = &table[0]; tp < &table[NTAB]; tp++) {
+                       if(tp->name == 0)
+                               continue;
+                       printf("%s", tp->name);
+                       units(tp);
+               }
+               return;
+       }
+       if(c == '/')
+               while(c != '\n')
+                       c = get();
+       if(c == '\n')
+               goto l0;
+       np = cp;
+       while(c != ' ' && c != '\t') {
+               *cp++ = c;
+               c = get();
+               if(c == '\n') {
+                       *cp++ = 0;
+                       tp = hash(np);
+                       if(tp->name)
+                               goto redef;
+                       tp->name = np;
+                       tp->factor = lp->factor;
+                       for(c=0; c<NDIM; c++)
+                               tp->dim[c] = lp->dim[c];
+                       i++;
+                       goto l0;
+               }
+       }
+       *cp++ = 0;
+       lp = hash(np);
+       if(lp->name)
+               goto redef;
+       convr(lp);
+       lp->name = np;
+       f = 0;
+       i++;
+       if(lp->factor != 1.0)
+               goto l0;
+       for(c=0; c<NDIM; c++) {
+               t = lp->dim[c];
+               if(t>1 || (f>0 && t!=0))
+                       goto l0;
+               if(f==0 && t==1) {
+                       if(unames[c])
+                               goto l0;
+                       f = c+1;
+               }
+       }
+       if(f>0)
+               unames[f-1] = np;
+       goto l0;
+
+redef:
+       printf("redefination %s\n", np);
+       goto l0;
+}
+
+double
+getflt()
+{
+       register c, i, dp;
+       double d, e;
+       int f;
+
+       d = 0.;
+       dp = 0;
+       do
+               c = get();
+       while(c == ' ' || c == '\t');
+
+l1:
+       if(c >= '0' && c <= '9') {
+               d = d*10. + c-'0';
+               if(dp)
+                       dp++;
+               c = get();
+               goto l1;
+       }
+       if(c == '.') {
+               dp++;
+               c = get();
+               goto l1;
+       }
+       if(dp)
+               dp--;
+       if(c == '+' || c == '-') {
+               f = 0;
+               if(c == '-')
+                       f++;
+               i = 0;
+               c = get();
+               while(c >= '0' && c <= '9') {
+                       i = i*10 + c-'0';
+                       c = get();
+               }
+               if(f)
+                       i = -i;
+               dp =- i;
+       }
+       e = 1.;
+       i = dp;
+       if(i < 0)
+               i = -i;
+       while(i--)
+               e =* 10.;
+       if(dp < 0)
+               d =* e; else
+               d =/ e;
+       if(c == '|')
+               return(d/getflt());
+       peekc = c;
+       return(d);
+}
+
+get()
+{
+       register c;
+
+       if(c=peekc) {
+               peekc = 0;
+               return(c);
+       }
+       c = getc(ibuf);
+       if(c <= 0) {
+               if(ibuf[0])
+                       return(0);
+               printf("\n");
+               exit();
+       }
+       return(c);
+}
+
+hash(name)
+char *name;
+{
+       register struct table *tp;
+       register char *np;
+       register h;
+
+       h = 0;
+       np = name;
+       while(*np)
+               h = h*57 + *np++ - '0';
+       h = lrem(0, h, NTAB);
+       tp = &table[h];
+l0:
+       if(tp->name == 0)
+               return(tp);
+       if(equal(name, tp->name))
+               return(tp);
+       tp++;
+       if(tp >= &table[NTAB])
+               tp = table;
+       goto l0;
+}
+
+fperr()
+{
+
+       signal(8, fperr);
+       fperrc++;
+}
diff --git a/usr/source/s2/usort.c b/usr/source/s2/usort.c
new file mode 100644 (file)
index 0000000..8f58766
--- /dev/null
@@ -0,0 +1,649 @@
+#define        L       512
+#define        N       7
+#define        C       20
+#define        MEM     (16*2048)
+#define NF     10
+
+int    ibuf[259];
+int    obuf[259];
+char   *file;
+char   *filep;
+int    nfiles;
+int    nlines;
+int    ntext;
+int    *lspace;
+char   *tspace;
+int    cmp();
+int    term();
+int    mflg;
+char   *outfil;
+char   tabchar;
+int    eargc;
+char   **eargv;
+
+char   fold[128] {
+       0000,0001,0002,0003,0004,0005,0006,0007,
+       0010,0011,0012,0013,0014,0015,0016,0017,
+       0020,0021,0022,0023,0024,0025,0026,0027,
+       0030,0031,0032,0033,0034,0035,0036,0037,
+       0040,0041,0042,0043,0044,0045,0046,0047,
+       0050,0051,0052,0053,0054,0055,0056,0057,
+       0060,0061,0062,0063,0064,0065,0066,0067,
+       0070,0071,0072,0073,0074,0075,0076,0077,
+       0100,0101,0102,0103,0104,0105,0106,0107,
+       0110,0111,0112,0113,0114,0115,0116,0117,
+       0120,0121,0122,0123,0124,0125,0126,0127,
+       0130,0131,0132,0133,0134,0134,0136,0137,
+       0140,0101,0102,0103,0104,0105,0106,0107,
+       0110,0111,0112,0113,0114,0115,0116,0117,
+       0120,0121,0122,0123,0124,0125,0126,0127,
+       0130,0131,0132,0173,0174,0175,0176,0177
+};
+char   nofold[128];
+char   dict[128] {
+       1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,
+       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+       0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+       0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
+       1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
+       1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1
+};
+char   nodict[128] { 1 };
+
+struct field {
+       char *code;
+       char *ignore;
+       int nflg;
+       int rflg;
+       int bflg;
+       char *m[2];
+       char *n[2];
+}      fields[NF];
+int proto[9] {
+       &fold,
+       &nodict,
+       0,
+       1,
+       0,
+       0,-1,
+       0,0
+};
+int    nfields;
+int    error 1;
+
+main(argc, argv)
+char **argv;
+{
+       register a, i;
+       char *arg;
+       register int *p;
+       int *q;
+
+       for(a=0; a<128; a++)
+               nofold[a] = a;
+       nodict[127] = 1;
+       copyproto();
+       eargv = argv;
+       while (--argc > 0) {
+               if(**++argv == '-') for(arg = *argv;;) {
+                       switch(*++arg) {
+                       case '\0':
+                               if(arg[-1] == '-')
+                                       eargv[eargc++] = "-";
+                               break;
+
+                       case 'm':
+                               mflg++;
+                               continue;
+
+                       case 'o':
+                               if(--argc > 0)
+                                       outfil = *++argv;
+                               continue;
+
+                       default:
+                               field(++*argv,1);
+                               break;
+                       }
+                       break;
+               } else if (**argv == '+') {
+                       if(++nfields>=NF) {
+                               mess("Too many keys\n");
+                               exit(1);
+                       }
+                       copyproto();
+                       field(++*argv,0);
+               } else
+                       eargv[eargc++] = *argv;
+       }
+       q = &fields[0];
+       for(a=1; a<=nfields; a++) {
+               p = &fields[a];
+               for(i=0; i<5; i++)      /*sensitive to sizeof(proto)*/
+                       if(p[i] != proto[i])
+                               goto next;
+               for(i=0; i<5; i++)
+                       p[i] = q[i];
+next:  ;
+       }
+       if(eargc == 0)
+               eargv[eargc++] = "-";
+
+       a = MEM;
+       i = lspace = sbrk(0);
+       while(brk(a) == -1)
+               a =- 512;
+       brk(a =- 512);  /* for recursion */
+       a =- i;
+       nlines = ((a-L)>>1) & 077777;
+       nlines =/ 5;
+       ntext = nlines*8;
+       tspace = lspace+nlines;
+       file = "/usr/tmp/stmXaa";
+loop:
+       filep = file;
+       while(*filep != 'X')
+               filep++;
+       for(*filep = 'a';;(*filep)++) {
+               if(stat(file, lspace) < 0) {
+                       a = creat(file, 0600);
+                       if(a >= 0)
+                               break;
+               }
+               if(*filep == 'z') {
+                       if(file[1] != 't') {
+                               file = "/tmp/stmXaa";
+                               goto loop;
+                       }
+                       mess("Cannot locate temp\n");
+                       exit(1);
+               }
+       }
+       close(a);
+       filep++;
+       if ((signal(2, 1) & 01) == 0)
+               signal(2, term);
+       nfiles = eargc;
+       if(!mflg) {
+               ibuf[0] = -1;
+               sort();
+               close(0);
+       }
+       for(a = mflg?0:eargc; a+N < nfiles; a=+N) {
+               newfile();
+               merge(a, a+N);
+       }
+       if(a != nfiles) {
+               oldfile();
+               merge(a, nfiles);
+       }
+       error = 0;
+       term();
+}
+
+sort()
+{
+       register char *cp;
+       register *lp, c;
+       int done;
+       int i;
+       int f;
+
+       done = 0;
+       i = 0;
+       do {
+               cp = tspace;
+               lp = lspace;
+               while(lp < lspace+nlines && cp < tspace+ntext) {
+                       *lp++ = cp;
+                       while((*cp++ = c = getc(ibuf)) != '\n') {
+                               if(c >= 0) continue;
+                               cp--;
+                               close(ibuf[0]);
+                               if(i < eargc) {
+                                       if((f = setfil(i++)) == 0)
+                                               ibuf[0] = 0;
+                                       else if(fopen(f, ibuf) < 0)
+                                               cant(f);
+                               } else
+                                       break;
+                       }
+                       if(c < 0) {
+                               done++;
+                               lp--;
+                               break;
+                       }
+               }
+               qsort(lspace, lp-lspace, 2, cmp);
+               if(done == 0 || nfiles != eargc)
+                       newfile(); else
+                       oldfile();
+               while(lp > lspace) {
+                       cp = *--lp;
+                       if(*cp)
+                               do
+                               putc(*cp, obuf);
+                               while(*cp++ != '\n');
+               }
+               fflush(obuf);
+               close(obuf[0]);
+       } while(done == 0);
+}
+
+struct merg
+{
+       char    l[L];
+       int     b[259];
+};
+
+merge(a, b)
+{
+       register struct merg *p;
+       register char *cp;
+       register i;
+       struct { int *ip;};
+       int f;
+       int j;
+       int     k,l,c;
+
+       p = lspace;
+       j = 0;
+       for(i=a; i<b; i++) {
+               f = setfil(i);
+               if(f == 0)
+                       p->b[0] = dup(0);
+               else if(fopen(f, p->b) < 0)
+                       cant(f);
+               ibuf[j] = p;
+               if(!rline(p)) j++;
+               p++;
+       }
+
+       do {
+               i = j;
+               qsort(ibuf, i, 2, cmp);
+               l = 0;
+               while(i--) {
+                       cp = ibuf[i];
+                       if(*cp == '\0') {
+                               l = 1;
+                               if(rline(ibuf[i])) {
+                                       k = i;
+                                       while(++k < j)
+                                               ibuf[k-1] = ibuf[k];
+                                       j--;
+                               }
+                       }
+               }
+       } while(l);
+
+       i = j;
+       if(i > 0) for(;;) {
+               cp = ibuf[i-1];
+               if(i == 1 || cmp(&ibuf[i-1], &ibuf[i-2]))
+                       do
+                               putc(*cp, obuf);
+                       while(*cp++ != '\n');
+               if(rline(ibuf[i-1])) {
+                       i--;
+                       if(i == 0)
+                               break;
+               }
+               cp = &ibuf[i];
+               while (--cp.ip > ibuf && cmp(cp.ip, cp.ip-1) < 0) {
+                       p = *cp.ip;
+                       *cp.ip = *(cp.ip-1);
+                       *(cp.ip-1) = p;
+               }
+       }
+       p = lspace;
+       for(i=a; i<b; i++) {
+               close(p->b[0]);
+               p++;
+               if(i >= eargc)
+                       close(creat(setfil(i)));
+       }
+       fflush(obuf);
+       close(obuf[0]);
+}
+
+rline(mp)
+struct merg *mp;
+{
+       register char *cp;
+       register *bp, c;
+
+       bp = mp->b;
+       cp = mp->l;
+       do {
+               c = getc(bp);
+               if(c < 0)
+                       return(1);
+               *cp++ = c;
+       } while(c != '\n');
+       *cp = '\0';
+       return(0);
+}
+
+newfile()
+{
+
+       if(fcreat(setfil(nfiles), obuf) < 0) {
+               mess("Can't create temp\n");
+               term();
+       }
+       nfiles++;
+}
+
+char *
+setfil(i)
+{
+
+       if(i < eargc)
+               if(eargv[i][0] == '-' && eargv[i][1] == '\0')
+                       return(0);
+               else
+                       return(eargv[i]);
+       i =- eargc;
+       filep[0] = i/26 + 'a';
+       filep[1] = i%26 + 'a';
+       return(file);
+}
+
+oldfile()
+{
+
+       if(outfil) {
+               if(fcreat(outfil, obuf) < 0) {
+                       mess("Can't create output\n");
+                       term();
+               }
+       } else
+               obuf[0] = 1;
+}
+
+cant(f)
+{
+       mess("Can't open ");
+       mess(f);
+       mess("\n");
+       term();
+}
+
+term()
+{
+       register i;
+
+       if(nfiles == eargc)
+               nfiles++;
+       for(i=eargc; i<nfiles; i++) {
+               unlink(setfil(i));
+       }
+       exit(error);
+}
+
+cmp(a, b)
+int    *a,*b;
+{
+       register char   *ra, *rb;
+
+       ra = *a - 1;
+       rb = *b - 1;
+
+       while(*++ra == *++rb)
+               if(*ra == '\n')
+                       return(0);
+
+       return(*rb - *ra);
+}
+
+
+skip(pp, fp, j)
+struct field *fp;
+char *pp;
+{
+       register i;
+       register char *p;
+
+       p = pp;
+       if( (i=fp->m[j]) < 0)
+               return(-1);
+       while(i-- > 0) {
+               if(tabchar != 0) {
+                       while(*p != tabchar)
+                               if(*p != '\n')
+                                       p++;
+                               else goto ret;
+                       p++;
+               } else {
+                       while(blank(*p))
+                               p++;
+                       while(!blank(*p))
+                               if(*p != '\n')
+                                       p++;
+                               else goto ret;
+               }
+       }
+       if(fp->bflg)
+               while(blank(*p))
+                       p++;
+       i = fp->n[j];
+       while(i-- > 0) {
+               if(*p != '\n')
+                       p++;
+               else goto ret;
+       } 
+ret:
+       return(p);
+}
+
+digit(c)
+{
+
+       return(c <= '9' && c >= '0');
+}
+
+mess(s)
+char *s;
+{
+       while(*s)
+               write(2, s++, 1);
+}
+
+copyproto()
+{
+       register int i, *p, *q;
+
+       p = proto;
+       q = &fields[nfields];
+       for(i=0; i<sizeof(proto)/2; i++)
+               *q++ = *p++;
+}
+
+field(s,k)
+char *s;
+{
+       register struct field *p;
+       p = &fields[nfields];
+       for(; *s!=0; s++) {
+               switch(*s) {
+               case '\0':
+                       return;
+
+               case 'a':
+                       p->code = nofold;
+                       break;
+
+               case 'b':
+                       p->bflg++;
+                       break;
+
+               case 'd':
+                       p->ignore = dict;
+                       break;
+
+               case 'n':
+                       p->nflg++;
+                       break;
+               case 't':
+                       tabchar = *++s;
+                       if(tabchar == 0) s--;
+                       break;
+
+               case 'r':
+                       p->rflg = -1;
+                       break;
+
+               default:
+                       p->m[k] = number(&s);
+                       if(*s == '.')
+                               s++;
+                       p->n[k] = number(&s);
+                       s--;
+               }
+       }
+}
+
+number(ppa)
+char **ppa;
+{
+       int n;
+       register char *pa;
+       pa = *ppa;
+       n = 0;
+       while(digit(*pa))
+               n = n*10 + *pa++ - '0';
+       *ppa = pa;
+       return(n);
+}
+
+blank(c)
+{
+       if(c==' ' || c=='\t')
+               return(1);
+       return(0);
+}
+
+int    (*qscmp)();
+int    qses;
+
+qsort(a, n, es, fc)
+char *a;
+int n, es;
+int (*fc)();
+{
+       qscmp = fc;
+       qses = es;
+       qs1(a, a+n*es);
+}
+
+qs1(a, l)
+char *a, *l;
+{
+       register char *i, *j, *es;
+       char **k;
+       char *lp, *hp;
+       int n, c;
+
+
+       es = qses;
+
+start:
+       if((n=l-a) <= es)
+               return;
+
+
+       n = ((n/(2*es))*es) & 077777;
+       hp = lp = a+n;
+       i = a;
+       j = l-es;
+
+
+       for(;;) {
+               if(i < lp) {
+                       if((c = (*qscmp)(i, lp)) == 0) {
+                               qsexc(i, lp =- es);
+                               continue;
+                       }
+                       if(c < 0) {
+                               i =+ es;
+                               continue;
+                       }
+               }
+
+loop:
+               if(j > hp) {
+                       if((c = (*qscmp)(hp, j)) == 0) {
+                               qsexc(hp =+ es, j);
+                               goto loop;
+                       }
+                       if(c > 0) {
+                               if(i == lp) {
+                                       qstexc(i, hp =+ es, j);
+                                       i = lp =+ es;
+                                       goto loop;
+                               }
+                               qsexc(i, j);
+                               j =- es;
+                               i =+ es;
+                               continue;
+                       }
+                       j =- es;
+                       goto loop;
+               }
+
+
+               if(i == lp) {
+                       for(k=lp+2; k<=hp;) *(*k++)='\0';
+                       if(lp-a >= l-hp) {
+                               qs1(hp+es, l);
+                               l = lp;
+                       } else {
+                               qs1(a, lp);
+                               a = hp+es;
+                       }
+                       goto start;
+               }
+
+
+               qstexc(j, lp =- es, i);
+               j = hp =- es;
+       }
+}
+
+qsexc(i, j)
+char *i, *j;
+{
+       register char *ri, *rj, c;
+       int n;
+
+       n = qses;
+       ri = i;
+       rj = j;
+       do {
+               c = *ri;
+               *ri++ = *rj;
+               *rj++ = c;
+       } while(--n);
+}
+
+qstexc(i, j, k)
+char *i, *j, *k;
+{
+       register char *ri, *rj, *rk;
+       char    c;
+       int     n;
+
+       n = qses;
+       ri = i;
+       rj = j;
+       rk = k;
+       do {
+               c = *ri;
+               *ri++ = *rk;
+               *rk++ = *rj;
+               *rj++ = c;
+       } while(--n);
+}