$CONTROL USLINIT,CODE,MAP                                               00010000
<< JOBSCHED.  Contains miscellaneous procedures for the   >>            00015000
<< handling for jobs.  Most of the code for Job           >>            00020000
<< Scheduling resides here.                               >>            00025000
                                                                        00030000
begin                                                                   00035000
                                                                        00040000
   INTRINSIC READ, PRINT, ASCII, BINARY, MYCOMMAND, SEARCH,             00045000
             DATELINE, CALENDAR, CLOCK, FMTDATE;                        00050000
                                                                        00055000
                                                                        00060000
<< The following EQUATEs are for error message numbers.    >>           00065000
   EQUATE                                                               00070000
      SCHEDUNKNOWNKEY          = 6300,                                  00075000
      SCHEDHADBOTHABSANDREL    = 6301,                                  00080000
      SCHEDHADBOTHDAYDATE      = 6302,                                  00085000
      SCHEDSPECBEFORENOW       = 6303,                                  00090000
      SCHEDNOSEMI              = 6304,                                  00095000
                                                                        00100000
      SCHEDTOOMANYATS          = 6308,                                  00105000
      SCHEDATWANTSEQ           = 6309,                                  00110000
      SCHEDEXPECTEDHHMM        = 6310,                                  00115000
      SCHEDBADHHVAL            = 6311,                                  00120000
      SCHEDNOHHMMCOLON         = 6312,                                  00125000
      SCHEDNEEDBOTHHHMM        = 6313,                                  00130000
      SCHEDBADMMVAL            = 6314,                                  00135000
      SCHEDBADAT               = 6310,                                  00140000
                                                                        00145000
      SCHEDTOOMANYDAYS         = 6318,                                  00150000
      SCHEDDAYWANTSEQ          = 6319,                                  00155000
      SCHEDNODAYSPEC           = 6320,                                  00160000
      SCHEDDOMTOOBIG           = 6321,                                  00165000
      SCHEDBADAYSPEC           = 6322,                                  00170000
      SCHEDDEMTOOBIG           = 6323,                                  00175000
      SCHEDDOMZERO             = 6324,                                  00180000
                                                                        00185000
      SCHEDTOOMANYDATES        = 6328,                                  00190000
      SCHEDNOEQSAFTERDATE      = 6329,                                  00195000
      SCHEDNODATESPEC          = 6330,                                  00200000
      SCHEDBADATE              = 6330,                                  00205000
      SCHEDBADATEMONTH         = 6331,                                  00210000
      SCHEDNOTSLASHINDATE      = 6332,                                  00215000
      SCHEDBADATEDAY           = 6333,                                  00220000
      SCHEDBADATEYEAR          = 6334,                                  00225000
                                                                        00230000
      SCHEDTOOMANYINS          = 6338,                                  00235000
      SCHEDINWANTSEQS          = 6339,                                  00240000
      SCHEDINOPARMS            = 6340,                                  00245000
      SCHEDINNODAY             = 6341,                                  00250000
      SCHEDINNOHOURS           = 6342,                                  00255000
      SCHEDINNOMINS            = 6343,                                  00260000
      SCHEDINEGDOM             = 6341,                                  00265000
      SCHEDINEGHH              = 6342,                                  00270000
      SCHEDINEGMM              = 6343,                                  00275000
                                                                        00280000
      SCHEDTOOEARLY            = 6355;                                  00285000
                                                                        00290000
<< The following equates are used for the printing of      >>           00295000
<< normal processing messages.                             >>           00300000
   EQUATE                                                               00305000
      SYSSET                   = 1,                                     00310000
      SCHEDJOBARRIVED          = 85;                                    00315000
                                                                        00320000
                                                                        00325000
DEFINE                                                                  00330000
   EXECUTORHEAD = (PARMSP, ERRNUM, PARMNUM);                            00335000
                  BYTE ARRAY PARMSP;                                    00340000
                  INTEGER ERRNUM, PARMNUM;                              00345000
                  OPTION PRIVILEGED, UNCALLABLE #;                      00350000
                                                                        00355000
                                                                        00360000
<< The following definitions are used for communications   >>           00365000
<< with UCOP.                                              >>           00370000
   EQUATE                                                               00375000
      ABSYS    = %1000,                                                 00380000
      JOBSYNC  = %121,                                                  00385000
      JUNKWAIT = %20,                                                   00390000
      UCOPLPIN = 2;                                                     00395000
                                                                        00400000
   DEFINE                                                               00405000
      ABSYS'JOBSYNC   = ABSOLUTE(ABSYS+JOBSYNC) #,                      00410000
      JOBREADY'F      = 13:1 #;                                         00415000
                                                                        00420000
   DEFINE                                                               00425000
      ENABLE          = ASSEMBLE( SED 1 ) #,                            00430000
      DISABLE         = ASSEMBLE( SED 0 ) #;                            00435000
                                                                        00440000
   INTEGER                                                              00445000
      X               = X,       << X register.            >>           00450000
      S0              = S-0;                                            00455000
                                                                        00460000
$PAGE "JMAT (Job Master Table) Definitions"                             00465000
$INCLUDE INCLJMAT                                                       00470000
                                                                        00475000
                                                                        00480000
<< The following definitions are for the modifications to  >>           00485000
<< the JMAT table.  Note that some of these definitions    >>           00490000
<< should be added to the standard $INCLUDE file.  They    >>           00495000
<< here for the time being.                                >>           00500000
EQUATE                                                                  00505000
   JOBCHAINEND       = 0,   << Null link at the end of a   >>           00510000
                            << JMAT job queue.             >>           00515000
   JOBSCHED          = %70; << JMAT entry state.           >>           00520000
                                                                        00525000
$CONTROL SEGMENT=JOBSCHED                                               00530000
$PAGE "External procedures."                                            00535000
PROCEDURE CIERR( A, B, C, D );                                          00540000
   VALUE   A, C, D;                                                     00545000
   INTEGER A, C, D;                                                     00550000
   BYTE ARRAY B;                                                        00555000
OPTION EXTERNAL, VARIABLE;                                              00560000
                                                                        00565000
                                                                        00570000
PROCEDURE ALMANAC( DATE, ERROR, YEAR, MONTH, DAY, WEEKDAY );            00575000
   VALUE   DATE;                                                        00580000
   LOGICAL DATE;                                                        00585000
   INTEGER YEAR, MONTH, DAY, WEEKDAY;                                   00590000
   LOGICAL ARRAY ERROR;                                                 00595000
OPTION PRIVILEGED, VARIABLE, EXTERNAL;                                  00600000
                                                                        00605000
                                                                        00610000
<< SCHEDSTREAM is a special entry point into the command   >>           00615000
<< executor for the :STREAM command.                       >>           00620000
PROCEDURE SCHEDSTREAM( PARMSP, ERRNUM, PARMNUM );                       00625000
   BYTE ARRAY PARMSP;                                                   00630000
   INTEGER ERRNUM, PARMNUM;                                             00635000
OPTION PRIVILEGED, EXTERNAL;                                            00640000
                                                                        00645000
                                                                        00650000
<< SIR handling procedures.                                >>           00655000
LOGICAL PROCEDURE GETSIR( SIRVAL );                                     00660000
   VALUE SIRVAL;                                                        00665000
   LOGICAL SIRVAL;                                                      00670000
OPTION PRIVILEGED, UNCALLABLE, EXTERNAL;                                00675000
                                                                        00680000
PROCEDURE RELSIR( SIRVAL, SAVEVAL );                                    00685000
   VALUE SIRVAL, SAVEVAL;                                               00690000
   LOGICAL SIRVAL, SAVEVAL;                                             00695000
OPTION PRIVILEGED, UNCALLABLE, EXTERNAL;                                00700000
                                                                        00705000
                                                                        00710000
<< EXCHANGEDB switches DB to point to another DST.         >>           00715000
LOGICAL PROCEDURE EXCHANGEDB( DSTN );                                   00720000
   VALUE DSTN;                                                          00725000
   LOGICAL DSTN;                                                        00730000
OPTION PRIVILEGED, UNCALLABLE, EXTERNAL;                                00735000
                                                                        00740000
                                                                        00745000
<< SYSPROC returns a PCB index of a system process.        >>           00750000
LOGICAL PROCEDURE SYSPROC( LPIN );                                      00755000
   VALUE   LPIN;                                                        00760000
   LOGICAL LPIN;                                                        00765000
OPTION PRIVILEGED, UNCALLABLE, EXTERNAL;                                00770000
                                                                        00775000
                                                                        00780000
<< GENMSG generates a system catalog message.              >>           00785000
INTEGER PROCEDURE GENMSG(SETN,MSG,MASK,P1,P2,P3,P4,P5,                  00790000
                         DEST,REPLY,BUFF,DST,IOTYPE   );                00795000
   VALUE   SETN,MSG,MASK,P1,P2,P3,P4,P5,DEST,                           00800000
           REPLY,BUFF,DST,IOTYPE;                                       00805000
   LOGICAL SETN,MSG,MASK,P1,P2,P3,P4,P5,DEST,                           00810000
           REPLY,BUFF,DST,IOTYPE;                                       00815000
OPTION VARIABLE, EXTERNAL;                                              00820000
                                                                        00825000
                                                                        00830000
<< WRITEDSEG copys the DST out to disc.                    >>           00835000
   PROCEDURE WRITEDSEG( DST );                                          00840000
      VALUE   DST;                                                      00845000
      INTEGER DST;                                                      00850000
   OPTION EXTERNAL;                                                     00855000
                                                                        00860000
                                                                        00865000
<< AWAKE signals a designated process to resume.           >>           00870000
   PROCEDURE AWAKE( PCBPT, N, WAITF );                                  00875000
      VALUE   PCBPT, N, WAITF;                                          00880000
      INTEGER PCBPT, N, WAITF;                                          00885000
   OPTION EXTERNAL;                                                     00890000
$PAGE "SCHEDDAYTIME:  Formats the internal time specification."         00895000
PROCEDURE SCHEDDAYTIME( OUT, TIME );                                    00900000
   BYTE ARRAY OUT;                                                      00905000
   INTEGER ARRAY TIME;                                                  00910000
OPTION PRIVILEGED, UNCALLABLE;                                          00915000
BEGIN                                                                   00920000
                                                                        00925000
<<*********************************************************>>           00930000
<<                                                         >>           00935000
<< This procedure formats the date and time specified by   >>           00940000
<< TIME into a condensed, 14 character string returned in  >>           00945000
<< OUT.  This string has the following format:             >>           00950000
<<                                                         >>           00955000
<<               0         1                               >>           00960000
<<               012345678901234                           >>           00965000
<<               MM/DD/YY HH:MM0                           >>           00970000
<<                                                         >>           00975000
<< where "HH" is a military (24 hour) specification.  For  >>           00980000
<< this release, the algorithm used here is brute force:   >>           00985000
<< TIME is the three word integer array holding a CALENDAR >>           00990000
<< format in the first word and a CLOCK format in the last >>           00995000
<< two words.  This information is passed to FMTDATE, and  >>           01000000
<< the information returned is used to build the OUT       >>           01005000
<< string.  Once Native Language Support intrinsics become >>           01010000
<< available, a localized format could be developed.       >>           01015000
<<                                                         >>           01020000
<< Note:  OUT(14) contains a zero byte (ASCII null) as a   >>           01025000
<<        delimiter for GENMSG.                            >>           01030000
<<                                                         >>           01035000
<< Split stack calls are not allowed.  This procedure      >>           01040000
<< returns CCE if no problems were detected and CCG other- >>           01045000
<< wise.                                                   >>           01050000
<<                                                         >>           01055000
<<*********************************************************>>           01060000
                                                                        01065000
   DOUBLE                                                               01070000
      TIME'D;       << Machine internal format.            >>           01075000
                                                                        01080000
   INTEGER                                                              01085000
      DATE,                                                             01090000
      TIME'1 = TIME'D,                                                  01095000
      TIME'2 = TIME'D + 1,                                              01100000
      TEMPI;                                                            01105000
                                                                        01110000
   BYTE ARRAY                                                           01115000
      TEMPARR(0:27);                                                    01120000
                                                                        01125000
<< The following declaractions are for handling the        >>           01130000
<< setting of the status register.                         >>           01135000
   INTEGER                                                              01140000
      STATUS = Q-1;                                                     01145000
                                                                        01150000
   EQUATE                                                               01155000
      CCE    = 0,                                                       01160000
      CCG    = 2;                                                       01165000
                                                                        01170000
   INTRINSIC                                                            01175000
      FMTDATE, BINARY, ASCII;                                           01180000
                                                                        01185000
