# ed --- editor with Georgia Tech extensions

include "ed_def.r.i"

# edit --- main routine

   subroutine edit (filenm, fdin, fdout)
   character filenm (ARB)
   integer fdin, fdout

   include "ed_com.r.i"

   character lin(MAXLINE)

   integer ckglob, docmd, doglob, doread, getlin, getlst
   integer cursav, i, status

   logical intrpt, brkflag

   external dologout
   shortcall mkonu$ (22)

   call break$ (DISABLE)            # disable break key

   Fdin = fdin
   Fdout = fdout

   probation = 0
   saverrcode = ENOERR
   errcode = ENOERR
   prompt(1) = EOS
   pat(1) = EOS
   tlpat(1) = EOS
   subs(1) = EOS
   savfil(1) = EOS
   savknm = DEFAULTNAME
   nldef(1) = EOS
   ddir = FORWARD
   tune = 0
   globals = NO
   call setlog(MAKE_LOG_FILE)
   call setbuf
   curln = 0
   if (filenm (1) ~= EOS) {
      call ctoc (filenm, savfil, MAXLINE)
      if (doread(0, savfil) == ERR)
         call remark("?"p)
      else
         curln = min0 (1, lastln)
      }
   saverrcode = errcode   # in case of error above
   updflg = NO
   call mkonu$ ("LOGOUT$"v, loc (dologout))  # catch logouts
   while (getlin(lin, Fdin) ~= EOF) {
      if (intrpt(brkflag))
         status = ERR
      else {
         i = 1
         errcode = EEGARB  # default error code for garbage at end
         cursav = curln
         call log(lin)
         if (getlst(lin, i, status) == OK) {
            if (ckglob(lin, i, status) == OK)
               status = doglob(lin, i, cursav, status)
            else if (status ~= ERR)
               status = docmd(lin, i, NO, status)
            # else error, do nothing
            }
         }
      if (status == ERR) {
         call remark("?"p)
         if (cursav <= lastln) {
            curln = cursav
            call putdec(curln, 0, safety_logfile)
            call putch(NEWLINE, safety_logfile)
            }
         saverrcode = errcode
         }
      else if (status == EOF)
         break
      # else status is OK
      call putlin(prompt, Fdout)
#      call idle # tell file primitives we aren't especially busy
      if (intrpt(brkflag))
         ; # too late to worry about it
      }
   call clrbuf
   if (updflg == NO)
      call setlog(UNMAKE_LOG_FILE)
   else
      call close(safety_logfile)
   call break$ (ENABLE)                # enable break key
   return
   end



# append --- append lines after "line"

   integer function append(line, glob)
   integer line, glob

   include "ed_com.r.i"

   character lin(MAXLINE)

   integer getlin, inject

   if (glob == YES) {
      append = ERR
      errcode = EGLOBA
      }
   else {
      curln = line
      for (append = NOSTATUS; append == NOSTATUS; ) {
         if (getlin(lin, Fdin) == EOF)
            append = EOF
         else if (lin(1) == '.'c && lin(2) == NEWLINE)
            append = OK
         else if (inject(lin) == ERR)
            append = ERR
         else
            updflg = YES
         call log(lin)
         }
      }
   return
   end



# bump --- advance line number and corresponding index simultaneously

   subroutine bump(line, ix, way)
   integer line, ix, way

   include "ed_com.r.i"

   integer getind

   if (way == FORWARD) {
      ix = buf(ix + NEXT)
      if (ix == line0)
         line = 0
      else
         line += 1
      }
   else { # way is BACKWARD
      if (ix == line0)
         line = lastln
      else
         line -= 1
      ix = buf(ix + PREV)
      }
#   if (getind(line) ~= ix) call error("in bump: can't happen.")
   return
   end



# catlin --- concatenate lin onto new; delete any NEWLINE at the end

   subroutine catlin(lin, new, i, maxnew)
   character lin(ARB), new(maxnew)
   integer i, maxnew

   integer f

   for (f = 1; lin(f) ~= EOS && lin(f) ~= NEWLINE; f += 1) {
      if (i > maxnew)
         break  # no error status needed; i > maxnew.
      new(i) = lin(f)
      i += 1
      }
   return
   end



# ckchar --- look for flag character of ch or altch on lin at i, set flag

   integer function ckchar(ch, altch, lin, i, flag, status)
   integer lin(ARB), i, flag, status
   character ch, altch

   if (lin(i) == ch || lin(i) == altch) {
      i += 1
      flag = YES
      }
   else
      flag = NO
   status = OK # always
   ckchar = OK
   return
   end



# ckglob --- if global prefix, mark lines to be affected
#            return EOF iff no global prefix

   integer function ckglob(lin, i, status)
   character lin(MAXLINE)
   integer i, status

   include "ed_com.r.i"

   integer k, line, usepat, usemark, tmp
   integer defalt, match, optpat, getkn

   logical intrpt, brkflag

   status = OK
   usepat = EOF
   usemark = EOF
   if (lin(i) == GMARK || lin(i) == XMARK) {
      if (lin(i) == GMARK)
         usemark = YES
       else
         usemark = NO
      i += 1
      if (getkn(lin, i, savknm, savknm) == ERR)
         status = ERR
      }
   if (lin(i) == GLOBAL || lin(i) == EXCLUDE || lin(i) == UCGLOBAL
      || lin(i) == UCEXCLUDE) {
      if (lin(i) == GLOBAL || lin(i) == UCGLOBAL)
         usepat = YES
      else
         usepat = NO
      i += 1
      if (optpat(lin, i) == ERR)
         status = ERR
      else
         i += 1
      }
   if (status == OK && usepat == EOF && usemark == EOF)
      status = EOF
   else if (status == OK)
      status = defalt(1, lastln, status)
   if (status == OK) {
      k = line0
      for (line = 0; line < line1; line += 1) {
         buf(k + MARK) = NO
         k = buf(k + NEXT)
         }
      for ( ; line <= line2; line += 1) {
         if (intrpt(brkflag)) {
            ckglob = ERR
            status = ERR
            return
            }
         tmp = NO
         if (usemark == EOF || usemark == YES && buf(k + NAME) == savknm
           || usemark == NO && buf(k + NAME) ~= savknm)
            if (usepat == EOF)
               tmp = YES
            else {
               call gtxt(k)
               if (match(txt, pat) == usepat)
                  tmp = YES
               }
         buf(k + MARK) = tmp
         k = buf(k + NEXT)
         }
      for ( ; k ~= line0; k = buf(k + NEXT))
         buf(k + MARK) = NO
      }
   ckglob = status
   return
   end



# ckp --- check for "p" after command

   integer function ckp(lin, i, pflag, status)
   character lin(MAXLINE)
   integer i, pflag, status

   integer j

   j = i
   if (lin(j) == PRINT || lin(j) == UCPRINT) {
      j += 1
      pflag = YES
      }
   else
      pflag = NO
   if (lin(j) == NEWLINE)
      status = OK
   else
      status = ERR
   ckp = status
   return
   end



# ckupd --- make sure it is ok to destroy the buffer

   integer function ckupd(lin, i, status)
   integer i, status
   character lin(ARB)

   include "ed_com.r.i"

   integer flag
   integer ckchar

   status = ckchar ('!'c, '!'c, lin, i, flag, status) # "!" for NOW!
   if (flag == NO && updflg == YES && probation == NO) {
      status = ERR
      errcode = ESTUPID
      call remark("(not saved)"p)
      probation = YES   # if very next command calls us, we'll keep silent
      }
   ckupd = status
   return
   end



# copy --- copy line1 through line2 after line3

   integer function copy (line3)
   integer line3

   include "ed_com.r.i"

   integer i, k, ptr3, after3
   integer inject, getind

   copy = OK
   ptr3 = getind (line3)
   after3 = buf (ptr3 + NEXT)
   if (line1 <= 0 ) {
      copy = ERR
      errcode = ELINE1
      }
   else {
      curln = line3
      k = getind (line1)
      for (i = line1; i <= line2; i += 1) {
         call gtxt (k)
         if (inject(txt) == ERR) {
            copy = ERR
            break
            }
         if (k == ptr3)
            k = after3
         else
            k = buf (k + NEXT)
         }
      }
   return
   end



# defalt --- set defaulted line numbers

   integer function defalt(def1, def2, status)
   integer def1, def2, status

   include "ed_com.r.i"

   if (nlines == 0) {
      line1 = def1
      line2 = def2
      }
   if (line1 > line2) {
      status = ERR
      errcode = EBACKWARD
      }
   else if (line1 <= 0) {
      status = ERR
      errcode = ELINE1
      }
   else
      status = OK
   defalt = status
   return
   end



# delete --- delete lines from through to

   integer function delete(pfrom, pto, status)
   integer pfrom, pto, status

   include "ed_com.r.i"

   integer k1, k2, j1, j2, l1, l2, from, to
   integer getind, nextln, prevln

   from = pfrom
   to = pto

   if (from <= 0) {
      status = ERR
      errcode = ELINE1
      }

# The following lines of commented-out code, when they were in,
# caused the v command to fail if there was only one line in the
# buffer and no modifications had been made.  Things would get
# horribly confused.  I don't know the reason for the bug, but
# getting rid of the following "improvement" fixed it.  WJW
#   else if (from == 1 & to == lastln & updflg == NO) {
#      call clrbuf
#      call setbuf
#      status = OK
#      }
   else {
      k1 = getind(prevln(from))
      j1 = getind(from)
      j2 = getind(to)
      k2 = getind(nextln(to))
      lastln -= to - from + 1
      curln = prevln(from)
      call relink(k1, k2, k1, k2)
      if (limbo ~= NOMORE) { # put it on free list
         l1 = limbo
         l2 = buf(l1 + PREV)
         buf(l1 + PREV) = free
         free = l2
         }
      limbo = j1       # put what we just deleted in limbo
      limcnt = to - from + 1 # number of lines "deleted"
      call relink(j2, j1, j2, j1) # close the ring
      status = OK
      updflg = YES
      }
   delete = status
   return
   end



