========== change program from chapter 5 ==========
define(MAXPAT,128)
define(MAXARG,128)
define(ESCAPE,ATSIGN)
define(DITTO,(-3))
# catsub - add replacement text to end of  new
   subroutine catsub(lin, from, to, sub, new, k, maxnew)
   integer addset
   integer from, i, j, junk, k, maxnew, to
   character lin(MAXLINE), new(maxnew), sub(MAXPAT)
   for (i = 1; sub(i) ~= EOS; i = i + 1)
      if (sub(i) == DITTO)
         for (j = from; j < to; j = j + 1)
            junk = addset(lin(j), new, k, maxnew)
      else
         junk = addset(sub(i), new, k, maxnew)
   return
   end
# change - change  "from"  into  "to"
   character lin(MAXLINE), new(MAXLINE), pat(MAXPAT), sub(MAXPAT)
   character arg(MAXARG)
   integer addset, amatch, getarg, getlin, getpat, getsub
   integer i, junk, k, lastm, m
   if (getarg(1, arg, MAXARG) == EOF)
      call error("usage: change from to.")
   if (getpat(arg, pat) == ERR)
      call error("illegal from pattern.")
   if (getarg(2, arg, MAXARG) == EOF)
      arg(1) = EOS
   if (getsub(arg, sub) == ERR)
      call error("illegal to.")
   while (getlin(lin, STDIN) ~= EOF) {
      k = 1
      lastm = 0
      for ( i =1; lin(i) ~= EOS; ) {
         m = amatch(lin, i, pat)
         if (m > 0 & lastm ~= m) {   # replace matched text
            call catsub(lin, i, m, sub, new, k, MAXLINE)
            lastm = m
            $@$
         if (m == 0 | m == i) {   # no match or null match
            junk = addset(lin(i), new, k, MAXLINE)
            i = i + 1
            $@$
         else            # skip matched text
            i = m
         $@$
      if (addset(EOS, new, k, MAXLINE) == NO) {
         k = MAXLINE
         junk = addset(EOS, new, k, MAXLINE)
         call remark("line truncated:.")
         call putlin(new, ERROUT)
         call putch(NEWLINE, ERROUT)
         $@$
      call putlin(new, STDOUT)
      $@$
   stop
   end
# getsub - get substitution pattern into sub
   integer function getsub(arg, sub)
   character arg(MAXARG), sub(MAXPAT)
   integer maksub
   getsub = maksub(arg, 1, EOS, sub)
   return
   end
# maksub - make substitution string in sub
   integer function maksub(arg, from, delim, sub)
   character esc
   character arg(MAXARG), delim, sub(MAXPAT)
   integer addset
   integer from, i, j, junk
   j = 1
   for (i = from; arg(i) ~= delim & arg(i) ~= EOS; i = i + 1)
      if (arg(i) == AND)
         junk = addset(DITTO, sub, j, MAXPAT)
      else
         junk = addset(esc(arg, i), sub, j, MAXPAT)
   if (arg(i) ~= delim)   # missing delimiter
      maksub = ERR
   else if (addset(EOS, sub, j, MAXPAT) == NO)   # no room
      maksub = ERR
   else
      maksub = i
   return
   end
