# memo --- automated memo and reminder system

define (MAXSP, 32)      # never underestimate the power of a two
define (MEMSIZE, 1000)

include "memo.stacc.defs"

   call initialize
   call memo

   stop
   end



# initialize --- set up symbol tables, temp files, conditions, etc.

   subroutine initialize

   include "memo_com.r.i"

   integer val, month, day, year
   integer ctoi, get_dow

   pointer mktabl

   character dattim (9)

   call dsinit (MEMSIZE)
   Symtab = mktabl (1)

   call enter ("sunday"s,     1, Symtab)
   call enter ("sun"s,        1, Symtab)
   call enter ("monday"s,     2, Symtab)
   call enter ("mon"s,        2, Symtab)
   call enter ("tuesday"s,    3, Symtab)
   call enter ("tue"s,        3, Symtab)
   call enter ("wednesday"s,  4, Symtab)
   call enter ("wed"s,        4, Symtab)
   call enter ("thursday"s,   5, Symtab)
   call enter ("thu"s,        5, Symtab)
   call enter ("friday"s,     6, Symtab)
   call enter ("fri"s,        6, Symtab)
   call enter ("saturday"s,   7, Symtab)
   call enter ("sat"s,        7, Symtab)

   call enter ("january"s,    1, Symtab)
   call enter ("jan"s,        1, Symtab)
   call enter ("february"s,   2, Symtab)
   call enter ("feb"s,        2, Symtab)
   call enter ("march"s,      3, Symtab)
   call enter ("mar"s,        3, Symtab)
   call enter ("april"s,      4, Symtab)
   call enter ("apr"s,        4, Symtab)
   call enter ("may"s,        5, Symtab)
   call enter ("june"s,       6, Symtab)
   call enter ("jun"s,        6, Symtab)
   call enter ("july"s,       7, Symtab)
   call enter ("jul"s,        7, Symtab)
   call enter ("august"s,     8, Symtab)
   call enter ("aug"s,        8, Symtab)
   call enter ("september"s,  9, Symtab)
   call enter ("sep"s,        9, Symtab)
   call enter ("october"s,   10, Symtab)
   call enter ("oct"s,       10, Symtab)
   call enter ("november"s,  11, Symtab)
   call enter ("nov"s,       11, Symtab)
   call enter ("december"s,  12, Symtab)
   call enter ("dec"s,       12, Symtab)

   call date (SYS_DATE, dattim)
   val = 1
   month = ctoi (dattim, val)
   val = 4
   day = ctoi (dattim, val)
   val = 7
   year = ctoi (dattim, val)

   call enter ("month"s, month, Symtab)
   call enter ("day"s, day, Symtab)
   call enter ("year"s, year, Symtab)
   call enter ("dow"s, get_dow (month, day, year), Symtab)

   call date (SYS_TIME, dattim)
   val = 1
   call enter ("hour"s, ctoi (dattim, val), Symtab)
   val = 4
   call enter ("minute"s, ctoi (dattim, val), Symtab)

   call date (SYS_USERID, To_user)
   call mapstr (To_user, LOWER)

   call scopy ("always"s, 1, Display_cond, 1)

   call scopy ("always"s, 1, Erase_cond, 1)

   return
   end



# errmsg --- print error message

   subroutine errmsg (msg)
   character msg (ARB)

   call print (ERROUT, "*s*n"p, msg)

   return
   end



# eval --- evaluate boolean expression, return YES/NO/ERR

   integer function eval (expr)
   character expr (ARB)

   include "memo_com.r.i"

   integer state

   call scopy (expr, 1, Expression, 1)
   Ep = 1
   Sp = 0

   call getsym

   call bexpr (state)

   if (state == FAILURE)
      return (ERR)
   if (Symbol ~= NEWLINE && Symbol ~= EOS) {
      call errmsg ("bogus character in expression"s)
      return (ERR)
      }
   if (state == NOMATCH)
      return (ERR)

   if (Stack (1) ~= 0)
      return (YES)

   return (NO)
   end



# get_dow --- get day-of-week corresponding to month,day,year

   integer function get_dow (month, day, year)
   integer month, day, year

   integer lmonth, lday, lyear

   lmonth = month - 2
   lday = day
   lyear = year

   if (lmonth <= 0) {
      lmonth = lmonth + 12
      lyear = lyear - 1
      }

   get_dow = mod (lday + (26 * lmonth - 2) / 10 + lyear + lyear / 4 - 34,
       7) + 1

   return
   end



# getsym --- get next symbol in expression text

   subroutine getsym

   include "memo_com.r.i"

   integer i
   integer lookup, equal

   character token (MAXLINE)

   while (Expression (Ep) == ' 'c || Expression (Ep) == TAB)
      Ep += 1

   if (IS_LOWER (Expression (Ep))) {
      for(i = 1; IS_LOWER (Expression (Ep)); i += 1) {
         token (i) = Expression (Ep)
         Ep += 1
         }
      token (i) = EOS
      if (equal (token, "always"s) == YES)
         Symbol = ALWAYS
      elif (equal (token, "never"s) == YES)
         Symbol = NEVER
      elif (lookup (token, Symval, Symtab) == YES)
         Symbol = CONSTANT
      else
         call errmsg ("undefined variable"s)
      }

   elif (IS_DIGIT (Expression (Ep))) {
      Symval = 0
      for (; IS_DIGIT (Expression (Ep)); Ep += 1)
         Symval = 10 * Symval + Expression (Ep) - '0'c
      Symbol = CONSTANT
      }

   else {
      Symbol = Expression (Ep)
      if (Symbol ~= NEWLINE && Symbol ~= EOS)
         Ep += 1
      }

   return
   end