# docmd --- handle all commands except globals

   integer function docmd(lin, i, glob, status)
   character lin (MAXLINE)
   integer i, glob, status

   include "ed_com.r.i"

   integer gflag, line3, pflag, flag, junk, kname, allbut
   integer append, delete, doprnt, doread, dowrit, move, subst,
      domark, prntkn, getkn, doopt, ckchar, ckupd, getstr, makset,
      getrange, dotlit,ckp, defalt, getfn, getone, getrhs, nextln,
      optpat, prevln, doundo, copy, eval, join, doshell, getpstr

   character file(MAXLINE), sub(MAXPAT)

   logical intrpt, brkflag
   integer j, missing_delim

   pflag = NO      # may be set by d, m, s, u, y
   status = ERR
   if (intrpt(brkflag))
      ;
   else
   select (lin (i))
   when ('?'c) {
      if (lin(i + 1) == NEWLINE) {
         status = OK
         call printverboseerrormessage
         }
      }
   when (APPENDCOM, UCAPPENDCOM) {
      if (lin(i + 1) == NEWLINE)
         status = append(line2, glob)
      }
   when (OVERLAYCOM, UCOVERLAYCOM) {
      if (lin(i + 1) == NEWLINE
        && defalt(curln, curln, status) == OK)
         call extend(status)
         }
   when (CHANGE, UCCHANGE) {
      if (lin(i + 1) == NEWLINE
        && defalt(curln, curln, status) == OK
        && delete(line1, line2, status) == OK)
         status = append(prevln(line1), glob)
      }
   when (DELCOM, UCDELCOM) {
      if (ckp(lin, i + 1, pflag, status) == OK
        && defalt(curln, curln, status) == OK
        && delete(line1, line2, status) == OK
        && ddir == FORWARD
        && nextln(curln) ~= 0)
         curln = nextln(curln)
      }
   when (INSERT, UCINSERT) {
      if (lin(i + 1) == NEWLINE)
         status = append(prevln(line2), glob)
      }
   when (PRINTCUR) {
      if (ckp(lin, i + 1, pflag, status) == OK) {
         call putdec(line2, 1, Fdout)
         call putch(NEWLINE,Fdout)
         }
      }
   when (MOVECOM, UCMOVECOM) {
      i += 1
      if (getone(lin, i, line3, status) == EOF)
         status = ERR
      if (status == OK
        && ckp(lin, i, pflag, status) == OK
        && defalt(curln, curln, status) == OK)
         status = move(line3)
      }
   when (COPYCOM, UCCOPYCOM) {
      i += 1
      if (getone(lin, i, line3, status) == EOF)
         status = ERR
      if (status == OK
        && ckp(lin, i, pflag, status) == OK
        && defalt(curln, curln, status) == OK)
         status = copy (line3)
      }
   when (SUBSTITUTE, UCSUBSTITUTE) {
      i += 1
      if (lin (i) == NEWLINE) {
         lin (i + 0) = '/'c
         lin (i + 1) = '/'c
         lin (i + 2) = '&'c
         lin (i + 3) = '/'c
         lin (i + 4) = 'p'c
         lin (i + 5) = NEWLINE
         lin (i + 6) = EOS
         }
      else {   # try to handle "s/stuff<NEWLINE>"
         missing_delim = YES

         for (j = i + 1; lin (j) ~= EOS; j += 1)
            if (lin (j) == ESCAPE && lin (j + 1) == lin (i))
               j += 1   # skip esc, loop will skip char
            else if (lin (j) == lin (i)) {
               missing_delim = NO
               break # for
               }

         if (missing_delim == YES) {
            for (; lin (j) ~= EOS; j += 1)
               ;
            j -= 1   # j now at NEWLINE

            # now supply trailing delimiter
            lin (j) = lin (i)
            lin (j + 1) = NEWLINE
            lin (j + 2) = EOS
            # rest of routines will continue to fix it up
            }
         }

      if (optpat(lin, i) == OK
        && getrhs(lin, i, sub, gflag) == OK
        && ckp(lin, i + 1, pflag, status) == OK
        && defalt(curln, curln, status) == OK)
         status = subst(sub, gflag, glob)
      }
   when (TLITCOM, UCTLITCOM) {
      i += 1
      if (lin (i) == NEWLINE) {
         lin (i + 0) = '/'c
         lin (i + 1) = '/'c
         lin (i + 2) = '&'c
         lin (i + 3) = '/'c
         lin (i + 4) = 'p'c
         lin (i + 5) = NEWLINE
         lin (i + 6) = EOS
         }
      else {   # try to handle "t/stuff<NEWLINE>"
         missing_delim = YES

         for (j = i + 1; lin (j) ~= EOS; j += 1)
            if (lin (j) == ESCAPE && lin (j + 1) == lin (i))
               j += 1   # skip esc, loop will skip char
            else if (lin (j) == lin (i)) {
               missing_delim = NO
               break # for
               }

         if (missing_delim == YES) {
            for (; lin (j) ~= EOS; j += 1)
               ;
            j -= 1   # j now at NEWLINE

            # now supply trailing delimiter
            lin (j) = lin (i)
            lin (j + 1) = NEWLINE
            lin (j + 2) = EOS
            # rest of routines will continue to fix it up
            }
         }

      if (getrange (lin, i, tlpat, MAXPAT, allbut) == OK
      && makset (lin, i, sub, MAXPAT) == OK
      && ckp (lin, i + 1, pflag, status) == OK
      && defalt (curln, curln, status) == OK)
         status = dotlit (sub, allbut)
      }
   when (JOINCOM, UCJOINCOM) {
      i += 1
      if (getstr(lin, i, sub, MAXPAT) == OK
        && ckp(lin, i + 1, pflag, status) == OK
        && defalt(prevln(curln), curln, status) == OK)
         status = join(sub)
      }
   when (UNDOCMD, UCUNDOCMD) {
      i += 1
      junk = defalt(curln, curln, junk)
      if (ckchar(UCDELCOM, DELCOM, lin, i, flag, status) == OK
        && ckp(lin, i, pflag, status) == OK)
         status = doundo(flag, status)
      }
   when (ENTER, UCENTER) {
      i += 1
      if (nlines == 0
        && ckupd(lin, i, status) == OK)
         if (getfn(lin, i - 1, file) == OK) {
            call scopy(file, 1, savfil, 1)
            call clrbuf
            call setbuf
            status = doread(0, file)
            if (status == ERR)
               curln = 0
            else
               curln = 1
            updflg = NO
            }
         else
            status = ERR
      }
   when (PRINTFIL, UCPRINTFIL) {
      if (nlines == 0
        && getfn(lin, i, file) == OK) {
         call scopy(file, 1, savfil, 1)
         call putlin(savfil, Fdout)
         call putch(NEWLINE, Fdout)
         status = OK
         }
      }
   when (READCOM, UCREADCOM) {
      if (getfn(lin, i, file) == OK)
         status = doread(line2, file)
      }
   when (WRITECOM, UCWRITECOM) {
      i += 1
      if (ckchar ('+'c, '>'c, lin, i, flag, junk) == OK
        && getfn(lin, i - 1, file) == OK
        && defalt(1, lastln, status) == OK)
         status = dowrit(line1, line2, file, flag)
      }
   when (PRINT, UCPRINT) {
      if (lin(i + 1) == NEWLINE
        && defalt(curln, curln, status) == OK)
         status = doprnt(line1, line2)
      }
   when (PAGECOM) {
      if (lin (i + 1) == NEWLINE) {
         status = defalt (nextln (curln), lastln, status)
         if (nlines == 1)
            line2 = lastln
         if (status == OK) {
            status = doprnt (line1, min (line2, line1 + 22))
            }
         }
      }
   when (NAMECOM, UCNAMECOM) {
      if (lin(i + 1) == NEWLINE) {
         if (defalt(curln, curln, status) == OK)
            status = prntkn(line1, line2)
         }
      else { # uniquely name the line, rather than printing its name
        i += 1
        if (getkn(lin, i, kname, DEFAULTNAME) == OK
          && lin(i) == NEWLINE)
           call uniquely_name(kname, status)
        }
      }
   when (MARKCOM, UCMARKCOM) {
      i += 1
      if (getkn(lin, i, kname, DEFAULTNAME) == OK
        && lin(i) == NEWLINE
        && defalt(curln, curln, status) == OK)
         status = domark(kname)
      }
   when (NEWLINE) {
      status = OK
      if (nlines == 0)
#        if (nldef(1) == EOS) # this test only for speed
            line2 = nextln(curln)
#        else
#           line2 = eval(nldef, status)
      if (status == OK)
         status = doprnt(line2, line2)
      }
   when (LOCATECMD, UCLOCATECMD) {
      call whereami
      status = OK
      }
   when (OPTCOM, UCOPTCOM)
      status = doopt(lin,i)
   when (QUIT, UCQUIT) {
      i += 1
      if (nlines == 0
        && ckupd(lin, i, status) == OK)
         if (lin(i) == NEWLINE)
            status = EOF
         else
            status = ERR
      }
   when (SHELLCOM) {
      i += 1
      if (defalt (curln, curln, status) == OK)
         status = doshell (lin, i)
      }

   else # command not recognized
      errcode = EWHATZAT

   if (status == OK) {
      if (pflag == YES)
         status = doprnt(curln, curln)
      probation = NO
      }
   docmd = status
   return
   end



