2
0

legacyutil.inc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2020 Karoly Balogh, Free Pascal Development team
  4. Amiga utility.library legacy (OS 1.x/2.x) support functions
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {
  12. This unit implements some of the utility.library functions for OS 1.x,
  13. where this library is missing, so the legacy OS support can be implemented
  14. with minimal changes to the normal system unit and common Amiga-like code
  15. Please note that this code doesn't aim to be API feature complete, just
  16. functional enough for the RTL code.
  17. }
  18. const
  19. // Start day of every month (without leap)
  20. StartOfMonth: array[0..11] of LongInt = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
  21. SecsPerMin = 60;
  22. SecsPerHour = 60 * SecsPerMin;
  23. SecsPerDay = 24 * SecsPerHour;
  24. SecsPerYear = 365 * SecsPerDay;// without leap
  25. AmigaStartYear = 1978; // Amiga starts @1978;
  26. DaysPerYear = 365;
  27. DaysPerLeapYear = DaysPerYear + 1;
  28. Daysof4Years = DaysPerLeapYear + 3 * DaysPerYear;
  29. Daysof100Years = 24 * DaysPerLeapYear + 76 * DaysPerYear;
  30. Daysof400Years = 97 * DaysPerLeapYear + 303 * DaysPerYear;
  31. procedure Amiga2Date(seconds: Cardinal;
  32. result : PClockData); public name '_fpc_amiga_amiga2date';
  33. var
  34. IsLeap: boolean;
  35. d, y, i: LongWord;
  36. begin// how many days are passed
  37. d := seconds div SecsPerDay;
  38. // the easier time part
  39. Result^.wday := d mod 7;
  40. Result^.sec := seconds mod 60;
  41. seconds := seconds div 60;
  42. Result^.min := seconds mod 60;
  43. seconds := seconds div 60;
  44. Result^.hour := seconds mod 24;
  45. // the leap year correction part
  46. IsLeap := True;
  47. //
  48. // before 2100 easier case (function mostly used for now(), so its usually in this range)
  49. if d < 92 * DaysPerYear + 30 * DaysPerLeapYear then // 1978 - 2100 = 92 non leap, 30 leap years
  50. begin
  51. d := d + DaysPerLeapYear + DaysPerYear; // we want to start from 1976 (a leap year) so we add 2 more years to the nubmer we have
  52. y := 4 *(d div Daysof4Years) + 1976; // how many 4 year spans (1 leap + 3 non leap) are there?
  53. d := d mod Daysof4Years; //( get the day in the 4 year span)
  54. // the first yoear of such a 4 year span, is always a leap year, all other not (thats the reason we want to start at 1976)
  55. if d > DaysPerLeapYear then
  56. begin
  57. IsLeap := False;
  58. d := d - 1;
  59. y := y + d div DaysPerYear;
  60. d := d mod DaysPerYear;
  61. end;
  62. end
  63. else
  64. begin
  65. // more complicated way for dates > 2100 (not tested until now!)
  66. // we do the same as before but not 4 years together but 400 (because of the special years which are not leap even divided by 4)
  67. // and we start at 2000
  68. d := d - 17 * DaysPerYear + 5 * DaysPerLeapYear;
  69. y := 400 * (d div Daysof400Years) + 2000;
  70. d := d mod Daysof400Years;
  71. // first is always NOT leap year.. other we have to test
  72. if d >= DaysPerLeapYear then
  73. begin
  74. // we do the same again, and test for 100 year spans
  75. d := d - 1; // not a leap year one day down
  76. IsLeap := False;
  77. y := y + 100 * (d div Daysof100Years);
  78. d := d mod Daysof100Years;
  79. if d >= DaysPerYear then
  80. begin
  81. d := d + 1; // a leap year, one day up
  82. IsLeap := True;
  83. // and the same as we did before 4 years span
  84. y := y + 4 * (d div Daysof4Years);
  85. d := d mod Daysof4Years;
  86. if d >= DaysPerLeapYear then
  87. begin
  88. d := d - 1;
  89. IsLeap := False;
  90. y := y + d div DaysPerYear;
  91. d := d mod DaysPerYear;
  92. end;
  93. end;
  94. end;
  95. end;
  96. // the current year is a leap year and we are after Februar
  97. if IsLeap and (d >= StartOfMonth[2]) then
  98. d := d + 1;
  99. // get the actual month
  100. for i := 1 to High(StartOfMonth) do
  101. begin
  102. if StartOfMonth[i] > d then
  103. begin
  104. Result^.Month := i;
  105. d := d - (StartOfMonth[i - 1] + 1);
  106. break;
  107. end;
  108. end;
  109. Result^.year := y;
  110. Result^.mday := d;
  111. end;
  112. function Date2Amiga(date: PClockData): Cardinal; public name '_fpc_amiga_date2amiga';
  113. var
  114. Y: LongInt;
  115. Leaps, LeapsBefore1978, Res: LongWord;
  116. begin
  117. // the easy time part
  118. Res := date^.hour * SecsPerHour + date^.min * SecsPerMin + date^.sec;
  119. Res := Res + ((date^.mday - 1) + StartOfMonth[date^.month - 1]) * SecsPerDay;
  120. Res := Res + (date^.year - AmigaStartYear) * SecsPerYear;
  121. // leap year correction ;)
  122. // current year
  123. y := date^.year;
  124. // from IsLeapYear dos.pp
  125. if (y mod 400 = 0) or ((y mod 4 = 0) and (y mod 100 <> 0)) then
  126. begin
  127. // add a day if its after feb in a leap year
  128. if date^.month > 2 then
  129. Res := Res + SecsPerDay;
  130. end;
  131. // previous years
  132. y := date^.year - 1;
  133. Leaps := (y div 4) - (y div 100) + (y div 400);
  134. // exclude the ones before 1978
  135. LeapsBefore1978 := (AmigaStartYear div 4) - (AmigaStartYear div 100) + (AmigaStartYear div 400);
  136. Date2Amiga := Res + (leaps - leapsBefore1978) * SecsPerDay;
  137. end;