{$I version.pas} {$IFDEF BORPAS} {$IFDEF DEBUG} {$M $2000, 33000, 33000} {$ELSE} {$M $2000, 0, 0} {$ENDIF} {$ENDIF BORPAS} program NOWMINUS ; uses {$IFDEF DEBUG} Crt, {$ENDIF} {$IFDEF BORPAS} {$IFDEF DPMI} JRS_EnvD {$ELSE} JRS_EnvU {$ENDIF}, {$ENDIF} {$IFDEF DELPHI} SysUtils, {$ENDIF} {$IFNDEF DELPHI} Dos, {$ENDIF} DateProx ; const LZ = 0 { to block dateprox' LZ } ; var Scr : text ; procedure Help ; begin Writeln(Scr, 'NOWMINUS ', {$IFDEF BORPAS} '16', {$ENDIF} {$IFDEF DELPHI} '32', {$ENDIF} '-bit www.merlyn.demon.co.uk >= 2006-04-29; see NOWMINUS.TXT.', ^M^J' To set Now, or offset Now, in chosen form', {$IFDEF BORPAS} ' to the Environment', {$ENDIF} '.' ) ; HALT end {Help} ; type S80 = string [80] ; S32 = string [32] ; S3 = string [3] ; const Base : word = 10 ; RandRange : word = 0 ; NM = ' NOWMINUS: ' ; Gen : integer = 8 { TS default } ; Alf : string [36] = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' ; Dogs : boolean = false ; function StrF(Q : longint ; const n : byte) : S32 ; var i : byte ; St : string [15] ; begin if Q<0 then begin Writeln(Scr, NM, Q, ' Out<0 ! **') ; HALT(1) end ; St := '' ; for i := 1 to n do begin St := Alf[Succ(Q mod Base)] + St ; Q := Q div Base end ; StrF := St end {StrF} ; function D2(const Q : longint) : S32 ; begin D2 := StrF(Q, 2) end {D2} ; procedure Norm(var Y : integer ; var M, D : byte ; var DD, IsS : longint) ; var MJD : longint ; begin MJD := YMDtoMJD(Y, M, D)+DD ; DD := 0 ; while IsS < 0 do begin MJD := MJD-1 ; Inc(IsS, 86400) end ; while IsS >= 86400 do begin MJD := MJD+1 ; Dec(IsS, 86400) end ; MJDtoYMD(MJD, Y, M, D) ; end {Norm} ; {$IFDEF BORPAS} function EnvGet(const St : S80) : string ; var Ostr : string ; Status : byte ; begin Environ(Gen, Get, St, Ostr, Status) ; {} {$IFDEF DEBUG} Writeln('*** C: Ostr="', Ostr, '"') ; {$ENDIF} if Status<>0 then Writeln(Scr, NM, 'Environ Status = ', Status, ' OK=', Status=0, #32, St, '=', Ostr) ; EnvGet := Ostr end {EnvGet} ; {$ENDIF BORPAS} function GetLI(St : S32) : longint ; var F : longint ; J : integer ; B : boolean ; begin GetLI := 0 ; if St='' then EXIT ; B := false ; {$IFDEF BORPAS} if St[1]='#' then begin B := St[2]='-' ; Delete(St, 1, 2) ; St := EnvGet(St) ; if St='' then EXIT ; end ; {$ENDIF BORPAS} Val(St, F, J) ; if J<>0 then begin Writeln(Scr, NM, '"', St, '" Bad number') ; HALT(2) end ; if B then F := -F ; GetLI := F end {GetLI} ; function FSep(const St : S3) : S3 ; begin if St='' then FSep := #32 else FSep := St[1] ; if St[1] in ['0'..'9'] then FSep := '' end {Fsep} ; type Bitz = (NoTime, NoDate, WeekNo, Use_JD, time_t, UKTaxW, UKTaxM, ThreeD, RFCfmt, Quartr, DaySec, UKform, TDdiff, B13, B14, RandNo) ; BSet = set of Bitz ; {Option Globals, preset} const { UTZ : integer = 0 ; } Sep : string [1] = 'T' ; Dsp : string [1] = '-' ; Tsp : string [1] = ':' ; Fmt : Bset = [] ; Beg : byte = 1 ; Len : byte = 255 ; Mon : boolean = false ; USA : boolean = false ; Summer : boolean = false ; AndStr : string [10] = '' ; {Date-Time Globals} var Yr, XYr : integer ; Mo, XMo, Dy, XDy : byte ; PlusDays, PlusSecs, XSecs : longint ; procedure UTCfromEuroTime(const TZhrs : longint) ; var PsHrs, ST_on, SToff : word ; begin (* USA : With DST; 1987-2006 rules *) if not USA then begin { Shift to UK Civil } Dec(PlusSecs, TZhrs) ; Norm(Yr, Mo, Dy, PlusDays, PlusSecs) end ; PsHrs := (Mo*word(32)+ Dy )*24 + (PlusSecs div 3600) ; ST_on := (03*word(32)+LastSun(Yr, 03, 31))*24 + 1 ; SToff := (10*word(32)+LastSun(Yr, 10, 31))*24 + 2 ; if USA then begin Inc(ST_on, 7*24+1) ; { Inc(SToff) } end ; Summer := (PsHrs >= ST_on) and (PsHrs < SToff) ; if Mon then Writeln(Scr, NM, 'Summer=', Summer) ; if USA then Dec(PlusSecs, TZhrs) ; if Summer then Dec(PlusSecs, 3600) end {UTCfromEuroTime} ; function OutStrF : S32 ; const D : byte = 10 ; PM : array [boolean] of string [1] = ('+', '-') ; var LI : longint ; Yu, M, S : integer ; H, Mu, Du : byte ; Wu : shortint ; Ch : Char ; Q : S32 ; Sign : string [1] ; begin Sign := '' ; if Base=10 then D := 10 ; if Base=16 then D := 8 ; if Base=36 then D := 6 ; (** ??? **) repeat { until true } if RandRange>0 then begin Q := StrF(Random(RandRange), 5) ; BREAK end ; if TDdiff in Fmt then begin LI := YMDtoMJD(Yr, Mo, Dy)*86400+PlusSecs ; Sign := PM[LI<0] ; Q := StrF(Abs(LI), D) ; BREAK end ; if RandNo in Fmt then begin if Base=10 then Q := StrF(Random(10000), 4) ; if Base=16 then Q := StrF(Random($100), 2)+StrF(Random($100), 2) ; if Base=36 then Q := StrF(Random(36*36*36), 3) ; BREAK end ; if time_t in Fmt then begin Q := StrF((YMDtoMJD(Yr, Mo, Dy)-40587)*86400+PlusSecs, D) ; BREAK end ; M := PlusSecs div 60 ; S := PlusSecs mod 60 ; H := M div 60 ; M := M mod 60 ; if (UKTaxW in Fmt) then begin UKTaxWeekNo(Yr, Mo, Dy, Yu, Wu, Du) ; Mu := Wu end else if (UKTaxM in Fmt) then begin UKTaxMonthDay(Yr, Mo, Dy, Yu, Wu, Du) ; Mu := Wu end else if (WeekNo in Fmt) then begin CTWeekNo_Day(Yr, Mo, Dy, Yu, Wu, Du) ; Mu := Wu end else begin Yu := Yr ; Mu := Mo ; Du := Dy end ; if noDate in Fmt then Q := '' else if (Use_JD in Fmt) then Q := StrF(YMDtoMJD(Yr, Mo, Dy)+2400001, D) else if (RFCfmt in Fmt) then Q := WkDstr[DayOfWeek(YMDtoMJD(Yu, Mu, Du))] + ', ' + D2(Du) + #32 + MonthS[Mu] + #32 + StrF(Yu, 4) else begin Q := StrF(Yu, 4) ; if Quartr in Fmt then begin Wu := (Mu-1) div 3 ; Ch := char(49 + Wu) ; Q := Q+Dsp + Ch + Dsp + D2(YMDtoMJD(Yr, Mo, Dy)-YMDtoMJD(Yr, 1+3*Wu, 1)+1) + #32 + Ch + 'Q' + D2(Yu mod 100) + #32 + Ch + 'Q' + StrF(Yu, 4) + #32 ; end else if ThreeD in Fmt then Q := Q+Dsp+StrF(YMDtoMJD(Yr, Mo, Dy)-YMDtoMJD(Yr, 1, 1)+1, 3) {Yu?} else if UKform in Fmt then Q := D2(Du)+Dsp+D2(Mu)+Dsp+Q else Q := Q+Dsp+D2(Mu)+Dsp+D2(Du) ; end ; if RFCfmt in Fmt then Q := Q + #32 else if Fmt*[noDate, noTime]=[] then Q := Q + Sep ; if not (noTime in Fmt) then begin if not (noDate in Fmt) then D := 5 ; if DaySec in Fmt then Q := Q + StrF(PlusSecs, D) {} else Q := Q + D2(H)+Tsp+D2(M)+Tsp+D2(S) ; end ; if RFCfmt in Fmt then if AndStr='' then Q := Q + ' GMT' else Q := Q + #32 + Copy(AndStr, Succ(5*Ord(Summer)), 5) ; until true ; OutStrF := Sign + Copy(Q, Beg, Len) end {OutStrF} ; procedure Zed(Z : byte) ; var Y : integer ; W : shortint ; D : byte ; const G : array [6..7, 15..17] of shortint = ((-1, -1, +2), (-2, +1, +1)) ; begin if Z in [15..17] then begin CTWeekNo_Day(Yr, Mo, Dy, Y, W, D) ; if D>=6 then PlusDays := G[D, Z] ; EXIT end ; if Z=14 then begin Mo := 1 + 3*(Pred(Mo) div 3) ; Z := 4 end ; if Z=13 then begin if word(Mo)*32+Dy < 04*32+06 then Dec(Yr) ; Mo := 04 ; Dy := 06 ; Z := 3 end ; if Z in [11,12] then begin if Z=12 then UKTaxMonthDay(Yr, Mo, Dy, Y, W, D) {} else UKTaxWeekNo(Yr, Mo, Dy, Y, W, D) ; PlusDays := -(D-1) ; Z := 3 end ; if Z=10 then begin Yr := 1970 ; Mo := 01 ; Dy := 01 ; Z := 3 end ; if Z=9 then begin Yr := 1858 ; Mo := 11 ; Dy := 17 ; Z := 3 end ; if Z in [7,8] then begin CTWeekNo_Day(Yr, Mo, Dy, Y, W, D) ; PlusDays := -(D-1) ; if Z=8 then Dec(PlusDays, 7*(W-1)) ; Z := 3 end ; if Z>=6 then Yr := 0001 ; if Z>=5 then Mo := 01 ; if Z>=4 then Dy := 01 ; if Z>=3 then PlusSecs := 86400*(PlusSecs div 86400) ; if Z>=2 then PlusSecs := 3600*(PlusSecs div 3600) ; if Z>=1 then PlusSecs := 60*(PlusSecs div 60) ; end {Zed} ; procedure Initialise ; var {$IFDEF BORPAS} X, DoW, {$ENDIF} Y, M, D, Hr, Mi, Sc, Cs : word ; {$IFDEF DELPHI} DT : TDateTime ; {$ENDIF} begin Randomize { caveat if scheduled } ; {$IFDEF BORPAS} GetDate(Y, M, D, DoW) ; repeat X := DoW ; GetTime(Hr, Mi, Sc, Cs) ; GetDate(Y, M, D, Dow) until DoW=X ; {$ENDIF BORPAS} {$IFDEF DELPHI} DT := Now ; DecodeTime(DT, Hr, Mi, Sc, Cs {!} ) ; DecodeDate(DT, Y, M, D) ; {$ENDIF DELPHI} Yr := Y ; Mo := M ; Dy := D ; PlusSecs := longint(Hr*60+Mi)*60+Sc ; PlusDays := 0 ; end {Initialise} ; procedure GetDT(St : S32) ; var Q : longint ; J, K, P : byte ; D, xD : boolean ; C : char ; begin if Mon then Writeln(Scr, NM, 'GetDT parameter "', St, '"') ; if Pos('%', St)>0 then Writeln(Scr, NM, 'warning: % in GetDT parameter') ; St := St+#32 ; if time_t in Fmt then Zed(10) else if Use_JD in Fmt then Zed(9) else if RandNo in Fmt then RandSeed := $87654321 else Zed(6) ; PlusSecs := 0 ; D := false ; J := 0 ; Q := 0 ; if NoDate in Fmt then K := 3 else K := 0 ; while J < Length(St) do begin xD := D ; Inc(J) ; C := St[J] ; P := Pos(UpCase(C), Alf) ; D := (P>0) and (P<=Base) ; if D then Q := Q*Base+Pred(P) else if XD then begin Inc(K) ; case K of 1 : if time_t in Fmt then PlusSecs := Q else if Use_JD in Fmt then MJDtoYMD(Q-2400001, Yr, Mo, Dy) else if RandNo in FMT then RandSeed := Q else if UKform in Fmt then Dy := Q else Yr := Q ; 2 : if not (ThreeD in Fmt) then Mo := Q else begin Mo := 1 ; Dy := 0 ; PlusDays := Q ; Inc(K) end ; 3 : if UKform in Fmt then Yr := Q else Dy := Q ; 4 : Inc(PlusSecs, 3600*Q) ; 5 : Inc(PlusSecs, 60*Q) ; 6 : Inc(PlusSecs, Q) ; else begin Writeln(Scr, NM, 'too many fields') ; HALT(4) end ; end {K} ; Q := 0 ; end {XD} ; end {while} ; if WeekNo in Fmt then MJDtoYMD(ISO_WNDtoMJD(GrgCal, Yr, Mo, Dy), Yr, Mo, Dy) ; if UKTaxW in Fmt then MJDtoYMD(UKTax_WNDtoMJD(Yr, Mo, Dy), Yr, Mo, Dy) ; if UKTaxM in Fmt then MJDtoYMD(UKTax_WMDtoMJD(Yr, Mo, Dy), Yr, Mo, Dy) ; { if Mon then Write(Scr, NM, 'GetDT') ; } end {GetDT} ; { $IFDEF BORPAS} procedure FileDateStamp(var St : S80) ; var F : file ; LI : longint ; B : boolean ; const Prev : S80 = '' ; begin B := St[1]='*' ; if B then Delete(St, 1, 1) ; if St='' then St := Prev else Prev := St ; (* Delphi : fileopen FileAge FileGetDate FileSetDate FmxUtils *) Assign(F, St) ; {$I-} Reset(F) {$I+} ; if IOResult<>0 then begin Writeln(Scr, NM, 'cannot get "', St, '"') ; HALT(5) end ; case B of false : begin GetFTime(F, LI) ; Yr := (LI shr 25)+1980 ; Mo := (LI shr 21) and $F ; Dy := (LI shr 16) and $1F ; PlusSecs := ((LI shr 11) and $1F) * 3600 + ((LI shr 5) and $3F) * 60 + ((LI shr 0) and $1F) * 2 ; end ; true : begin LI := longint(((Yr-1980) shl 4 + Mo) shl 5 + Dy) shl 16 + (PlusSecs div 3600) shl 11 + (PlusSecs mod 3600 div 60) shl 5 + PlusSecs mod 60 div 2 ; SetFTime(F, LI) ; end ; end ; Close(F) end {FileDateStamp} ; { $ENDIF BORPAS} {$IFDEF BORPAS} function DCB(const X : byte) : byte ; begin DCB := 10*(X shr 4) + (X and $0F) end {DCB} ; procedure GetRTC ; var R : Registers ; XDL : byte ; begin with R do begin AH := $04 ; Intr($1A, R) ; repeat XDL := DL ; AH := $02 ; Intr($1A, R) ; PlusSecs := (DCB(CH)*longint(60)+DCB(CL))*60+DCB(DH) ; AH := $04 ; Intr($1A, R) ; Yr := DCB(CH)*100+DCB(CL) ; Mo := DCB(DH) ; Dy := DCB(DL) ; until XDL = DL ; end end {GetRTC} ; {$ENDIF BORPAS} procedure ExecFile(const St : string) ; forward ; procedure DoCommand(St : S80) ; var Z : longint ; Ult : word ; Ch : char ; {$IFNDEF DELPHI} Status, {$ENDIF} P : byte ; {$IFNDEF DELPHI} Zmt : Bset ; Ostr : string ; {$ENDIF} const DaysInMonth : array [1..12] of byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) ; begin if (Length(St)>1) and (St[1] in ['-', '/']) then Delete(St, 1, 1) ; Ch := UpCase(St[1]) ; Delete(St, 1, 1) ; case Ch of '?' : Help ; {$IFDEF BORPAS} 'E', 'V' : begin Ostr := OutStrF ; Environ(Gen, Put, St, Ostr, Status) ; if (Ch='E') or (Status<>0) then Writeln(Scr, NM, 'Environ Status = ', Status, ' OK=', Status=0, #32, St, '=', Ostr) ; end ; {$ENDIF BORPAS} 'P' : Writeln('SET ' + St + '=' + OutStrF) ; 'Q' : Writeln('@SET ' + St + '=' + OutStrF) ; 'R' : begin St := {$IFDEF BORPAS} GetEnv(St) {$ELSE} '' {$ENDIF} ; P := Pos('œ', St) ; if P>0 then St[P] := '=' ; Write(St + OutStrF) ; if Dogs then Write('"') ; Dogs := false ; Writeln end ; 'Y', '_' : begin Yr := Yr - GetLI(St) ; if (Ch<>'_') and (Mo=2) and (Dy>28) and not Greg_Leap_Year(Yr) then Dy := 28 ; end ; 'N', '~' : begin Z := Mo - GetLI(St) ; while Z<01 do begin Inc(Z, 12) ; Yr := Yr-1 end ; while Z>12 do begin Dec(Z, 12) ; Yr := Yr+1 end ; if Ch<>'~' then { crop days } begin Ult := DaysInMonth[Z] + Ord((Z=2) and Greg_Leap_Year(Yr)) ; if Dy>Ult then Dy := Ult ; end ; Mo := Z end ; 'W' : PlusDays := PlusDays - GetLI(St)*7 ; 'D' : PlusDays := PlusDays - GetLI(St) ; 'H' : PlusSecs := PlusSecs - GetLI(St)*3600 ; 'M' : PlusSecs := PlusSecs - GetLI(St)*60 ; 'S' : PlusSecs := PlusSecs - GetLI(St) ; 'F' : word(Fmt) := GetLI(St) ; 'I' : Sep := FSep(St) ; 'J' : Dsp := FSep(St) ; 'K' : Tsp := FSep(St) ; 'B' : Beg := GetLI(St) ; 'L' : Len := GetLI(St) ; 'Z' : Zed(GetLI(St)) ; 'X' : Mon := Odd(GetLI(St)) ; 'G' : Gen := GetLI(St) ; 'T' : GetDT(St) ; {$IFDEF BORPAS} 'O' : FileDateStamp(St) ; 'C' : begin Ostr := EnvGet(St) ; GetDT(Ostr) end ; {$ENDIF BORPAS} 'U' : UTCfromEuroTime(3600*GetLI(St)) ; 'A' : USA := Odd(GetLI(St)) ; '&' : AndStr := St ; ':' : if St[1]=':' then Writeln('??') else RandRange := GetLI(St) ; ']' : begin XYr := Yr ; XMo := Mo ; XDy := Dy ; XSecs := PlusSecs end ; '[' : begin Yr := XYr ; Mo := XMo ; Dy := XDy ; PlusSecs := XSecs end ; '-' : begin MJDtoYMD(YMDtoMJD(XYr, XMo, XDy)-YMDtoMJD(Yr, Mo, Dy), Yr, Mo, Dy) ; PlusSecs := XSecs - PlusSecs end ; {$IFDEF BORPAS} '^' : GetRTC ; {$ENDIF BORPAS} '$' : if St='$' then Base := 36 else Base := 16 ; '#' : Base := 10 ; 'œ' : begin Write(Scr, NM, 'œ ? ') ; Readln end ; '''' : Write(St) ; '*' : begin if St='*' then begin Write('"') ; Dogs := not Dogs end else begin if St='' then Z := 1 else Z := GetLI(St) ; while Z>0 do begin Write(#32) ; Dec(Z) end ; end ; end ; '@' : ExecFile(St) ; {$IFDEF BORPAS} '!' : begin Environ(Gen, Get, St, Ostr, Status) ; {} {$IFDEF DEBUG} Writeln(Scr, '*** !: Ostr="', Ostr, '"') ; {$ENDIF} if Status<>0 then Writeln(Scr, ^I, 'Environ Status = ', Status, ', OK=', Status=0 {, #32, St, '=', Ostr}) ; if Status<>0 then begin Writeln('Environment read failed') ; HALT(11) end ; SwapVectors ; Exec(GetEnv('COMSPEC'), ' /C '+Ostr) ; SwapVectors end ; {$ENDIF BORPAS} '=' : ; 'ª' : GregorianEaster(Yr, Mo, Dy) ; ';' : EXIT ; else begin Writeln(Scr, NM, Ch, ' = Bad option') ; HALT(3) end ; end {Ch} ; Norm(Yr, Mo, Dy, PlusDays, PlusSecs) ; if Mon then Writeln(Scr, NM, #32, Yr, #32, Mo, #32, Dy, ', ', PlusSecs) ; end {DoCommand} ; procedure ExecFile(const St : string) ; var F : text ; S : string ; P : byte ; begin Assign(F, St) ; Reset(F) ; while not EoF(F) do begin Readln(F, S) ; S := S + #32 ; repeat if S='' then BREAK ; P := Pos(#32, S) ; if P=1 then begin Delete(S, 1, 1) ; CONTINUE end ; DoCommand(Copy(S, 1, P-1)) ; Delete(S, 1, P) ; until false ; end { line } ; Close(F) end {ExecFile} ; procedure ProcessParameters ; var Par : word ; begin for Par := 1 to ParamCount do DoCommand(ParamStr(Par)) ; end {ProcessParameters} ; BEGIN ; {} {$IFDEF DEBUG} {} TextMode(LastMode + Font8x8) ; {} Writeln('*** NOWMINUS starting') ; {} {$ENDIF} Assign(Scr, 'CON') ; Rewrite(Scr) ; if ParamCount=0 then Help ; Initialise ; ProcessParameters ; if Mon then Writeln(Scr, NM, 'ends OK.') ; Close(Scr) ; { Examples in NOWMINUS.TXT } END.