# doglob --- do command at lin(i) on all marked lines

   integer function doglob(lin, i, cursav, status)
   character lin(MAXLINE)
   integer i, cursav, status

   include "ed_com.r.i"

   integer istart, k, line
   integer docmd, getlst

   logical intrpt, brkflag

   status = OK
   istart = i
   k = line0
   line = 0
   repeat {
      line += 1
      k = buf(k + NEXT)
      if (buf(k+MARK) == YES) {
         buf(k+MARK) = NO
         curln = line
         cursav = curln
         i = istart
         if (getlst(lin, i, status) == OK)
           status = docmd(lin, i, YES, status)
         line = 0
         k = line0
         }
      if (intrpt(brkflag))
         status = ERR
      } until (line > lastln || status ~= OK)
   doglob = status
   return
   end



# domark --- name lines line1 through line2 kname

   integer function domark(kname)
   integer kname

   include "ed_com.r.i"

   integer k, line
   integer getind

   logical intrpt, brkflag

   if (line1 <= 0) {
      errcode = ELINE1
      domark = ERR
      }
   else {
      k = getind(line1)
      for (line = line1; line <= line2; line += 1) {
         buf(k + NAME) = kname
         if (intrpt(brkflag)) {
            domark = ERR
            return
            }
         k = buf(k + NEXT)
         }
      domark = OK
      }
   return
   end



# whereami --- print out machine location

   subroutine whereami
   integer fd, open, getlin, length
   integer i
   character place (MAXLINE)
   string unknown "unknown"

   include "ed_com.r.i"

   fd = open ("=installation="s, READ)
   if (fd == ERR)
      call scopy (unknown, 1, place, 1)
   else {
      i = getlin (place, fd, MAXLINE)
      if (i == ERR || i == EOF)
         call scopy (unknown, 1, place, 1)
      call close (fd)
      }
   i = length (place)
   if (place (i) == NEWLINE)
      place (i) = EOS

   call print (Fdout, "*s*n"s, place)

   return
   end



# doopt --- interpret option command

   integer function doopt(lin, i)
   character lin(ARB)
   integer i

   include "ed_com.r.i"

   integer j
   integer ctoi, eval, doprnt, getstr, getpstr

   i += 1
   doopt = ERR

   select (lin (i))

   when ('g'c, 'G'c) {
      i += 1
      if (lin (i) == NEWLINE) {
         doopt = OK
         globals = YES + NO - globals
         if (globals == YES)
            call remark ("failed global substitutes continue"p)
         else
            call remark ("failed global substitutes stop"p)
         }
      }

   when ('p'c, 'P'c) {
      i += 1
      if (lin(i) == NEWLINE) {
         if (prompt(1) == EOS) {
            prompt(1) = '*'c
            prompt(2) = ' 'c
            prompt(3) = EOS
            }
         else
            prompt(1) = EOS
         doopt = OK
         }
      else if (getpstr(lin, i, prompt, MAXLINE) == OK
         && lin(i + 1) == NEWLINE)
            doopt = OK
      }
#  when ('n'c, 'N'c) {
#     i += 1
#     for (j = 1; lin(i) != NEWLINE; i += 1) {
#        nldef(j) = lin(i)
#        j += 1
#        }
#     nldef(j) = EOS
#     line2 = eval(nldef, doopt)
#     if (doopt == OK)
#        doopt = doprnt(line2, line2)
#     }
   when ('k'c, 'K'c) {
      if (lin(i + 1) == NEWLINE) {
         doopt = OK
         if (updflg == YES)
            call remark("not saved"p)
         else
            call remark("saved"p)
         }
      }
   when ('d'c, 'D'c) {
      if (lin(i + 1) == NEWLINE) {
         if (ddir == FORWARD)
            call putch('>'c, Fdout)
         else
            call putch('<'c, Fdout)
         call putch(NEWLINE, Fdout)
         doopt = OK
         }
      else if (lin(i + 2) ~= NEWLINE)
         errcode = EODLSSGTR
      else if (lin(i + 1) == '>'c) {
         doopt = OK
         ddir = FORWARD
         }
      else if (lin(i + 1) == '<'c) {
         doopt = OK
         ddir = BACKWARD
         }
      else
         errcode = EODLSSGTR
      }
T  when ('t'c, 'T'c) {
T     if (lin(i + 1) == NEWLINE) {
T        doopt = OK
T        call putdec(tune, 0, Fdout)
T        call putch(NEWLINE, Fdout)
T        }
T     else {
T        i += 1
T        j = ctoi(lin, i)
T        if (lin(i) == NEWLINE) {
T           doopt = OK
T           tune = j
T           }
T        }
T     }
   else # doopt = ERR
      errcode = EOWHAT
   return
   end



# doprnt --- print lines from through to

   integer function doprnt(from, to)
   integer from, to

   include "ed_com.r.i"

   integer i, j
   integer getind

   logical intrpt, brkflag

   if (from <= 0) {
      doprnt = ERR
      errcode = ELINE1
      }
   else {
      j = getind(from)
      for (i = from; i <= to; i += 1) {
         call gtxt(j)
         call putlin(txt, Fdout)
         if (intrpt(brkflag)) {
            doprnt = ERR
            curln = i # for now, this is negated by edit
            return
            }
         j = buf(j + NEXT)
         }
      curln = to
      doprnt = OK
      }
   return
   end



# dologout --- save things when a LOGOUT$ happens

   subroutine dologout (cp)
   long_int cp    # condition pointer, not used

   integer junk, i, length
   character newfile (MAXLINE), arg_zero (MAXLINE)

   include "ed_com.r.i"

   call getarg (0, arg_zero, MAXLINE)
   for (i = length (arg_zero); i > 1; i -= 1)
      if (arg_zero (i) == '/'c) {
         i += 1
         break
         }

   call encode (newfile, MAXLINE, "=home=/*s.logout"s, arg_zero (i))

   call remark ("saving buffer because of pending logout"p)
   call dowrit (1, lastln, newfile, NO)

   call clrbuf

   call cnsig$ (junk)         # continue the signal

   return
   end



# doread --- read "file" after "line"

   integer function doread(line, file)
   character file (MAXLINE)
   integer line

   include "ed_com.r.i"

   character lin(MAXLINE)

   integer count, fd
   integer getlin, inject, open

   logical intrpt, brkflag

   fd = open(file, READ)
   if (fd == ERR) {
      doread = ERR
      errcode = ECANTREAD
      }
   else {
      curln = line
      doread = OK
      for (count = 0; getlin(lin, fd) ~= EOF; count += 1) {
         doread = inject(lin)
         if (doread == ERR)
            break
         else
            updflg = YES # not needed since inject sets it
         if (intrpt(brkflag)) {
            doread = ERR
            break
            }
         }
      call close(fd)
      call putdec(count, 1, Fdout)
      call putch(NEWLINE,Fdout)
      }
   return
   end



# doshell --- escape to the shell to run one or more SWT commands

#  emulate USG Unix 5.0 ed: a ! as the first character is
#  replaced by the previous shell command; an unescaped % is replaced
#  by the saved file name.  The expanded command is echoed.

   integer function doshell (lin, in_i)
   character lin (ARB)
   integer in_i

   include "ed_com.r.i"

   character c
   integer i, j, k
   integer interactive, expanded
   character new_command (MAXLINE)
   character sav_com (MAXLINE)
   integer return_code, shell, subsys

   data sav_com (1) /EOS/      # to make static

   expanded = NO

   if (nlines == 0) {   # use normal 'ed' behavior
      if (lin (in_i) == NEWLINE)
         interactive = YES
      else
         interactive = NO

      # build command, checking for leading !, and % anywhere
      if (lin (in_i) == '!'c) {
         if (sav_com (1) ~= EOS) {
            for (j = 1; sav_com (j) ~= EOS; j += 1)
               new_command (j) = sav_com (j)
            if (new_command (j-1) == NEWLINE)
               j -= 1
            in_i += 1
            expanded = YES
            }
         else {
            errcode = ENOCMD
            return (ERR)
            }
         }
      else
         j = 1

      for (i = in_i; lin (i) ~= EOS; i += 1) {
         if (lin (i) == ESCAPE) {
            if (lin (i+1) ~= '%'c) {
               new_command (j) = ESCAPE
               new_command (j+1) = lin (i+1)
               j += 2
               i += 1      # will be incremented again by for loop
               }
            else {
               i += 1
               new_command (j) = lin (i)
               j += 1
               }
            }
         else if (lin (i) == '%'c) {
            for (k = 1; savfil (k) ~= EOS; k += 1) {
               new_command (j) = savfil (k)
               j += 1
               }
            expanded = YES
            }
         else {
            new_command (j) = lin (i)
            j += 1
            }
         }

      if (new_command (j-1) == NEWLINE)
         j -= 1
      new_command (j) = EOS

      call scopy (new_command, 1, sav_com, 1)   # save it

      if (interactive == YES)    # no command line supplied
         return_code = shell (STDIN)
      else {
         if (expanded == YES)
            call print (STDOUT, "*s*n"s, new_command) # echo it
         return_code = subsys (new_command)
         }

      call print (STDOUT, "*c*n"s, SHELLCOM)

      if (return_code == ERR) { # OK and EOF are allright
        errcode = ENOSHELL
        return (ERR)
        }
      else
        return (OK)
      }
   else
      call remark ("Not implemented"p)

   return (OK)

   end




