mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 16:09:23 +02:00
* android: Implemented clocale. Fixed makefile.
git-svn-id: trunk@34349 -
This commit is contained in:
parent
064375ea72
commit
4a661ea8f8
@ -12,8 +12,7 @@ Const
|
|||||||
// in workable state atm.
|
// in workable state atm.
|
||||||
UnixLikes = AllUnixOSes -[QNX]; // qnx never was active in 2.x afaik
|
UnixLikes = AllUnixOSes -[QNX]; // qnx never was active in 2.x afaik
|
||||||
|
|
||||||
// Android has a dummy clocale unit, while it also includes unix dir.
|
ClocaleOSes = UnixLikes -[beos,android];
|
||||||
ClocaleOSes = UnixLikes -[beos];
|
|
||||||
CLocaleIncOSes= [Aix,freebsd,netbsd,openbsd,solaris,darwin,iphonesim,dragonfly];
|
CLocaleIncOSes= [Aix,freebsd,netbsd,openbsd,solaris,darwin,iphonesim,dragonfly];
|
||||||
|
|
||||||
IPCOSes = UnixLikes-[aix,android,beos,haiku];
|
IPCOSes = UnixLikes-[aix,android,beos,haiku];
|
||||||
@ -82,6 +81,10 @@ begin
|
|||||||
P.IncludePath.Add('src/darwin',[iphonesim]);
|
P.IncludePath.Add('src/darwin',[iphonesim]);
|
||||||
P.IncludePath.Add('src/win',AllWindowsOSes);
|
P.IncludePath.Add('src/win',AllWindowsOSes);
|
||||||
|
|
||||||
|
// Add clocale for Android first in order to compile the source file
|
||||||
|
// from the 'android' dir, not the 'unix' dir.
|
||||||
|
T:=P.Targets.AddUnit('clocale.pp',[android]);
|
||||||
|
|
||||||
T:=P.Targets.AddUnit('ucomplex.pp',UComplexOSes);
|
T:=P.Targets.AddUnit('ucomplex.pp',UComplexOSes);
|
||||||
|
|
||||||
T:=P.Targets.AddUnit('objects.pp',ObjectsOSes);
|
T:=P.Targets.AddUnit('objects.pp',ObjectsOSes);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
This file is part of the Free Pascal run time library.
|
This file is part of the Free Pascal run time library.
|
||||||
Copyright (c) 2013 by the Free Pascal development team.
|
Copyright (c) 2016 by the Free Pascal development team.
|
||||||
|
|
||||||
Android locale support. !!! NOT IMPLEMENTED !!!
|
Android locale support.
|
||||||
|
|
||||||
See the file COPYING.FPC, included in this distribution,
|
See the file COPYING.FPC, included in this distribution,
|
||||||
for details about the copyright.
|
for details about the copyright.
|
||||||
@ -18,6 +18,332 @@ unit clocale;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
cwstring, SysUtils;
|
||||||
|
|
||||||
|
procedure GetAndroidFormatSettings(var ASettings: TFormatSettings; ALocale: utf8string = '');
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
UErrorCode = SizeInt;
|
||||||
|
int32_t = longint;
|
||||||
|
uint32_t = longword;
|
||||||
|
UBool = LongBool;
|
||||||
|
|
||||||
|
UDateFormat = pointer;
|
||||||
|
UDateFormatStyle = longint;
|
||||||
|
UDate = double;
|
||||||
|
UNumberFormat = pointer;
|
||||||
|
UNumberFormatStyle = longint;
|
||||||
|
UNumberFormatSymbol = longint;
|
||||||
|
|
||||||
|
const
|
||||||
|
UDAT_NONE = -1;
|
||||||
|
UDAT_FULL = 0;
|
||||||
|
UDAT_LONG = 1;
|
||||||
|
UDAT_MEDIUM = 2;
|
||||||
|
UDAT_SHORT = 3;
|
||||||
|
|
||||||
|
UNUM_DECIMAL_SEPARATOR_SYMBOL = 0;
|
||||||
|
UNUM_GROUPING_SEPARATOR_SYMBOL = 1;
|
||||||
|
UNUM_CURRENCY_SYMBOL = 8;
|
||||||
|
|
||||||
|
var
|
||||||
|
FunctionsInited: boolean;
|
||||||
|
|
||||||
|
udat_open: function (timeStyle: UDateFormatStyle; dateStyle: UDateFormatStyle; locale: PAnsiChar; tzID: PUnicodeChar; tzIDLength: int32_t;
|
||||||
|
pattern: PUnicodeChar; patternLength: int32_t; var status: UErrorCode): UDateFormat; cdecl;
|
||||||
|
udat_close: procedure (format: UDateFormat); cdecl;
|
||||||
|
udat_toPattern: function (format: UDateFormat; localized: UBool; result: PUnicodeChar; resultLength: int32_t; var status: UErrorCode): int32_t; cdecl;
|
||||||
|
udat_applyPattern: procedure (format: UDateFormat; localized: UBool; pattern: PUnicodeChar; patternLength: int32_t); cdecl;
|
||||||
|
udat_format: function (format: UDateFormat; dateToFormat: UDate; result: PUnicodeChar; resultLength: int32_t; position: pointer; var status: UErrorCode): int32_t; cdecl;
|
||||||
|
|
||||||
|
unum_open: function (style: UNumberFormatStyle; pattern: PUnicodeChar; patternLength: int32_t; locale: PAnsiChar; parseErr: pointer;
|
||||||
|
var status: UErrorCode): UNumberFormat; cdecl;
|
||||||
|
unum_close: procedure (fmt: UNumberFormat); cdecl;
|
||||||
|
unum_getSymbol: function (fmt: UNumberFormat; symbol: UNumberFormatSymbol; result: PUnicodeChar; resultLength: int32_t; var status: UErrorCode): int32_t; cdecl;
|
||||||
|
|
||||||
|
function GetIcuProc(const Name: AnsiString; out ProcPtr; libId: longint = 0): boolean; external name 'CWSTRING_GET_ICU_PROC';
|
||||||
|
|
||||||
|
procedure InitIcuFunctions;
|
||||||
|
begin
|
||||||
|
if FunctionsInited then exit;
|
||||||
|
if not GetIcuProc('udat_open', udat_open, 1) then exit;
|
||||||
|
if not GetIcuProc('udat_close', udat_close, 1) then exit;
|
||||||
|
if not GetIcuProc('udat_toPattern', udat_toPattern, 1) then exit;
|
||||||
|
if not GetIcuProc('udat_applyPattern', udat_applyPattern, 1) then exit;
|
||||||
|
if not GetIcuProc('udat_format', udat_format, 1) then exit;
|
||||||
|
if not GetIcuProc('unum_open', unum_open, 1) then exit;
|
||||||
|
if not GetIcuProc('unum_close', unum_close, 1) then exit;
|
||||||
|
if not GetIcuProc('unum_getSymbol', unum_getSymbol, 1) then exit;
|
||||||
|
|
||||||
|
FunctionsInited:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$ifdef android}
|
||||||
|
|
||||||
|
function GetCurrentLocaleStr: utf8string;
|
||||||
|
var
|
||||||
|
s: utf8string;
|
||||||
|
begin
|
||||||
|
Result:=GetSystemProperty('persist.sys.language');
|
||||||
|
if Result = '' then
|
||||||
|
exit;
|
||||||
|
s:=GetSystemProperty('persist.sys.country');
|
||||||
|
if s = '' then
|
||||||
|
exit;
|
||||||
|
Result:=Result + '_' + s;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$endif android}
|
||||||
|
|
||||||
|
function StrOfChar(c: AnsiChar; Count: integer): utf8string;
|
||||||
|
begin
|
||||||
|
SetLength(Result, Count);
|
||||||
|
FillChar(PAnsiChar(Result)^, Count, c);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ConvertFormatStr(const fmt: utf8string): utf8string;
|
||||||
|
var
|
||||||
|
cnt: integer;
|
||||||
|
c, q: AnsiChar;
|
||||||
|
p: PAnsiChar;
|
||||||
|
s: utf8string;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
q:=#0;
|
||||||
|
cnt:=1;
|
||||||
|
p:=PAnsiChar(fmt);
|
||||||
|
while p^<>#0 do
|
||||||
|
begin
|
||||||
|
s:='';
|
||||||
|
c:=p^;
|
||||||
|
if c in ['''', '"'] then
|
||||||
|
begin
|
||||||
|
if q=#0 then
|
||||||
|
q:=c
|
||||||
|
else
|
||||||
|
if c=q then
|
||||||
|
begin
|
||||||
|
q:=#0;
|
||||||
|
cnt:=1;
|
||||||
|
end;
|
||||||
|
s:=c;
|
||||||
|
end
|
||||||
|
else if q <> #0 then
|
||||||
|
s:=c
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (p+1)^=c then
|
||||||
|
Inc(cnt)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
case c of
|
||||||
|
'y', 'Y':
|
||||||
|
begin
|
||||||
|
c:='y';
|
||||||
|
if cnt > 2 then
|
||||||
|
cnt:=4
|
||||||
|
else
|
||||||
|
cnt:=2;
|
||||||
|
end;
|
||||||
|
'M', 'L':
|
||||||
|
begin
|
||||||
|
c:='m';
|
||||||
|
if cnt > 4 then
|
||||||
|
cnt:=3;
|
||||||
|
end;
|
||||||
|
'd':
|
||||||
|
if cnt > 2 then
|
||||||
|
cnt:=2;
|
||||||
|
'E', 'e', 'c':
|
||||||
|
begin
|
||||||
|
c:='d';
|
||||||
|
if (cnt < 3) or (cnt > 4) then
|
||||||
|
cnt:=3;
|
||||||
|
end;
|
||||||
|
'a':
|
||||||
|
begin
|
||||||
|
cnt:=0;
|
||||||
|
s:='ampm';
|
||||||
|
end;
|
||||||
|
'h', 'H', 'k', 'K':
|
||||||
|
begin
|
||||||
|
c:='h';
|
||||||
|
if cnt > 2 then
|
||||||
|
cnt:=2;
|
||||||
|
end;
|
||||||
|
'm':
|
||||||
|
begin
|
||||||
|
c:='n';
|
||||||
|
if cnt>2 then
|
||||||
|
cnt:=2;
|
||||||
|
end;
|
||||||
|
's':
|
||||||
|
if cnt>2 then
|
||||||
|
cnt:=2;
|
||||||
|
'S':
|
||||||
|
begin
|
||||||
|
c:='z';
|
||||||
|
cnt:=1;
|
||||||
|
end;
|
||||||
|
'G','u','Q','q','w','W','D','F','g','A','z','Z','v':
|
||||||
|
cnt:=0;
|
||||||
|
end;
|
||||||
|
if cnt>0 then
|
||||||
|
s:=StrOfChar(c, cnt);
|
||||||
|
cnt:=1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Inc(p);
|
||||||
|
if s<>'' then
|
||||||
|
Result:=Result+s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GetAndroidFormatSettings(var ASettings: TFormatSettings; ALocale: utf8string);
|
||||||
|
const
|
||||||
|
SGMT = 'GMT';
|
||||||
|
|
||||||
|
var
|
||||||
|
locale: ansistring;
|
||||||
|
|
||||||
|
function _GetFormat(dateStyle: UDateFormatStyle; timeStyle: UDateFormatStyle; const DefFormat: utf8string): utf8string;
|
||||||
|
var
|
||||||
|
fmt: UDateFormat;
|
||||||
|
err: UErrorCode;
|
||||||
|
res: unicodestring;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
err:=0;
|
||||||
|
fmt:=udat_open(timeStyle, dateStyle, PAnsiChar(locale), SGMT, Length(SGMT), nil, 0, err);
|
||||||
|
if fmt <> nil then
|
||||||
|
begin
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, udat_toPattern(fmt, False, PUnicodeChar(res), Length(res), err));
|
||||||
|
udat_close(fmt);
|
||||||
|
Result:=ConvertFormatStr(utf8string(res));
|
||||||
|
end;
|
||||||
|
if Result = '' then
|
||||||
|
Result:=DefFormat;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function _DateToStr(fmt: UDateFormat; const AFormat: unicodestring; AYear: integer; AMonth, ADay, AHour: byte): utf8string;
|
||||||
|
var
|
||||||
|
d: double;
|
||||||
|
err: UErrorCode;
|
||||||
|
res: unicodestring;
|
||||||
|
begin
|
||||||
|
d:=EncodeDate(AYear, AMonth, ADay) + EncodeTime(AHour, 0, 0, 0) - UnixDateDelta;
|
||||||
|
d:=MSecsPerDay*d;
|
||||||
|
udat_applyPattern(fmt, False, PUnicodeChar(AFormat), Length(AFormat));
|
||||||
|
err:=0;
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, udat_format(fmt, d, PUnicodeChar(res), Length(res), nil, err));
|
||||||
|
Result:=utf8string(res);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function _GetSeparator(dateStyle: UDateFormatStyle; timeStyle: UDateFormatStyle; DefSep: char): char;
|
||||||
|
var
|
||||||
|
fmt: UDateFormat;
|
||||||
|
err: UErrorCode;
|
||||||
|
s: utf8string;
|
||||||
|
p: PAnsiChar;
|
||||||
|
res: unicodestring;
|
||||||
|
begin
|
||||||
|
Result:=DefSep;
|
||||||
|
err:=0;
|
||||||
|
fmt:=udat_open(timeStyle, dateStyle, PAnsiChar(locale), SGMT, Length(SGMT), nil, 0, err);
|
||||||
|
if fmt <> nil then
|
||||||
|
begin
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, udat_toPattern(fmt, False, PUnicodeChar(res), Length(res), err));
|
||||||
|
s:=_DateToStr(fmt, res, 2000, 1, 1, 0);
|
||||||
|
udat_close(fmt);
|
||||||
|
s:=Trim(s);
|
||||||
|
p:=PAnsiChar(s);
|
||||||
|
while p^<>#0 do
|
||||||
|
if (p^>' ') and (p^<'A') and not (p^ in ['0'..'9']) then
|
||||||
|
begin
|
||||||
|
Result:=p^;
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Inc(p);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
fmt: UDateFormat;
|
||||||
|
nfmt: UNumberFormat;
|
||||||
|
err: UErrorCode;
|
||||||
|
i: integer;
|
||||||
|
res: unicodestring;
|
||||||
|
begin
|
||||||
|
if not FunctionsInited then
|
||||||
|
exit;
|
||||||
|
locale:=ALocale;
|
||||||
|
{$ifdef android}
|
||||||
|
if locale = '' then
|
||||||
|
locale:=GetCurrentLocaleStr;
|
||||||
|
{$endif android}
|
||||||
|
if locale = '' then
|
||||||
|
locale:='en_US';
|
||||||
|
err:=0;
|
||||||
|
with ASettings do
|
||||||
|
begin
|
||||||
|
nfmt:=unum_open(2, nil, 0, PAnsiChar(locale), nil, err);
|
||||||
|
if nfmt <> nil then
|
||||||
|
begin
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, unum_getSymbol(nfmt, UNUM_DECIMAL_SEPARATOR_SYMBOL, PUnicodeChar(res), Length(res), err));
|
||||||
|
if res <> '' then
|
||||||
|
DecimalSeparator:=ansichar(res[1]);
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, unum_getSymbol(nfmt, UNUM_GROUPING_SEPARATOR_SYMBOL, PUnicodeChar(res), Length(res), err));
|
||||||
|
if res <> '' then
|
||||||
|
if Ord(res[1]) < 128 then
|
||||||
|
ThousandSeparator:=ansichar(res[1])
|
||||||
|
else
|
||||||
|
ThousandSeparator:=' ';
|
||||||
|
SetLength(res, 200);
|
||||||
|
SetLength(res, unum_getSymbol(nfmt, 8, PUnicodeChar(res), Length(res), err));
|
||||||
|
CurrencyString:=utf8string(res);
|
||||||
|
unum_close(nfmt);
|
||||||
|
end;
|
||||||
|
|
||||||
|
DateSeparator:=_GetSeparator(UDAT_SHORT, UDAT_NONE, DateSeparator);
|
||||||
|
TimeSeparator:=_GetSeparator(UDAT_NONE, UDAT_SHORT, TimeSeparator);
|
||||||
|
|
||||||
|
LongDateFormat:=_GetFormat(UDAT_LONG, UDAT_NONE, LongDateFormat);
|
||||||
|
ShortDateFormat:=_GetFormat(UDAT_SHORT, UDAT_NONE, ShortDateFormat);
|
||||||
|
LongTimeFormat:=_GetFormat(UDAT_NONE, UDAT_MEDIUM, LongTimeFormat);
|
||||||
|
ShortTimeFormat:=_GetFormat(UDAT_NONE, UDAT_SHORT, ShortTimeFormat);
|
||||||
|
|
||||||
|
fmt:=udat_open(UDAT_NONE, UDAT_NONE, PAnsiChar(locale), SGMT, Length(SGMT), nil, 0, err);
|
||||||
|
if fmt <> nil then
|
||||||
|
begin
|
||||||
|
for i:=1 to 12 do
|
||||||
|
begin
|
||||||
|
LongMonthNames[i]:=_DateToStr(fmt, 'LLLL', 2006, i, 1, 0);
|
||||||
|
ShortMonthNames[i]:=_DateToStr(fmt, 'LLL', 2006, i, 1, 0);
|
||||||
|
end;
|
||||||
|
for i:=1 to 7 do
|
||||||
|
begin
|
||||||
|
LongDayNames[i]:=_DateToStr(fmt, 'cccc', 2006, 1, i, 0);
|
||||||
|
ShortDayNames[i]:=_DateToStr(fmt, 'ccc', 2006, 1, i, 0);
|
||||||
|
end;
|
||||||
|
TimeAMString:=_DateToStr(fmt, 'a', 2006, 1, 1, 1);
|
||||||
|
TimePMString:=_DateToStr(fmt, 'a', 2006, 1, 1, 13);
|
||||||
|
udat_close(fmt);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
InitIcuFunctions;
|
||||||
|
GetAndroidFormatSettings(DefaultFormatSettings);
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
unit clocale;
|
unit clocale;
|
||||||
|
|
||||||
|
{$ifdef android}
|
||||||
|
{$error This unit is not intended for Android. Something wrong with the make file. }
|
||||||
|
{$endif android}
|
||||||
|
|
||||||
{$mode objfpc}
|
{$mode objfpc}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
Loading…
Reference in New Issue
Block a user