home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / JTTLIB.ZIP / JTTLIB.PAS next >
Encoding:
Pascal/Delphi Source File  |  1987-02-06  |  22.2 KB  |  943 lines

  1. {Jttlib.Pas}
  2. {$V-}
  3.  
  4. (* The following types and vars must be declared global to the entire program
  5.    in order for the functions and procedures in JTTLIB to be usable :
  6. *)
  7. Const
  8.  
  9. Ref_Date = '01/01/80,2';  {Basis for Date math functions; 2 = Wednesday}
  10.  
  11. Type
  12.  
  13. Str2 = String[2];
  14. Str6 = String[6];
  15. Str8 = String[8];
  16. Str10 = String[10];
  17. Str12 = String[12];
  18. Str15 = String[15];
  19. Str25 = String[25];
  20. Str80 = String[80];
  21.  
  22. Regpack = Record
  23.   Ax,Bx,Cx,Dx,Bp,Di,Si,Ds,Es,Flags: Integer;
  24. End;
  25.  
  26. Var
  27.  
  28. Problem : Boolean;
  29. Vol : Str2;
  30. Err : Integer;
  31.  
  32. (* This is the end of the necessary declarations  *)
  33.  
  34. { ***** Miscellaneous/Utility *****}
  35.  
  36. Procedure Clrpos(First,Last : Byte);
  37. {
  38. Clears part of the screen from line First to line Last
  39. }
  40. Var L : Integer;
  41.  
  42. Begin
  43.   For L := First to Last Do
  44.     Begin
  45.       Gotoxy(1,L);
  46.       Clreol;
  47.     End;
  48.   Gotoxy(1,First);
  49. End;
  50.  
  51. Procedure Uc(Var St : Str80);
  52. {
  53. Upcases a string up to 80 characters long
  54. }
  55. Var I : Integer;
  56.  
  57. Begin
  58.   For I := 1 to Length(St) do St[I] := Upcase(St[I]);
  59. End;
  60.  
  61. Function Exist(F : Str25) : Boolean;
  62. {
  63. Determines if a file exists
  64. }
  65. Var Fil : File;
  66.  
  67. Begin
  68.   Exist := True;
  69.   Assign(Fil,F);
  70. {$I-}
  71.   Reset(Fil);
  72. {$I+}
  73.   Exist := (Ioresult = 0);
  74.   Close(Fil);
  75. End;
  76.  
  77. {***** Messages & Prompts *****}
  78.  
  79. Procedure Pause;
  80. {
  81. Causes the program to wait for a key to be pressed
  82. }
  83. Var Ch : Char;
  84.  
  85. Begin
  86.   Gotoxy(1,25);
  87.   Reset(Kbd);
  88.   Clreol;
  89.   Write('Press any key to continue.');
  90.   Read(Kbd,Ch);
  91.   Gotoxy(1,25);
  92.   Clreol;
  93. End;
  94.  
  95. Procedure Say(Yy : Byte; St : Str80);
  96. {
  97. Prints a message on line Yy for 1 second
  98. }
  99.  
  100. Begin
  101.   Gotoxy(1,Yy);
  102.   Clreol;
  103.   Write(St);
  104.   Delay(1000);
  105.   Gotoxy(1,Yy);
  106.   Clreol;
  107. End;
  108.  
  109. Procedure Error(St : Str80);
  110. {
  111. Prints an error message at the bottom of the screen, sets a flag, and beeps
  112. }
  113. Begin
  114.   Gotoxy(1,24);
  115.   Clreol;
  116.   Write(St,Chr(7));
  117.   Pause;
  118.   Gotoxy(1,24);
  119.   Clreol;
  120.   Problem := True;
  121. End;
  122.  
  123. Function Verify(What : Str25) : Boolean;
  124. {
  125. Used to verify the accuracy of inout; as in Repeat..Until Verify constructs
  126. }
  127. Var An : Char;
  128.     Xplace, Yplace : Byte;
  129.  
  130. Begin
  131.   Xplace := Wherex;
  132.   Yplace := Wherey;
  133.   Gotoxy(1,25);
  134.   Reset(Kbd);
  135.   Clreol;
  136.   Write('Is this ',What,' correct? ');
  137.     Repeat
  138.       Read(Kbd,An)
  139.     Until An in ['Y','N','y','n'];
  140.   Gotoxy(1,25);
  141.   Clreol;
  142.   Gotoxy(Xplace,Yplace);
  143.   Verify := An in ['Y','y'];
  144. End;
  145.  
  146. Function Ask(Yy : Byte; St : Str80) : Char;
  147. {
  148. Returns a Char answer to a prompt asked on line Yy
  149. }
  150. Var Ch : Char;
  151.  
  152. Begin
  153.   Gotoxy(1,Yy);
  154.   Reset(Kbd);
  155.   Clreol;
  156.   Write(St);
  157.   Read(Kbd,Ch);
  158.   Gotoxy(1,Yy);
  159.   Clreol;
  160.   Ask := Ch;
  161. End;
  162.  
  163. {***** Edit Checked Input *****}
  164.  
  165. Procedure Get_Vol(Var Drive : Str2);
  166. {
  167. Gets drive letter to be concated onto filenames
  168. }
  169. Var Ch : Char;
  170.  
  171. Begin
  172.   Gotoxy(1,3);
  173.   Clreol;
  174.   Reset(Kbd);
  175.   Write('Input letter of data disk (A,B, Or C) : ');
  176.   Repeat
  177.     Read(Kbd,Ch);
  178.     Ch := Upcase(Ch);
  179.   Until Ch in ['A','B','C'];
  180.   Drive := Concat(Ch,':');
  181.   Gotoxy(1,3);
  182.   Clreol;
  183. End;
  184.  
  185. Function Get_Real : Real;
  186. {
  187. Inputs a real number at the current cursor location
  188. }
  189. Var Inst : Str25;
  190.     Result : Real;
  191.     Xhold, Yhold : Byte;
  192.  
  193. Begin
  194.   Xhold := Wherex;
  195.   Yhold := Wherey;
  196.   Repeat
  197.     Inst := '0';
  198.     Gotoxy(Xhold,Yhold);
  199.     Clreol;
  200.     Readln(Inst);
  201.     If (Inst[1] = '.') then Inst := Concat('0',Inst);
  202.     Val(Inst,Result,Err);
  203.   Until (Err = 0);
  204.   Get_Real := Result;
  205. End;
  206.  
  207. Function Get_Integer : Integer;
  208. {
  209. Inputs an integer at the current cursor location
  210. }
  211. Var Inst : Str25;
  212.     Result : Integer;
  213.     Xhold, Yhold : Byte;
  214.  
  215. Begin
  216.   Xhold := Wherex;
  217.   Yhold := Wherey;
  218.   Repeat
  219.     Inst := '0';
  220.     Gotoxy(Xhold,Yhold);
  221.     Clreol;
  222.     Readln(Inst);
  223.     Val(Inst,Result,Err);
  224.   Until (Err = 0);
  225.   Get_Integer := Result;
  226. End;
  227.  
  228. Function Get_String(Show : Boolean; L : Byte) : Str80;
  229. {
  230. Inputs a string of length L at the current cursor location, optionally
  231. non-printing
  232. }
  233. Var Inst : Str80;
  234.     Cha : Char;
  235.     C1, Xplace, Yplace : Byte;
  236.  
  237. Begin
  238.   If (L > 0) Then
  239.     Begin
  240.       Xplace := Wherex;
  241.       Yplace := Wherey;
  242.       For C1 := 1 to L do Write('_');
  243.       Gotoxy(Xplace,Yplace);
  244.     End;
  245.   Reset(Kbd);
  246.   Inst := '';
  247.   Repeat
  248.     Read(Kbd,Cha);
  249.     If Show and (Ord(Cha) in [8,32..127]) then Write(Cha);
  250.     If Ord(Cha) in [32..126] Then
  251.     Inst := Concat(Inst,Cha)
  252.     else If Ord(Cha) = 8 then If (Length(Inst) > 0) Then
  253.       Begin
  254.         If Show then Write(' ',Chr(8));
  255.         Inst := Copy(Inst,1,(Length(Inst)-1));
  256.       End;
  257.   Until (Ord(Cha) in [9,10,12,13,26]);
  258.   If L <> 0 then Inst := Copy(Inst,1,L);
  259.   Get_String := Inst;
  260. End;
  261.  
  262. Function Read_String(L : Byte) : Str80;
  263. {
  264. Inputs a string of length L at the current cursor location
  265. }
  266. Var Inst : Str80;
  267.     C1, Xplace, Yplace : Byte;
  268.  
  269. {$C-}
  270. Begin
  271.   If (L > 0) Then
  272.     Begin
  273.       Xplace := Wherex;
  274.       Yplace := Wherey;
  275.       For C1 := 1 to L do Write('_');
  276.       Gotoxy(Xplace,Yplace);
  277.     End;
  278.   Reset(Kbd);
  279.   Readln(Inst);
  280.   If L <> 0 then Inst := Copy(Inst,1,L);
  281.   Read_String := Inst;
  282. {$C+}
  283. End;
  284.  
  285. Function Check_String(Inst, Template : Str80; Len : Byte) : Boolean;
  286. {
  287. Compares a string to a template for edit checking as follows:
  288.    Template character       Acceptable character(S) in string
  289.            A                          Any character
  290.            L                      Alphabetic characters
  291.            N            Digit characters excluding '.' '+' and '-'
  292.                   (Use Get_Real or Get_Integer for numeric edit checking)
  293.            D         Delimiter characters '.' '/' ',' '\' '-' and ' '
  294.          Other                       That character
  295.  
  296. Note that length checking is disabled if (Len = 0)
  297. }
  298. Var P, Size : Byte;
  299.     Ok : Boolean;
  300.  
  301. Begin
  302.   Ok := True;
  303.   If Len <> 0 then Ok := (Length(Inst) = Length(Template));
  304.   Size := Length(Inst);
  305.   If (Length(Template) < Size) then Size := Length(Template);
  306.   If Ok then For P := 1 to Size Do
  307.   If Template[P] in ['A','L','N','D'] Then
  308.     Begin
  309.         Case Template[P] Of
  310.          'L' : If Ok then Ok := Inst[P] in ['A'..'Z','a'..'z'];
  311.          'N' : If Ok then Ok := Inst[P] in ['0'..'9'];
  312.          'D' : If Ok then Ok := Inst[P] in ['.','/',',','\','-',' '];
  313.         End;
  314.     End
  315.   else If Ok then Ok := (Inst[P] = Template[P]);
  316.   Check_String := Ok;
  317. End;
  318.  
  319. Function Get_Filename(Present : Boolean; Ext : Str6) : Str25;
  320. {
  321. Returns an acceptable filename.  Present indicates whether it must already
  322. exist or be a new file; Ext is an optional extension that will be added if
  323. it has length > 0.
  324. }
  325. Var Ch : Char;
  326.     St : Str25;
  327.     There : Boolean;
  328.     Xhold, Yhold : Byte;
  329.     L : Byte;
  330.     Ok : Boolean;
  331.  
  332. Begin
  333.   Xhold := Wherex;
  334.   Yhold := Wherey;
  335.   Repeat
  336.     Ok := True;
  337.     Gotoxy(Xhold,Yhold);
  338.     Clreol;
  339.     St := Get_String(True,25);
  340.     If (Length(Ext) >= 1) then If (Pos('.',St) = 0) then St := Concat(St,Ext);
  341.     Uc(St);
  342.     For L := 1 to Length(St) Do
  343.     If not (St[L] in ['A'..'Z','a'..'z','.',':','\','0'..'9']) then Ok := False;
  344.     If (St[1] in ['0'..'9','.']) then Ok := False;
  345.     If Ok Then
  346.       Begin
  347.         There := Exist(St);
  348.         If There <> Present Then
  349.           Begin
  350.             Gotoxy(1,Yhold+2);
  351.             Clreol;
  352.             Write(Chr(7));
  353.             If There Then
  354.               Begin
  355.                 Write('File exists already.  Overwrite (Y/N) ? ');
  356.                 Repeat
  357.                   Read(Kbd,Ch);
  358.                   Ch := Upcase(Ch);
  359.                 Until Ch in ['Y','N'];
  360.                 If Ch = 'Y' then There := Present;
  361.               End
  362.             else Write('File not found');
  363.             Delay(1000);
  364.             Gotoxy(1,Yhold+2);
  365.             Clreol;
  366.           End;
  367.       End
  368.     else
  369.       Begin
  370.         Gotoxy(1,Yhold+2);
  371.         Clreol;
  372.         There := not Present;
  373.         Write(Chr(7),'Invalid file name');
  374.         Delay(1000);
  375.         Gotoxy(1,Yhold+2);
  376.         Clreol;
  377.       End;
  378.   Until There = Present;
  379.   Get_Filename := St;
  380. End;
  381.  
  382. {***** Time & Date *****}
  383.  
  384. Function Date: Str10;
  385. {
  386. DOS call that returns system date
  387. }
  388. Var Recpack : Regpack;
  389.     Month, Day : Str2;
  390.     Year : String[4];
  391.     Dx,Cx : Integer;
  392.  
  393. Begin
  394.   With Recpack Do
  395.     Begin
  396.       Ax := $2a Shl 8;
  397.     End;
  398.   Msdos(Recpack);
  399.   With Recpack Do
  400.     Begin
  401.       Str(Cx,Year);
  402.       Str(Dx Mod 256,Day);
  403.       Str(Dx Shr 8,Month);
  404.     End;
  405.   Year := Copy(Year,3,2);
  406.   If Length(Month) = 1 then Month := Concat('0',Month);
  407.   If Length(Day) = 1 then Day := Concat('0',Day);
  408.   Date := Month+'/'+Day+'/'+Year;
  409. End;
  410.  
  411. Procedure Read_Date(Var Dt : Str8);
  412. {
  413. Reads in a date in correct date format (mm/dd/yy) at the cursor location
  414. }
  415. Var Ch : Char;
  416.     I : Integer;
  417.     Ok : Boolean;
  418.     Sep, Xhold, Yhold : Byte;
  419.  
  420. Begin
  421.   Xhold := Wherex;
  422.   Yhold := Wherey;
  423.   Repeat
  424.     Dt := Date;
  425.     I := 0;
  426.     Sep := 0;
  427.     Gotoxy(Xhold,Yhold);
  428.     Lowvideo;
  429.     Write(Dt);
  430.     Normvideo;
  431.     Gotoxy(Xhold,Yhold);
  432.     Repeat
  433.       I := I + 1;
  434.       Ok := False;
  435.       While not Ok Do
  436.         Begin
  437.           Sep := (I-1) Div 2;
  438.           Gotoxy(Xhold+I+Sep - 1,Yhold);
  439.           Read(Kbd,Ch);
  440.           Write(Ch);
  441.           If (Ord(Ch) in [8,13,32]) Then
  442.             Begin
  443.                 Case Ord(Ch) Of
  444.                  32 : If (I < 7) Then
  445.                         Begin
  446.                           Ch := Dt[I+Sep];
  447.                           I := I + 1;
  448.                           Write(Chr(8),Ch);
  449.                         End;
  450.                   8 : If (I > 1) then I := I - 1;
  451.                  13 : Begin
  452.                         I := 7;
  453.                         Sep := 2;
  454.                         Ch := Dt[8];
  455.                       End;
  456.                 End;
  457.               If (I > 6) then Ok := True;
  458.             End
  459.           else
  460.             Begin
  461.               Case I Of
  462.                 5 : Ok := Ch in ['0'..'9'];
  463.                 6 : Ok := Ch in ['0'..'9'];
  464.                 1 : Ok := Ch in ['0','1'];
  465.                 2 : If Dt[1] = '0' then Ok := Ch in ['1'..'9']
  466.                     else Ok := Ch in ['0','1','2'];
  467.                 3 : Ok := Ch in ['0','1','2','3'];
  468.                 4 : If Dt[4] in ['0'..'2'] then Ok := Ch in ['0'..'9']
  469.                     else Ok := Ch in ['0','1'];
  470.               End;  {case}
  471.             End;
  472.         End;
  473.       If Ok then Dt[I+Sep] := Ch;
  474.     Until (I >= 6);
  475.   Until Verify('Date');
  476. End;
  477.  
  478. Function Last_Day(Mon : Integer; Year : Integer) : Integer;
  479. {
  480. Determines the last day of a month
  481. }
  482. Var Dys, Err : Integer;
  483.     Leap : Boolean;
  484.  
  485. Begin
  486.   Dys := 30;
  487.   Leap := ((Year/4) = (Year Div 4));
  488.     Case Mon Of
  489.       1,3,5,7,8,10,12 : Dys := 31;
  490.       4,6,9,11 : Dys := 30;
  491.       2 : If Leap then Dys := 29
  492.           else Dys := 28;
  493.     End;
  494.   Last_Day := Dys;
  495. End;
  496.  
  497. Function Date_Of(Julian : Integer) : Str8;
  498. {
  499. Date from the Julian date counted from the constant REF_DATE
  500. }
  501. Var Yr, Mo, Dy : Integer;
  502.     Ystr, Mstr, Dstr : Str2;
  503.     Datestr : Str8;
  504.  
  505. Begin
  506.   Val(Copy(Ref_Date,7,2),Yr,Err);
  507.   If (Julian > 366) Then
  508.     Begin
  509.       Repeat
  510.         Julian := Julian - 365;
  511.         If ((Yr Mod 4) = 0) then Julian := Julian - 1;
  512.         Yr := Yr + 1;
  513.       Until (Julian < 367);
  514.     End;
  515.   If (Julian = 366) then If ((Yr Mod 4) <> 0) Then
  516.     Begin
  517.       Julian := 1;
  518.       Yr := Yr + 1;
  519.     End;
  520.   If ((Yr Mod 4) <> 0) Then
  521.     Begin
  522.         Case Julian Of
  523.         1..31    : Begin
  524.                      Mo := 1;
  525.                      Dy := Julian;
  526.                    End;
  527.         32..59   : Begin
  528.                      Mo := 2;
  529.                      Dy := Julian - 31;
  530.                    End;
  531.         60..90   : Begin
  532.                      Mo := 3;
  533.                      Dy := Julian - 59;
  534.                    End;
  535.         91..120  : Begin
  536.                      Mo := 4;
  537.                      Dy := Julian - 90;
  538.                    End;
  539.         121..151 : Begin
  540.                      Mo := 5;
  541.                      Dy := Julian - 120;
  542.                    End;
  543.         152..181 : Begin
  544.                      Mo := 6;
  545.                      Dy := Julian - 151;
  546.                    End;
  547.         182..212 : Begin
  548.                      Mo := 7;
  549.                      Dy := Julian - 181;
  550.                    End;
  551.         213..243 : Begin
  552.                      Mo := 8;
  553.                      Dy := Julian - 212;
  554.                    End;
  555.         244..273 : Begin
  556.                      Mo := 9;
  557.                      Dy := Julian - 243;
  558.                    End;
  559.         274..304 : Begin
  560.                      Mo := 10;
  561.                      Dy := Julian - 273;
  562.                    End;
  563.         305..334 : Begin
  564.                      Mo := 11;
  565.                      Dy := Julian - 304;
  566.                    End;
  567.         335..365 : Begin
  568.                      Mo := 12;
  569.                      Dy := Julian - 334;
  570.                    End;
  571.         End;
  572.     End
  573.   else
  574.     Begin
  575.         Case Julian Of
  576.         1..31    : Begin
  577.                      Mo := 1;
  578.                      Dy := Julian;
  579.                    End;
  580.         32..60   : Begin
  581.                      Mo := 2;
  582.                      Dy := Julian - 31;
  583.                    End;
  584.         61..91   : Begin
  585.                      Mo := 3;
  586.                      Dy := Julian - 60;
  587.                    End;
  588.         92..121  : Begin
  589.                      Mo := 4;
  590.                      Dy := Julian - 91;
  591.                    End;
  592.         122..152 : Begin
  593.                      Mo := 5;
  594.                      Dy := Julian - 121;
  595.                    End;
  596.         153..182 : Begin
  597.                      Mo := 6;
  598.                      Dy := Julian - 152;
  599.                    End;
  600.         183..213 : Begin
  601.                      Mo := 7;
  602.                      Dy := Julian - 182;
  603.                    End;
  604.         214..244 : Begin
  605.                      Mo := 8;
  606.                      Dy := Julian - 213;
  607.                    End;
  608.         245..274 : Begin
  609.                      Mo := 9;
  610.                      Dy := Julian - 244;
  611.                    End;
  612.         275..305 : Begin
  613.                      Mo := 10;
  614.                      Dy := Julian - 274;
  615.                    End;
  616.         306..335 : Begin
  617.                      Mo := 11;
  618.                      Dy := Julian - 305;
  619.                    End;
  620.         336..366 : Begin
  621.                      Mo := 12;
  622.                      Dy := Julian - 335;
  623.                    End;
  624.         End;
  625.     End;
  626.   Str(Yr,Ystr);
  627.   Str(Mo,Mstr);
  628.   Str(Dy,Dstr);
  629.   If (Length(Ystr) = 1) then Ystr := '0' + Ystr;
  630.   If (Length(Mstr) = 1) then Mstr := '0' + Mstr;
  631.   If (Length(Dstr) = 1) then Dstr := '0' + Dstr;
  632.   Datestr := Mstr + '/'+ Dstr + '/' + Ystr;
  633.   Date_Of := Datestr;
  634. End;
  635.  
  636. Function Num_Days(Dte : Str8) : Integer;
  637. {
  638. Number of days since Ref_Date
  639. }
  640. Var Yr, Mo, Dy : Integer;
  641.     Yr1, Mo1, Dy1 : Integer;
  642.     Difference : Integer;
  643.     I : Integer;
  644.  
  645. Begin
  646.   Difference := 0;
  647.   If (Dte <> Copy(Ref_Date,1,8)) Then
  648.     Begin
  649.       Val(Copy(Dte,1,2),Mo,Err);
  650.       Val(Copy(Dte,4,2),Dy,Err);
  651.       Val(Copy(Dte,7,2),Yr,Err);
  652.       Val(Copy(Ref_Date,1,2),Mo1,Err);
  653.       Val(Copy(Ref_Date,4,2),Dy1,Err);
  654.       Val(Copy(Ref_Date,7,2),Yr1,Err);
  655.       If (Yr1 < Yr) Then
  656.        For I := Yr1 to (Yr-1) Do
  657.        If ((I/4) = (I Div 4)) Then
  658.         Difference := Difference + 1;
  659.       Difference := Difference + ((Yr - Yr1) * 365) + Dy - Dy1;
  660.       If Mo > Mo1 Then
  661.         Begin
  662.           For I := Mo1 to (Mo-1) Do
  663.           Difference := Difference + Last_Day(I,Yr);
  664.         End;
  665.     End;
  666.   Num_Days := Difference + 1;
  667. End;
  668.  
  669. Function Month_Name(Mon : Byte) : Str12;
  670. {
  671. Returns a string for the month from the ordinal month
  672. }
  673.  
  674. Begin
  675.   Month_Name := 'na';
  676.     Case Mon Of
  677.       1 : Month_Name := 'January';
  678.       2 : Month_Name := 'February';
  679.       3 : Month_Name := 'March';
  680.       4 : Month_Name := 'April';
  681.       5 : Month_Name := 'May';
  682.       6 : Month_Name := 'June';
  683.       7 : Month_Name := 'July';
  684.       8 : Month_Name := 'August';
  685.       9 : Month_Name := 'September';
  686.       10 : Month_Name := 'October';
  687.       11 : Month_Name := 'November';
  688.       12 : Month_Name := 'December';
  689.     End;
  690. End;
  691.  
  692. Function Day_Name(Etad : Str8) : Str12;
  693. {
  694. Returns a string for the name of the day portion of Etad
  695. }
  696. Var Num, Dae, Plus : Integer;
  697. Sub : Str2;
  698.  
  699. Begin
  700.   Num := Num_Days(Etad) - 1;
  701.   Sub := Copy(Ref_Date,Pos(',',Ref_Date)+1,1);
  702.   Val(Sub,Plus,Err);
  703.   Dae := (Num+Plus) Mod 7;
  704.   If not (Dae in [0..6]) then Error('Day out of range')
  705.   else
  706.     Case Dae Of
  707.       0 : Day_Name := 'Sunday';
  708.       1 : Day_Name := 'Monday';
  709.       2 : Day_Name := 'Tuesday';
  710.       3 : Day_Name := 'Wednesday';
  711.       4 : Day_Name := 'Thursday';
  712.       5 : Day_Name := 'Friday';
  713.       6 : Day_Name := 'Saturday';
  714.     End;
  715. End;
  716.  
  717. Procedure Add_Day_To(Var Dt : Str8);
  718. {
  719. Increments a string date by 1.  This could also be accomplished by converting
  720. to Julian, adding 1, then converting back to a string
  721. }
  722. Var Yr, Mo, Dy, Max : Integer;
  723.     Ystr, Mstr, Dstr : Str2;
  724.  
  725. Begin
  726.   Val(Copy(Dt,1,2),Mo,Err);
  727.   Val(Copy(Dt,4,2),Dy,Err);
  728.   Val(Copy(Dt,7,2),Yr,Err);
  729.   Max := Last_Day(Mo,Yr);
  730.   Dy := Dy + 1;
  731.   If (Dy > Max) Then
  732.     Begin
  733.       Dy := 1;
  734.       Mo := Mo + 1;
  735.       If (Mo > 12) Then
  736.         Begin
  737.           Mo := 1;
  738.           Yr := Yr + 1;
  739.           If (Yr > 100) then Yr := 0;
  740.         End;
  741.     End;
  742.   Str(Mo,Mstr);
  743.   Str(Dy,Dstr);
  744.   Str(Yr,Ystr);
  745.   If (Length(Mstr) = 1) then Mstr := '0' + Mstr;
  746.   If (Length(Dstr) = 1) then Dstr := '0' + Dstr;
  747.   If (Length(Ystr) = 1) then Ystr := '0' + Ystr;
  748.   Dt := Mstr + '/' + Dstr + '/' + Ystr;
  749. End;
  750.  
  751. Function Get_Month(Dt : Str8) : Integer;
  752. {
  753. Extracts the month from a date in mm/dd/yy format
  754. }
  755. Var Month_Int, Err : Integer;
  756.     Month_Str : Str2;
  757.  
  758. Begin
  759.   Month_Str := Copy(Dt,1,2);
  760.   Val(Month_Str,Month_Int,Err);
  761.   If (Err <> 0) then Month_Int := 13;
  762.   Get_Month := Month_Int;
  763. End;
  764.  
  765. Function Time : Str8;
  766. {
  767. DOS call that returns system time
  768. }
  769. Var Recpack : Regpack;
  770.     Ah,Al,Ch,Cl,Dh : Byte;
  771.     Hour,Min,Sec : Str2;
  772.  
  773. Begin
  774.   Ah := $2c;
  775.   With Recpack Do
  776.     Begin
  777.       Ax := Ah Shl 8 + Al;
  778.     End;
  779.   Intr($21,Recpack);
  780.   With Recpack Do
  781.     Begin
  782.       Str(Cx Shr 8,Hour);
  783.       Str(Cx Mod 256,Min);
  784.       Str(Dx Shr 8,Sec);
  785.     End;
  786.   If (Length(Hour) = 1) then Hour := '0' + Hour;
  787.   If (Length(Min) = 1) then Min := '0' + Min;
  788.   If (Length(Sec) = 1) then Sec := '0' + Sec;
  789.   Time := Hour+':'+Min+':'+Sec;
  790. End;
  791.  
  792. Procedure Read_Time(Var Hr : Str8);
  793. {
  794. Reads in a time in correct time format (hh:mm) at current cursor location
  795. }
  796. Var Ch : Char;
  797.     I : Integer;
  798.     Ok : Boolean;
  799.     Sep, Xhold, Yhold : Byte;
  800.  
  801. Begin
  802.   Xhold := Wherex;
  803.   Yhold := Wherey;
  804.   Repeat
  805.     Hr := Copy(Time,1,5);
  806.     I := 0;
  807.     Sep := 0;
  808.     Gotoxy(Xhold,Yhold);
  809.     Lowvideo;
  810.     Write(Hr);
  811.     Normvideo;
  812.     Gotoxy(Xhold,Yhold);
  813.     Repeat
  814.       I := I + 1;
  815.       Ok := False;
  816.       While not Ok Do
  817.         Begin
  818.             Case I Of
  819.             1,2 : Sep := 0;
  820.             3,4 : Sep := 1;
  821.             5,6 : Sep := 2;
  822.             End;
  823.           Gotoxy(Xhold+I+Sep - 1,Yhold);
  824.           Read(Kbd,Ch);
  825.           Write(Ch);
  826.           If (Ord(Ch) = 8) and (I > 1) then I := I - 1
  827.           else
  828.             Begin
  829.               Case I Of
  830.                 1 : Ok := Ch in ['0'..'2'];
  831.                 2 : If Hr[1] in ['0','1'] then Ok := Ch in ['0'..'9']
  832.                     else Ok := Ch in ['0'..'3'];
  833.                 3 : Ok := Ch in ['0'..'5'];
  834.                 4 : Ok := Ch in ['0'..'9'];
  835.                 5 : Ok := Ch in ['0'..'5'];
  836.                 6 : Ok := Ch in ['0'..'9'];
  837.               End;  {case}
  838.             End;
  839.         End;
  840.       Hr[I+Sep] := Ch;
  841.     Until (I >= 4);
  842.   Until Verify('time');
  843. End;
  844.  
  845. {***** String Handling *****}
  846.  
  847. Function Ljust(St : Str80; W : Byte) : Str80;
  848. {
  849. Returns a string left-justified in a given field width
  850. }
  851. Var S, L : Integer;
  852.  
  853. Begin
  854.   L := Length(St);
  855.   If (L < W) then For S := L to (W-1) do St := Concat(St,' ');
  856.   Ljust := St;
  857. End;
  858.  
  859. Function Cjust(St : Str80; W : Byte) : Str80;
  860. {
  861. Returns a string center-justified in a given field width
  862. }
  863. Var S, L, Half : Integer;
  864.  
  865. Begin
  866.   L := Length(St);
  867.   If (L < W) Then
  868.     Begin
  869.       Half := (W-L) Div 2;
  870.       For S := L to (L + Half) do St := Concat(St,' ');
  871.     End;
  872.   Cjust := St;
  873. End;
  874.  
  875. Function Rjust(St : Str80; W : Byte) : Str80;
  876. {
  877. Returns a string right-justified in a given field width
  878. }
  879. Var S, L : Integer;
  880.  
  881. Begin
  882.   L := Length(St);
  883.   If (L < W) then For S := L to (W-1) do St := Concat(' ',St);
  884.   Rjust := St;
  885. End;
  886.  
  887. Function Plural(Singular : Str25) : Str80;
  888. {
  889. Returns the correct plural of most strings up to 25 characters long
  890. }
  891. Var Last : Byte;
  892.     St : Str80;
  893.  
  894. Begin
  895.   Last := Length(Singular);
  896.   If Singular[Last] in ['F','H','N','S','Y','Z','f','h','n','s','y','z'] Then
  897.     Case Singular[Last] Of
  898.      'F' : St := Concat(Copy(Singular,1,(Last-1)),'VES');
  899.      'f' : St := Concat(Copy(Singular,1,(Last-1)),'ves');
  900.      'S','Z' : St := Concat(Singular,'ES');
  901.      's','z' : St := Concat(Singular,'es');
  902.      'H' : If (Singular[Last-1] in ['C','S','c','s']) Then
  903.            St := Concat(Singular,'ES')
  904.            else St := Concat(Singular,'S');
  905.      'h' : If (Singular[Last-1] in ['C','S','c','s']) Then
  906.            St := Concat(Singular,'es')
  907.            else St := Concat(Singular,'s');
  908.      'N' : If (Singular[Last-1] in ['A','a']) Then
  909.            St := Concat(Copy(Singular,1,Last-2),'EN')
  910.            else St := Concat(Singular,'S');
  911.      'n' : If (Singular[Last-1] in ['A','a']) Then
  912.            St := Concat(Copy(Singular,1,Last-2),'en')
  913.            else St := Concat(Singular,'s');
  914.      'Y' : If not (Singular[Last-1] in ['A','E','I','O','U']) Then
  915.            St := Concat(Copy(Singular,1,Last-1),'IES')
  916.            else St := Concat(Singular,'S');
  917.      'y' : If not (Singular[Last-1] in ['a','e','i','o','u']) Then
  918.            St := Concat(Copy(Singular,1,Last-1),'ies')
  919.            else St := Concat(Singular,'s');
  920.     End
  921.   else
  922.   If Singular[Last] <> Upcase(Singular[Last]) Then
  923.   St := Concat(Singular,'s')
  924.   else St := Concat(Singular,'S');
  925.   Plural := St;
  926. End;
  927.  
  928. {***** Math *****}
  929.  
  930. Function Raise(X, Y : Real) : Real;
  931. {
  932. Raises a non-negative real to a power
  933. }
  934. Var A : Real;
  935.  
  936. Begin
  937.   If (X > 0) then A := Ln(X) else A := 0;
  938.   A := A * Abs(Y);
  939.   A := Exp(A);
  940.   If (Y < 0) then A := 1 / A;
  941.   Raise := A;
  942. End;
  943.