123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- {
- 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 (timer<time_t(transitions[0])) then
- begin
- i:=0;
- while (i<num_types) and (types[i].isdst) do
- inc(i);
- if (i=num_types) then
- i:=0;
- end
- else
- begin
- for i:=1 to num_transitions do
- if (timer<transitions[i]) then
- break;
- i:=type_idxs[i-1];
- end;
- find_transition:=@types[i];
- end;
- procedure GetLocalTimezone(timer:time_t;var leap_correct,leap_hit:longint);
- var
- info : pttinfo;
- i : longint;
- begin
- { reset }
- TZDaylight:=false;
- TZSeconds:=0;
- TZName[false]:=nil;
- TZName[true]:=nil;
- leap_correct:=0;
- leap_hit:=0;
- { get info }
- info:=find_transition(timer);
- if not assigned(info) then
- exit;
- TZDaylight:=info^.isdst;
- TZSeconds:=info^.offset;
- i:=0;
- while (i<num_types) do
- begin
- tzname[types[i].isdst]:=@zone_names[types[i].idx];
- inc(i);
- end;
- tzname[info^.isdst]:=@zone_names[info^.idx];
- i:=num_leaps;
- repeat
- if i=0 then
- exit;
- dec(i);
- until (timer>leaps[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;
|