# dotlit --- transliterate characters

   integer function dotlit (sub, allbut)
   character sub (ARB)
   integer allbut

   include "ed_com.r.i"

   character new (MAXLINE)

   integer collap, x, i, j, line, lastsub, inx, kname, status
   integer length, xindex, inject, getind, gettxt

   logical brkflag, intrpt

   dotlit = ERR
   if (line1 <= 0) {
      errcode = ELINE1
      return
      }
   lastsub = length (sub)
   if (length (tlpat) > lastsub || allbut == YES)
      collap = YES
   else
      collap = NO
   for (line = line1; line <= line2; line += 1) {
      if (intrpt (brkflag)) {
         dotlit = ERR
         return
         }
      inx = gettxt (line)
      j = 1
      for (i = 1; txt (i) ~= EOS; i += 1) {
         x = xindex (tlpat, txt (i), allbut, lastsub)
         if (collap == YES && x >= lastsub && lastsub > 0) { # collapse
            new (j) = sub (lastsub)
            j += 1
            for (i += 1; txt (i) ~= EOS; i += 1) {
               x = xindex (tlpat, txt (i), allbut, lastsub)
               if (x < lastsub)
                  break
               }
            }
         if (txt (i) == EOS)
            break
         if (x > 0 && lastsub > 0) {   # tranlsiterate
            new (j) = sub (x)
            j += 1
            }
         else if (x == 0) {   # copy
            new (j) = txt (i)
            j += 1
            }
                              # else delete
         }
      new (j) = EOS
      kname = buf (inx + NAME)
      call delete (line, line, status)
      dotlit = inject (new)
      if (dotlit == ERR)
         break
      inx = getind (curln)
      buf (inx + NAME) = kname
      dotlit = OK
      updflg = YES  # not needed as delete and inject both set it
      }
   return
   end



# doundo --- restore last set of lines deleted

   integer function doundo (dflg, status)
   integer status, dflg

   include "ed_com.r.i"

   integer k1, k2, l1, l2, oldcnt
   integer nextln, getind

   status = ERR
   if (dflg == NO && line1 <= 0)
      errcode = ELINE1
   else if (limbo == NOMORE)
      errcode = ENOLIMBO
   else if (line1 > line2)
      errcode = EBACKWARD
   else if (line2 > lastln)
      errcode = ELINE2
   else {
      status = OK
      curln = line2
      k1 = getind(line2)
      k2 = getind(nextln(line2))
      l1 = limbo
      l2 = buf(l1 + PREV)
      call relink(k1, l1, l2, k2)
      call relink(l2, k2, k1, l1)
      oldcnt = limcnt
      limcnt = 0
      limbo = NOMORE
      lastln += oldcnt
      if (dflg == NO)
         call delete(line1, line2, status)
      curln += oldcnt
      }
   doundo = status
   return
   end



# dowrit --- write "from" through "to" into file

   integer function dowrit(from, to, file, aflag)
   integer from, to
   character file(MAXLINE)
   integer aflag # append to end of file

   include "ed_com.r.i"

   integer fd, k, line
   integer create, getind, open

   logical intrpt, brkflag

   if (aflag == YES)
      fd = open (file, READWRITE)
   else
      fd = create (file, WRITE)
   if (fd == ERR) {
      dowrit = ERR
      errcode = ECANTWRITE
      }
   else {
      dowrit = OK
      if (aflag == YES)
         call wind (fd)
      k = getind(from)
      for (line = from; line <= to; line += 1) {
         if (intrpt(brkflag)) {
            dowrit = ERR
            break
            } # else continue...
         call gtxt(k)
         call putlin(txt, fd)
         k = buf(k + NEXT)
         }
      call close(fd)
      call putdec(line - from, 1, Fdout)
      call putch(NEWLINE,Fdout)
      if (from == 1 && line - 1 == lastln) {
         call setlog(UNMAKE_LOG_FILE)
         call setlog(MAKE_LOG_FILE)
         updflg = NO
         }
      }
   return
   end



# eval --- evaluate line number expression

   integer function eval(str, status)
   character str(ARB)
   integer status

   include "ed_com.r.i"

   integer i
   integer getone, nextln

   i = 1
   if (str(1) == EOS) {
      status = OK
      eval = nextln(curln)
      }
   else if (getone(str, i, eval, status) == EOF)
      status = ERR
   return
   end



# extend --- let user type onto end of lines

   subroutine extend(status)
   integer status

   include "ed_com.r.i"

   character new(MAXLINE)

   integer lng, junk, lngnew
   integer getlin, gettxt, inject, length

   for (curln = line1; curln <= line2; curln += 1) {
      junk = gettxt(curln)
      lng = length(txt)
      txt(lng) = EOS       # Clobber the newline character
      call putlin(txt, Fdout)
      lngnew = getlin(new, Fdin)
      if (lngnew == EOF) {
         status = EOF
         return
         }
      if (new(1) == '.'c && new(2) == NEWLINE) {
         status = OK
         return
         }
      if (new(1) == NEWLINE)
         next
      status = ERR
      if (lng + lngnew >= MAXLINE) {
         errcode = E2LONG
         return
         }
      call scopy(new, 1, txt, lng)
      call delete(curln, curln, status)
      if (status == OK)
         status = inject(txt)
      if (status == ERR)
         return
      }
   curln = line2
   return
   end



# getfn --- get file name from lin(i)...

   integer function getfn(lin, i, file)
   character lin(MAXLINE), file(MAXLINE)
   integer i

   include "ed_com.r.i"

   integer j, k

   getfn = ERR
   if (lin(i + 1) == ' 'c) {
      j = i + 2      # get new file name
      call skipbl(lin, j)
      for (k = 1; lin(j) ~= NEWLINE; k += 1) {
         file(k) = lin(j)
         j += 1
         }
      file(k) = EOS
      if (k > 1)
         getfn = OK
      }
   else if (lin(i + 1) == NEWLINE && savfil(1) ~= EOS) {
      call scopy(savfil, 1, file, 1)   # or old name
      getfn = OK
      }
   else # error
      if (lin(i + 1) == NEWLINE)
         errcode = ENOFN
      else
         errcode = EFILEN
   if (getfn == OK & savfil(1) == EOS)
      call scopy(file, 1, savfil, 1)   # save if no old one
   return
   end



# getind --- locate line index in buffer

   integer function getind(line)
   integer line

   include "ed_com.r.i"

   integer j, k

   k = line0
   for (j = 0; j < line; j += 1)
      k = buf(k + NEXT)
   getind = k
   return
   end



# getkn --- get mark name from lin(i), increment i

   integer function getkn(lin, i, kname, dfltnm)
   character lin(ARB)
   integer i, kname, dfltnm

   if (lin(i) == NEWLINE || lin(i) == EOS)
      kname = dfltnm
   else {
      kname = lin(i)
      i += 1
      }
   getkn = OK
   return
   end



# getlst --- collect line numbers (if any) at lin(i), increment i

   integer function getlst(lin, i, status)
   character lin(MAXLINE)
   integer i, status

   include "ed_com.r.i"

   integer num
   integer getone, min

   line2 = 0
   for (nlines = 0; getone(lin, i, num, status) == OK; ) {
      line1 = line2
      line2 = num
      nlines += 1
      if (lin(i) ~= ','c && lin(i) ~= ';'c)
         break
      if (lin(i) == ';'c)
         curln = num
      i += 1
      }
   nlines = min(nlines, 2)
   if (nlines == 0)
      line2 = curln
   if (nlines <= 1)
      line1 = line2
   if (status ~= ERR)
      status = OK
   getlst = status
   return
   end



# getnum --- convert one term to line number

   integer function getnum(lin, i, pnum, status)
   character lin(MAXLINE)
   integer i, pnum, status

   include "ed_com.r.i"

   integer j
   integer missing_delim, k
   integer ctoi, optpat, ptscan, knscan, getkn

   getnum = OK
   SKIPBL (lin ,i)

   select (lin (i))
   when ('0'c, '1'c, '2'c, '3'c, '4'c, '5'c, '6'c, '7'c, '8'c, '9'c) {
      pnum = ctoi(lin, i)
      i -= 1      # move back; to be advanced at the end
      }
   when (CURLINE)
      pnum = curln
   when (LASTLINE)
      pnum = lastln
   when (PREVLINE, PREVLINE2)
      pnum = curln - 1
   when (SCAN, BACKSCAN) {
      missing_delim = YES

      # see if trailing delim supplied, since command can follow pattern
      for (k = i + 1; lin (k) ~= EOS; k += 1)
         if (lin (k) == ESCAPE && lin (k+1) == lin (i))
            k += 1   # will skip esc, loop will skip escaped char
         else if (lin (k) == lin (i)) {
            missing_delim = NO
            break
            }

      if (missing_delim == YES) {
         for (; lin (k) ~= EOS; k += 1)
            ;
         k -= 1   # k now at NEWLINE

         # supply trailing delimiter
         lin (k) = lin (i)
         lin (k + 1) = NEWLINE
         lin (k + 2) = EOS
         }

      if (optpat(lin, i) == ERR)   # build the pattern
         getnum = ERR
      else if (lin(i) == SCAN)
         getnum = ptscan(FORWARD, pnum)
      else
         getnum = ptscan(BACKWARD, pnum)
      }
   when (SEARCH, BACKSEARCH) {
      j = i
      i += 1
      if (getkn(lin, i, savknm, savknm) == ERR)
         getnum = ERR
      else if (lin(j) == SEARCH)
         getnum = knscan(FORWARD, pnum)
      else
         getnum = knscan(BACKWARD, pnum)
         i -= 1    # undone below
      }
   else
      getnum = EOF

   if (getnum == OK)
      i += 1      # point at next character to be examined
   status = getnum
   return
   end



