! Version of Mar 87
%option "-low-nocheck-nodiag-noline-nostack"
%include "moose:mouse.inc"

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

%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
%constinteger pagesize=24
%owninteger linesleft=pagesize-1

%owninteger initialised = 0
%Owninteger gotit = 0
%OwnRecord(semaphorefm)%name inmutex,outmutex

%Ownrecord(semaphorefm)%name notfull
%Ownrecord(semaphorefm)%name notempty

%Constinteger kbbs = 512-1
%Recordformat kb buff fm(%Integer sem,bs,be,in,out,notempty,
                         %Bytearray buff(0:kbbs),%integer op)
%ownrecord(kbbufffm)%name kb buff

%Constinteger opbs = 1024-1
%Recordformat op buff fm(%Integer notfull,bs,in,out,
                         %bytearray buff(0:opbs),%integer code,ctrlo,
                         %Integer xonsem, %integer xonflag, %integer gotsem)

%Ownrecord(opbufffm)%name op buff

%systemroutinespec phex (%Integer x)

%Externalroutine set terminal mode (%Integer x)
   terminal mode = x
%End

%Routine Psymr (%Integer sym)
   %Integer k,t,a
   %Returnif opbuff_Ctrlo=1
   %if opbuff_xonflag = 1 %start
      Semaphore wait (record(opbuff_xonsem))
   %finish
   a = (opbuff_in&opbs)+opbuff_bs
   t = opbuff_in
   byteinteger(a) = sym
   opbuff_in = t+1
   semaphore wait (notfull) %while opbuff_in-opbuff_out = opbs-20
   %if t = opbuff_out %start
      acias =16_B1
   %finish
%End

%Routine psym (%Integer sym)
   %if opbuff_gotsem=0 %or gotit=0 %Start
      semaphorewait(outmutex) 
      opbuff_gotsem = 1
      gotit = 1
   %Finish
   psymr(sym)
   %If sym = NL %or sym = 0 %start
      opbuff_gotsem=0 
      gotit =0
      signal semaphore (outmutex)
   %Finish
%End

%Integerfn Extract Character
   %Integer t,k
   t=kbbuff_out
   %If kbbuff_in # t %start
      k=byteinteger(t)
      t=t+1
      t=kbbuff_bs %if t=kbbuff_be
      kbbuff_out=t
      %Result=k
   %Else
      %Result = -1
   %Finish
%End

%externalintegerfn testsymbol
%integer k
   k = extract character
   k=k!!(cr!!nl) %if k=cr %or k=nl
   %result = k
%End

%Integerfn rsym
   ! This should be rewritten once there is no signal per character
   %integer k
   %Cycle
      semaphore wait (record(kbbuff_notempty))
      k = extract character
   %repeatuntil k # -1
   %Result = k
%End
   
%Routine cancel ctrlo
   opbuff_ctrlo = 0
%End

!%Externalroutine screen put (%Integer x)
!   psym(x)
!%End

%externalroutine release terminal
   putstring("Rel")
   %if gotit # 0 %start
      putstring("eased")
      opbuff_gotsem=0 
      gotit =0
      signal semaphore (outmutex)
   %finish
%End   

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

  %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
    semaphore wait (inmutex)
    cancel ctrlo
    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
    signal semaphore(outmutex) %and opbuff_gotsem=0 %if opbuff_gotsem=1
    %cycle
      k = rsym
      k = k!!(cr!!nl) %if (k=cr %or k=nl) {%and terminalmode&single=0}
      put(k) %and signalsemaphore(inmutex) %and-
        %returnif terminalmode&single#0 %or-
        (k&31=k %and 1<<k&terminalmask#0)
      signalsemaphore(inmutex) %andreturnif k=etx
      signalsemaphore(inmutex) %and %signal 0,1,,"abort" %if k='Y'-64
      %if k=del %start
        %continueif scb_l=scb_p
        scb_l = scb_l-1
        psymr(bs) %and psymr(' ') %and psymr(bs) %if terminalmode&noecho=0
        %continue
      %finish
      %if k='R'-64 %start
         cancel ctrlo
         psym(13);psym(10)
         %If scb_a#0 %start
            psym(byteinteger(scb_a+k)) %for k=1,1,byteinteger(scb_a)
         %finish
         %for k=scb_p,1,scb_l-1 %cycle
            psym(byteinteger(k))
         %Repeat
         signal semaphore(outmutex) %and opbuff_gotsem=0 %if opbuff_gotsem=1
         %Continue
      %Finish
      %if k='X'-64 %or k=bs %start
        %while scb_l>scb_p %cycle
          scb_l = scb_l-1; psymr(bs); psymr(' '); psymr(bs)
        %repeat
        %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='?'
         %Continue
      %finish
      signalsemaphore(inmutex) %andsignal 9,,,"End of file" %if k=eot %or k='Z'-64
      %if k&31=k %start
        %exitif 1<<k&terminatormask#0
        psymr(bel); %continue
      %finish
      put(k); psymr(k) %if terminalmode&noecho=0
    %repeat
    put(k)
    %if terminalmode&notermecho=0 %start
      psymr(cr) %if k=nl; psymr(k)
    %finish
    signalsemaphore(inmutex)
  %end

  %routine flush(%record(scb fm)%name scb,%integer sym)
    psym(cr) %if sym=nl %and terminalmode&single=0 ; 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

  %If initialised = 0 %start
      t = Find Entry ("T_MUTEX_IN",poa_logdict)
      %Signal 3,0,0,"Failed to find T_MUTEX_IN" %if t=0
      inmutex  == record(integer(t))       
      t = Find Entry ("T_MUTEX_OUT",poa_logdict)
      %Signal 3,0,0,"Failed to find T_MUTEX_OUT" %if t=0
      outmutex == record(integer(t))
      t = Find Entry ("T_OP_BUFFER",poa_logdict)
      %Signal 3,0,0,"Failed to find T_OP_BUFFER" %if t=0
      opbuff==record(integer(t))
      notfull  == record(opbuff_notfull)
      t = Find Entry ("T_KB_BUFFER",poa_logdict)
      %Signal 3,0,0,"Failed to find T_KB_BUFFER" %if t=0
      kbbuff==record(integer(t))
      notempty == record(kbbuff_notempty)
      initialised = 1
  %Finish
  scb == record(heapget(sizeof(scb))); scb = 0
  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
