EXTERNAL progname::date;

{       This is a complete collection of the various date routines,
       set up for separate compilation under Pascal/Z, ver 3.2 or
       later.

       DATE.LIB contains the necessary subprogram calls for inclusion
       in the main program.

       Note that <progname> has to be substituted with the name of the
       main program to be separately compiled.

       The following global declarations must be made in the main
       program:
               TYPE    string0 = string 0;
                       string255 = string 255;
                       byte = 0..255;
               PROCEDURE setlength;
               FUNCTION length;
}

PROCEDURE prompt (msg : string255);

CONST   msglength = 12; { should be longer than longest message }
       leader = '.';   { could be a space if desire }
       endprompt = ' =>  ';

VAR     count : integer;
       esc : char;

begin
       append (msg,' ');
       if length(msg) < msglength then
               for count := succ(length(msg)) to msglength do
                       append (msg,leader);
       write (msg,endprompt)
end;

PROCEDURE getdate (msg : string255; VAR mo, da, yr : byte);

CONST   yrspan = 89;
       yrbase = 10;

VAR     ch : char;
       good : boolean;
       temp : integer;

begin
       repeat
               good := true;
               prompt (msg);
               readln (mo,ch,da,ch,temp);
               temp := temp mod 100 - yrbase;
               if (da < 1) or (da > 31) or (mo < 1) or (mo >12)
                       or (temp < 0) or (temp > yrspan) then
                       begin
                               good := false;
                               writeln (' *** Bad date ***')
                       end
       until good;
       yr := temp
end;

FUNCTION makedate (msg : string255) : integer;

CONST   yrbase = 10;

VAR     days : integer;
       da, mo, yr : byte;
       str : string255;

begin
       getdate (msg,mo,da,yr);
       case mo of
               1 : days := 0;
               2 : days := 31;
               3 : days := 59;
               4 : days := 90;
               5 : days := 120;
               6 : days := 151;
               7 : days := 181;
               8 : days := 212;
               9 : days := 243;
               10 : days := 273;
               11 : days := 304;
               12 : days := 334;
               end;
       days := days + (yr*365) + (yr div 4) + da;
       if ((yr + yrbase) mod 4 = 0) and (mo > 2) then days := days + 1;
       makedate := days
end;

PROCEDURE rgetdate (msg : string255; minyr, maxyr : byte;
                       VAR mo, da, yr : byte);

CONST   yrspan = 89;
       yrbase = 10;

VAR     ch : char;
       good : boolean;
       temp : integer;

begin
       repeat
               good := true;
               prompt (msg);
               readln (mo,ch,da,ch,temp);
               temp := temp mod 100;
               if (da < 1) or (da > 31) or (mo < 1) or (mo >12)
                       or (temp < minyr) or (temp > maxyr) then
                       begin
                               good := false;
                               writeln (' *** Bad date ***')
                       end
       until good;
       yr := temp - yrbase
end;

FUNCTION rmakedate (msg : string255; minyr, maxyr : byte) : integer;

CONST   yrbase = 10;

VAR     days : integer;
       da, mo, yr : byte;
       str : string255;

begin
       rgetdate (msg,minyr,maxyr,mo,da,yr);
       case mo of
               1 : days := 0;
               2 : days := 31;
               3 : days := 59;
               4 : days := 90;
               5 : days := 120;
               6 : days := 151;
               7 : days := 181;
               8 : days := 212;
               9 : days := 243;
               10 : days := 273;
               11 : days := 304;
               12 : days := 334;
               end;
       days := days + (yr*365) + (yr div 4) + da;
       if ((yr + yrbase) mod 4 = 0) and (mo > 2) then days := days + 1;
       rmakedate := days
end;

PROCEDURE brkdate (days : integer; VAR mo, da, yr, weekday : byte);

CONST   yrbase = 10;
       yrfix = yrbase - 1;

VAR     data, temp, adjust, yradj : integer;