# getone --- evaluate one line number expression

   integer function getone(lin, i, num, status)
   character lin(MAXLINE)
   integer i, num, status

   include "ed_com.r.i"

   integer istart, mul, pnum, porm
   integer getnum

   istart = i
   num = 0
   call skipbl(lin, i)
   if (getnum(lin, i, num, status) == OK)   # first term
      repeat {            # + or - terms
         porm = NO
         call skipbl(lin, i)
         if (lin(i) == '-'c) {
            mul = -1
            porm = YES
            i += 1
            }
         else {
            if (lin(i) == '+'c) {
               i += 1
               porm = YES
               }
            mul = +1
            }
         call skipbl(lin, i)
         if (getnum(lin, i, pnum, status) == OK) {
            num += mul * pnum
            }
         if (status == EOF
           && porm == YES)
              status = ERR
         } until (status ~= OK)
   if (num < 0 || num > lastln) {
      status = ERR
      errcode = EORANGE
      }
   if (status == ERR)
      getone = ERR
   else if (i <= istart)
      getone = EOF
   else
      getone = OK
   status = getone
   return
   end



# getpstr --- get string from lin at i, copy to dst, bump i

### this routine is a modified version of the original 'getstr', used
### for getting the prompt string for the 'op' command.

   integer function getpstr (lin, i, dst, maxdst)
   character lin (MAXLINE), dst (maxdst)
   integer i, maxdst

   include "ed_com.r.i"

   character delim
   character esc
   integer j, k, d

   j = i
   getpstr = ERR
   errcode = EBADSTR

   delim = lin (j)

   if (delim == NEWLINE) {
      lin (j) = '/'c
      lin (j + 1) = '/'c
      lin (j + 2) = NEWLINE
      lin (j + 3) = EOS
      delim = lin (j)
      # now fall thru

      # return  # old way
      }
   else if ((delim == 'p'c || delim == 'P'c) && lin (j + 1) == NEWLINE) { # jp
      lin (j) = '/'c
      lin (j + 1) = '/'c
      lin (j + 2) = delim    # 'p' or 'P'
      lin (j + 3) = NEWLINE
      lin (j + 4) = EOS
      delim = lin (j)
      # now fall thru
      }

   if (lin (j + 1) == NEWLINE) { # treat "j/" same as "j//"
      dst (1) = EOS
      errcode = ENOERR
      return (OK)

      # return    # old way
      }

   for (k = j + 1; lin (k) ~= NEWLINE; k += 1)
      ;  # find end

   k -= 1   # k points to char before newline

   if (lin (k) == 'p'c || lin (k) == 'P'c) {
      k -= 1
      if (lin (k) == delim &&
            (lin (k-1) ~= ESCAPE || lin (k-2) == ESCAPE))
         ;  # it's ok, leave it alone
      else {
         # ESCAPE delim p NEWLINE is the join string
         # supply  missing delim
         k += 2
         lin (k) = delim
         lin (k + 1) = NEWLINE
         lin (k + 2) = EOS
         }
      }
   else if (lin (k) ~= delim           # no delim, and no p
            || (lin (k-1) == ESCAPE    # or last char is escaped delim
               && lin (k - 2) ~= ESCAPE)) {
      # simply missing trailing delimiter
      # supply it
      k += 1
      lin (k) = delim
      lin (k + 1) = NEWLINE
      lin (k + 2) = EOS
      }
   # else
      # delim is there
      # leave well enough alone

   for (k = j + 1; lin (k) ~= delim; k += 1) {  # find end
      if (lin (k) == NEWLINE || lin (k) == EOS)
         if (delim == ' 'c)
            break
         else
            return
      call esc (lin, k)
      }

   if (k - j > maxdst)  # string is too long for dst
      return

   for ({d = 1; j += 1}; j < k; {d += 1; j += 1})
      dst (d) = esc (lin, j)
   dst (d) = EOS

   i = j
   errcode = EEGARB     # the default

   return (OK)

   end



# getrange --- get  from  range for tlit command

   integer function getrange (array, k, set, size, allbut)
   character array (ARB), set (ARB)
   integer k, size, allbut

   include "ed_com.r.i"

   integer i, j
   integer addset

   errcode = EBADLIST
   i = k + 1
   if (array (i) == '~'c) {
      allbut = YES
      i += 1
      }
   else
      allbut = NO
   j = 1
   getrange = ERR
   call filset (array (k), array, i, set, j, size)
   if (array (i) ~= array (k)) {
      set (1) = EOS
      return
      }
   if (set (1) == EOS) {
      errcode = ENOLIST
      return
      }
   if (j > 1 && addset (EOS, set, j, size) == NO) {
      set (1) = EOS
      return
      }
   k = i
   getrange = OK
   errcode = EEGARB
   return
   end



# getrhs --- get substitution string for "s" command

   integer function getrhs (lin, i, sub, gflag)
   character lin (MAXLINE), sub (MAXPAT)
   integer gflag, i

   include "ed_com.r.i"

   integer maksub
   integer j

   errcode = EBADSUB
   getrhs = ERR

   if (lin (i) == EOS)  # missing the middle delimiter
      return

   if (lin (i + 1) == '&'c && (lin (i + 2) == lin (i)
                               || lin (i + 2) == NEWLINE)) {
###
### s//&/ --- should mean do the same thing as I did last time
###           even if I deleted something. So we comment out these lines.
###
#     if (Subs (1) == EOS) {
#        Errcode = ENOSUB
#        return
#        }
#
      call ctoc (subs, sub, MAXPAT)
      i += 2
      if (lin (i) == NEWLINE) {
         # fix it up for pattern macthing routines
         lin (i) = lin (i - 2)
         lin (i + 1) = 'p'c
         lin (i + 2) = NEWLINE
         lin (i + 3) = EOS
         }
      }

   else {
      if (lin (i + 1) == NEWLINE) {
         # missing the trailing delimiter
         # pattern was empty
         lin (i + 1) = lin (i)   # supply trailing delmiter
         lin (i + 2) = 'p'c
         lin (i + 3) = NEWLINE
         lin (i + 4) = EOS
         # return (ERR)    # original action
         }
      else {      # stuff in pattern, check end of line
         for (j = i; lin (j) ~= EOS; j += 1)
            ;
         j -= 2   # j now points to char before NEWLINE

         if (lin (j) == 'p'c || lin (j) == 'P'c) {
            j -= 1
            if (lin (j) == GLOBAL || lin (j) == UCGLOBAL) {
               if (j > i + 1 && lin (j - 1) == lin (i) &&
                     (lin (j - 2) ~= ESCAPE || lin (j - 3) == ESCAPE))
                  ;  # leave alone
               else {
                  # @<delim>gp@n is the pattern
                  # supply trailing delim
                  j += 2   # j now at NEWLINE
                  lin (j) = lin (i)
                  lin (j + 1) = 'p'c
                  lin (j + 2) = NEWLINE
                  lin (j + 3) = EOS
                  }
               }
            else if (j > i + 1 && lin (j) == lin (i) &&
                  (lin (j-1) ~= ESCAPE || lin (j - 2) == ESCAPE))
               ;  # leave alone
            else {
               # @<delim>p@n is the pattern
               # supply trailing delim
               j += 2
               lin (j) = lin (i)
               lin (j + 1) = 'p'c
               lin (j + 2) = NEWLINE
               lin (j + 3) = EOS
               }
            }
         else if (lin (j) == GLOBAL || lin (j) == UCGLOBAL) {
            j -= 1
            if (j > i + 1 && lin (j) == lin (i) &&
                  (lin (j - 1) ~= ESCAPE || lin (j - 2) == ESCAPE))
               ; # leave alone
            else {
               # @<delim>g@n is the pattern
               # supply trailing deliim
               j += 2   # j now at NEWLINE
               lin (j) = lin (i)
               lin (j + 1) = 'p'c
               lin (j + 2) = NEWLINE
               lin (j + 3) = EOS
               }
            }
         else if (lin (j) ~= lin (i) ||
                  (lin (j) == lin (i) && lin (j-1) == ESCAPE &&
                  lin (j-2) ~= ESCAPE)) {
            # escaped delimiter, missing final one
            # or simply missing final delimiter
            # supply it
            j += 1
            lin (j) = lin (i)
            lin (j + 1) = 'p'c
            lin (j + 2) = NEWLINE
            lin (j + 3) = EOS
            }
         # else
            # delim is there, leave well enough alone
         }

      i = maksub (lin, i + 1, lin (i), sub)
      if (i == ERR)
         return

      call ctoc (sub, subs, MAXPAT) # save pattern for later
      }

   if (lin (i + 1) == GLOBAL || lin (i + 1) == UCGLOBAL) {
      i += 1
      gflag = YES
      }
   else
      gflag = NO

   errcode = EEGARB     # the default

   return (OK)

   end



# getstr --- get string from lin at i, copy to dst, bump i