# memo --- parse argument list, call memo sender or scanner

   subroutine memo

   include "memo_com.r.i"

   character arg (MAXLINE)

   integer ap
   integer getarg, equal, vfyusr

   for (ap = 1; getarg (ap, arg, MAXLINE) ~= EOF; ap += 1) {
      call mapstr (arg, LOWER)

      if (equal (arg, "-t"s) == YES) {
         ap += 1
         if (getarg (ap, To_user, MAXLINE) == EOF)
            call usage
         call mapstr (To_user, LOWER)
         if (vfyusr (To_user) == ERR)
            call error ("illegal user name"p)
         }

      elif (equal (arg, "-d"s) == YES) {
         ap += 1
         if (getarg (ap, Display_cond, MAXLINE) == EOF)
            call usage
         call mapstr (Display_cond, LOWER)
         }

      elif (equal (arg, "-e"s) == YES) {
         ap += 1
         if (getarg (ap, Erase_cond, MAXLINE) == EOF)
            call usage
         call mapstr (Erase_cond, LOWER)
         }

      elif (vfyusr (arg) == OK)
         call scopy (arg, 1, To_user, 1)

      else {
         call remark ("illegal user name or improper argument syntax"p)
         call usage
         }
      }

   if (ap > 1)       # are we sending something?
      call send_memo
   else
      call scan_memos

   return
   end



# scan_memos --- scan the user's memo file, displaying and/or erasing

   subroutine scan_memos

   include "memo_com.r.i"

   integer memof, tempf, display, erase, junk
   integer open, getlin, eval

   character id (MAXLINE)

   memof = open ("=extra=/memo/=user="s, READWRITE)
   if (memof == ERR)
      call error ("can't open memo file.")

   tempf = mktemp (READWRITE)

   while (getlin (id, memof) ~= EOF) {

      if (getlin (Display_cond, memof) == EOF
        || getlin (Erase_cond, memof) == EOF) {
         call close (memof)
         call rmtemp (tempf)
         call error ("badly-formed memo file.")
         }

      display = eval (Display_cond)
      erase = eval (Erase_cond)

      if (erase == NO && display == NO) {
         call putlin (id, tempf)
         call putlin (Display_cond, tempf)
         call putlin (Erase_cond, tempf)
         repeat {
            junk = getlin (id, memof)
            call putlin (id, tempf)
            } until (id (1) == '.'c)
         }

      elif (erase == YES && display == NO) {
         repeat
            junk = getlin (id, memof)
            until (id (1) == '.'c)
         }

      elif (erase == NO && display == YES) {
         call print (STDOUT, "*n*n*s*n"p, id)
         call putlin (id, tempf)
         call putlin (Display_cond, tempf)
         call putlin (Erase_cond, tempf)
         repeat {
            junk = getlin (id, memof)
            call putlin (id, tempf)
            call putlin (id (2), STDOUT)     # subarray
            } until (id (1) == '.'c)
         }

      elif (erase == YES && display == YES) {
         call print (STDOUT, "*n*n*s*n"p, id)
         repeat {
            junk = getlin (id, memof)
            call putlin (id (2), STDOUT)
            } until (id (1) == '.'c)
         }

      }  # while ...

   call rewind (memof)
   call rewind (tempf)

   call fcopy (tempf, memof)
   call trunc (memof)

   call close (memof)
   call rmtemp (tempf)

   return
   end



# send_memo --- send a memo to the designated user

   subroutine send_memo

   include "memo_com.r.i"

   integer memof, i, tempf
   integer open, scopy, mktemp, getlin, eval

   character mfname (MAXLINE), user (MAXUSERNAME), tim (9), dat (9)
   character buf (MAXLINE)

   i = eval (Display_cond)
   if (i == ERR)
      return
   i = eval (Erase_cond)
   if (i == ERR)
      return

   tempf = mktemp (READWRITE)
   call fcopy (STDIN, tempf)
   call rewind (tempf)

   i = scopy ("=extra=/memo/"s, 1, mfname, 1)
   i = scopy (To_user, 1, mfname, i + 1)

   memof = open (mfname, READWRITE)
   if (memof == ERR)
      call error ("memo file not available.")
   call wind (memof)

   call date (SYS_USERID, user)
   call mapstr (user, LOWER)
   call date (SYS_DATE, dat)
   call date (SYS_TIME, tim)

   call print (memof, "Memo from *s at *s *s*n"p, user, tim, dat)
   call print (memof, "*s*n"p, Display_cond)
   call print (memof, "*s*n"p, Erase_cond)

   while (getlin (buf, tempf) ~= EOF) {
      call putch (' 'c, memof)
      call putlin (buf, memof)
      }

   call print (memof, ".*n"p)

   call close (memof)
   call rmtemp (tempf)

   return
   end



# usage --- print usage message, then die

   subroutine usage

   call error ("Usage: memo {[-t] user|-d display_cond|-e erase_cond}"p)

   return
   end



include "memo.stacc.r"