begin
       adjust := 1 + yrfix mod 4 + (((yrfix mod 28) div 4) * 5);
       yradj := (yrbase mod 4) * 365;
       weekday := (days + adjust) mod 7;
       data := trunc((days + yradj) / 365.25) - yrbase mod 4;
       yr := data + yrbase;
       temp := days - (365 * data) - (data + yrfix mod 4) div 4;
       mo := 0;
       data := 0;
       repeat
               if (data < temp) then
                       begin
                       mo := mo + 1;
                       temp := temp - data
                       end;
               case mo of
                       1,3,5,7,8,10,12 : data := 31;
                       4,6,9,11 : data := 30;
                       2 : if (yr mod 4 = 0) then data := 29
                               else data := 28
                       end
       until (data >= temp) or (mo = 12);
       da := temp
end;

FUNCTION dastrlong (days : integer; withday : boolean) : string255;

CONST   zero = 48;

VAR     day, mo, date, yr : byte;
       str, str2 : string255;

begin
       brkdate (days,mo,date,yr,day);
       if withday then
               begin
               case day of
                       0 : str := 'Sunday';
********************************************************************************************************************************;
                       6 : str := 'Saturday'
                       end;
               append (str,', ')
               end
               else setlength (str,0);
       case mo of
               1 : str2 := 'January';
               2 : str2 := 'February';
               3 : str2 := 'March';
               4 : str2 := 'April';
               5 : str2 := 'May';
               6 : str2 := 'June';
               7 : str2 := 'July';
               8 : str2 := 'August';
               9 : str2 := 'September';
               10 : str2 := 'October';
               11 : str2 := 'November';
               12 : str2 := 'December'
               end;
       append (str,str2);
       append (str,' ');
       if (date > 9) then append (str,chr((date div 10) + zero));
       append (str,chr((date mod 10) + zero));
       append (str,', 19');
       append (str,chr((yr div 10) + zero));
       append (str,chr((yr mod 10) + zero));
       dastrlong := str
end;

FUNCTION dastrshort (days : integer; withday : boolean) : string255;

CONST   zero = 48;

VAR     day, mo, date, yr : byte;
       str, str2 : string255;

begin
       brkdate (days,mo,date,yr,day);
       if withday then
               begin
                       case day of
                               0 : str := 'Sun';
                               1 : str := 'Mon';
                               2 : str := 'Tues';
                               3 : str := 'Wed';
                               4 : str := 'Thurs';
                               5 : str := 'Fri';
                               6 : str := 'Sat'
                               end;
                       append (str,', ')
               end
               else setlength (str,0);
       case mo of
               1 : str2 := 'Jan';
               2 : str2 := 'Feb';
               3 : str2 := 'Mar';
               4 : str2 := 'Apr';
               5 : str2 := 'May';
               6 : str2 := 'June';
               7 : str2 := 'July';
               8 : str2 := 'Aug';
               9 : str2 := 'Sept';
               10 : str2 := 'Oct';
               11 : str2 := 'Nov';
               12 : str2 := 'Dec'
       end;
       append (str,str2);
       append (str,' ');
       if (date > 9) then append (str,chr((date div 10) +********************************************************************************************************************************chr((yr mod 10) + zero));
       dastrshort := str
end;

FUNCTION strbyte (val : byte; withspace : boolean) : string255;

CONST   zero = 48;

VAR     ch : char;
       str : string255;

begin
       setlength (str,0);
       if (val div 10 = 0) and withspace
               then str := ' '
               else str := chr (val div 10 + zero);
       append (str,chr(val mod 10 + zero));
       strbyte := str
end;

FUNCTION dastrfixed (days : integer; spaces : boolean) : string255;

CONST   zero = 48;
       separator = '-';

VAR     day, mo, da, yr : byte;
       str : string255;

begin
       brkdate (days,mo,da,yr,day);
       setlength (str,0);
       append (str,strbyte(mo,spaces));
       append (str,separator);
       append (str,strbyte(da,spaces));
       append (str,separator);
       append (str,strbyte(yr,false));
       dastrfixed := str
end;