### this routine called just for join.  It used to be called for the
### op command (setting the prompt).  Instead, that one calls a new
### routine 'getpstr', which is just this routine without the stuff
### to default to blank.

   integer function getstr (lin, i, dst, maxdst)
   character lin (MAXLINE), dst (maxdst)
   integer i, maxdst

   include "ed_com.r.i"

   character delim
   character esc
   integer j, k, d

   j = i
   getstr = ERR
   errcode = EBADSTR

   delim = lin (j)

   if (delim == NEWLINE) {
      lin (j) = '/'c
      lin (j + 1) = ' 'c     # join lines with a single blank
      lin (j + 2) = '/'c
      lin (j + 3) = 'p'c
      lin (j + 4) = NEWLINE
      lin (j + 5) = EOS
      delim = lin (j)
      # now fall thru

      # return  # old way
      }
   else if ((delim == 'p'c || delim == 'P'c) && lin (j + 1) == NEWLINE) { # jp
      lin (j) = '/'c
      lin (j + 1) = ' 'c     # join lines with a single blank
      lin (j + 2) = '/'c
      lin (j + 3) = delim    # 'p' or 'P'
      lin (j + 4) = NEWLINE
      lin (j + 5) = EOS
      delim = lin (j)
      # now fall thru
      }

   if (lin (j + 1) == NEWLINE) { # treat "j/" same as "j//"
      dst (1) = EOS
      errcode = ENOERR
      return (OK)

      # return    # old way
      }

   for (k = j + 1; lin (k) ~= NEWLINE; k += 1)
      ;  # find end

   k -= 1   # k points to char before newline

   if (lin (k) == 'p'c || lin (k) == 'P'c) {
      k -= 1
      if (lin (k) == delim &&
            (lin (k-1) ~= ESCAPE || lin (k-2) == ESCAPE))
         ;  # it's ok, leave it alone
      else {
         # ESCAPE delim p NEWLINE is the join string
         # supply  missing delim
         k += 2
         lin (k) = delim
         lin (k + 1) = 'p'c
         lin (k + 2) = NEWLINE
         lin (k + 3) = EOS
         }
      }
   else if (lin (k) ~= delim           # no delim, and no p
            || (lin (k-1) == ESCAPE    # or last char is escaped delim
               && lin (k-2) ~= ESCAPE)) {
      # simply missing trailing delimiter
      # supply it
      k += 1
      lin (k) = delim
      lin (k + 1) = 'p'c
      lin (k + 2) = NEWLINE
      lin (k + 3) = EOS
      }
   # else
      # delim is there
      # leave well enough alone

   for (k = j + 1; lin (k) ~= delim; k += 1) {  # find end
      if (lin (k) == NEWLINE || lin (k) == EOS)
         if (delim == ' 'c)
            break
         else
            return
      call esc (lin, k)
      }

   if (k - j > maxdst)  # string is too long for dst
      return

   for ({d = 1; j += 1}; j < k; {d += 1; j += 1})
      dst (d) = esc (lin, j)
   dst (d) = EOS

   i = j
   errcode = EEGARB     # the default

   return (OK)

   end



# gettxt --- locate text for line, copy to txt

   integer function gettxt(line)
   integer line

   integer k
   integer getind

   k = getind(line)
   call gtxt(k)
   gettxt = k
   return
   end



# join --- join a group of lines into a single line

   integer function join(sub)
   character sub (MAXPAT)

   include "ed_com.r.i"

   character new(MAXLINE)

   integer t, line, k
   integer inject, delete, getind

   logical intrpt, brkflag

   join = ERR
   if (line1 <= 0)
      errcode = ELINE1
   else {
      t = 1
      line = line1
      k = getind(line)
      repeat {
         if (intrpt(brkflag))
            return
         call gtxt(k)
         call catlin(txt, new, t, MAXLINE)
         if (line >= line2)
            break
         call catlin(sub, new, t, MAXLINE)
         line += 1
         k = buf(k + NEXT)
         } # forever
      if (t + 2 > MAXLINE)
         errcode = E2LONG
      else {
         new(t) = NEWLINE
         new(t + 1) = EOS
         join = delete(line1, line2, join)
         if (join == OK)
            join = inject(new)
         }
      }
   return
   end



# knscan --- scan for a line with given mark name

   integer function knscan(way, num)
   integer way, num

   include "ed_com.r.i"

   integer k
   integer getind

   logical intrpt, brkflag

   num = curln
   k = getind(num)
   repeat {
      call bump(num, k, way)
      if (buf(k + NAME) == savknm) {
         knscan = OK
         return
         }
      } until (num == curln || intrpt(brkflag))
   knscan = ERR
   if (errcode == EEGARB)
      errcode = EKNOTFND
   return
   end



# log --- write a line to the safety logfile

   subroutine log(stuff)
   character stuff(ARB)

   include "ed_com.r.i"

   call putlin(stuff, safety_logfile)

   return
   end



# makset --- make set from array (k) in set

   integer function makset (array, k, set, size)
   character array (ARB), set (ARB)
   integer k, size

   include "ed_com.r.i"

   integer i, j, l
   integer addset

   makset = ERR
   errcode = EBADLIST

   # try to allow missing delimiter for translit command

   if (array (k) == EOS)
      return

   if (array (k+1) == '&'c && (array (k+2) == array (k)
                                    || array (k+2) == NEWLINE)) {
      call ctoc (tset, set, MAXPAT)
      k += 2
      if (array (k) == NEWLINE) {
         # fix it up for the rest of the routines
         array (k) = array (k-2)
         array (k+1) = 'p'c
         array (k+2) = NEWLINE
         array (k+3) = EOS
         }
      }
   else {
      for (l = k; array (l) ~= EOS; l += 1)
         ;

      l -= 2      # l now points to char before NEWLINE

      if (l == k) {  # "t/.../NEWLINE"
         array (k + 1) = array (k)  # add delimiter
         array (k + 2) = 'p'c
         array (k + 3) = NEWLINE
         array (k + 4) = EOS
         }
      else if (array (l) == 'p'c || array (l) == 'P'c) {
         l -= 1
         if (l >= k + 1 && array (l) == array (k) &&
               (array (l - 1) ~= ESCAPE || array (l - 2) == ESCAPE))
            ;  # leave alone
         else {
            # ESCAPE <delim> p NEWLINE is the set
            # supply trailing delim
            l += 2
            array (l) = array (k)
            array (l + 1) = 'p'c
            array (l + 2) = NEWLINE
            array (l + 3) = EOS
            }
         }
      else if (array (l) ~= array (k)        # no delim, and no p
               || (array (l - 1) == ESCAPE   # or last char is escaped delim
                  && array (l - 2) ~= ESCAPE)) {
         # simply missing trailing delimiter
         # supply it
         l += 1
         array (l) = array (k)
         array (l + 1) = 'p'c
         array (l + 2) = NEWLINE
         array (l + 3) = EOS
         }
      # else
         # delim is there
         # leave well enough alon

      # end inserted code to kludge trailing delimiters

      j = 1
      i = k + 1
      call filset (array (k), array, i, set, j, size)

      if (array (i) ~= array (k))
         return

      if (addset (EOS, set, j, size) == NO)
         return

      call ctoc (set, tset, MAXPAT) # save for later

      k = i
      }

   errcode = EEGARB

   return (OK)

   end



# move --- move line1 through line2 after line3

   integer function move(line3)
   integer line3

   include "ed_com.r.i"

   integer k0, k1, k2, k3, k4, k5
   integer getind, nextln, prevln

   move = ERR
   if (line1 <= 0)
      errcode = ELINE1
   else if (line1 <= line3 & line3 <= line2)
      errcode = EINSIDEOUT
   else {
      k0 = getind(prevln(line1))
      k3 = getind(nextln(line2))
      k1 = getind(line1)
      k2 = getind(line2)
      call relink(k0, k3, k0, k3)
      if (line3 > line1) {
         curln = line3
         line3 -= line2 - line1 + 1
         }
      else
         curln = line3 + (line2 - line1 + 1)
      k4 = getind(line3)
      k5 = getind(nextln(line3))
      call relink(k4, k1, k2, k5)
      call relink(k2, k5, k4, k1)
      move = OK
      updflg = YES
      }
   return
   end



# nextln --- get line after "line"

   integer function nextln(line)
   integer line

   include "ed_com.r.i"

   nextln = line + 1
   if (nextln > lastln)
      nextln = 0
   return
   end



# optpat --- make pattern if specified at lin(i)

   integer function optpat(lin, i)
   character lin(MAXLINE)
   integer i

   include "ed_com.r.i"

   integer makpat

   if (lin(i) == EOS || lin (i + 1) == EOS)
      i = ERR
   else if (lin(i + 1) == lin(i))   # repeated delimiter
      i += 1            # leave existing pattern alone
   else
      i = makpat(lin, i + 1, lin(i), pat)
   if (pat(1) == EOS) {
      optpat = ERR
      errcode = ENOPAT
      }
   else if (i == ERR) {
      pat(1) = EOS
      optpat = ERR
      errcode = EBADPAT
      }
   else
      optpat = OK
   return
   end



# prevln --- get line before "line"

   integer function prevln(line)
   integer line

   include "ed_com.r.i"

   prevln = line - 1
   if (prevln < 0)
      prevln = lastln
   return
   end



