========== smaller programs from chapter 3 ==========
define(INFILE1,1)
define(INFILE2,2)
define(NAMESIZE,50)
# compare  (simple version) - compare file 1 to file 2
   character line1(MAXLINE), line2(MAXLINE)
   integer equal, getlin
   integer lineno, m1, m2
   lineno = 0
   repeat {
      m1 = getlin(line1, INFILE1)
      m2 = getlin(line2, INFILE2)
      if (m1 == EOF | m2 == EOF)
         break
      lineno = lineno + 1
      if (equal(line1, line2) == NO)
         call difmsg(lineno, line1, line2)
      $@$
   if (m1 == EOF & m2 ~= EOF)
      call remark("eof on file 1.")
   else if (m2 == EOF & m1 ~= EOF)
      call remark("eof on file 2.")
   # else they match
   stop
   end
# difmsg - print line numbers and differing lines
   subroutine difmsg(lineno, line1, line2)
   character line1(ARB), line2(ARB)
   integer lineno
   call putdec(lineno, 5)
   call putc(NEWLINE)
   call putlin(line1, STDOUT)
   call putlin(line2, STDOUT)
   return
   end
define(NAMESIZE,50)
# compare - compare two files for equality
   character arg1(MAXLINE), arg2(MAXLINE)
   character line1(MAXLINE), line2(MAXLINE)
   integer equal, getarg, getlin, open
   integer infil1, infil2, lineno, m1, m2
   if (getarg(1, arg1, MAXLINE) == EOF
      | getarg(2, arg2, MAXLINE) == EOF)
      call error("usage: compare file1 file2.")
   infil1 = open(arg1, READ)
   if (infil1 == ERR)
      call cant(arg1)
   infil2 = open(arg2, READ)
   if (infil2 == ERR)
      call cant(arg2)
   lineno = 0
   repeat {
      m1 = getlin(line1, infil1)
      m2 = getlin(line2, infil2)
      if (m1 == EOF | m2 == EOF)
         break
      lineno = lineno + 1
      if (equal(line1, line2) == NO)
         call difmsg(lineno, line1, line2)
      $@$
   if (m1 == EOF & m2 ~= EOF)
      call remark("eof on file 1.")
   else if (m2 == EOF & m1 ~= EOF)
      call remark("eof on file 2.")
   stop
   end
#difmsg
   subroutine difmsg(lineno, line1, line2)
   integer line1(MAXLINE), line2(MAXLINE)
   integer lineno
   call putdec(lineno, 5)
   call putc(NEWLINE)
   call putlin(line1, STDOUT)
   call putlin(line2, STDOUT)
   return
   end
define(NFILES,5)
# include - replace  include file  by contents of file
   character line(MAXLINE), str(MAXLINE)
   integer equal, getlin, getwrd, open
   integer infile(NFILES), len, level, loc
#   string incl "include"
   integer incl(8)
   data incl(1) /LETI/
   data incl(2) /LETN/
   data incl(3) /LETC/
   data incl(4) /LETL/
   data incl(5) /LETU/
   data incl(6) /LETD/
   data incl(7) /LETE/
   data incl(8) /EOS/
   infile(1) = STDIN
   for (level = 1; level > 0; level = level - 1) {
      while (getlin(line, infile(level)) ~= EOF) {
         loc = 1
         len = getwrd(line, loc, str)
         if (equal(str, incl) == NO)
            call putlin(line, STDOUT)
         else {
            level = level + 1
            if (level > NFILES)
               call error("includes nested too deeply.")
            len = getwrd(line, loc, str)
            infile(level) = open(str, READ)
            if (infile(level) == ERR)
               call cant(str)
            $@$
         $@$
      if (level > 1)
         call close(infile(level))
      $@$
   stop
   end
# getwrd - get non-blank word from in(i) into  out, increment i
   integer function getwrd(in, i, out)
   character in(ARB), out(ARB)
   integer i, j
   while (in(i) == BLANK | in(i) == TAB)
      i = i + 1
   j = 1
   while (in(i) ~= EOS & in(i) ~= BLANK
      & in(i) ~= TAB & in(i) ~= NEWLINE) {
      out(j) = in(i)
      i = i + 1
      j = j + 1
      $@$
   out(j) = EOS
   getwrd = j - 1
   return
   end
define(NAMESIZE,50)
# concat - concatenate named files onto standard output
   character name(NAMESIZE)
   integer getarg, open
   integer fin, i
   for (i = 1; getarg(i, name, NAMESIZE) ~= EOF; i = i + 1) {
      fin = open(name, READ)
      if (fin == ERR)
         call cant(name)
      call fcopy(fin, STDOUT)
      call close(fin)
      $@$
   stop
   end
define(NAMESIZE,50)
define(MARGIN1,3)
define(MARGIN2,2)
define(MARGIN3,2)
define(MARGIN4,3)
define(BOTTOM,60)
define(PAGELEN,66)
# print - print files with headings
   character name(NAMESIZE)
   integer getarg, open
   integer fin, i
   for (i = 1; getarg(i, name, NAMESIZE) ~= EOF; i = i + 1) {
      fin = open(name, READ)
      if (fin == ERR)
         call cant(name)
      call fprint(name, fin)
      call close(fin)
      $@$
   stop
   end
# fprint - print file "name" from  fin
   subroutine fprint(name, fin)
   character line(MAXLINE), name(NAMESIZE)
   integer getlin, open
   integer fin, lineno, pageno
   pageno = 0
   lineno = 0
   while (getlin(line, fin) ~= EOF) {
      if (lineno == 0) {
         call skip(MARGIN1)
         pageno = pageno + 1
         call head(name, pageno)
         call skip(MARGIN2)
         lineno = MARGIN1 + MARGIN2 + 1
         $@$
      call putlin(line, STDOUT)
      lineno = lineno + 1
      if (lineno >= BOTTOM) {
         call skip(PAGELEN-lineno)
         lineno = 0
         $@$
      $@$
   if (lineno > 0)
      call skip(PAGELEN-lineno)
   return
   end
# skip - output  n  blank lines
   subroutine skip(n)
   integer i, n
   for (i = 1; i <= n; i = i + 1)
      call putc(NEWLINE)
   return
   end
# head - print top of page header
   subroutine head(name, pageno)
   character name(NAMESIZE)
   integer pageno
#   string page " Page  "
   integer page(7)
   data page(1) /BLANK/
   data page(2) /LETP/
   data page(3) /LETA/
   data page(4) /LETG/
   data page(5) /LETE/
   data page(6) /BLANK/
   data page(7) /EOS/
   call putlin(name, STDOUT)
   call putlin(page, STDOUT)
   call putdec(pageno, 1)
   call putc(NEWLINE)
   return
   end
define(NAMESIZE,50)
define(MARGIN1,3)
define(MARGIN2,2)
define(MARGIN3,2)
define(MARGIN4,3)
define(BOTTOM,60)
define(PAGELEN,66)
# print  (default input STDIN) - print files with headings
   character name(NAMESIZE)
   integer getarg, open
   integer fin, i
#   string null ""
   integer null(1)
   data null(1) /EOS/
   for (i = 1; getarg(i, name, NAMESIZE) ~= EOF; i = i + 1) {
      fin = open(name, READ)
      if (fin == ERR)
         call cant(name)
      call fprint(name, fin)
      call close(fin)
      $@$
   if (i == 1)      # no files specified
      call fprint(null, STDIN)
   stop
   end
# fprint - print file "name" from  fin
   subroutine fprint(name, fin)
   integer line(MAXLINE), name(NAMESIZE)
   integer getlin, open
   integer fin, lineno, pageno
   pageno = 0
   lineno = 0
   while (getlin(line, fin) ~= EOF) {
      if (lineno == 0) {
         call skip(MARGIN1)
         pageno = pageno + 1
         call head(name, pageno)
         call skip(MARGIN2)
         lineno = MARGIN1 + MARGIN2 + 1
         $@$
      call putlin(line, STDOUT)
      lineno = lineno + 1
      if (lineno >= BOTTOM) {
         call skip(PAGELEN-lineno)
         lineno = 0
         $@$
      $@$
   if (lineno > 0)
      call skip(PAGELEN-lineno)
   return
   end
# skip - output  n  blank lines
   subroutine skip(n)
   integer i, n
   for (i = 1; i <= n; i = i + 1)
      call putc(NEWLINE)
   return
   end
# head - print top of page header
   subroutine head(name, pageno)
   integer name(NAMESIZE)
   integer pageno
#   string page " Page  "
   integer page(7)
   data page(1) /BLANK/
   data page(2) /LETP/
   data page(3) /LETA/
   data page(4) /LETG/
   data page(5) /LETE/
   data page(6) /BLANK/
   data page(7) /EOS/
   call putlin(name, STDOUT)
   call putlin(page, STDOUT)
   call putdec(pageno, 1)
   call putc(NEWLINE)
   return
   end
define(NAMESIZE,50)
# makecopy - copy one file to another
   character iname(NAMESIZE), oname(NAMESIZE)
   integer create, getarg, open
   integer fin, fout
   if (getarg(1, iname, NAMESIZE) == EOF
      | getarg(2, oname, NAMESIZE) == EOF)
      call error("usage: makecopy input output.")
   fin = open(iname, READ)
   if (fin == ERR)
      call cant(iname)
   fout = create(oname, WRITE)
   if (fout == ERR)
      call cant(oname)
   call fcopy(fin, fout)
   call close(fin)
   call close(fout)
   stop
   end