<< Start of main code, SCHEDDAYTIME.                       >>           01190000
   STATUS.(6:2) := CCE;                                                 01195000
                                                                        01200000
   DATE := TIME;                                                        01205000
   TIME'1 := TIME(1);                                                   01210000
   TIME'2 := TIME(2);                                                   01215000
   FMTDATE( DATE, TIME'D, TEMPARR );                                    01220000
                                                                        01225000
   IF TEMPARR(5) = "JAN"                                                01230000
      THEN MOVE OUT := " 1"                                             01235000
   ELSE IF TEMPARR(5) = "FEB"                                           01240000
      THEN MOVE OUT := " 2"                                             01245000
   ELSE IF TEMPARR(5) = "MAR"                                           01250000
      THEN MOVE OUT := " 3"                                             01255000
   ELSE IF TEMPARR(5) = "APR"                                           01260000
      THEN MOVE OUT := " 4"                                             01265000
   ELSE IF TEMPARR(5) = "MAY"                                           01270000
      THEN MOVE OUT := " 5"                                             01275000
   ELSE IF TEMPARR(5) = "JUN"                                           01280000
      THEN MOVE OUT := " 6"                                             01285000
   ELSE IF TEMPARR(5) = "JUL"                                           01290000
      THEN MOVE OUT := " 7"                                             01295000
   ELSE IF TEMPARR(5) = "AUG"                                           01300000
      THEN MOVE OUT := " 8"                                             01305000
   ELSE IF TEMPARR(5) = "SEP"                                           01310000
      THEN MOVE OUT := " 9"                                             01315000
   ELSE IF TEMPARR(5) = "OCT"                                           01320000
      THEN MOVE OUT := "10"                                             01325000
   ELSE IF TEMPARR(5) = "NOV"                                           01330000
      THEN MOVE OUT := "11"                                             01335000
   ELSE IF TEMPARR(5) = "DEC"                                           01340000
      THEN MOVE OUT := "12"                                             01345000
   ELSE    MOVE OUT := "??";                                            01350000
                                                                        01355000
   OUT(2) := "/";                                                       01360000
                                                                        01365000
   MOVE OUT(3) := TEMPARR(9), (2);                                      01370000
                                                                        01375000
   OUT(5) := "/";                                                       01380000
                                                                        01385000
   MOVE OUT(6) := TEMPARR(15), (2);                                     01390000
                                                                        01395000
<< Convert to Military Time (Zero origin, 24 hour clock).  >>           01400000
   IF TEMPARR(19) = " "                                                 01405000
      THEN TEMPI := BINARY( TEMPARR(20), 1 )                            01410000
      ELSE TEMPI := BINARY( TEMPARR(19), 2 );                           01415000
   IF TEMPI = 12                                                        01420000
      THEN IF TEMPARR(25) = "A"                                         01425000
              THEN TEMPI := 0                                           01430000
              ELSE TEMPI := 12                                          01435000
   ELSE IF TEMPARR(25) = "P"                                            01440000
           THEN TEMPI := TEMPI + 12;                                    01445000
   MOVE OUT(8) := "   ";                                                01450000
   ASCII( TEMPI, -10, OUT(10) );                                        01455000
                                                                        01460000
   MOVE OUT(11) := TEMPARR(21), (3);                                    01465000
   OUT(14) := 0;                                                        01470000
                                                                        01475000
END;  << SCHEDDAYTIME >>                                                01480000
$PAGE "DELINKSCHED:  Delinks JMAT from the Scheduled Jobs Queue."       01485000
PROCEDURE DELINKSCHED( JMATIND );                                       01490000
   VALUE   JMATIND;                                                     01495000
   INTEGER JMATIND;                                                     01500000
OPTION UNCALLABLE, PRIVILEGED;                                          01505000
BEGIN                                                                   01510000
                                                                        01515000
<<*********************************************************>>           01520000
<<                                                         >>           01525000
<< This procedure is patterned after DELINK'JMAT and is    >>           01530000
<< used to remove a JMAT entry from the Scheduled Jobs     >>           01535000
<< queue.  This procedure assumes that DB is pointing at   >>           01540000
<< the JMAT and that JMATIND is an index pointing into the >>           01545000
<< JMAT indicating the entry to be deleted.  Note that     >>           01550000
<< this procedure does no error checking.  If JMATIND is   >>           01555000
<< not pointing to a Scheduled Job, this procedure will    >>           01560000
<< give no indication of the problem.  Also note that the  >>           01565000
<< JMAT SIR should be held by this procedure's caller.     >>           01570000
<<                                                         >>           01575000
<<*********************************************************>>           01580000
                                                                        01585000
   INTEGER                                                              01590000
      PREVINX;         << Index to previous entry in queue.>>           01595000
                                                                        01600000
   INTEGER ARRAY                                                        01605000
      JMATARR(*) = DB+0;  << For JMAT referencing.         >>           01610000
                                                                        01615000
<< Start of Main Code for DELINKSCHED.                     >>           01620000
   PREVINX := JOBCHAINEND;                                              01625000
   IF JMATIND = JMATSCHEDHEAD  << Delinking the queue head.>>           01630000
      THEN JMATSCHEDHEAD                                                01635000
              := JMATARR( JMATIND + JMATSCHEDLINKOFF )                  01640000
                                                                        01645000
   ELSE                                                                 01650000
   BEGIN                                                                01655000
                                                                        01660000
   << The JMAT entry to be deleted is not at the head.     >>           01665000
   << Traverse queue to find it, and delete it if found.   >>           01670000
   << Note that if JMATIND is not found, this code can     >>           01675000
   << loop forever or hit a bounds violation.  We have     >>           01680000
   << serious problems if this procedure is called         >>           01685000
   << incorrectly.                                         >>           01690000
      PREVINX := JMATSCHEDHEAD;                                         01695000
      WHILE JMATARR(PREVINX+JMATSCHEDLINKOFF) <> JMATIND                01700000
         DO PREVINX := JMATARR( PREVINX + JMATSCHEDLINKOFF );           01705000
                                                                        01710000
      JMATARR( PREVINX + JMATSCHEDLINKOFF )                             01715000
         := JMATARR( JMATIND + JMATSCHEDLINKOFF );                      01720000
                                                                        01725000
   END;                                                                 01730000
                                                                        01735000
END;  << DELINKSCHED >>                                                 01740000
$PAGE "COMPTIME:  Compares two times (in internal format)."             01745000
INTEGER PROCEDURE COMPTIME( TIME1, TIME2, DIFF, ERROR );                01750000
   INTEGER ARRAY  TIME1, TIME2;                                         01755000
   DOUBLE DIFF;                                                         01760000
   INTEGER ERROR;                                                       01765000
OPTION PRIVILEGED, UNCALLABLE, VARIABLE;                                01770000
BEGIN                                                                   01775000
                                                                        01780000
<<*********************************************************>>           01785000
<<                                                         >>           01790000
<< This procedure compares two time specifications (in     >>           01795000
<< internal format).  Optionally, the difference in        >>           01800000
<< machine ticks is returned in DIFF.  The return values   >>           01805000
<< are as follows:                                         >>           01810000
<<                                                         >>           01815000
<<    -1:  TIME1 < TIME2; DIFF undefined.                  >>           01820000
<<     0:  TIME1 = TIME2; DIFF = 0D.                       >>           01825000
<<     1:  TIME1 > TIME2; DIFF contains the number of      >>           01830000
<<                        machine ticks.                   >>           01835000
<<     2:  TIME1 > TIME2; DIFF is undefined since 32 bits  >>           01840000
<<                        are insufficient to hold the     >>           01845000
<<                        difference between the two times.>>           01850000
<<    10:  Error found; ERROR contains an error number.    >>           01855000
<<                                                         >>           01860000
<< Semantics can be difficult since we are not used to     >>           01865000
<< thinking about one time being "larger" than another     >>           01870000
<< time.  The rule to remember is: "Later is Greater".     >>           01875000
<< That is, the later the time is, the larger it is        >>           01880000
<< considered to be.  Thus, if TIME1 will occur after      >>           01885000
<< TIME2, then TIME1 > TIME2.                              >>           01890000
<<                                                         >>           01895000
<< Note that DIFF is constrained to be 24 days or less,    >>           01900000
<< even though a 32-bit unsigned integer is capable of     >>           01905000
<< handling approximately 24.86 days.  For current and     >>           01910000
<< forseen applications of this procedure, 24 days is      >>           01915000
<< ample.  Note that return value of 2 is only possible if >>           01920000
<< DIFF was passed in; otherwise, only a return value of   >>           01925000
<< 1 is used to specify TIME1 > TIME2.                     >>           01930000
<<                                                         >>           01935000
<< At present, the only error detected is if both TIME1    >>           01940000
<< and TIME2 are not present in its call.  If no error is  >>           01945000
<< detected, a zero is returned to ERROR.                  >>           01950000
<<                                                         >>           01955000
<< TIME1 and TIME2 are both required parameters.  Values   >>           01960000
<< are assigned to DIFF and ERROR only if present.         >>           01965000
<<                                                         >>           01970000
<< The value returned in DIFF can be used for Timer        >>           01975000
<< Request List calls if the time in TIME2 is the current  >>           01980000
<< time.                                                   >>           01985000
<<                                                         >>           01990000
$PAGE                                                                   01995000
<< This routine is used in the management of Scheduled     >>           02000000
<< Jobs.  The internal time specs have this format:        >>           02005000
<<                                                         >>           02010000
<<        +-----------------------------------------+      >>           02015000
<< Word 0 | Year of Centry  |    Day of Year        |      >>           02020000
<<        +-----------------------------------------+      >>           02025000
<< Word 1 |  Hour of Day      |   Minute of Hour    |      >>           02030000
<<        +-----------------------------------------+      >>           02035000
<< Word 2 |    Seconds        |  Tenths of Seconds  |      >>           02040000
<<        +-----------------------------------------+      >>           02045000
<<        0                 7  8                   15      >>           02050000
<<                                                         >>           02055000
<<                                                         >>           02060000
<< Note:  Unfortunately, split stack calls are not allowed.>>           02065000
<<                                                         >>           02070000
<<*********************************************************>>           02075000
                                                                        02080000
                                                                        02085000
<< The following definitions are used to determine which   >>           02090000
<< parameters were present in the call.                    >>           02095000
   LOGICAL                                                              02100000
      PMASK        = Q-4;   << Passed parameter mask.      >>           02105000
                                                                        02110000
   DEFINE                                                               02115000
      P'TIME1      = PMASK.(12:1) #,                                    02120000
      P'TIME2      = PMASK.(13:1) #,                                    02125000
      P'DIFF       = PMASK.(14:1) #,                                    02130000
      P'ERROR      = PMASK.(15:1) #;                                    02135000
                                                                        02140000
<< The following definitions encompass the various return  >>           02145000
<< values.                                                 >>           02150000
   INTEGER                                                              02155000
      LOCERROR    := 0,     << Local error value.          >>           02160000
      RETURNVAL   := 0;     << Initially "equals".         >>           02165000
                                                                        02170000
   EQUATE                                                               02175000
      ERROR'RETURN = 10,    << Error found in processing.  >>           02180000
      T1'LT'T2     = -1,  << TIME1 < TIME2                 >>           02185000
      T1'EQ'T2     = 0,   << TIME1 = TIME2                 >>           02190000
      T1'GT'T2     = 1,   << TIME1 > TIME2; DIFF<=24 days. >>           02195000
      T1'GGT'T2    = 2;   << TIME1 > TIME2; DIFF>24 days.  >>           02200000
                                                                        02205000
   DEFINE                                                               02210000
      MILLPERDAY   = 86400000D#,     << Milliseconds in a  >>           02215000
                                     << day.               >>           02220000
      MILLPERMIN   = 60000D#,        << Milliseconds in a  >>           02225000
                                     << minute.            >>           02230000
      DAYSLIMIT    = 24D#;           << Schedule jobs in   >>           02235000
                                     << the next 24 days.  >>           02240000
                                                                        02245000
      << Note:  24 days is about the maximum number of     >>           02250000
      <<        milliseconds that can be held in a double  >>           02255000
      <<        integer.                                   >>           02260000
                                                                        02265000
   DOUBLE                                                               02270000
      MILLILIMIT;         << Milliseconds in DAYSLIMIT.    >>           02275000
                                                                        02280000
<< The following equates are for the possible error values.>>           02285000
   EQUATE                                                               02290000
      REQ'PARMS'ERROR     = 1;                                          02295000
                                                                        02300000
<< The following definitions are intermediate values.      >>           02305000
   INTEGER                                                              02310000
      DAY1, DAY2,                                                       02315000
      MIN1, MIN2,                                                       02320000
      SEC1, SEC2;                                                       02325000
                                                                        02330000
   DOUBLE                                                               02335000
      LOCDIFF       := 0D;                                              02340000
                                                                        02345000
<< Start of Main Code for COMPTIME.                        >>           02350000
                                                                        02355000
                                                                        02360000
<< Initialize the DIFF limit (in milliseconds).            >>           02365000
   MILLILIMIT := MILLPERDAY * DAYSLIMIT;                                02370000
                                                                        02375000
<< Check for required parameters.                          >>           02380000
   IF NOT ( P'TIME1 LAND P'TIME2 ) THEN                                 02385000
   BEGIN                                                                02390000
                                                                        02395000
      RETURNVAL := ERROR'RETURN;                                        02400000
      LOCERROR  := REQ'PARMS'ERROR;                                     02405000
                                                                        02410000
   END                                                                  02415000
   ELSE                                                                 02420000
   BEGIN                                                                02425000
                                                                        02430000
   << All the required parameters have been found.  Make   >>           02435000
   << the comparison.  Assume equals until otherwise.      >>           02440000
      RETURNVAL := T1'EQ'T2;                                            02445000
      MIN1 := TIME1(1).(0:8) * 60 + TIME1(1).(8:8);                     02450000
      MIN2 := TIME2(1).(0:8) * 60 + TIME2(1).(8:8);                     02455000
      SEC1 := TIME1(2).(0:8) * 10 + TIME1(2).(8:8);                     02460000
      SEC2 := TIME2(2).(0:8) * 10 + TIME2(2).(8:8);                     02465000
                                                                        02470000
      IF TIME1(0) > TIME2(0)                                            02475000
         THEN RETURNVAL := T1'GT'T2                                     02480000
                                                                        02485000
      ELSE IF TIME1(0) < TIME2(0)                                       02490000
         THEN RETURNVAL := T1'LT'T2                                     02495000
                                                                        02500000
   << Year and Day specifications are equal, check hours   >>           02505000
   << and minutes.                                         >>           02510000
      ELSE IF MIN1 > MIN2                                               02515000
         THEN RETURNVAL := T1'GT'T2                                     02520000
                                                                        02525000
      ELSE IF MIN1 < MIN2                                               02530000
         THEN RETURNVAL := T1'LT'T2                                     02535000
                                                                        02540000
   << Year, Day, Hours, and Minutes are equal.  Check the  >>           02545000
   << seconds and tenths of seconds specifications.        >>           02550000
      ELSE IF SEC1 > SEC2                                               02555000
         THEN RETURNVAL := T1'GT'T2                                     02560000
                                                                        02565000
      ELSE IF SEC1 < SEC2                                               02570000
         THEN RETURNVAL := T1'LT'T2;                                    02575000
                                                                        02580000
   << All checks are complete.  If appropriate, return     >>           02585000
   << the difference value.                                >>           02590000
      IF P'DIFF LAND (RETURNVAL = T1'GT'T2) THEN                        02595000
      BEGIN                                                             02600000
                                                                        02605000
      << Check to see if DIFF can be expressed (i.e. DIFF  >>           02610000
      << will be less than MILLILIMIT).                    >>           02615000
         IF TIME1(0).(0:7) > TIME2(0).(0:7) + 2                         02620000
            THEN RETURNVAL := T1'GGT'T2                                 02625000
                                                                        02630000
         ELSE                                                           02635000
         BEGIN                                                          02640000
                                                                        02645000
            DAY1 := TIME1(0).(7:9);                                     02650000
            DAY2 := TIME2(0).(7:9);                                     02655000
            IF TIME1(0).(0:7) <> TIME2(0).(0:7) THEN                    02660000
            BEGIN                                                       02665000
               DAY1 := DAY1 + 365;                                      02670000
               IF ( (TIME1(0).(0:7) MOD 4 = 0) LAND                     02675000
                    (TIME1(0).(0:7) <> 100)         )                   02680000
                  THEN DAY1 := DAY1 + 1;   << Leap Year    >>           02685000
            END;                                                        02690000
                                                                        02695000
            IF DAY1 > DAY2 + INTEGER( DAYSLIMIT )                       02700000
               THEN RETURNVAL := T1'GGT'T2                              02705000
                                                                        02710000
            ELSE                                                        02715000
            BEGIN                                                       02720000
                                                                        02725000
            << DIFF is small enough to be calculated.      >>           02730000
               LOCDIFF := MILLPERDAY * DOUBLE( DAY1 - DAY2 );           02735000
               LOCDIFF := LOCDIFF +                                     02740000
                  MILLPERMIN * DOUBLE( MIN1 - MIN2 );                   02745000
               LOCDIFF := LOCDIFF +                                     02750000
                  100D * DOUBLE( SEC1 - SEC2 );                         02755000
                                                                        02760000
            END;  << DIFF calculation >>                                02765000
                                                                        02770000
         END;  << DIFF < 24 days >>                                     02775000
                                                                        02780000
      END;  << DIFF should be returned >>                               02785000
                                                                        02790000
   END;  << Check for required parameters. >>                           02795000
                                                                        02800000
<< Assign values to the appropriate return variables and   >>           02805000
<< quit.                                                   >>           02810000
   IF P'DIFF     THEN DIFF := LOCDIFF;                                  02815000
   IF P'ERROR    THEN ERROR := LOCERROR;                                02820000
   COMPTIME := RETURNVAL;                                               02825000
                                                                        02830000
END;  << COMPTIME >>                                                    02835000
$PAGE "SCHEDULESCHED:  Links JMAT entry to Scheduled Jobs queue"        02840000
PROCEDURE SCHEDULESCHED (JMATP);                                        02845000
   VALUE JMATP;                                                         02850000
   INTEGER POINTER JMATP;                                               02855000
   OPTION UNCALLABLE, PRIVILEGED;                                       02860000
BEGIN                                                                   02865000
                                                                        02870000
<<*********************************************************>>           02875000
<<                                                         >>           02880000
<< This procedure takes the JMAT entry pointed to by JMATP >>  <<*8942>>02885000
<< (which is in INTRO state) and links it into the         >>  <<*8942>>02890000
<< appropriate spot in the Scheduled Jobs queue.  If the   >>  <<*8942>>02895000
<< time stamp in the JMAT entry is less than the current   >>  <<*8942>>02900000
<< time, the job will be placed at the head of the queue   >>  <<*8942>>02905000
<< and when UCOP is wakened it will place the job in WAIT  >>  <<*8942>>02910000
<< state by a call to SCHEDULEJOB.  Otherwise, the job     >>  <<*8942>>02915000
<< will remain in the Scheduled Jobs queue in the SCHED    >>  <<*8942>>02920000
<< state.  The algorithm used in this procedure was copied >>  <<*8942>>02925000
<< from SCHEDULEJOB (in Nursery).                          >>  <<*8942>>02930000
<<                                                         >>           02935000
<< The entry point RECOVERSCHED is used by PROGEN when it  >>           02940000
<< is recovering the JMAT after a WARMSTART.  There are    >>           02945000
<< only two differences from the normal processing:        >>           02950000
<< first, UCOP is not awakened after linking the JMAT      >>           02955000
<< entry into the Scheduled Jobs queue (PROGEN awakens     >>           02960000
<< UCOP once the entire JMAT has been recovered), and      >>           02965000
<< second, the JMAT is not written out to disk (PROGEN     >>           02970000
<< will do this once recovery is complete).                >>           02975000
<<                                                         >>           02980000
<< Note that the JMAT SIR is locked during this operation  >>           02985000
<< to prevent the corruption caused by JMAT contention.    >>           02990000
<< This procedure assumes that DB is pointing to the       >>           02995000
<< caller's stack.  Since COMPTIME cannot be called in     >>           03000000
<< split-stack mode, this procedure uses MOVE FROM/TO DATA >>           03005000
<< SEGMENT instructions for the accessing of the JMAT.     >>           03010000
<<                                                         >>           03015000
<<*********************************************************>>           03020000
                                                                        03025000
                                                                        03030000
   INTEGER           SAVESIR,                                           03035000
                     COMPRETURN;                                        03040000
   LOGICAL           DONE;                                              03045000
                                                                        03050000
   EQUATE            LESSTHAN = -1;  << COMPTIME value.    >>           03055000
                                                                        03060000
<< The following declarations are used for the referencing >>           03065000
<< JMAT with the standard $INCLUDE file definitions.       >>           03070000
   INTEGER ARRAY     JMATARR(0:JMATENTRYSIZE);                          03075000
   INTEGER           JMATINX,                                           03080000
                     SAVESCHEDHEAD,                                     03085000
                     CURRINX,                                           03090000
                     LASTINX;                                           03095000
                                                                        03100000
   INTEGER ARRAY     JMATPTIME(0:2),                                    03105000
                     INDEXTIME(0:2);                                    03110000
                                                                        03115000
<< The following definitions are used for the JMAT recovery >>          03120000
<< entry point, RECOVERSCHED.                               >>          03125000
   ENTRY             RECOVERSCHED;                                      03130000
   LOGICAL           RECOVERING;                                        03135000
                                                                        03140000
                                                                        03145000
                                                                        03150000
<< Standard DST accessing subroutines.                      >>          03155000
   SUBROUTINE MOVEFROMDSEG( TARGET, DSTN, OFFSET, COUNT );              03160000
      VALUE   TARGET, DSTN, OFFSET, COUNT;                              03165000
      LOGICAL TARGET, DSTN, OFFSET, COUNT;                              03170000
   BEGIN                                                                03175000
                                                                        03180000
      X := TOS;     << Save subroutine return address.      >>          03185000
      ASSEMBLE( MFDS 0 );                                               03190000
      TOS := X;     << Restore return address.              >>          03195000
                                                                        03200000
   END;                                                                 03205000
                                                                        03210000
                                                                        03215000
   SUBROUTINE MOVETODSEG( DSTN, OFFSET, SOURCE, COUNT );                03220000
      VALUE   DSTN, OFFSET, SOURCE, COUNT;                              03225000
      LOGICAL DSTN, OFFSET, SOURCE, COUNT;                              03230000
   BEGIN                                                                03235000
                                                                        03240000
      X := TOS;     << Save subroutine return address.      >>          03245000
      ASSEMBLE( MTDS 0 );                                               03250000
      TOS := X;                                                         03255000
                                                                        03260000
   END;                                                                 03265000
                                                                        03270000
$PAGE                                                                   03275000
<< Start of Main Code for SCHEDULESCHED.                    >>          03280000
   RECOVERING := FALSE;                                                 03285000
   GOTO MAINCODE;                                                       03290000
                                                                        03295000
RECOVERSCHED:                                                           03300000
   RECOVERING := TRUE;                                                  03305000
                                                                        03310000
MAINCODE:                                                               03315000
                                                                        03320000
<< Save the time specifications for the entry to be added   >>          03325000
<< to the Scheduled Jobs list.                              >>          03330000
   SAVESIR := GETSIR( JMATSIR );                                        03335000
   CURRINX := @JMATP;                                                   03340000
   MOVEFROMDSEG( @JMATARR, JMATDST, CURRINX, JMATENTRYSIZE );           03345000
   JMATINX := 0;     << For accessing entry in JMATARR.     >>          03350000
   JMATPTIME := JMATCALENDAR;                                           03355000
   MOVE JMATPTIME(1) := JMATTIME, (2);                                  03360000
                                                                        03365000
<< Traverse the Scheduled Jobs queue until a job of later   >>          03370000
<< starting time is found.  Insert the new entry there.     >>          03375000
<<    CURRINX is the index of the entry whose scheduling    >>          03380000
<<            time is checked.                              >>          03385000
<<    LASTINX is the index of the entry previous to         >>          03390000
<<            JMATINX's entry.                              >>          03395000
<<    JMATP   is a POINTER to the JMAT entry to be inserted.>>          03400000
   MOVEFROMDSEG( @JMATARR, JMATDST, 0, JMATENTRYSIZE );                 03405000
   SAVESCHEDHEAD := JMATSCHEDHEAD;                                      03410000
   CURRINX := LASTINX := JMATSCHEDHEAD;                                 03415000
                                                                        03420000
   DONE := FALSE;                                                       03425000
   WHILE NOT DONE DO                                                    03430000
   BEGIN                                                                03435000
                                                                        03440000
      IF CURRINX = JOBCHAINEND                                          03445000
         THEN DONE := TRUE                                              03450000
      ELSE                                                              03455000
      BEGIN                                                             03460000
         MOVEFROMDSEG( @JMATARR, JMATDST, CURRINX,                      03465000
                       JMATENTRYSIZE );                                 03470000
         INDEXTIME := JMATCALENDAR;                                     03475000
         MOVE INDEXTIME(1) := JMATTIME, (2);                            03480000
         COMPRETURN := COMPTIME( JMATPTIME, INDEXTIME );                03485000
         IF COMPRETURN = LESSTHAN                                       03490000
            THEN DONE := TRUE                                           03495000
         ELSE                                                           03500000
         BEGIN                                                          03505000
            LASTINX := CURRINX;                                         03510000
            CURRINX := JMATSCHEDLINK;                                   03515000
         END;                                                           03520000
      END;                                                              03525000
                                                                        03530000
   END;                                                                 03535000
                                                                        03540000
<< CURRINX is now pointing at the JMAT entry which belongs >>           03545000
<< after JMATP, and LASTINX is pointing at the entry which >>           03550000
<< belongs before JMATP.                                   >>           03555000
   IF CURRINX = SAVESCHEDHEAD THEN  << Insert at the head  >>           03560000
   BEGIN                            << of the queue.       >>           03565000
      MOVEFROMDSEG( @JMATARR, JMATDST, 0, JMATENTRYSIZE );              03570000
      JMATSCHEDHEAD := @JMATP;                                          03575000
      MOVETODSEG( JMATDST, 0, @JMATARR, JMATENTRYSIZE );                03580000
   END                                                                  03585000
   ELSE                                                                 03590000
   BEGIN                                                                03595000
      MOVEFROMDSEG( @JMATARR, JMATDST, LASTINX,                         03600000
                    JMATENTRYSIZE );                                    03605000
      JMATSCHEDLINK := @JMATP;                                          03610000
      MOVETODSEG( JMATDST, LASTINX, @JMATARR,                           03615000
                  JMATENTRYSIZE );                                      03620000
   END;                                                                 03625000
                                                                        03630000
   MOVEFROMDSEG( @JMATARR, JMATDST, @JMATP, JMATENTRYSIZE );            03635000
   JMATSCHEDLINK := CURRINX;                                            03640000
                                                                        03645000
<< Any subsequent reference to the new JMAT entry will use >>           03650000
<< the standard table definitions.  Changes its state to   >>           03655000
<< "Scheduled" and inform the operator of its arrival.     >>           03660000
   JMATJOBSTATE := JOBSCHED;                                            03665000
   MOVETODSEG( JMATDST, @JMATP, @JMATARR, JMATENTRYSIZE );              03670000
                                                                        03675000
<< If we are recovering the JMAT entry, then our work is   >>           03680000
<< done.  Otherwise, write the JMAT out to disk so that it >>           03685000
<< can be recovered on the next WARMSTART.                 >>           03690000
   IF RECOVERING THEN                                                   03695000
   BEGIN                                                                03700000
      RELSIR( JMATSIR, SAVESIR );                                       03705000
      RETURN;                                                           03710000
   END;                                                                 03715000
                                                                        03720000
<< Inform UCOP that it has work to do.  Note that the same >>           03725000
<< synchroniztion protocol as a Job-Made-Ready is used.    >>           03730000
<< Note that the JMATARR array still holds the entry for   >>           03735000
<< the job just scheduled.                                 >>           03740000
   WRITEDSEG(JMATDST);                                                  03745000
   TOS := JMATJINDEV;                                                   03750000
   GENMSG(SYSSET,SCHEDJOBARRIVED,%10000,S0,,,,,0);                      03755000
   DEL;                                                                 03760000
                                                                        03765000
   DISABLE;                                                             03770000
   ABSYS'JOBSYNC.(JOBREADY'F) := TRUE;                                  03775000
   ENABLE;                                                              03780000
   AWAKE (SYSPROC(UCOPLPIN),JUNKWAIT,0);                                03785000
                                                                        03790000
   RELSIR (JMATSIR, SAVESIR);                                           03795000
                                                                        03800000
   END;    <<SCHEDULESCHED>>                                            03805000