# printverboseerrormessage --- print verbose error message

   subroutine printverboseerrormessage

   include "ed_com.r.i"

   select (saverrcode)
   when (EBACKWARD)
      call remark("Line numbers in backward order"p)
   when (ECANTINJECT)
      call remark("Can't inject new line!"p)
   when (EBADPAT)
      call remark("Bad syntax in pattern"p)
   when (EBADSTR)
      call remark("Bad syntax in string parameter"p)
   when (EBADSUB)
      call remark("Bad syntax in substitution string"p)
   when (ECANTREAD)
      call remark("Can't open file to read"p)
   when (ECANTWRITE)
      call remark("Can't open file to write"p)
   when (EEGARB)
      call remark("There seems to be garbage after your command"p)
   when (EFILEN)
      call remark("Bad syntax in file name"p)
   when (EGLOBA)
      call remark("You can't append in a global operation"p)
   when (EINSIDEOUT)
      call remark("I'm sure you don't want to move a group into itself"p)
   when (EKNOTFND)
      call remark("I can't find a line with that mark name"p)
   when (ELINE1)
      call remark("At end or beginning"p)
   when (E2LONG)
      call remark("Resulting line too long to handle"p)
   when (ENOMATCH)
      call remark("No match for pattern"p)
   when (ENOERR)
      call remark("No error to report"p)
   when (ENOLIMBO)
      call remark("No lines have been deleted since last undelete"p)
   when (EODLSSGTR)
      call remark("Expected '<', '>', or nothing after 'od'"p)
   when (EORANGE)
      call remark("Line number out of range (< 0 or > $)"p)
   when (EOWHAT)
      call remark("Can't recognize option after 'o'"p)
   when (EPNOTFND)
      call remark("No line matching that pattern could be found"p)
   when (ESTUPID)
      call remark("Changes have been made since last 'w' command"p)
   when (EWHATZAT)
      call remark("No command recognized"p)
   when (ELINE2)
      call remark("The last in your list of line numbers is > $"p)
   when (EBREAK)
      call remark("You interrupted me"p)
   when (ENOPAT)
      call remark("No saved pattern -- sorry"p)
   when (ENOLIST)
      call remark ("No saved character list -- sorry"p)
   when (ENOFN)
      call remark("No saved filename"p)
   when (EBADLIST)
      call remark("Bad syntax in character list"p)
   when (ENOSUB)
      call remark("No saved replacement --- sorry"p)
   when (ENOSHELL)
      call remark ("Shell returned ERR"p)
   when (ENOCMD)
      call remark ("No saved shell command -- sorry"p)
   else
      call remark("In printverboseerrormessage: can't happen"p)
   saverrcode = ENOERR
   return
   end



# prntkn --- print mark names of lines from through to

   integer function prntkn(from, to)
   integer from, to

   include "ed_com.r.i"

   integer i, j
   integer getind

   logical intrpt, brkflag

   if (from <= 0) {
      prntkn = ERR
      errcode = ELINE1
      }
   else {
      for (i = from; i <= to; i += 1) {
         if (intrpt(brkflag)) {
            prntkn = ERR
            return
            }
         j = getind(i)
         call putch(buf(j + NAME), Fdout)
         call putch(NEWLINE, Fdout)
         }
      curln = to
      prntkn = OK
      }
   return
   end



# ptscan --- scan for next occurrence of pattern

   integer function ptscan(way, num)
   integer way, num

   include "ed_com.r.i"

   integer k
   integer match, getind

   logical intrpt, brkflag

   num = curln
   k = getind(num)
   repeat {
      call bump(num, k, way)
      call gtxt(k)
      if (match(txt, pat) == YES) {
         ptscan = OK
         return
         }
      } until (num == curln || intrpt(brkflag))
   ptscan = ERR
   if (errcode == EEGARB)
      errcode = EPNOTFND
   return
   end



# relink --- rewrite two half links

   subroutine relink(a, x, y, b)
   integer a, b, x, y

   include "ed_com.r.i"

   buf(x + PREV) = a
   buf(y + NEXT) = b
   return
   end



# setlog --- initiate or terminate safety logfile

   subroutine setlog(action)
   integer action

   include "ed_com.r.i"

   integer junk
   integer create, remove

   string filename "=temp=/scriptxxxx"

   if (action == MAKE_LOG_FILE) {
      call date(SYS_PIDSTR, filename(14))
      safety_logfile = create(filename, WRITE)
      if (safety_logfile == ERR)
         call error("Cannot create safety logfile"p)
      if (savfil(1) ~= EOS) { # Log an 'e' command on the file
         call putch(ENTER, safety_logfile)
         call putch(' 'c, safety_logfile)
         call putlin(savfil, safety_logfile)
         call putch(NEWLINE, safety_logfile)
         }
      }
    else  {   # action is UNMAKE_LOG_FILE
      call close(safety_logfile)
      junk = remove(filename)
      }
   return
   end



# skipbl --- skip blanks and tabs at lin(i)...

   subroutine skipbl(lin, i)
   character lin(ARB)
   integer i

   while (lin(i) == ' 'c || lin(i) == TAB)
      i += 1
   return
   end



# subst --- substitute "sub" for occurrences of pattern

   integer function subst(sub, gflag, glob)
   character sub (MAXPAT)
   integer gflag, glob

   include "ed_com.r.i"

   character new(MAXLINE)

   integer j, junk, k, lastm, line, m, status, subbed, inx,
      kname, tagbeg (10), tagend (10)
   integer addset, amatch, gettxt, inject, getind

   logical intrpt, brkflag

   if (globals == YES && glob == YES)
      subst = OK
   else
      subst = ERR

   if (line1 <= 0) {
      errcode = ELINE1
      return
      }
   for (line = line1; line <= line2; line += 1) {
      if (intrpt(brkflag)) {
         subst = ERR
         return
         }
      j = 1
      subbed = NO
      inx = gettxt(line)
      lastm = 0
      for (k = 1; txt(k) ~= EOS; ) {
         do m = 2, 10; {
            tagbeg (m) = 0
            tagend (m) = 0
            }
         if (gflag == YES || subbed == NO)
            m = amatch(txt, k, pat, tagbeg (2), tagend (2))
         else
            m = 0
         if (m > 0 && lastm ~= m) {   # replace matched text
            tagbeg (1) = k
            tagend (1) = m
            subbed = YES
            call catsub(txt, tagbeg, tagend, sub, new, j, MAXLINE)
            lastm = m
            }
         if (m == 0 || m == k) {   # no match or null match
            junk = addset(txt(k), new, j, MAXLINE)
            k += 1
            }
         else            # skip matched text
            k = m
         }
      if (subbed == YES) {
         if (addset(EOS, new, j, MAXLINE) == NO) {
            subst = ERR
            errcode = E2LONG
            break
            }
         kname = buf (inx + NAME)
         call delete(line, line, status)   # remembers dot
         subst = inject(new)
         if (subst == ERR)
            break
         inx = getind(curln)
         buf(inx + NAME) = kname
         subst = OK
         updflg = YES # not needed as delete and inject both set it
         }
      else  # subbed equals NO
         errcode = ENOMATCH
      }
   return
   end



# uniquely_name --- mark-name line; make sure no other line named same

   subroutine uniquely_name(kname, status)
   integer kname, status

   include "ed_com.r.i"

   integer k, line
   integer defalt

   if (defalt(curln, curln, status) ~= OK)
      return
   if (line2 <= 0) {
      status = ERR
      errcode = ELINE1
      return
      }
   status = OK
   line = 0
   k = line0
   repeat {
      line += 1
      k = buf(k + NEXT)
      if (line == line2)
         buf(k + NAME) = kname
      else if (buf(k + NAME) == kname)
         buf(k + NAME) = DEFAULTNAME
      } until (line >= lastln)
   return
   end



# xindex --- invert condition returned by index

   integer function xindex (array, c, allbut, lastto)
   character array (ARB), c
   integer allbut, lastto

   integer index

   if (c == EOS)
      xindex = 0
   else if (allbut == NO)
      xindex = index (array, c)
   else if (index (array, c) > 0)
      xindex = 0
   else
      xindex = lastto + 1
   return
   end



###########################################################

# File primitives for ed - the Georgia Tech version of edit
#
#   note: gettxt is no longer considered a file primitive, and it
#      has been moved up to the editor proper.  Gettxt is now written
#      in terms of the new primitive gtxt, which uses an index, rather
#      than a line number.
#
#   This section includes gtxt, inject, and all the routines below them
#      in the calling hierarchy.

# definitions used only in this section:
include PRIMOS_KEYS     # for KNDAM, KPOSN, KPREA, KREAD, KWRIT
define(WRITTEN,2)
define(WORD,2)
define(RECNO,0)
define(RECLENG,880)
define(REC,1)
define(POOP,3)
define(NODESIZE,(RECLENG + 3))
define(MAXPRI,16000)
define(FENCEMARGIN,1000) # Must be several RECLENG's less than MAXBUF
define(BOGUSRECNO,-2)
# There are other definitions used only in this section,
# but they are of
# fields of line pointer nodes, and those have been kept together.



# gtxt --- (scratch file) locate text for index k, copy to txt

   subroutine gtxt(k)
   integer k

   include "ed_com.r.i"

   integer j

   call seekv(buf(k + SEEKADR))
   call readv(txt, buf(k + LENG))
   j = buf(k + LENG) + 1
   if (j > 1)
      txt(j - 1) = NEWLINE
   txt(j) = EOS
   return
   end



# inject --- (scratch file) insert lin after curln, write scratch

   integer function inject(lin)
   character lin(MAXLINE)

   include "ed_com.r.i"

   integer i, k1, k2, k3
   integer getind, maklin, nextln

   for (i = 1; lin(i) ~= EOS; ) {
      i = maklin(lin, i, k3)
      if (i == ERR) {
         inject = ERR
         errcode = ECANTINJECT
         break
         }
      k1 = getind(curln)
      k2 = getind(nextln(curln))
      call relink(k1, k3, k3, k2)
      call relink(k3, k2, k1, k3)
      curln += 1
      lastln += 1
      inject = OK
      }
   return
   end



# readf --- read raw text from scratch file

   subroutine readf(buffer, count, fd)
   integer buffer(ARB), count, fd

   integer junk, code
   integer mapfd

   call prwf$$ (KREAD, mapfd (fd), loc (buffer), count, intl (0),
      junk, code)
   if (code == 0)
      return
   call errpr$ (0, code, "fatal scratch file error", 24, "readf", 5)
   end



