home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / tug__002 / timer.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-08-08  |  22.7 KB  |  669 lines

  1. {TUG PDS CERT 1.01 (Pascal)
  2.  
  3. ==========================================================================
  4.  
  5.                   TUG PUBLIC DOMAIN SOFTWARE CERTIFICATION
  6.  
  7. The Turbo User Group (TUG) is recognized by Borland International as the
  8. official support organization for Turbo languages.  This file has been
  9. compiled and verified by the TUG library staff.  We are reasonably certain
  10. that the information contained in this file is public domain material, but
  11. it is also subject to any restrictions applied by its author.
  12.  
  13. This diskette contains PROGRAMS and/or DATA determined to be in the PUBLIC
  14. DOMAIN, provided as a service of TUG for the use of its members.  The
  15. Turbo User Group will not be liable for any damages, including any lost
  16. profits, lost savings or other incidental or consequential damages arising
  17. out of the use of or inability to use the contents, even if TUG has been
  18. advised of the possibility of such damages, or for any claim by any
  19. other party.
  20.  
  21. To the best of our knowledge, the routines in this file compile and function
  22. properly in accordance with the information described below.
  23.  
  24. If you discover an error in this file, we would appreciate it if you would
  25. report it to us.  To report bugs, or to request information on membership
  26. in TUG, please contact us at:
  27.  
  28.              Turbo User Group
  29.              PO Box 1510
  30.              Poulsbo, Washington USA  98370
  31.  
  32. --------------------------------------------------------------------------
  33.                        F i l e    I n f o r m a t i o n
  34.  
  35. * DESCRIPTION
  36. Version 1.01. Author Rob Rosenberger. Turbo Pascal 4.0 unit source code
  37. provides 256 independent stop-watch timers. Great for timing the execution
  38. of a routine or an I/O access. Timer #0 specifically times the overall
  39. program, the rest are at your disposal. Fully compatible with other
  40. programs and units since it dosen't use clock ticks.
  41.  
  42. * ASSOCIATED FILES
  43.  
  44.  
  45. * CHECKED BY
  46. DRM - 08/08/88
  47.  
  48. * KEYWORDS
  49. TURBO PASCAL V4.0 TIME TIMER CLOCK
  50.  
  51. ==========================================================================
  52. }
  53. {$R-,S+,I+,D+,T-,F-,V+,B-,N-,L+ }
  54.  
  55. UNIT Timer;  {Version 1.01, released to the public domain on 20 June 1988 }
  56.  
  57. {
  58. Created by:          Rob Rosenberger             CompuServe
  59.                       P.O. Box #643              74017,1344
  60.                    O'Fallon, IL  62269
  61.  
  62.  
  63.    This unit takes the hassles off the programmer when it comes to timing
  64. programming routines, disk accesses, etc.  Just place the appropriate routine
  65. calls where you want to start/start the timer, or catch a lap-time.  This
  66. unit does the rest!
  67.    You can use up to 255 different timers at once!  Just supply the number of
  68. the timer you want to use.  Clock #zero is a special timer that starts when
  69. the program begins.  You can tell how long your program has been running just
  70. by using GetLapTime(0)!
  71.    The unit does NOT count clock ticks or anything like that.  It asks DOS for
  72. the current date & time and calculates the elapsed time from that.  It should
  73. be compatible with any program or unit.
  74.    Please send a letter or CompuServe EasyPlex message if you have any ideas
  75. that will make this unit even better.  I'll give you credit for your ideas!
  76.  
  77. Version 1.00: released to the public domain on 24 Feb 88.
  78.  
  79. Version 1.01: released to the public domain on 20 Jun 88
  80.    Altered the returned strings for GetLapTime and RestartTimer so they would
  81. only show the time-lapse portion.  The programmer must attach a description to
  82. the time, i.e. WRITE(OUTPUT,Timer0msg + GetLapTime(0)).
  83.    Added logic to the program to account for a DOS 3.20 bug which doesn't roll
  84. the date when the DOS clock ticks past midnight.  The TIMER unit now accounts
  85. for just such a possibility and, if it comes across it, it will add one day to
  86. the current time.  Note: This means a time-lapse is limited to 24 hours.  Any
  87. multiple-day lapses will be lost because of the DOS 3.20 bug.
  88. }
  89.  
  90. INTERFACE {section}
  91.  
  92. USES DOS;
  93.  
  94.  
  95. PROCEDURE StartTimer (WhichClock : BYTE);
  96.   {Starts the internal clock.  Resets the clock if it was previously set.}
  97.  
  98. FUNCTION  GetLapTime (WhichClock : BYTE) : STRING;
  99.   {Returns a string showing the elapsed time.  The returned string is...
  100.     "xx:xx:xx.xx".  The clock continues to run.}
  101.  
  102. PROCEDURE RestartTimer (WhichClock : BYTE);
  103.   {Restarts the clock if the StopTimer procedure stopped the clock.  It does
  104.     nothing if the clock is still running.}
  105.  
  106. FUNCTION  StopTimer (WhichClock : BYTE) : STRING;
  107.   {Stops the timer without clearing the elapsed time.  Returned string will be
  108.     one of the following...  "xx:xx:xx.xx", or "Can't stop clock #0!".}
  109.  
  110. {----------------------------------------------------------------------------}
  111.  
  112.  
  113.  
  114. IMPLEMENTATION {section}
  115.  
  116. CONST
  117.    NullChar = $00;
  118.    Colon    = ':';
  119.    Period   = '.';
  120.    Space    = ' ';
  121.    Zero     = '0';
  122.  
  123. TYPE
  124.    DateRecord = RECORD
  125.                 Year      : WORD;
  126.                 Month     : WORD;
  127.                 Date      : WORD;
  128.                 DayOfWeek : WORD
  129.                 END;
  130.  
  131.    TimeRecord = RECORD
  132.                 Hour      : WORD;
  133.                 Minute    : WORD;
  134.                 Second    : WORD;
  135.                 Hundredth : WORD
  136.                 END;
  137.  
  138.    ClockRecord = RECORD
  139.                  ClockStartDate : DateRecord;
  140.                  ClockStartTime : TimeRecord;
  141.                  ElapsedTime    : TimeRecord;
  142.                  ClockIsRunning : BOOLEAN;
  143.                  END;
  144.  
  145. VAR
  146.    ClockArray : ARRAY [BYTE] OF ClockRecord;
  147.  
  148.  
  149. {============================================================================}
  150. PROCEDURE AddTogetherTwoTimeRecords(TimeRecordOne : TimeRecord;
  151.                                     TimeRecordTwo : TimeRecord;
  152.                                 VAR ResultRecord  : TimeRecord);
  153.    {This is an internal procedure.}
  154.  
  155.    {This procedure adds two time records and stores the result in the third
  156. record.  It is up to the calling routine to deal with times that go beyond the
  157. 24-hour mark.}
  158.  
  159. BEGIN {AdditionOfTwoTimes}
  160. ResultRecord.Hundredth := (TimeRecordOne.Hundredth + TimeRecordTwo.Hundredth);
  161. ResultRecord.Second    := (TimeRecordOne.Second    + TimeRecordTwo.Second);
  162. ResultRecord.Minute    := (TimeRecordOne.Minute    + TimeRecordTwo.Minute);
  163. ResultRecord.Hour      := (TimeRecordOne.Hour      + TimeRecordTwo.Hour);
  164.  
  165. WHILE (ResultRecord.Hundredth >= 100)
  166.  DO BEGIN
  167.     DEC(ResultRecord.Hundredth,100);
  168.     INC(ResultRecord.Second)
  169.     END;
  170. WHILE (ResultRecord.Second >= 60)
  171.  DO BEGIN
  172.     DEC(ResultRecord.Second,60);
  173.     INC(ResultRecord.Minute)
  174.     END;
  175. WHILE (ResultRecord.Minute >= 60)
  176.  DO BEGIN
  177.     DEC(ResultRecord.Minute,60);
  178.     INC(ResultRecord.Hour)
  179.     END
  180. END; {AdditionOfTwoTimes}
  181. {============================================================================}
  182.  
  183. {============================================================================}
  184. PROCEDURE AddOneDayToDate(VAR TheDateRecord : DateRecord);
  185.    {This is an internal procedure.}
  186.  
  187.    {This procedure adds one day to TheDateRecord.  Results are unpredictable
  188. with an invalid date.}
  189.  
  190. BEGIN {AddOneDayToDate}
  191. WITH TheDateRecord
  192.  DO BEGIN
  193.     INC(Date);
  194.     CASE Month OF
  195.       1, 3, 5, 7, 8, 10, 12 :
  196.         IF (Date > 31)
  197.          THEN
  198.             BEGIN
  199.             DEC(Date,31);
  200.             INC(Month)
  201.             END;
  202.       4, 6, 9, 11 :
  203.         IF (Date > 30)
  204.          THEN
  205.             BEGIN
  206.             DEC(Date,30);
  207.             INC(Month)
  208.             END;
  209.       2 :
  210.         IF (Date > 29)
  211.          THEN
  212.             BEGIN
  213.             DEC(Date,29);
  214.             Month := 3
  215.             END
  216.          ELSE
  217.             IF ((Date > 28) AND NOT (((Year MOD 4) = 0)
  218.              AND (((Year MOD 100) <> 0) OR ((Year MOD 400) = 0))))
  219.              THEN
  220.                 BEGIN
  221.                 DEC(Date,28);
  222.                 Month := 3
  223.                 END
  224.      END; {CASE Month}
  225.     WHILE (Month > 12)
  226.      DO BEGIN
  227.         DEC(Month,12);
  228.         INC(Year)
  229.         END;
  230.     INC(DayOfWeek);
  231.     DayOfWeek := (DayOfWeek MOD 7)
  232.     END {WITH TheDateRec}
  233. END; {AddOneDayToDate}
  234. {============================================================================}
  235.  
  236. {============================================================================}
  237. FUNCTION JulianDate(TheDate : DateRecord) : LONGINT;
  238.    {This is an internal function.}
  239.  
  240.    {This function returns TheDate as a long integer which is the value of the
  241. date as a julian date.  It assumes the date is valid or at least zeroed-out.
  242. The syntax of the julian date is Year*1000 + the day of the year.  Be sure the
  243. year is in the format 19xx, not just xx!
  244.    Julian dates are nice in that you can compare them to see which date comes
  245. first in history.}
  246.  
  247. VAR
  248.    TempLongInt : LONGINT;
  249.  
  250. BEGIN {JulianDate}
  251. TempLongInt := TheDate.Year;
  252. TempLongInt := (TempLongInt * 1000);
  253.    {We do this portion of the logic in two steps because we would get overflow
  254.    if we said "TempLongInt := (DateRecord.Year * 1000)".  See the TP4 manual,
  255.    p. 210 for an in-depth explanation.}
  256.  
  257. CASE TheDate.Month OF
  258.   02 : INC(TempLongInt,31);
  259.   03 : INC(TempLongInt,59);
  260.   04 : INC(TempLongInt,90);
  261.   05 : INC(TempLongInt,120);
  262.   06 : INC(TempLongInt,151);
  263.   07 : INC(TempLongInt,181);
  264.   08 : INC(TempLongInt,212);
  265.   09 : INC(TempLongInt,243);
  266.   10 : INC(TempLongInt,273);
  267.   11 : INC(TempLongInt,304);
  268.   12 : INC(TempLongInt,334)
  269.  END; {CASE DateRecord.Month}
  270. IF (((TheDate.Year MOD 4) = 0) AND (TheDate.Month > 2))
  271.  THEN
  272.     IF (((TheDate.Year MOD 100) <> 0) OR ((TheDate.Year MOD 400) = 0))
  273.      THEN INC(TempLongInt); {add a day for leapyears}
  274.  
  275. TempLongInt := (TempLongInt + TheDate.Date);
  276.  
  277. JulianDate := TempLongInt
  278. END; {JulianDate}
  279. {============================================================================}
  280.  
  281. {============================================================================}
  282. PROCEDURE SubtractOneDayFromDate(VAR TheDateRecord : DateRecord);
  283.    {This is an internal procedure.}
  284.  
  285.    {This procedure subtracts one day to TheDateRecord.  Results are unpredict-
  286. able with an invalid date.}
  287.  
  288. BEGIN {SubtractOneDayFromDate}
  289. WITH TheDateRecord
  290.  DO BEGIN
  291.     IF Date = 1
  292.      THEN
  293.         BEGIN
  294.         IF Month = 1
  295.          THEN
  296.             BEGIN
  297.             DEC(Year);
  298.             Month := 12;
  299.             Date := 31
  300.             END
  301.          ELSE
  302.             BEGIN
  303.             DEC(Month);
  304.             CASE Month OF
  305.               1, 3, 5, 7, 8, 10, 12 :
  306.                 Date := 31;
  307.               4, 6, 9, 11 :
  308.                 Date := 30;
  309.               2 :
  310.                 IF (((Year MOD 4) = 0)
  311.                  AND (((Year MOD 100) <> 0) OR ((Year MOD 400) = 0)))
  312.                  THEN Date := 29
  313.                  ELSE Date := 28
  314.              END {CASE Month}
  315.             END
  316.         END
  317.      ELSE
  318.         DEC(Date);
  319.     IF (DayOfWeek = 0)
  320.      THEN
  321.         DayOfWeek := 6
  322.      ELSE
  323.         DEC(DayOfWeek)
  324.     END {WITH TheDateRec}
  325. END; {SubtractOneDayFromDate}
  326. {============================================================================}
  327.  
  328. {============================================================================}
  329. FUNCTION  ConvertTimeToString(TheTimeRec : TimeRecord) : STRING;
  330.    {This is an internal function.}
  331.  
  332.    {This function creates a time string from TheTimeRec.  It doesn't check to
  333. see if the time is valid.}
  334.  
  335. VAR
  336.    TempString1 : STRING;
  337.    TempString2 : STRING;
  338.    Index       : BYTE;
  339.  
  340. BEGIN {ConvertTimeToString}
  341. STR(TheTimeRec.Hour:2,{VAR} TempString1);
  342. STR(TheTimeRec.Minute:2,{VAR} TempString2);
  343. TempString1 := (TempString1 + Colon + TempString2);
  344. STR(TheTimeRec.Second:2,{VAR} TempString2);
  345. TempString1 := (TempString1 + Colon + TempString2);
  346. STR(TheTimeRec.Hundredth:2,{VAR} TempString2);
  347. TempString1 := (TempString1 + Period + TempString2);
  348.  
  349. FOR Index := 1 TO LENGTH(TempString1)
  350.  DO IF (TempString1[Index] = Space)
  351.      THEN TempString1[Index] := Zero;
  352. ConvertTimeToString := TempString1
  353. END; {ConvertTimeToString}
  354. {============================================================================}
  355.  
  356. {============================================================================}
  357. FUNCTION  DatesAreEqual(DateRecord1 : DateRecord;
  358.                         DateRecord2 : DateRecord) : BOOLEAN;
  359.  
  360.    {This function determines if two date records are identical.  It does not
  361. compare the day of the week.}
  362.  
  363. BEGIN {DatesAreEqual}
  364. IF ((DateRecord1.Date = DateRecord2.Date)
  365.  AND (DateRecord1.Month = DateRecord2.Month)
  366.  AND (DateRecord1.Year = DateRecord2.Year))
  367.  THEN DatesAreEqual := TRUE
  368.  ELSE DatesAreEqual := FALSE
  369. END; {DatesAreEqual}
  370. {============================================================================}
  371.  
  372. {============================================================================}
  373. FUNCTION  JulianTime(TimeRecord : TimeRecord) : LONGINT;
  374.  
  375.    {This function returns the given TimeRecord as a long integer which is the
  376. value of the time as a julian time.  Julian times are nice in that you can
  377. compare them to see which time is earlier in the day.}
  378.  
  379. VAR
  380.    TempLongInt  : LONGINT;
  381.    TempVariable : LONGINT;
  382.  
  383. BEGIN {JulianTime}
  384. TempLongInt  := TimeRecord.Hour;
  385. TempLongInt  := (TempLongInt * 1000000);
  386. TempVariable := TimeRecord.Minute;
  387. TempLongInt  := (TempLongInt
  388.                    + (TempVariable * 10000)
  389.                    + (TimeRecord.Second * 100)
  390.                    + TimeRecord.Hundredth);
  391.   {We do some portions of the logic in two steps because we would get overflow
  392.     if we said "TempLongInt := (TimeRecord.Hour * 1000000)", etc.  See the TP4
  393.     manual, p. 210 for an in-depth explanation.}
  394.  
  395. JulianTime := TempLongInt
  396. END; {JulianTime}
  397. {============================================================================}
  398.  
  399. {============================================================================}
  400. PROCEDURE DetermineLengthBetweenTwoDateTimes(StartDateRecord   : DateRecord;
  401.                                              StartTimeRecord   : TimeRecord;
  402.                                              EndDateRecord     : DateRecord;
  403.                                              EndTimeRecord     : TimeRecord;
  404.                                          VAR ElapsedTimeRecord : TimeRecord);
  405.    {This is an internal procedure.}
  406.  
  407.    {This procedure determines the length of time between two dates/times.  It
  408. assumes the starting date/time comes after the ending date/time.
  409.    This procedure quickly calculates the elapsed time, then begins adding one
  410. day at a time until it determines the date separation.  Lengthy separations
  411. will require quite a few add-one-day repetitions!
  412.    Should the starting date be GREATER THAN the ending date, this procedure
  413. will assume DOS 3.20 is in use and it's date-rollover bug has popped up.  It
  414. will add one day to the ending date as a compromise.}
  415.  
  416. VAR
  417.    JulianEndDate : LONGINT;
  418.  
  419. BEGIN {DetermineLengthBetweenTwoDateTimes}
  420. {Initialize.}
  421. WITH ElapsedTimeRecord
  422.  DO BEGIN
  423.     Hour      := 0;
  424.     Minute    := 0;
  425.     Second    := 0;
  426.     Hundredth := 0
  427.     END;
  428.  
  429. IF ((JulianDate(StartDateRecord) > JulianDate(EndDateRecord))
  430.  OR (DatesAreEqual(StartDateRecord,EndDateRecord)
  431.  AND (JulianTime(StartTimeRecord) > JulianTime(EndTimeRecord))))
  432.  THEN {StartDateRecord comes chronologically after EndDateRecord!}
  433.     AddOneDayToDate({VAR} EndDateRecord);
  434.  
  435. WHILE (EndTimeRecord.Hundredth < StartTimeRecord.Hundredth)
  436.  DO BEGIN
  437.     INC(EndTimeRecord.Hundredth,100);
  438.     IF (EndTimeRecord.Second = 0)
  439.      THEN
  440.         BEGIN
  441.         EndTimeRecord.Second := 59;
  442.         IF (EndTimeRecord.Minute = 0)
  443.          THEN
  444.             BEGIN
  445.             EndTimeRecord.Minute := 59;
  446.             IF (EndTimeRecord.Hour = 0)
  447.              THEN
  448.                 BEGIN
  449.                 EndTimeRecord.Hour := 23;
  450.                 SubtractOneDayFromDate(EndDateRecord)
  451.                 END
  452.              ELSE
  453.                 DEC(EndTimeRecord.Hour)
  454.             END
  455.          ELSE
  456.             DEC(EndTimeRecord.Minute)
  457.         END
  458.      ELSE
  459.         DEC(EndTimeRecord.Second)
  460.     END; {WHILE (EndTimeRecord.Hundreth < StartTimeRecord.Hundredth)}
  461. ElapsedTimeRecord.Hundredth := (EndTimeRecord.Hundredth
  462.                                         - StartTimeRecord.Hundredth);
  463.  
  464. WHILE (EndTimeRecord.Second < StartTimeRecord.Second)
  465.  DO BEGIN
  466.     INC(EndTimeRecord.Second,60);
  467.     IF (EndTimeRecord.Minute = 0)
  468.      THEN
  469.         BEGIN
  470.         EndTimeRecord.Minute := 59;
  471.         IF (EndTimeRecord.Hour = 0)
  472.          THEN
  473.             BEGIN
  474.             EndTimeRecord.Hour := 23;
  475.             SubtractOneDayFromDate(EndDateRecord)
  476.             END
  477.          ELSE
  478.             DEC(EndTimeRecord.Hour)
  479.         END
  480.      ELSE
  481.         DEC(EndTimeRecord.Minute)
  482.     END; {WHILE (EndTimeRecord.Second < StartTimeRecord.Second)}
  483. ElapsedTimeRecord.Second := (EndTimeRecord.Second - StartTimeRecord.Second);
  484.  
  485. WHILE (EndTimeRecord.Minute < StartTimeRecord.Minute)
  486.  DO BEGIN
  487.     INC(EndTimeRecord.Minute,60);
  488.     IF (EndTimeRecord.Hour = 0)
  489.      THEN
  490.         BEGIN
  491.         EndTimeRecord.Hour := 23;
  492.         SubtractOneDayFromDate(EndDateRecord)
  493.         END
  494.      ELSE
  495.         DEC(EndTimeRecord.Hour)
  496.     END; {WHILE (EndTimeRecord.Minute < StartTimeRecord.Minute)}
  497. ElapsedTimeRecord.Minute := (EndTimeRecord.Minute - StartTimeRecord.Minute);
  498.  
  499. WHILE (EndTimeRecord.Hour < StartTimeRecord.Hour)
  500.  DO BEGIN
  501.     INC(EndTimeRecord.Hour,24);
  502.     SubtractOneDayFromDate(EndDateRecord)
  503.     END; {WHILE (EndTimeRecord.Hour < StartTimeRecord.Hour)}
  504. ElapsedTimeRecord.Hour := (EndTimeRecord.Hour - StartTimeRecord.Hour);
  505.  
  506. JulianEndDate := JulianDate(EndDateRecord);
  507. WHILE (JulianDate(StartDateRecord) <> JulianEndDate)
  508.  DO BEGIN
  509.     INC(ElapsedTimeRecord.Hour,24);
  510.     AddOneDayToDate({VAR} StartDateRecord)
  511.     END {WHILE}
  512. END; {DetermineLengthBetweenTwoDateTimes}
  513. {============================================================================}
  514.  
  515. {============================================================================}
  516. PROCEDURE StartTimer (WhichClock : BYTE);
  517.  
  518.   {Starts the internal clock.  Resets the clock if it was previously set.}
  519.  
  520. BEGIN {StartTimer}
  521. IF (WhichClock = 0)
  522.  THEN {can't reset the program-timer clock!}
  523.     EXIT
  524.  ELSE
  525.     WITH ClockArray[WhichClock]
  526.      DO BEGIN
  527.         WITH ClockStartDate
  528.          DO GETDATE({VAR} Year,Month,Date,DayOfWeek);
  529.         WITH ClockStartTime
  530.          DO GETTIME({VAR} Hour,Minute,Second,Hundredth);
  531.         WITH ElapsedTime
  532.          DO BEGIN
  533.             Hour      := 0;
  534.             Minute    := 0;
  535.             Second    := 0;
  536.             Hundredth := 0
  537.             END;
  538.         ClockIsRunning := TRUE
  539.         END
  540. END; {StartTimer}
  541. {============================================================================}
  542.  
  543. {============================================================================}
  544. FUNCTION  GetLapTime (WhichClock : BYTE) : STRING;
  545.  
  546.   {Returns a string showing the elapsed time.  The returned string is...
  547.     "xx:xx:xx.xx".  The clock continues to run.}
  548.  
  549. VAR
  550.    CurrentDate : DateRecord;
  551.    CurrentTime : TimeRecord;
  552.    ElapsedTime : TimeRecord;
  553.    TempString  : STRING[3];
  554.  
  555. BEGIN {GetLapTime}
  556. {Initialize.}
  557. WITH CurrentDate
  558.  DO GETDATE({VAR} Year,Month,Date,DayOfWeek);
  559. WITH CurrentTime
  560.  DO GETTIME({VAR} Hour,Minute,Second,Hundredth);
  561. FILLCHAR(ElapsedTime,SIZEOF(ElapsedTime),NullChar);
  562. STR(WhichClock,{VAR} TempString);
  563.  
  564. {Determine how long it's been since timer was started.}
  565. DetermineLengthBetweenTwoDateTimes(ClockArray[WhichClock].ClockStartDate,
  566.                                    ClockArray[WhichClock].ClockStartTime,
  567.                                    CurrentDate,
  568.                                    CurrentTime,
  569.                              {VAR} ElapsedTime);
  570. {Add that to any lap time that was stored when StopTimer routine was called.}
  571. AddTogetherTwoTimeRecords(ElapsedTime,
  572.                           ClockArray[WhichClock].ElapsedTime,
  573.                     {VAR} ElapsedTime);
  574.  
  575. {Feed information back to the calling routine.}
  576. GetLapTime := ConvertTimeToString(ElapsedTime)
  577. END; {GetLapTime}
  578. {============================================================================}
  579.  
  580. {============================================================================}
  581. PROCEDURE RestartTimer (WhichClock : BYTE);
  582.  
  583.   {Restarts the clock if the StopTimer procedure stopped the clock.  It does
  584.     nothing if the clock is still running.}
  585.  
  586. BEGIN {RestartTimer}
  587. WITH ClockArray[WhichClock]
  588.  DO BEGIN
  589.     WITH ClockStartDate
  590.      DO GETDATE({VAR} Year,Month,Date,DayOfWeek);
  591.     WITH ClockStartTime
  592.      DO GETTIME({VAR} Hour,Minute,Second,Hundredth);
  593.     {Leave the elapsed time alone.}
  594.     ClockIsRunning := TRUE
  595.     END
  596. END; {RestartTimer}
  597.  
  598. {============================================================================}
  599.  
  600.  
  601. {============================================================================}
  602. FUNCTION  StopTimer (WhichClock : BYTE) : STRING;
  603.  
  604.   {Stops the timer without clearing the elapsed time.  Returned string will be
  605.     one of the following...  "xx:xx:xx.xx", or "Can't stop clock #0!".}
  606.  
  607. CONST
  608.    CantStopClockZeroText = 'Can''t stop clock #0!';
  609.  
  610. VAR
  611.    CurrentDate : DateRecord;
  612.    CurrentTime : TimeRecord;
  613.    ElapsedTime : TimeRecord;
  614.    TempString  : STRING[3];
  615.  
  616. BEGIN {StopTimer}
  617. IF ((WhichClock = 0)
  618.  OR (NOT ClockArray[WhichClock].ClockIsRunning))
  619.  THEN {tell programmer we can't stop the overall program timer}
  620.     StopTimer := (CantStopClockZeroText)
  621.  ELSE
  622.     BEGIN
  623.     {Initialize.}
  624.     WITH CurrentDate
  625.      DO GETDATE({VAR} Year,Month,Date,DayOfWeek);
  626.     WITH CurrentTime
  627.      DO GETTIME({VAR} Hour,Minute,Second,Hundredth);
  628.     FILLCHAR(ElapsedTime,SIZEOF(ElapsedTime),NullChar);
  629.     STR(WhichClock,{VAR} TempString);
  630.  
  631.     {Determine how long it's been since timer was started.}
  632.     DetermineLengthBetweenTwoDateTimes(ClockArray[WhichClock].ClockStartDate,
  633.                                        ClockArray[WhichClock].ClockStartTime,
  634.                                        CurrentDate,
  635.                                        CurrentTime,
  636.                                  {VAR} ElapsedTime);
  637.     {Add that to any lap time currently stored.}
  638.     AddTogetherTwoTimeRecords(ElapsedTime,
  639.                               ClockArray[WhichClock].ElapsedTime,
  640.                         {VAR} ClockArray[WhichClock].ElapsedTime);
  641.  
  642.     ClockArray[WhichClock].ClockIsRunning := FALSE;
  643.  
  644.     {Feed information back to the calling routine.}
  645.     StopTimer := ConvertTimeToString(ElapsedTime)
  646.     END
  647. END; {StopTimer}
  648. {============================================================================}
  649.  
  650.  
  651.  
  652.  
  653.  
  654. BEGIN {Timer UNIT}
  655.  
  656. {Zero-out the ClockArray.}
  657. FILLCHAR(ClockArray,SIZEOF(ClockArray),NullChar);
  658.  
  659. {Start the program timer, AKA ClockArray(0).}
  660. WITH ClockArray[0]
  661.  DO BEGIN
  662.     WITH ClockStartDate
  663.      DO GETDATE({VAR} Year,Month,Date,DayOfWeek);
  664.     WITH ClockStartTime
  665.      DO GETTIME({VAR} Hour,Minute,Second,Hundredth);
  666.     ClockIsRunning := TRUE
  667.     END
  668.  
  669. END. {Timer UNIT}