$PAGE "TIMEPARMS:  Parses the time specifying parms"           <<*8942>>03810000
<< TIMEPARMS:  Parses STREAM's time specifying parms.    >>    <<*8942>>03815000
                                                                        03820000
PROCEDURE TIMEPARMS( STRING, TIME, ERROR, PRINTERROR );                 03825000
   VALUE   PRINTERROR;                                                  03830000
   LOGICAL PRINTERROR;                                                  03835000
   BYTE ARRAY STRING;                                                   03840000
   LOGICAL ARRAY TIME;                                                  03845000
   INTEGER ERROR;                                                       03850000
OPTION PRIVILEGED, UNCALLABLE;                                          03855000
BEGIN                                                                   03860000
                                                                        03865000
<<*********************************************************>>           03870000
<<                                                         >>           03875000
<< TIMEPARMS:  This procedure parses the information in    >>           03880000
<< STRING and returns either a syntax error number in      >>           03885000
<< ERROR or an absolute time specification in the three    >>           03890000
<< word array TIME.  The TIME array will be returned with  >>  <<*8942>>03895000
<< all zeroes if STRING is empty or if it specifies a time >>  <<*8942>>03900000
<< earlier or at the current time.  PRINTERROR indicates   >>  <<*8942>>03905000
<< whether error messages (via a call to CIERR) are to be  >>  <<*8942>>03910000
<< printed.                                                >>  <<*8942>>03915000
<<                                                         >>           03920000
<< The expected syntax in STRING is as follows:            >>           03925000
<<                                                         >>           03930000
<<     [;AT=hh,mm]                                         >>           03935000
<<     [;DAY= {DOW|DOM|DEM}   | ;DATE=mm/dd/yy ]           >>           03940000
<<                      or                                 >>           03945000
<<     [;IN=[days] [, [hours] [, minutes] ] ]              >>           03950000
<<                                                         >>           03955000
<< The end of the STRING is delimited by a carriage        >>           03960000
<< return.  IN cannot be specified with any other keyword. >>           03965000
<< Both DAY and DATE cannot be specified.                  >>           03970000
<<                                                         >>           03975000
<< TIME has a standard format that is used throughout the  >>           03980000
<< Job Scheduling code.  It is as follows:                 >>           03985000
<<                                                         >>           03990000
<<        +-----------------------------------------+      >>           03995000
<< Word 0 | Year of Centry  |    Day of Year        |      >>           04000000
<<        +-----------------------------------------+      >>           04005000
<< Word 1 |  Hour of Day      |   Minute of Hour    |      >>           04010000
<<        +-----------------------------------------+      >>           04015000
<< Word 2 |    Seconds        |  Tenths of Seconds  |      >>           04020000
<<        +-----------------------------------------+      >>           04025000
<<        0                 7  8                   15      >>           04030000
<<                                                         >>           04035000
<< There are several routines available for manipulating   >>           04040000
<< these TIME specification values.                        >>           04045000
<<                                                         >>           04050000
<<*********************************************************>>           04055000
$PAGE                                                                   04060000
                                                                        04065000