# writef --- write raw text onto scratch file

   subroutine writef(buffer, count, fd)
   integer buffer(ARB), count, fd

   integer junk, code
   integer mapfd

   call prwf$$ (KWRIT, mapfd (fd), loc (buffer), count, intl (0),
      junk, code)
   if (code == 0)
      return

   call errpr$ (0, code, "fatal scratch file error", 24, "writef", 6)
   end



# seek --- position file to offset

   subroutine seek(offset, fd)
   integer offset(2), fd

   include "ed_com.r.i"

   integer junk, code
   integer mapfd

   longint pos

   pos = intl (offset (1)) * intl (RECLENG) + intl (offset (2))
   call prwf$$ (KPOSN + KPREA, mapfd (fd), loc (0), 0, pos, junk, code)
   if (code == 0)
      return
   call errpr$ (0, code, "fatal scratch file error", 24, "seek", 4)
   end



# maklin --- (scratch file) make new line entry, copy text to scratch

   integer function maklin(lin, i, newind)
   character lin(MAXLINE)
   integer i, newind

   include "ed_com.r.i"

   integer j, k, junk, txtend
   integer addset, length, mkroom

   maklin = ERR
   if (free == NOMORE) {
      newind = lastbf
      while (lastbf + BUFENT > fence)
         if (mkroom(junk) == ERR)
            return # no room for new line entry
      lastbf = lastbf + BUFENT
      }
   else {
      newind = free
      free = buf(free + PREV)
      }
   txtend = 1
   for (j = i; lin(j) ~= EOS; ) {
      junk = addset(lin(j), txt, txtend, MAXLINE)
      j += 1
      if (lin(j - 1) == NEWLINE)
         break
      }
   if (addset(EOS, txt, txtend, MAXLINE) == NO)
      return
   call seekv(scrend)       # add line to end of virtual scratch file
   buf(newind + SEEKREC) = scrend(REC)
   buf(newind + SEEKWORD) = scrend(WORD)
   k = length(txt)
   buf(newind + LENG) = k
   call writev(txt, k)
   scrend(WORD) += k
   while (scrend(WORD) >= RECLENG) {
      scrend(WORD) -= RECLENG
      scrend(REC)  += 1
      }
   buf(newind + MARK) = NO
   buf(newind + NAME) = DEFAULTNAME
   updflg = YES
   maklin = j         # next character to be examined in lin
   return
   end



# setbuf --- create virtual scratch file, set up line 0

   subroutine setbuf

   include "ed_com.r.i"

   integer i, k, junk
   integer create, maklin

   string null ""
   string stemp "=temp=/edxxxx"

   call scopy(stemp, 1, scrfil, 1)
   call date(SYS_PIDSTR, scrfil(10))
   scr = create (scrfil, READWRITE + KNDAM)
   if (scr == ERR)
      call error("Can't open scratch file"p)
   scrend(REC) = 0
   scrend(WORD) = 0
   truend = 0
   for (i = MAXBUF + 1 - NODESIZE; i > FENCEMARGIN; i -= NODESIZE) {
      buf(i + RECNO) = BOGUSRECNO
      buf(i + WRITTEN) = YES
      fence = i
      }
   curbuf = fence
   robin = fence              # Arbitrary.
   line0 = 1 # to stay that way
   lastbf = line0
   free = NOMORE                 # make empty free list
   limbo = NOMORE
   limcnt = 0
   junk = maklin(null, 1, k)   # create empty line 0
   call relink(k, k, k, k)   # establish initial linked list
   buf(k + NAME) = EOS       # prevent mark name matches with line 0
   curln = 0              # .
   lastln = 0             # $
   return
   end



# clrbuf --- dispose of scratch file

   subroutine clrbuf

   include "ed_com.r.i"

   call close(scr)
   call remove(scrfil)
   return
   end



# idle --- do something useful while user ponders next move

   subroutine idle
   return
   end



# seekv --- seek in virtual scratch file

   subroutine seekv(addr)
   integer addr(2)

   include "ed_com.r.i"

   vaddr(REC) = addr(REC)
   vaddr(WORD) = addr(WORD)
   return
   end



# mkroom --- increase size of pointer buffer at expense of file buffer

   integer function mkroom(status)
   integer status

   include "ed_com.r.i"

   integer b

   if (tune > 0)
      call remark("(mkroom)"p)
   b = fence
   if (fence + NODESIZE > MAXBUF)
      status = ERR                   # no more room
   else {
      if (curbuf == fence)
         curbuf = MAXBUF + 1 - NODESIZE # arbitrary
      if (buf(fence + RECNO) <= truend && buf(fence + WRITTEN) == NO)
         call wout(fence)
      fence += NODESIZE
      if (buf(b + WRITTEN) == NO) {
         # This will occour iff buf(fence + RECNO) > truend.
         vaddr(WORD) = 0
         vaddr(REC) = buf(b + RECNO)
         call writev(buf(b + POOP), RECLENG)
         if (tune > 0)
            call remark("(shuffle)"p)
         }
      status = OK
      }
   mkroom = status
   return
   end



# wout --- write out buffer b to file, set WRITTEN

   subroutine wout(b)
   integer b

   include "ed_com.r.i"

   integer ix, addr(2)

   addr(REC) = buf(b + RECNO)
   addr(WORD) = 0
   call seek(addr, scr)
   ix = b + POOP
   call writef(buf(ix), RECLENG, scr)
T  call debug(b, "w"p)
   if (addr(REC) == truend)
      truend = addr(REC) + 1
   else if (addr(REC) > truend)
      call error("in wout: can't happen"p)
   # else leave truend alone
   buf(b + WRITTEN) = YES
   return
   end



# writev --- write virtual scratch file

   subroutine writev(ubuf, nwords)
   integer ubuf(ARB), nwords

   include "ed_com.r.i"

   integer p, t, tgt

   call findbf(tgt)
   for (p = 1; p <= nwords; p += 1) {
      t = vaddr(WORD) + tgt
      buf(t) = ubuf(p)
      vaddr(WORD) += 1
      if (vaddr(WORD) >= RECLENG) {
         buf(curbuf + WRITTEN) = NO
         vaddr(WORD) = 0
         vaddr(REC) += 1
         call findbf(tgt)
         }
      }
   buf(curbuf + WRITTEN) = NO
   return
   end



# readv --- read virtual scratch file

   subroutine readv(ubuf, nwords)
   integer ubuf(ARB), nwords

   include "ed_com.r.i"

   integer p, t, tgt

   call findbf(tgt)
   for (p = 1; p <= nwords; p += 1) {
      t = vaddr(WORD) + tgt
      ubuf(p) = buf(t)
      vaddr(WORD) += 1
      if (vaddr(WORD) >= RECLENG) {
         vaddr(WORD) = 0
         vaddr(REC) += 1
         call findbf(tgt)
         }
      }
   return
   end



# findbf --- "find" core buffer associated with vaddr(REC)
#          store its location in tgt

   subroutine findbf(tgt)
   integer tgt

   include "ed_com.r.i"

   integer b, addr(2), a, lasta

   data lasta/0/   # data statement forces static storage

   b = curbuf
   a = vaddr(REC)  # and stays that way
   if (buf(b + RECNO) == a && b >= fence) {
      tgt = b + POOP
      return
      }
   for (b = fence; b < MAXBUF; b += NODESIZE)
      if (buf(b + RECNO) == a) {
T        if (tune > 2)
T           call debug(b, "in mem"p)
         break
         }
   if (b > MAXBUF) { # search failed, is not in primary memory
      call decide(b)
      if (buf(b + RECNO) > a && a > lasta
        || buf(b + RECNO) < a && a < lasta)
         call decide(b)    # Just fishing for a better candidate
      lasta = a
T     if (tune >= 4)
T         call debug(b, "axed"p)
      if (buf(b + WRITTEN) == NO)
         call wout(b)
      buf(b + RECNO) = a
      if (buf(b + RECNO) < truend) { # needs to be read
         addr(REC) = buf(b + RECNO)
         addr(WORD) = 0
         call seek(addr, scr)
         call readf(buf(b + POOP), RECLENG, scr)
T        call debug(b, "r"p)
         }
T     else if (tune > 2)
T        call debug(b, "alloc"p)
      }
   tgt = b + POOP
   curbuf = b
   return
   end



# decide --- determine buffer to roll out; store its index in 'b'

   subroutine decide(b)
   integer b

   include "ed_com.r.i"

   repeat
      if (robin >= MAXBUF + 1 - NODESIZE)
         robin = fence
      else
         robin = robin + NODESIZE
      until (buf(robin + RECNO) <= truend ||
         buf(robin + WRITTEN) == YES)
   b = robin
   return
   end



# debug --- output debugging information about a buffer node

T  subroutine debug(node, message)
T  integer node, message(ARB)

T  include "ed_com.r.i"

T  if (tune < 2)
T     return
T  call putdec(node, 5, ERROUT)
T  call putdec(buf(node + RECNO), 4, ERROUT)
T  call putch(' 'c, ERROUT)
T  call remark(message)
T  return
T  end
# tune >= 0        no tuning output
# tune >= 1        (mkroom), (shuffle), etc.
# tune >= 2        scratch I/O
# tune >= 3        in memory
# tune >= 4        axings (de-allocating)



# intrpt --- see if there has been an interrupt from terminal

   logical function intrpt(arg)
   logical arg

   include "ed_com.r.i"

   logical tquit$

   intrpt = tquit$ (arg)
   if (intrpt) {
      errcode = EBREAK
      call wind(Fdin)
      }
   return
   end
