! Terminal Device Driver

%option "-low-nocheck-nodiag-noline"
%include "mouse.inc"

%constinteger buffer size = 128
%constinteger cr=13,eot=4,esc=27,bs=8,del=127,etx=3,dle=16,bel=7
%constinteger noecho=1,notermecho=2,single=4,nopage=8,frozen=16
%externalinteger terminalmode=0
%externalinteger terminalmask=0
%externalinteger terminatormask=1<<nl+1<<cr
%constinteger pagesize=24
%owninteger linesleft=pagesize-1

@16_4000c0 %byte *,acia s,*,acia d

%externalroutine psym %alias "screenput" (%integer sym)
  %cycle
  %repeatuntil acia s&2#0
  acia d = sym
%end

%integerfn rsym
  %cycle
  %repeatuntil acia s&1#0
  %result = acia d & 127
%end

%externalintegerfn testsymbol
  %result = -1 %if acia s&1=0
  %result = rsym
%end

%externalroutine setterminalmode(%integer x)
  terminalmode = x
%end

%externalrecord(scb fm)%map open %alias "t_open" -
  (%integer mode, %string(255)file)
%record(scb fm)%name scb
%integer x

  %routine refresh(%record(scb fm)%name scb)
  %integer k
    %routine put(%integer x)
      %returnif scb_l=scb_bl
      byteinteger(scb_l) = x; scb_l = scb_l+1
    %end
    scb_p = scb_bs; scb_l = scb_bs
    linesleft = pagesize-1
    %if scb_a#0 %start
      psym(byteinteger(scb_a+k)) %for k = 1,1,byteinteger(scb_a)
    %finish
    %cycle
      k = rsym
      k = k!!(cr!!nl) %if k=cr %or k=nl
      put(k) %andreturnif terminalmode&single#0 %or-
        (k&31=k %and 1<<k&terminalmask#0)
      %returnif k=etx
      %signal 0,1,,"abort" %if k='Y'-64
      %if k=del %start
        %continueif scb_l=scb_p
        scb_l = scb_l-1
        psym(bs) %and psym(' ') %and psym(bs) %if terminalmode&noecho=0
        %continue
      %finish
      %if k='X'-64 %or k=bs %start
        %while scb_l>scb_p %cycle
          scb_l = scb_l-1; psym(bs); psym(' '); psym(bs)
        %repeat
        %continue
      %finish
      %if k='T'-64 %start
        *trap #14 {??}
        %continue
      %finish
      %if k=dle %start
        put(rsym); %continue
      %finish
      %if k=esc %start
        put(esc)
        k = rsym; put(k)
        k = rsym %and put(k) %if k='?'
        %return
      %finish
      %signal 9,,,"End of file" %if k=eot %or k='Z'-64
      %if k&31=k %start
        %exitif 1<<k&terminatormask#0
        psym(bel); %continue
      %finish
      put(k); psym(k) %if terminalmode&noecho=0
    %repeat
    put(k)
    %if terminalmode&notermecho=0 %start
      psym(cr) %if k=nl; psym(k)
    %finish
  %end

  %routine flush(%record(scb fm)%name scb,%integer sym)
    %if sym=nl %and terminalmode&nopage=0 %start
      linesleft = linesleft-1
      %if linesleft<=0 %start
        psym('@'); psym(bs); linesleft = pagesize-1
        sym = rsym; terminalmode = terminalmode!!nopage %if sym='Q'-64
        psym(' '); sym = nl
      %finish
    %finish
    psym(cr) %if sym=nl; psym(sym)
  %end

  %routine closin(%record(scb fm)%name scb)
    heapput(scb_a) %unless scb_a=0
    heapput(scb_bs); scb_bs = 0
  %end

  %routine prompt(%record(scb fm)%name scb,%integer stringad)
    heapput(scb_a) %unless scb_a=0
    scb_a = 0 %andreturnif byteinteger(stringad)=0
    scb_a = heapget(byteinteger(stringad)+1)
{}  byteinteger(scb_a-4) = 1  {HEAP frig to prevent release}
    string(scb_a) = string(stringad)
  %end

  %routine service(%record(scb fm)%name scb,%integer op,parm)
  %switch sw(0:7)
    ->sw(op&7)
sw(serclosin):  closin(scb);      %return
sw(serclosout):                   %return
sw(serprompt):  prompt(scb,parm); %return
sw(serdropout):                   %return
sw(sersetin):                     %return
sw(sersetout):                    %return
sw(serrefresh): refresh(scb);     %return
sw(serflush):   flush(scb,parm)
  %end

  scb == newscb(file)
  scb_mode = mode
  scb_gla = a4
  *lea service,a0; *move.l a0,x
  scb_serpc = x
  %if mode=inputmode %start
    *lea refresh,a0; *move.l a0,x
    scb_fastpc = x
  %else
    *lea flush,a0; *move.l a0,x
    scb_fastpc = x
  %finish
  scb_bs = heapget(buffersize)
  scb_bl = scb_bs+buffersize
  scb_fs = scb_bs
  scb_fl = scb_bs
  scb_p = scb_bs
  scb_l = scb_bs
  %result == scb
%end
