fpc/rtl/beos/timezone.inc
peter 4ace790492 * remove $Log
git-svn-id: trunk@231 -
2005-06-07 09:47:55 +00:00

429 lines
8.6 KiB
PHP

{
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;