{ $Id$ This file is part of the Free Pascal run time library. Copyright (c) 2002 by the Free Pascal development team. Timezone extraction routines See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} const TZ_MAGIC = 'TZif'; type plongint=^longint; pbyte=^byte; ttzhead=packed record tzh_magic : array[0..3] of char; tzh_reserved : array[1..16] of byte; tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt : longint; end; pttinfo=^tttinfo; tttinfo=packed record offset : longint; isdst : boolean; idx : byte; isstd : byte; isgmt : byte; end; pleap=^tleap; tleap=record transition : longint; change : longint; end; var num_transitions, num_leaps, num_types : longint; transitions : plongint; type_idxs : pbyte; types : pttinfo; zone_names : pchar; leaps : pleap; function find_transition(timer:time_t):pttinfo; var i : longint; begin if (num_transitions=0) or (timerleaps[i].transition); leap_correct:=leaps[i].change; if (timer=leaps[i].transition) and (((i=0) and (leaps[i].change>0)) or (leaps[i].change>leaps[i-1].change)) then begin leap_hit:=1; while (i>0) and (leaps[i].transition=leaps[i-1].transition+1) and (leaps[i].change=leaps[i-1].change+1) do begin inc(leap_hit); dec(i); end; end; end; procedure GetLocalTimezone(timer:longint); var lc,lh : longint; begin GetLocalTimezone(timer,lc,lh); end; procedure ReadTimezoneFile(fn:string); procedure decode(var l:longint); var k : longint; p : pbyte; begin p:=pbyte(@l); if (p[0] and (1 shl 7))<>0 then k:=not 0 else k:=0; k:=(k shl 8) or p[0]; k:=(k shl 8) or p[1]; k:=(k shl 8) or p[2]; k:=(k shl 8) or p[3]; l:=k; end; var f : File; tzdir : string; tzhead : ttzhead; i : longint; chars : longint; buf : pbyte; _result : longint; label lose; begin if fn = '' then exit; {$IFOPT I+} {$DEFINE IOCHECK_ON} {$ENDIF} {$I-} Assign(F, fn); Reset(F,1); If IOResult <> 0 then exit; {$IFDEF IOCHECK_ON} {$I+} {$ENDIF} {$UNDEF IOCHECK_ON} BlockRead(f,tzhead,sizeof(tzhead),i); if i<>sizeof(tzhead) then goto lose; if tzhead.tzh_magic<>TZ_MAGIC then begin goto lose; end; decode(tzhead.tzh_timecnt); decode(tzhead.tzh_typecnt); decode(tzhead.tzh_charcnt); decode(tzhead.tzh_leapcnt); decode(tzhead.tzh_ttisstdcnt); decode(tzhead.tzh_ttisgmtcnt); num_transitions:=tzhead.tzh_timecnt; num_types:=tzhead.tzh_typecnt; chars:=tzhead.tzh_charcnt; reallocmem(transitions,num_transitions*sizeof(longint)); reallocmem(type_idxs,num_transitions); reallocmem(types,num_types*sizeof(tttinfo)); reallocmem(zone_names,chars); reallocmem(leaps,num_leaps*sizeof(tleap)); BlockRead(f,transitions^,num_transitions*4,_result); if _result <> num_transitions*4 then begin goto lose; end; BlockRead(f,type_idxs^,num_transitions,_result); if _result <> num_transitions then begin goto lose; end; {* Check for bogus indices in the data file, so we can hereafter safely use type_idxs[T] as indices into `types' and never crash. *} for i := 0 to num_transitions-1 do if (type_idxs[i] >= num_types) then begin goto lose; end; for i:=0 to num_transitions-1 do decode(transitions[i]); for i:=0 to num_types-1 do begin blockread(f,types[i].offset,4,_result); if _result <> 4 then begin goto lose; end; blockread(f,types[i].isdst,1,_result); if _result <> 1 then begin goto lose; end; blockread(f,types[i].idx,1,_result); if _result <> 1 then begin goto lose; end; decode(types[i].offset); types[i].isstd:=0; types[i].isgmt:=0; end; blockread(f,zone_names^,chars,_result); if _result<>chars then begin goto lose; end; for i:=0 to num_leaps-1 do begin blockread(f,leaps[i].transition,4); if _result <> 4 then begin goto lose; end; blockread(f,leaps[i].change,4); begin goto lose; end; decode(leaps[i].transition); decode(leaps[i].change); end; getmem(buf,tzhead.tzh_ttisstdcnt); blockread(f,buf^,tzhead.tzh_ttisstdcnt,_result); if _result<>tzhead.tzh_ttisstdcnt then begin goto lose; end; for i:=0 to tzhead.tzh_ttisstdcnt-1 do types[i].isstd:=byte(buf[i]<>0); freemem(buf); getmem(buf,tzhead.tzh_ttisgmtcnt); blockread(f,buf^,tzhead.tzh_ttisgmtcnt); if _result<>tzhead.tzh_ttisgmtcnt then begin goto lose; end; for i:=0 to tzhead.tzh_ttisgmtcnt-1 do types[i].isgmt:=byte(buf[i]<>0); freemem(buf); close(f); exit; lose: close(f); end; { help function to extract TZ variable data } function extractnumberend(tzstr: string; offset : integer): integer; var j: integer; begin j:=0; extractnumberend := 0; repeat if (offset+j) > length(tzstr) then begin exit; end; inc(j); until not (tzstr[offset+j] in ['0'..'9']); extractnumberend := offset+j; end; function getoffsetseconds(tzstr: string): longint; { extract GMT timezone information } { Returns the number of minutes to } { add or subtract to the GMT time } { to get the local time. } { Format of TZ variable (POSIX) } { std offset dst } { std = characters of timezone } { offset = hh[:mm] to add to GMT } { dst = daylight savings time } { CURRENTLY DOES NOT TAKE CARE } { OF SUMMER TIME DIFFERENCIAL } var s: string; i, j: integer; code : integer; hours : longint; minutes : longint; negative : boolean; begin hours:=0; minutes:=0; getoffsetseconds := 0; negative := FALSE; i:=-1; { get to offset field } repeat if i > length(tzstr) then begin exit; end; inc(i); until (tzstr[i] = '-') or (tzstr[i] in ['0'..'9']); if tzstr[i] = '-' then begin Inc(i); negative := TRUE; end; j:=extractnumberend(tzstr,i); s:=copy(tzstr,i,j-i); val(s,hours,code); if code <> 0 then begin exit; end; if tzstr[j] = ':' then begin i:=j; Inc(i); j:=extractnumberend(tzstr,i); s:=copy(tzstr,i,j-i); val(s,minutes,code); if code <> 0 then begin exit; end; end; if negative then begin minutes := -minutes; hours := -hours; end; getoffsetseconds := minutes*60 + hours*3600; end; procedure InitLocalTime; var tloc: time_t; s : string; begin TZSeconds:=0; { try to get the POSIX version } { of the local time offset } { if '', then it does not exist } { if ': ..', then non-POSIX } s:=GetTimezoneString; if (s<>'') and (s[1]<>':') then begin TZSeconds := getoffsetseconds(s); end else begin s:=GetTimeZoneFile; { only read if there is something to read } if s<>'' then begin ReadTimezoneFile(s); tloc:=sys_time(tloc); GetLocalTimezone(tloc); end; end; end; procedure DoneLocalTime; begin if assigned(transitions) then freemem(transitions); if assigned(type_idxs) then freemem(type_idxs); if assigned(types) then freemem(types); if assigned(zone_names) then freemem(zone_names); if assigned(leaps) then freemem(leaps); num_transitions:=0; num_leaps:=0; num_types:=0; end; { $Log$ Revision 1.3 2002-09-07 16:01:26 peter * old logs removed and tabs fixed Revision 1.2 2002/08/10 13:42:36 marco * Fixes Posix dir copied to devel branch Revision 1.1.2.2 2002/05/01 14:06:13 carl * bugfix for stricter POSIX checking + TZ is now taken from GetTimezoneSitrng instead of getenv }