BYTE ARRAY KEYWORDS(0:1)=PB:=   << Known syntax keywords.  >>           04070000
     4, 2, "AT",                << Will be used with the   >>           04075000
     5, 3, "DAY",               << SEARCH intrinsic.       >>           04080000
     6, 4, "DATE",                                                      04085000
     4, 2, "IN",                                                        04090000
     0;                                                                 04095000
EQUATE KEYWORDLEN = 20;         << Length of KEYWORDS list.>>           04100000
BYTE ARRAY                                                              04105000
     LOCALKEYS(0:KEYWORDLEN-1); << Local copy of KEYWORDS. >>           04110000
                                                                        04115000
INTEGER                                                                 04120000
   KEY;                                                                 04125000
                                                                        04130000
EQUATE                                                                  04135000
   MAXPARMS       = 20,         << Actually, less is the   >>           04140000
                                << limit, but check for    >>           04145000
                                << error reporting sake.   >>           04150000
   COMMA          = 0,          << Delimiter values return >>           04155000
   EQUALS         = 1,          <<    by MYCOMMAND.        >>           04160000
   SEMICOLON      = 2,                                                  04165000
   CR             = 3;                                                  04170000
                                                                        04175000
<< The following declarations are used with MYCOMMAND for  >>           04180000
<< the parsing of the command image parameters.            >>           04185000
DOUBLE ARRAY PARM(0:MAXPARMS-1) = Q;                                    04190000
INTEGER ARRAY PARM'I(*) = PARM;                                         04195000
                                                                        04200000
BYTE POINTER CURRENTPARM;                                               04205000
                                                                        04210000
LOGICAL ARRAY                                                           04215000
   LOCERROR'(0:1);                                                      04220000
                                                                        04225000
INTEGER                                                                 04230000
   LOCERROR = LOCERROR',                                                04235000
   I,                                                                   04240000
   NUMPARMS := 0,                                                       04245000
   CURRENTLEN,                                                          04250000
   CURRENTDELIMITER,                                                    04255000
   FILENAMELEN,                                                         04260000
   PNUM;                                                                04265000
                                                                        04270000
LOGICAL                                                                 04275000
   DONE;      << Local loop flag. >>                                    04280000
                                                                        04285000
                                                                        04290000
<< The following logicals keep track of the amount of      >>           04295000
<< parsing already done.                                   >>           04300000
LOGICAL                                                                 04305000
   ATSEEN    := FALSE,                                                  04310000
   DAYSEEN   := FALSE,                                                  04315000
   DATESEEN  := FALSE,                                                  04320000
   INSEEN    := FALSE;                                                  04325000
                                                                        04330000
<< The following variables are used to specify the current >>           04335000
<< day and time to be used in resolving user's specs.      >>           04340000
LOGICAL ARRAY                                                  <<*8942>>04345000
   CURRTIME(0:2) = Q;                                          <<*8942>>04350000
                                                               <<*8942>>04355000
DOUBLE                                                         <<*8942>>04360000
   CURRCLOCK     = CURRTIME + 1;                               <<*8942>>04365000
                                                               <<*8942>>04370000
                                                                        04375000
INTEGER                                                                 04380000
   CURRCAL       = CURRTIME,                                   <<*8942>>04385000
   CURRCLOCK'0   = CURRCLOCK,                                           04390000
   CURRYEAR      := 0,                                                  04395000
   CURRMONTH     := 0,                                                  04400000
   CURRDAY       := 0,                                                  04405000
   CURRWEEKDAY   := 0,                                                  04410000
   CURRHOUR      := 0,                                                  04415000
   CURRMIN       := 0,                                         <<*8942>>04420000
   COMPRETURN;                                                 <<*8942>>04425000
                                                                        04430000
INTEGER                                                                 04435000
   HHSPEC        := 0,                                                  04440000
   MMSPEC        := 0,                                                  04445000
   DOWSPEC       := -1,       << -1 is an illegal value.   >>           04450000
   DOMSPEC,                                                             04455000
   DEMSPEC,                                                             04460000
   DOYSPEC       := 0,                                                  04465000
   MONTHSPEC,                                                           04470000
   YEARSPEC      := 0;                                                  04475000
                                                                        04480000
LOGICAL                                                                 04485000
   ISTODAY,            << Indicates user time specs is the >>           04490000
                       << current day.                     >>           04495000
   NEXTDAY := FALSE,   << This indicates that the time     >>           04500000
                       << specified by "AT" will fall next >>           04505000
                       << tommorrow.                       >>           04510000
   WEEKDAYSEEN         << This indicates that a weekday    >>           04515000
      := FALSE;        << specified by "DAY".  If that     >>           04520000
                       << weekday is the same as today and >>           04525000
                       << NEXTDAY is TRUE, then next week  >>           04530000
                       << is implied.                      >>           04535000
                                                                        04540000
