#  ========== translit program from chapter 2 ==========
define(MAXARR,100)
define(MAXSET,100)
define(ESCAPE,ATSIGN)
define(DASH,MINUS)
define(NOT,BANG)
# addset - put  c  in  set(j)  if it fits,  increment  j
   integer function addset(c, set, j, maxsiz)
   integer j, maxsiz
   character c, set(maxsiz)

   if (j > maxsiz)
      addset = NO
   else {
      set(j) = c
      j = j + 1
      addset = YES
      }
   return
   end
# dodash - expand array(i-1)-array(i+1) into set(j)... from valid
   subroutine dodash(valid, array, i, set, j, maxset)
   character esc
   integer addset, index
   integer i, j, junk, k, limit, maxset
   character array(ARB), set(maxset), valid(ARB)

   i = i + 1
   j = j - 1
   limit = index(valid, esc(array, i))
   for (k = index(valid, set(j)); k <= limit; k = k + 1)
      junk = addset(valid(k), set, j, maxset)
   return
   end
# esc - map  array(i)  into escaped character if appropriate
   character function esc(array, i)
   character array(ARB)
   integer i

   if (array(i) ^= ESCAPE)
      esc = array(i)
   else if (array(i+1) == EOS)   # \*a not special at end
      esc = ESCAPE
   else {
      i = i + 1
      if (array(i) == LETN)
         esc = NEWLINE
      else if (array(i) == LETT)
         esc = TAB
      else
         esc = array(i)
      }
   return
   end
# filset - expand set at  array(i)  into  set(j),  stop at  delim
   subroutine filset(delim, array, i, set, j, maxset)
   character esc
   integer addset, index
   integer i, j, junk, maxset
   character array(ARB), delim, set(maxset)
#   string digits "0123456789"
   integer digits(11)
#   string lowalf "abcdefghijklmnopqrstuvwxyz"
   integer lowalf(27)
#   string upalf "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   integer upalf(27)
   data digits(1)/DIG0/, digits(2)/DIG1/, digits(3)/DIG2/
   data digits(4)/DIG3/, digits(5)/DIG4/, digits(6)/DIG5/
   data digits(7)/DIG6/, digits(8)/DIG7/, digits(9)/DIG8/
   data digits(10)/DIG9/, digits(11)/EOS/
   data lowalf(01)/LETA/
   data lowalf(02)/LETB/
   data lowalf(03)/LETC/
   data lowalf(04)/LETD/
   data lowalf(05)/LETE/
   data lowalf(06)/LETF/
   data lowalf(07)/LETG/
   data lowalf(08)/LETH/
   data lowalf(09)/LETI/
   data lowalf(10)/LETJ/
   data lowalf(11)/LETK/
   data lowalf(12)/LETL/
   data lowalf(13)/LETM/
   data lowalf(14)/LETN/
   data lowalf(15)/LETO/
   data lowalf(16)/LETP/
   data lowalf(17)/LETQ/
   data lowalf(18)/LETR/
   data lowalf(19)/LETS/
   data lowalf(20)/LETT/
   data lowalf(21)/LETU/
   data lowalf(22)/LETV/
   data lowalf(23)/LETW/
   data lowalf(24)/LETX/
   data lowalf(25)/LETY/
   data lowalf(26)/LETZ/
   data lowalf(27)/EOS/
   data upalf(01) /BIGA/
   data upalf(02) /BIGB/
   data upalf(03) /BIGC/
   data upalf(04) /BIGD/
   data upalf(05) /BIGE/
   data upalf(06) /BIGF/
   data upalf(07) /BIGG/
   data upalf(08) /BIGH/
   data upalf(09) /BIGI/
   data upalf(10) /BIGJ/
   data upalf(11) /BIGK/
   data upalf(12) /BIGL/
   data upalf(13) /BIGM/
   data upalf(14) /BIGN/
   data upalf(15) /BIGO/
   data upalf(16) /BIGP/
   data upalf(17) /BIGQ/
   data upalf(18) /BIGR/
   data upalf(19) /BIGS/
   data upalf(20) /BIGT/
   data upalf(21) /BIGU/
   data upalf(22) /BIGV/
   data upalf(23) /BIGW/
   data upalf(24) /BIGX/
   data upalf(25) /BIGY/
   data upalf(26) /BIGZ/
   data upalf(27) /EOS/

   for ( ; array(i) ^= delim & array(i) ^= EOS; i = i + 1)
      if (array(i) == ESCAPE)
         junk = addset(esc(array, i), set, j, maxset)
      else if (array(i) ^= DASH)
         junk = addset(array(i), set, j, maxset)
      else if (j <= 1 ! array(i+1) == EOS)   # literal -
         junk = addset(DASH, set, j, maxset)
      else if (index(digits, set(j-1)) > 0)
         call dodash(digits, array, i, set, j, maxset)
      else if (index(lowalf, set(j-1)) > 0)
         call dodash(lowalf, array, i, set, j, maxset)
      else if (index(upalf, set(j-1)) > 0)
         call dodash(upalf, array, i, set, j, maxset)
      else
         junk = addset(DASH, set, j, maxset)
   return
   end
# makset - make set from  array(k)  in  set
   integer function makset(array, k, set, size)
   integer addset
   integer i, j, k, size
   character array(ARB), set(size)

   i = k
   j = 1
   call filset(EOS, array, i, set, j, size)
   makset = addset(EOS, set, j, size)
   return
   end
# translit - map characters
   character getc
   character arg(MAXARR), c, from(MAXSET), to(MAXSET)
   integer getarg, length, makset, xindex
   integer allbut, collap, i, lastto

   if (getarg(1, arg, MAXARR) == EOF)
      call error("usage: translit from to.")
   else if (arg(1) == NOT) {
      allbut = YES
      if (makset(arg, 2, from, MAXSET) == NO)
         call error("from: too large.")
      }
   else {
      allbut = NO
      if (makset(arg, 1, from, MAXSET) == NO)
         call error("from: too large.")
      }
   if (getarg(2, arg, MAXARR) == EOF)
      to(1) = EOS
   else if (makset(arg, 1, to, MAXSET) == NO)
         call error("to: too large.")

   lastto = length(to)
   if (length(from) > lastto ! allbut == YES)
      collap = YES
   else
      collap = NO
   repeat {
      i = xindex(from, getc(c), allbut, lastto)
      if (collap == YES & i >= lastto & lastto > 0) {  # collapse
         call putc(to(lastto))
         repeat
            i = xindex(from, getc(c), allbut, lastto)
            until (i < lastto)
         }
      if (c == EOF)
         break
      if (i > 0 & lastto > 0)   # translate
         call putc(to(i))
      else if (i == 0)      # copy
         call putc(c)
                  # else delete
      }
   stop
   end
# xindex - invert condition returned by index
   integer function xindex(array, c, allbut, lastto)
   character array(ARB), c
   integer index
   integer allbut, lastto

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