<< The following DEFINEs are used to indicate the various  >>           04545000
<< parts of the TIME array.                                >>           04550000
DEFINE                                                                  04555000
   YEARPART   = 0).(0:7  #,                                             04560000
   DAYPART    = 0).(7:9  #,                                             04565000
   HOURPART   = 1).(0:8  #,                                             04570000
   MINPART    = 1).(8:8  #;                                             04575000
                                                                        04580000
<< The following declarations are used to examine months   >>           04585000
<< during parsing.                                         >>           04590000
EQUATE                                                                  04595000
   JANUARY    = 1,                                                      04600000
   FEBRUARY   = 2,                                                      04605000
   MARCH      = 3,                                                      04610000
   APRIL      = 4,                                                      04615000
   MAY        = 5,                                                      04620000
   JUNE       = 6,                                                      04625000
   JULY       = 7,                                                      04630000
   AUGUST     = 8,                                                      04635000
   SEPTEMBER  = 9,                                                      04640000
   OCTOBER    = 10,                                                     04645000
   NOVEMBER   = 11,                                                     04650000
   DECEMBER   = 12;                                                     04655000
                                                                        04660000
DEFINE                                                                  04665000
   LEAP'YEAR                                                            04670000
      = ( ( YEARSPEC MOD 4 = 0    ) LAND                                04675000
          ( YEARSPEC MOD 100 <> 0 )      ) #,                           04680000
                                                                        04685000
   FEB'IN'LEAP                                                          04690000
      = ( ( MONTHSPEC = FEBRUARY  ) LAND                                04695000
          LEAP'YEAR                      ) #,                           04700000
                                                                        04705000
   LEAPYEARADJ                                                          04710000
      = ( IF FEB'IN'LEAP THEN 1 ELSE 0   ) #;                           04715000
                                                                        04720000
INTEGER ARRAY                                                           04725000
   DAYS'PER'MONTH(1:12);                                                04730000
                                                                        04735000
                                                                        04740000
<< The following declarations are used for parsing the     >>           04745000
<< weekday names that can be specified as part of "DAY".   >>           04750000
BYTE ARRAY WEEKDAY'FULL'NAMES(0:1) = PB :=                              04755000
      8, 6, "SUNDAY",                                                   04760000
      8, 6, "MONDAY",                                                   04765000
      9, 7, "TUESDAY",                                                  04770000
     11, 9, "WEDNESDAY",                                                04775000
     10, 8, "THURSDAY",                                                 04780000
      8, 6, "FRIDAY",                                                   04785000
     10, 8, "SATURDAY",                                                 04790000
      0;                                                                04795000
EQUATE FULLNAMELEN = 65;                                                04800000
                                                                        04805000
BYTE ARRAY WEEKDAY'ABBR(0:1) = PB :=                                    04810000
      5, 3, "SUN",                                                      04815000
      5, 3, "MON",                                                      04820000
      5, 3, "TUE",                                                      04825000
      5, 3, "WED",                                                      04830000
      5, 3, "THU",                                                      04835000
      5, 3, "FRI",                                                      04840000
      5, 3, "SAT",                                                      04845000
      0;                                                                04850000
EQUATE ABBRLEN = 36;                                                    04855000
                                                                        04860000
BYTE ARRAY                                                              04865000
   SEARCH'ARRAY(0:FULLNAMELEN-1);                                       04870000
                                                                        04875000
EQUATE                                                                  04880000
   UNKNOWN'WEEKDAY   = 0,                                               04885000
   SUNDAY            = 1,                                               04890000
   MONDAY            = 2,                                               04895000
   TUESDAY           = 3,                                               04900000
   WEDNESDAY         = 4,                                               04905000
   THURSDAY          = 5,                                               04910000
   FRIDAY            = 6,                                               04915000
   SATURDAY          = 7;                                               04920000
                                                                        04925000
                                                                        04930000
<< The following declarations are used to do some sub-     >>           04935000
<< parsing of the DATE and AT keyworded parameters.        >>           04940000
BYTE ARRAY EXTRADELIMS (0:7);                                           04945000
DOUBLE ARRAY EXTRAPARMS(0:4) = Q;                                       04950000
INTEGER ARRAY EXTRA'P'I(*) = EXTRAPARMS;                                04955000
INTEGER NUMEXTRAPARMS := 0;                                             04960000
BYTE POINTER                                                            04965000
   ATHOUR,                                                              04970000
   ATMIN,                                                               04975000
   DATEMONTH,                                                           04980000
   DATEDAY,                                                             04985000
   DATEYEAR;                                                            04990000
                                                                        04995000
DEFINE                                                                  05000000
   ATHOURLEN      = EXTRA'P'I(1).(0:8)  #,                              05005000
   ATHOURDELIM    = EXTRA'P'I(1).(11:5) #,                              05010000
   ATMINLEN       = EXTRA'P'I(3).(0:8)  #,                              05015000
   ATMINDELIM     = EXTRA'P'I(3).(11:5) #,                              05020000
   DATEMONTHLEN   = EXTRA'P'I(1).(0:8)  #,                              05025000
   DATEMONTHDELIM = EXTRA'P'I(1).(11:5) #,                              05030000
   DATEDAYLEN     = EXTRA'P'I(3).(0:8)  #,                              05035000
   DATEDAYDELIM   = EXTRA'P'I(3).(11:5) #,                              05040000
   DATEYEARLEN    = EXTRA'P'I(5).(0:8)  #,                              05045000
   DATEYEARDELIM  = EXTRA'P'I(5).(11:5) #;                              05050000
                                                                        05055000
DEFINE                                                                  05060000
   ATDELIMS       = ",=; : " #,                                         05065000
   DATEDELIMS     = ",=; / " #;                                         05070000
                                                                        05075000
EQUATE                                                                  05080000
   COLON   = 4,  << Delimiter position. >>                              05085000
   SLASH   = 4;  << Delimiter position. >>                              05090000
                                                                        05095000
EQUATE                                                         <<*8942>>05100000
   T1'EQ'T2 = 0;                                               <<*8942>>05105000
                                                                        05110000
INTRINSIC                                                               05115000
   CALENDAR, CLOCK, BINARY, MYCOMMAND, SEARCH;                          05120000
                                                                        05125000
                                                                        05130000
$PAGE                                                                   05135000
INTEGER SUBROUTINE CONVERTSPECS;                                        05140000
BEGIN                                                                   05145000
                                                                        05150000
<<*********************************************************>>           05155000
<<                                                         >>           05160000
<< This subroutine is called after all the user parameters >>           05165000
<< have been parsed and the appropriate assignments to the >>           05170000
<< following variables have been made:  YEARSPEC, DOMSPEC, >>           05175000
<< MONTHSPEC, HHSPEC, MMSPEC, NEXTDAY, and WEEKDAYSEEN.    >>           05180000
<< NEXTDAY indicates that the time specified by "AT" is    >>           05185000
<< earlier in the day than the current time.  WEEKDAYSEEN  >>           05190000
<< indicates that the specification to the "DAY" parameter >>           05195000
<< was a weekday name.  These are used to adjust the       >>           05200000
<< values for YEARSPEC, MONTHSPEC, and DOMSPEC if it is    >>           05205000
<< appropriate.  Note that if "DATE" is used to specify    >>           05210000
<< the current day or if another specification of "DAY"    >>           05215000
<< indicates the current day, an illegal specification has >>           05220000
<< occurred.                                               >>           05225000
<<                                                         >>           05230000
<<*********************************************************>>           05235000
                                                                        05240000
   CONVERTSPECS := 0;                                                   05245000
   IF   ( CURRYEAR = YEARSPEC )   LAND                                  05250000
        ( CURRMONTH = MONTHSPEC ) LAND                                  05255000
        ( CURRDAY = DOMSPEC )                                           05260000
      THEN  ISTODAY := TRUE                                             05265000
      ELSE  ISTODAY := FALSE;                                           05270000
                                                                        05275000
<< If the time specified by "AT" will not next fall in the >>           05280000
<< current day, then adjust the day specification if it is >>           05285000
<< appropriate.                                            >>           05290000
   IF NEXTDAY LAND ISTODAY THEN                                         05295000
   BEGIN                                                                05300000
      IF DATESEEN         LOR                                           05305000
         (DAYSEEN LAND (NOT WEEKDAYSEEN)) THEN                          05310000
      BEGIN                                                             05315000
         CONVERTSPECS := SCHEDSPECBEFORENOW;                            05320000
         RETURN;                                                        05325000
      END;                                                              05330000
      IF WEEKDAYSEEN                                                    05335000
         THEN DOMSPEC := DOMSPEC + 7                                    05340000
         ELSE DOMSPEC := DOMSPEC + 1;                                   05345000
      IF DOMSPEC > DAYS'PER'MONTH( MONTHSPEC ) THEN                     05350000
      BEGIN                                                             05355000
         IF FEB'IN'LEAP                                                 05360000
            THEN DOMSPEC := DOMSPEC - 29                                05365000
            ELSE DOMSPEC                                                05370000
                   := DOMSPEC - DAYS'PER'MONTH( MONTHSPEC );            05375000
         IF MONTHSPEC = DECEMBER THEN                                   05380000
         BEGIN                                                          05385000
            MONTHSPEC := JANUARY;                                       05390000
            YEARSPEC := YEARSPEC + 1;                                   05395000
         END                                                            05400000
         ELSE MONTHSPEC := MONTHSPEC + 1;                               05405000
      END;                                                              05410000
   END;                                                                 05415000
                                                                        05420000
<< Resolve the month, day, and year into day of year.      >>           05425000
   I := JANUARY - 1;                                                    05430000
   DOYSPEC := 0;                                                        05435000
   WHILE (I:=I+1) < MONTHSPEC                                           05440000
      DO IF (I = FEBRUARY) AND (LEAP'YEAR)                              05445000
            THEN DOYSPEC := DOYSPEC + 29                                05450000
            ELSE DOYSPEC := DOYSPEC + DAYS'PER'MONTH( I );              05455000
   DOYSPEC := DOYSPEC + DOMSPEC;                                        05460000
                                                                        05465000
<< Make the appropriate assignments to the parts of the    >>           05470000
<< time specifying data structure.                         >>           05475000
   TIME(0) := 0;                                                        05480000
   TIME(1) := 0;                                                        05485000
   TIME(2) := 0;                                                        05490000
   TIME(YEARPART)  := YEARSPEC;                                         05495000
   TIME(DAYPART)   := DOYSPEC;                                          05500000
   TIME(HOURPART)  := HHSPEC;                                           05505000
   TIME(MINPART)   := MMSPEC;                                           05510000
                                                                        05515000
END;  << CONVERTSPECS >>                                                05520000
$PAGE                                                                   05525000
                                                                        05530000
LOGICAL SUBROUTINE GETNEXTPARM;                                         05535000
BEGIN                                                                   05540000
                                                                        05545000
<<*********************************************************>>           05550000
<<                                                         >>           05555000
<< This subroutine sets the values of CURRENTPARM,         >>           05560000
<< CURRENTLEN, and CURRENTDELIMITER to the values implied  >>           05565000
<< by the next parameter in the command image.  If another >>           05570000
<< parameter is found, this routine returns TRUE, and if   >>           05575000
<< the previous parameter is the last one on the line, it  >>           05580000
<< returns false.  The value of PNUM always indicates the  >>           05585000
<< current parameter being examined.  Note that PNUM uses  >>           05590000
<< zero origin indexing.                                   >>           05595000
<<                                                         >>           05600000
<<*********************************************************>>           05605000
                                                                        05610000
   IF PNUM >= NUMPARMS THEN                                             05615000
   BEGIN                                                                05620000
                                                                        05625000
   << Current parameter is the last one in the command.    >>           05630000
      GETNEXTPARM := FALSE;                                             05635000
      RETURN;                                                           05640000
                                                                        05645000
   END;                                                                 05650000
                                                                        05655000
<< Assume that there is another parameter.  Set the        >>           05660000
<< various variables pointing to it.                       >>           05665000
   PNUM := PNUM + 1;                                                    05670000
   @CURRENTPARM := PARM'I(PNUM*2);                                      05675000
   CURRENTLEN := PARM'I(PNUM*2+1).(0:8);                                05680000
   CURRENTDELIMITER := PARM'I(PNUM*2+1).(11:5);                         05685000
   GETNEXTPARM := TRUE;                                                 05690000
                                                                        05695000
END;  << GETNEXTPARM >>                                                 05700000
$PAGE                                                                   05705000
                                                                        05710000
                                                                        05715000
INTEGER SUBROUTINE PROCESSAT;                                           05720000
BEGIN                                                                   05725000
                                                                        05730000
<<*********************************************************>>           05735000
<<                                                         >>           05740000
<< This subroutine processes the "AT" parameter.  The      >>           05745000
<< expected syntax is "HH:MM" where HH and MM are both     >>           05750000
<< numerals such that 0<=HH<=23 and 0<=MM<=59.  If no      >>           05755000
<< errors are detected, the functional return for this     >>           05760000
<< subroutine is zero, otherwise an positive return        >>           05765000
<< indicates an error was detected and a negative return   >>           05770000
<< indicates a warning was detected.  This routine does    >>           05775000
<< not call error message printing routines--that must be  >>           05780000
<< done by the caller to this routine.                     >>           05785000
<<                                                         >>           05790000
<< If no errors were detected, the correct values will be  >>           05795000
<< assigned to the following variables:  HHSPEC, MMSPEC,   >>           05800000
<< and NEXTDAY.  NEXTDAY is used to indicate that the      >>           05805000
<< specified time next falls in the next day, not the      >>           05810000
<< current day.                                            >>           05815000
<<                                                         >>           05820000
<< Since ":" is a non-standard delimiter, a special call   >>           05825000
<< to MYCOMMAND is made for the time specification parse.  >>           05830000
<<                                                         >>           05835000
<<*********************************************************>>           05840000
                                                                        05845000
                                                                        05850000
   PROCESSAT := 0;                                                      05855000
                                                                        05860000
   IF ATSEEN THEN     << "AT" redundantly specified.       >>           05865000
   BEGIN                                                                05870000
      PROCESSAT := SCHEDTOOMANYATS;                                     05875000
      RETURN;                                                           05880000
   END;                                                                 05885000
                                                                        05890000
   ATSEEN := TRUE;                                                      05895000
                                                                        05900000
   IF INSEEN THEN     << Can't specify "IN" and "AT" in    >>           05905000
   BEGIN              << same command invocation.          >>           05910000
      PROCESSAT := SCHEDHADBOTHABSANDREL;                               05915000
      RETURN;                                                           05920000
   END;                                                                 05925000
                                                                        05930000
<< Look for and process the "HH" parameter.                >>           05935000
   IF CURRENTDELIMITER <> EQUALS THEN                                   05940000
   BEGIN                                                                05945000
      PROCESSAT := SCHEDATWANTSEQ;                                      05950000
      RETURN;                                                           05955000
   END;                                                                 05960000
                                                                        05965000
   IF NOT GETNEXTPARM THEN                                              05970000
   BEGIN                                                                05975000
      PROCESSAT := SCHEDBADAT;                                          05980000
      RETURN;                                                           05985000
   END;                                                                 05990000
                                                                        05995000
   IF CURRENTLEN = 0 THEN                                               06000000
   BEGIN                                                                06005000
      PROCESSAT := SCHEDBADAT;                                          06010000
      RETURN;                                                           06015000
   END;                                                                 06020000
                                                                        06025000
   MOVE EXTRADELIMS := ATDELIMS;                                        06030000
   EXTRADELIMS(5) := %15;     << Carriage return. >>                    06035000
   MYCOMMAND( CURRENTPARM, EXTRADELIMS, 3, NUMEXTRAPARMS,               06040000
              EXTRAPARMS );                                             06045000
   @ATHOUR := EXTRA'P'I(0);                                             06050000
   @ATMIN  := EXTRA'P'I(2);                                             06055000
                                                                        06060000
   IF NUMEXTRAPARMS < 2 THEN                                            06065000
   BEGIN                                                                06070000
      PROCESSAT := SCHEDBADAT;                                          06075000
      RETURN;                                                           06080000
   END;                                                                 06085000
                                                                        06090000
   HHSPEC := BINARY( ATHOUR, ATHOURLEN );                               06095000
   IF <> THEN                                                           06100000
   BEGIN                                                                06105000
      PROCESSAT := SCHEDBADHHVAL;                                       06110000
      RETURN;                                                           06115000
   END;                                                                 06120000
                                                                        06125000
   IF NOT (0<=HHSPEC<=23) THEN                                          06130000
   BEGIN                                                                06135000
      PROCESSAT := SCHEDBADHHVAL;                                       06140000
      RETURN;                                                           06145000
   END;                                                                 06150000
                                                                        06155000
<< Look for and process the "MM" parameter.                >>           06160000
   IF ATHOURDELIM <> COLON THEN                                         06165000
   BEGIN                                                                06170000
      PROCESSAT := SCHEDNOHHMMCOLON;                                    06175000
      RETURN;                                                           06180000
   END;                                                                 06185000
                                                                        06190000
   MMSPEC := BINARY( ATMIN, ATMINLEN );                                 06195000
   IF <> THEN                                                           06200000
   BEGIN                                                                06205000
      PROCESSAT := SCHEDBADMMVAL;                                       06210000
      RETURN;                                                           06215000
   END;                                                                 06220000
                                                                        06225000
   IF NOT (0<=MMSPEC<=59) THEN                                          06230000
   BEGIN                                                                06235000
      PROCESSAT := SCHEDBADMMVAL;                                       06240000
      RETURN;                                                           06245000
   END;                                                                 06250000
                                                                        06255000
<< If we made it this far, then HHSPEC and MMSPEC contain  >>           06260000
<< legal values and we are done.  Note that later, it must >>           06265000
<< be resolved whether the specified time is in the        >>           06270000
<< current day or the next day, or whether the time        >>           06275000
<< specified is illegal.  If "DAY" is used to specify the  >>           06280000
<< current day by using either a positive or negative      >>           06285000
<< number, or if "DATE" was specified, and if the "AT"     >>           06290000
<< is earlier than the current time, the user's time       >>           06295000
<< specifications are illegal.  If "DAY" is a day-of-week  >>           06300000
<< specification, than next week is assumed.  The variable >>           06305000
<< NEXTDAY is used to resolve this issue later (in         >>           06310000
<< CONVERTSPECS).                                          >>           06315000
   IF ( MMSPEC + HHSPEC*60 ) >= ( CURRMIN + CURRHOUR*60 )               06320000
      THEN  NEXTDAY := FALSE                                            06325000
      ELSE  NEXTDAY := TRUE;                                            06330000
                                                                        06335000
                                                                        06340000
   PROCESSAT := 0;                                                      06345000
                                                                        06350000
END;  << PROCESSAT >>                                                   06355000
$PAGE                                                                   06360000
                                                                        06365000
                                                                        06370000
INTEGER SUBROUTINE PROCESSDAY;                                          06375000
BEGIN                                                                   06380000
                                                                        06385000
<<*********************************************************>>           06390000
<<                                                         >>           06395000
<< This subroutine processes the "DAY" parameter.  The     >>           06400000
<< expected syntax is complex:  if a number is specified,  >>           06405000
<< it represents the day of the month if it was positive   >>           06410000
<< or the day from the end of the month if it was negative.>>           06415000
<< A day of the week could also have been specified,       >>           06420000
<< either with a three-character abbreviation or with the  >>           06425000
<< weekday name spelled out.  This routine returns a zero  >>           06430000
<< if no errors were detected, a positive error number, or >>           06435000
<< a negative warning number.  This routine does not call  >>           06440000
<< error message printing routines--that must be done by   >>           06445000
<< the caller of this routine.                             >>           06450000
<<                                                         >>           06455000
<< Processing of DAY requires comparisons with the current >>           06460000
<< week and month.  It is assumed that the values in the   >>           06465000
<< variables CURRYEAR, CURRMONTH, CURRDAY, and CURRWEEKDAY >>           06470000
<< have been initialized.  If no errors were detected,     >>           06475000
<< this routine will assign the correct values to the      >>           06480000
<< following variables:  YEARSPEC, MONTHSPEC, and DOMSPEC. >>           06485000
<<                                                         >>           06490000
<<*********************************************************>>           06495000
                                                                        06500000
                                                                        06505000
   PROCESSDAY := 0;                                                     06510000
                                                                        06515000
   IF DAYSEEN THEN     << "DAY" redundantly specified.     >>           06520000
   BEGIN                                                                06525000
      PROCESSDAY := SCHEDTOOMANYDAYS;                                   06530000
      RETURN;                                                           06535000
   END;                                                                 06540000
                                                                        06545000
   IF DATESEEN THEN   << Can't specify both "DAY" and      >>           06550000
   BEGIN              << "DATE".                           >>           06555000
      PROCESSDAY := SCHEDHADBOTHDAYDATE;                                06560000
      RETURN;                                                           06565000
   END;                                                                 06570000
                                                                        06575000
   IF INSEEN THEN     << Can't specify "IN" and "DAY" in   >>           06580000
   BEGIN              << same command invocation.          >>           06585000
      PROCESSDAY := SCHEDHADBOTHABSANDREL;                              06590000
      RETURN;                                                           06595000
   END;                                                                 06600000
                                                                        06605000
   DAYSEEN := TRUE;                                                     06610000
                                                                        06615000
   IF CURRENTDELIMITER <> EQUALS THEN                                   06620000
   BEGIN                                                                06625000
      PROCESSDAY := SCHEDDAYWANTSEQ;                                    06630000
      RETURN;                                                           06635000
   END;                                                                 06640000
                                                                        06645000
   IF NOT GETNEXTPARM THEN                                              06650000
   BEGIN                                                                06655000
      PROCESSDAY := SCHEDNODAYSPEC;                                     06660000
      RETURN;                                                           06665000
   END;                                                                 06670000
                                                                        06675000
   IF CURRENTLEN = 0 THEN                                               06680000
   BEGIN                                                                06685000
      PROCESSDAY := SCHEDNODAYSPEC;                                     06690000
      RETURN;                                                           06695000
   END;                                                                 06700000
                                                                        06705000
<< Try first for either Day Of Month or Day From End Of    >>           06710000
<< Month specification.  It is easier to process.          >>           06715000
   DOMSPEC := BINARY( CURRENTPARM, CURRENTLEN );                        06720000
   IF = THEN        << Found a number.  Check its          >>           06725000
   BEGIN            << validity.                           >>           06730000
                                                                        06735000
   << Resolve the Day of Month (or Day From End of Month)  >>           06740000
   << specification to an absolute day and month.          >>           06745000
      IF DOMSPEC > 0 THEN    << Day of Month.              >>           06750000
      BEGIN                                                             06755000
         IF DOMSPEC >= CURRDAY                                          06760000
            THEN MONTHSPEC := CURRMONTH                                 06765000
            ELSE IF CURRMONTH = DECEMBER                                06770000
                    THEN MONTHSPEC := JANUARY                           06775000
                    ELSE MONTHSPEC := CURRMONTH + 1;                    06780000
         IF DOMSPEC > DAYS'PER'MONTH(MONTHSPEC) + LEAPYEARADJ           06785000
         THEN                                                           06790000
         BEGIN                                                          06795000
            PROCESSDAY := SCHEDDOMTOOBIG;                               06800000
            RETURN;                                                     06805000
         END;                                                           06810000
      END                                                               06815000
                                                                        06820000
      ELSE IF DOMSPEC = 0 THEN                                          06825000
      BEGIN                                                             06830000
         PROCESSDAY := SCHEDDOMZERO;                                    06835000
         RETURN;                                                        06840000
      END                                                               06845000
                                                                        06850000
      ELSE                   << Day From End of the Month. >>           06855000
      BEGIN                                                             06860000
         DEMSPEC := DOMSPEC + 1;   << Convert to zero      >>           06865000
                                   << origin indexing.     >>           06870000
         IF DAYS'PER'MONTH(CURRMONTH)+DEMSPEC >= CURRDAY                06875000
            THEN MONTHSPEC := CURRMONTH                                 06880000
            ELSE IF CURRMONTH = DECEMBER                                06885000
                    THEN MONTHSPEC := JANUARY                           06890000
                    ELSE MONTHSPEC := CURRMONTH + 1;                    06895000
         IF 1-DEMSPEC > DAYS'PER'MONTH(MONTHSPEC)+LEAPYEARADJ           06900000
         THEN                                                           06905000
         BEGIN                                                          06910000
            PROCESSDAY := SCHEDDEMTOOBIG;                               06915000
            RETURN;                                                     06920000
         END;                                                           06925000
         DOMSPEC := DAYS'PER'MONTH(MONTHSPEC) + DEMSPEC;                06930000
      END;                                                              06935000
                                                                        06940000
                                                                        06945000
   END                                                                  06950000
   ELSE                                                                 06955000
   BEGIN                                                                06960000
                                                                        06965000
   << "DAY" specification was not a numeral.  It could be  >>           06970000
   << day of the week specification.  Check both full      >>           06975000
   << names and abbreviations.                             >>           06980000
      MOVE SEARCH'ARRAY := WEEKDAY'FULL'NAMES,                          06985000
                           (FULLNAMELEN);                               06990000
      DOWSPEC := SEARCH( CURRENTPARM, CURRENTLEN,                       06995000
                          SEARCH'ARRAY );                               07000000
      IF DOWSPEC = UNKNOWN'WEEKDAY THEN                                 07005000
      BEGIN                                                             07010000
                                                                        07015000
      << Wasn't a full name, try a weekday abbreviation.   >>           07020000
         MOVE SEARCH'ARRAY := WEEKDAY'ABBR, (ABBRLEN);                  07025000
         DOWSPEC := SEARCH( CURRENTPARM, CURRENTLEN,                    07030000
                            SEARCH'ARRAY             );                 07035000
         IF DOWSPEC = UNKNOWN'WEEKDAY THEN                              07040000
         BEGIN                                                          07045000
            PROCESSDAY := SCHEDBADAYSPEC;                               07050000
            RETURN;                                                     07055000
         END;                                                           07060000
                                                                        07065000
      END;                                                              07070000
                                                                        07075000
   WEEKDAYSEEN := TRUE;                                        <<*8942>>07080000
                                                               <<*8942>>07085000
   << Got a legal day of the week.  Resolve it to be a     >>           07090000
   << month and day specification.                         >>           07095000
      IF DOWSPEC >= CURRWEEKDAY                                         07100000
         THEN DOMSPEC := CURRDAY + (DOWSPEC-CURRWEEKDAY)                07105000
         ELSE DOMSPEC := CURRDAY + (DOWSPEC-CURRWEEKDAY) + 7;           07110000
      IF DOMSPEC > DAYS'PER'MONTH( CURRMONTH ) THEN                     07115000
      BEGIN                                                             07120000
         IF CURRMONTH = DECEMBER                                        07125000
            THEN MONTHSPEC := JANUARY                                   07130000
            ELSE MONTHSPEC := CURRMONTH + 1;                            07135000
         DOMSPEC := DOMSPEC - DAYS'PER'MONTH( CURRMONTH );              07140000
      END;                                                              07145000
                                                                        07150000
   END;                                                                 07155000
                                                                        07160000
<< If we got this far, we have resolved the user's         >>           07165000
<< specifications to a month and day of the month.         >>           07170000
<< Adjust the year specification if wrapped around.        >>           07175000
   IF (CURRMONTH = DECEMBER ) AND ( MONTHSPEC = JANUARY )               07180000
      THEN YEARSPEC := CURRYEAR + 1                                     07185000
      ELSE YEARSPEC := CURRYEAR;                                        07190000
                                                                        07195000
END;  << PROCESSDAY >>                                                  07200000
$PAGE                                                                   07205000
                                                                        07210000
                                                                        07215000
                                                                        07220000
INTEGER SUBROUTINE PROCESSDATE;                                         07225000
BEGIN                                                                   07230000
                                                                        07235000
<<*********************************************************>>           07240000
<<                                                         >>           07245000
<< This subroutine processes the "DATE" parameter.  For    >>           07250000
<< now, the expected syntax is of the form, "MM/DD/YY".    >>           07255000
<< When the Native Language Support project is completed,  >>           07260000
<< the "Custom Date" formatting intrinsics will be used.   >>           07265000
<< This routine will return a zero if no errors were       >>           07270000
<< detected, a negative error number if a warning          >>           07275000
<< condition was detected, and a positive error number if  >>           07280000
<< an error is detected.  This routine does not call any   >>           07285000
<< error message printing routines--that must be done by   >>           07290000
<< the caller of this routine.                             >>           07295000
<<                                                         >>           07300000
<< If no errors were detected, this routine will assign    >>           07305000
<< the correct values to YEARSPEC, MONTHSPEC, and DOMSPEC. >>           07310000
<<                                                         >>           07315000
<<*********************************************************>>           07320000
                                                                        07325000
   PROCESSDATE := 0;                                                    07330000
                                                                        07335000
   IF DATESEEN THEN     << "DATE" redundantly specified.   >>           07340000
   BEGIN                                                                07345000
      PROCESSDATE := SCHEDTOOMANYDATES;                                 07350000
      RETURN;                                                           07355000
   END;                                                                 07360000
                                                                        07365000
   IF DAYSEEN THEN    << Can't specify both "DAY" and      >>           07370000
   BEGIN              << "DATE".                           >>           07375000
      PROCESSDATE := SCHEDHADBOTHDAYDATE;                               07380000
      RETURN;                                                           07385000
   END;                                                                 07390000
                                                                        07395000
   IF INSEEN THEN     << Can't specify "IN" and "DATE" in  >>           07400000
   BEGIN              << same command invocation.          >>           07405000
      PROCESSDATE := SCHEDHADBOTHABSANDREL;                             07410000
      RETURN;                                                           07415000
   END;                                                                 07420000
                                                                        07425000
   DATESEEN := TRUE;                                                    07430000
                                                                        07435000
   IF CURRENTDELIMITER <> EQUALS THEN                                   07440000
   BEGIN                                                                07445000
      PROCESSDATE := SCHEDNOEQSAFTERDATE;                               07450000
      RETURN;                                                           07455000
   END;                                                                 07460000
                                                                        07465000
   IF NOT GETNEXTPARM THEN                                              07470000
   BEGIN                                                                07475000
      PROCESSDATE := SCHEDNODATESPEC;                                   07480000
      RETURN;                                                           07485000
   END;                                                                 07490000
                                                                        07495000
   IF CURRENTLEN = 0 THEN                                               07500000
   BEGIN                                                                07505000
      PROCESSDATE := SCHEDNODATESPEC;                                   07510000
      RETURN;                                                           07515000
   END;                                                                 07520000
                                                                        07525000
<< A special call to MYCOMMAND is done here to use "/" as  >>           07530000
<< a delimiter in the parsing of the date specification.   >>           07535000
   MOVE EXTRADELIMS := DATEDELIMS;                                      07540000
   EXTRADELIMS(5) := %15;     << Carriage Return. >>                    07545000
   MYCOMMAND( CURRENTPARM, EXTRADELIMS, 4, NUMEXTRAPARMS,               07550000
              EXTRAPARMS );                                             07555000
   @DATEMONTH := EXTRA'P'I(0);                                          07560000
   @DATEDAY   := EXTRA'P'I(2);                                          07565000
   @DATEYEAR  := EXTRA'P'I(4);                                          07570000
                                                                        07575000
   IF NUMEXTRAPARMS < 3 THEN                                            07580000
   BEGIN                                                                07585000
      PROCESSDATE := SCHEDBADATE;                                       07590000
      RETURN;                                                           07595000
   END;                                                                 07600000
                                                                        07605000
   MONTHSPEC := BINARY( DATEMONTH, DATEMONTHLEN );                      07610000
   IF <> THEN                                                           07615000
   BEGIN                                                                07620000
      PROCESSDATE := SCHEDBADATEMONTH;                                  07625000
      RETURN;                                                           07630000
   END;                                                                 07635000
                                                                        07640000
   IF DATEMONTHDELIM <> SLASH THEN                                      07645000
   BEGIN                                                                07650000
      PROCESSDATE := SCHEDNOTSLASHINDATE;                               07655000
      RETURN;                                                           07660000
   END;                                                                 07665000
                                                                        07670000
   IF NOT ( JANUARY <= MONTHSPEC <= DECEMBER ) THEN                     07675000
   BEGIN                                                                07680000
      PROCESSDATE := SCHEDBADATEMONTH;                                  07685000
      RETURN;                                                           07690000
   END;                                                                 07695000
                                                                        07700000
   IF DATEDAYDELIM <> SLASH THEN                                        07705000
   BEGIN                                                                07710000
      PROCESSDATE := SCHEDNOTSLASHINDATE;                               07715000
      RETURN;                                                           07720000
   END;                                                                 07725000
                                                                        07730000
   DOMSPEC := BINARY( DATEDAY, DATEDAYLEN );                            07735000
   IF <> THEN                                                           07740000
   BEGIN                                                                07745000
      PROCESSDATE := SCHEDBADATEDAY;                                    07750000
      RETURN;                                                           07755000
   END;                                                                 07760000
                                                                        07765000
   YEARSPEC := BINARY( DATEYEAR, DATEYEARLEN );                         07770000
   IF <> THEN                                                           07775000
   BEGIN                                                                07780000
      PROCESSDATE := SCHEDBADATEYEAR;                                   07785000
      RETURN;                                                           07790000
   END;                                                                 07795000
                                                                        07800000
   IF NOT ( CURRYEAR <= YEARSPEC <= 99 ) THEN                           07805000
   BEGIN                                                                07810000
      PROCESSDATE := SCHEDBADATEYEAR;                                   07815000
      RETURN;                                                           07820000
   END;                                                                 07825000
                                                                        07830000
   IF NOT ( 1 <= DOMSPEC <= DAYS'PER'MONTH( MONTHSPEC ) )               07835000
   THEN                                                                 07840000
   BEGIN                                                                07845000
      IF NOT( (FEB'IN'LEAP)     LAND                                    07850000
              (DOMSPEC = 29)         )                                  07855000
      THEN                                                              07860000
      BEGIN                                                             07865000
         PROCESSDATE := SCHEDBADATEDAY;                                 07870000
         RETURN;                                                        07875000
      END;                                                              07880000
                                                                        07885000
   END;                                                                 07890000
                                                                        07895000
END;  << PROCESSDATE >>                                                 07900000
$PAGE                                                                   07905000
                                                                        07910000
                                                                        07915000
INTEGER SUBROUTINE PROCESSIN;                                           07920000
BEGIN                                                                   07925000
                                                                        07930000
<<*********************************************************>>           07935000
<<                                                         >>           07940000
<< This subroutine processes the "IN" parameter.  Its      >>           07945000
<< syntax is as follows:                                   >>           07950000
<<                                                         >>           07955000
<<      ;IN = [Days] [, [Hours] [, Minutes ] ] ]           >>           07960000
<<                                                         >>           07965000
<< "IN" cannot be specified with any other keyword parm.   >>           07970000
<< "IN" is used to specify a time relative to the current  >>           07975000
<< time--this subroutine assumes that the values in the    >>           07980000
<< "CURRxx" variables have been set to the current time.   >>           07985000
<< This routine returns a zero if no errors were detected, >>           07990000
<< a negative error number if a warning condition was      >>           07995000
<< detected, and a positive error number if an error       >>           08000000
<< condition was detected.  This routine does not print    >>           08005000
<< any error messages--that is the responsibility of the   >>           08010000
<< caller of this routine.                                 >>           08015000
<<                                                         >>           08020000
<< If no errors were detected, this routine will assign    >>           08025000
<< the correct values to the YEARSPEC, MONTHSPEC, DOMSPEC, >>           08030000
<< HHSPEC, and MMSPEC.  Note that NEXTDAY has already been >>           08035000
<< initialized to FALSE, so no extra processing will be    >>           08040000
<< done for it in CONVERTSPECS.                            >>           08045000
<<                                                         >>           08050000
<<*********************************************************>>           08055000
                                                                        08060000
                                                                        08065000
   PROCESSIN := 0;                                                      08070000
                                                                        08075000
   IF INSEEN THEN      << "IN" redundantly specified.      >>           08080000
   BEGIN                                                                08085000
      PROCESSIN := SCHEDTOOMANYINS;                                     08090000
      RETURN;                                                           08095000
   END;                                                                 08100000
                                                                        08105000
   IF DATESEEN OR DAYSEEN OR ATSEEN THEN                                08110000
   BEGIN               << Can't specify an absolute and    >>           08115000
                       << relative times.                  >>           08120000
      PROCESSIN := SCHEDHADBOTHABSANDREL;                               08125000
      RETURN;                                                           08130000
   END;                                                                 08135000
                                                                        08140000
   INSEEN := TRUE;                                                      08145000
                                                                        08150000
   IF CURRENTDELIMITER <> EQUALS THEN                                   08155000
   BEGIN                                                                08160000
      PROCESSIN := SCHEDINWANTSEQS;                                     08165000
      RETURN;                                                           08170000
   END;                                                                 08175000
                                                                        08180000
<< So far, so good.  Days, Hours, and Minutes are          >>           08185000
<< processed in turn.  Once they are all read in, they are >>           08190000
<< converted to absolute Month, Day, and Year specs.       >>           08195000
   IF NOT GETNEXTPARM THEN                                              08200000
   BEGIN                                                                08205000
      PROCESSIN := SCHEDINOPARMS;                                       08210000
      RETURN;                                                           08215000
   END;                                                                 08220000
                                                                        08225000
   DOMSPEC := 0;                                                        08230000
   HHSPEC  := 0;                                                        08235000
   MMSPEC  := 0;                                                        08240000
                                                                        08245000
   DOMSPEC := BINARY( CURRENTPARM, CURRENTLEN );                        08250000
   IF <> THEN                                                           08255000
   BEGIN                                                                08260000
      PROCESSIN := SCHEDINNODAY;                                        08265000
      RETURN;                                                           08270000
   END;                                                                 08275000
                                                                        08280000
   IF CURRENTDELIMITER = COMMA THEN                                     08285000
   BEGIN                                                                08290000
                                                                        08295000
      IF NOT GETNEXTPARM THEN                                           08300000
      BEGIN                                                             08305000
         PROCESSIN := SCHEDINNOHOURS;                                   08310000
         RETURN;                                                        08315000
      END;                                                              08320000
                                                                        08325000
      HHSPEC := BINARY( CURRENTPARM, CURRENTLEN );                      08330000
      IF <> THEN                                                        08335000
      BEGIN                                                             08340000
         PROCESSIN := SCHEDINNOHOURS;                                   08345000
         RETURN;                                                        08350000
      END;                                                              08355000
                                                                        08360000
      IF CURRENTDELIMITER = COMMA THEN                                  08365000
      BEGIN                                                             08370000
                                                                        08375000
         IF NOT GETNEXTPARM THEN                                        08380000
         BEGIN                                                          08385000
            PROCESSIN := SCHEDINNOMINS;                                 08390000
            RETURN;                                                     08395000
         END;                                                           08400000
                                                                        08405000
         MMSPEC := BINARY( CURRENTPARM, CURRENTLEN );                   08410000
         IF <> THEN                                                     08415000
         BEGIN                                                          08420000
            PROCESSIN := SCHEDINNOMINS;                                 08425000
            RETURN;                                                     08430000
         END;                                                           08435000
                                                                        08440000
      END;  << Minutes >>                                               08445000
                                                                        08450000
   END;  << Hours >>                                                    08455000
                                                                        08460000
<< Right now, the "xxSPEC" variables contain the user      >>           08465000
<< specified values.  Negative specifications, here are    >>           08470000
<< not valid.  Check these values, and if no errors are    >>           08475000
<< found, convert them to absolute specifications.         >>           08480000
   IF DOMSPEC < 0 THEN                                                  08485000
   BEGIN                                                                08490000
      PROCESSIN := SCHEDINEGDOM;                                        08495000
      RETURN;                                                           08500000
   END;                                                                 08505000
   IF HHSPEC < 0 THEN                                                   08510000
   BEGIN                                                                08515000
      PROCESSIN := SCHEDINEGHH;                                         08520000
      RETURN;                                                           08525000
   END;                                                                 08530000
   IF MMSPEC < 0 THEN                                                   08535000
   BEGIN                                                                08540000
      PROCESSIN := SCHEDINEGMM;                                         08545000
      RETURN;                                                           08550000
   END;                                                                 08555000
                                                                        08560000
   MMSPEC := MMSPEC + CURRMIN;                                          08565000
   HHSPEC := HHSPEC + CURRHOUR;                                         08570000
   DOMSPEC := DOMSPEC + CURRDAY;                                        08575000
   MONTHSPEC := CURRMONTH;                                              08580000
   YEARSPEC := CURRYEAR;                                                08585000
   WHILE MMSPEC > 59 DO                                                 08590000
   BEGIN                                                                08595000
      MMSPEC := MMSPEC - 60;                                            08600000
      HHSPEC := HHSPEC + 1;                                             08605000
   END;                                                                 08610000
   WHILE HHSPEC > 23 DO                                                 08615000
   BEGIN                                                                08620000
      HHSPEC := HHSPEC - 24;                                            08625000
      DOMSPEC := DOMSPEC + 1;                                           08630000
   END;                                                                 08635000
   WHILE (DOMSPEC > DAYS'PER'MONTH( MONTHSPEC ) ) LOR                   08640000
         ((FEB'IN'LEAP)                           LAND                  08645000
          (DOMSPEC>29)                                ) DO              08650000
   BEGIN                                                                08655000
      IF FEB'IN'LEAP                                                    08660000
         THEN DOMSPEC := DOMSPEC - 29                                   08665000
         ELSE DOMSPEC := DOMSPEC - DAYS'PER'MONTH(MONTHSPEC);           08670000
      MONTHSPEC := MONTHSPEC + 1;                                       08675000
      IF MONTHSPEC > DECEMBER THEN                                      08680000
      BEGIN                                                             08685000
         MONTHSPEC := JANUARY;                                          08690000
         YEARSPEC := YEARSPEC + 1;                                      08695000
      END;                                                              08700000
   END;                                                                 08705000
                                                                        08710000
END;  << PROCESSIN >>                                                   08715000
$PAGE                                                                   08720000
                                                                        08725000
                                                                        08730000
                                                                        08735000
<<*********************************************************>>           08740000
<<                                                         >>           08745000
<< Start of Main Code for TIMEPARMS.                       >>           08750000
<<                                                         >>           08755000
<<*********************************************************>>           08760000
                                                                        08765000
                                                                        08770000
<< Initialize the DAYS'PER'MONTH values.                   >>           08775000
   DAYS'PER'MONTH( JANUARY   )  := 31;                                  08780000
   DAYS'PER'MONTH( FEBRUARY  )  := 28;                                  08785000
   DAYS'PER'MONTH( MARCH     )  := 31;                                  08790000
   DAYS'PER'MONTH( APRIL     )  := 30;                                  08795000
   DAYS'PER'MONTH( MAY       )  := 31;                                  08800000
   DAYS'PER'MONTH( JUNE      )  := 30;                                  08805000
   DAYS'PER'MONTH( JULY      )  := 31;                                  08810000
   DAYS'PER'MONTH( AUGUST    )  := 31;                                  08815000
   DAYS'PER'MONTH( SEPTEMBER )  := 30;                                  08820000
   DAYS'PER'MONTH( OCTOBER   )  := 31;                                  08825000
   DAYS'PER'MONTH( NOVEMBER  )  := 30;                                  08830000
   DAYS'PER'MONTH( DECEMBER  )  := 31;                                  08835000
                                                                        08840000
<< Set up the parsing by examining the input string and    >>           08845000
<< initializing the various return values.  Note that the  >>           08850000
<< current time and date are the default values for the    >>           08855000
<< user's specifications.  However, if the user doesn't    >>  <<*8942>>08860000
<< specify a time, then all zeroes are returned.           >>  <<*8942>>08865000
   MYCOMMAND( STRING, , MAXPARMS, NUMPARMS, PARM );                     08870000
   CURRCAL := CALENDAR;                                                 08875000
   CURRCLOCK := CLOCK;                                                  08880000
   ALMANAC( CURRCAL, LOCERROR', CURRYEAR, CURRMONTH, CURRDAY,           08885000
            CURRWEEKDAY );                                              08890000
                                                                        08895000
   CURRHOUR := CURRCLOCK'0.(0:8);                                       08900000
   CURRMIN := CURRCLOCK'0.(8:8);                                        08905000
   HHSPEC := CURRHOUR;                                                  08910000
   MMSPEC := CURRMIN;                                                   08915000
   MONTHSPEC := CURRMONTH;                                              08920000
   DOMSPEC := CURRDAY;                                                  08925000
   YEARSPEC := CURRYEAR;                                                08930000
   MOVE TIME := 3(0);                                                   08935000
   ERROR := 0;                                                          08940000
                                                                        08945000
   IF NUMPARMS <> 0 THEN                                       <<*8942>>08950000
   BEGIN                                                       <<*8942>>08955000
                                                               <<*8942>>08960000
   << Initialize the parameter pointer by setting PNUM to   >>          08965000
   << minus one.  This way, GETNEXTPARM will get the PNUM+1 >>          08970000
   << parameter.  Process each of the present keywords.     >>          08975000
      PNUM := -1;                                                       08980000
      MOVE LOCALKEYS := KEYWORDS, (KEYWORDLEN);                         08985000
      DONE := FALSE;                                                    08990000
      GETNEXTPARM;                                             <<*8942>>08995000
                                                                        09000000
      WHILE NOT DONE DO                                                 09005000
      BEGIN                                                             09010000
                                                                        09015000
      << Process this particular keyword.                   >>          09020000
         KEY := SEARCH( CURRENTPARM, CURRENTLEN, LOCALKEYS );           09025000
         CASE KEY OF                                                    09030000
         BEGIN                                                          09035000
                                                                        09040000
         << Unknown >>                                                  09045000
            ERROR := SCHEDUNKNOWNKEY;                                   09050000
                                                                        09055000
         << AT >>                                                       09060000
            ERROR := PROCESSAT;                                         09065000
                                                                        09070000
         << DAY >>                                                      09075000
            ERROR := PROCESSDAY;                                        09080000
                                                                        09085000
         << DATE >>                                                     09090000
            ERROR := PROCESSDATE;                                       09095000
                                                                        09100000
         << IN >>                                                       09105000
            ERROR := PROCESSIN;                                         09110000
                                                                        09115000
         END;  << CASE statement >>                                     09120000
                                                                        09125000
      << Handle any detected errors.                        >>          09130000
         IF ERROR <> 0 THEN                                             09135000
         BEGIN                                                          09140000
            IF PRINTERROR                                               09145000
               THEN CIERR( ERROR, CURRENTPARM );                        09150000
            IF ERROR > 0 THEN RETURN;                                   09155000
         END;                                                           09160000
                                                                        09165000
      << Each of the "PROCESSxx" subroutines should leave   >>          09170000
      << CURRENTPARM at the last parameter for this keyword.>>          09175000
      << If there are still other keywords, process them.   >>          09180000
         IF CURRENTDELIMITER = CR                                       09185000
            THEN DONE := TRUE                                           09190000
         ELSE IF CURRENTDELIMITER <> SEMICOLON THEN                     09195000
         BEGIN                                                          09200000
            GETNEXTPARM;                                       <<*8942>>09205000
            ERROR := SCHEDNOSEMI;                                       09210000
            DONE := TRUE;                                               09215000
         END                                                            09220000
         ELSE IF NOT GETNEXTPARM                                        09225000
            THEN DONE := TRUE;                                          09230000
                                                                        09235000
      END;  << WHILE loop that processes keywords. >>                   09240000
                                                                        09245000
   << Handle any remaining errors . >>                         <<*8942>>09250000
      IF ERROR <> 0 THEN                                       <<*8942>>09255000
      BEGIN                                                    <<*8942>>09260000
         IF PRINTERROR THEN CIERR( ERROR, CURRENTPARM );       <<*8942>>09265000
         IF ERROR > 0 THEN RETURN;                             <<*8942>>09270000
      END;                                                     <<*8942>>09275000
                                                               <<*8942>>09280000
   << Finally, convert the user specifications into the    >>  <<*8942>>09285000
   << machine internal format.  If the parsed time is less >>  <<*8942>>09290000
   << than the current time, then let the user know and    >>  <<*8942>>09295000
   << zero the TIME array.                                 >>  <<*8942>>09300000
                                                               <<*8942>>09305000
      ERROR := CONVERTSPECS;                                   <<*8942>>09310000
      IF ERROR = 0 THEN                                        <<*8942>>09315000
      BEGIN                                                    <<*8942>>09320000
                                                               <<*8942>>09325000
         COMPRETURN := COMPTIME( TIME, CURRTIME );             <<*8942>>09330000
         IF COMPRETURN <= T1'EQ'T2 THEN                        <<*8942>>09335000
         BEGIN                                                 <<*8942>>09340000
            MOVE TIME := 3(0);                                 <<*8942>>09345000
            ERROR := -SCHEDTOOEARLY;                           <<*8942>>09350000
         END;                                                  <<*8942>>09355000
                                                               <<*8942>>09360000
      END;                                                     <<*8942>>09365000
                                                               <<*8942>>09370000
      IF ERROR <> 0 AND PRINTERROR THEN                        <<*8942>>09375000
         CIERR( ERROR );                                       <<*8942>>09380000
                                                               <<*8942>>09385000
   END;   << of NUMPARMS <> 0 >>                               <<*8942>>09390000
                                                                        09395000
END;  << TIMEPARMS >>                                                   09400000
$PAGE                                                                   09405000
$CONTROL SEGMENT=OB'                                                    09410000
END.                                                                    09415000
