[fpc-devel] Unix internationalization patch

petr.kristan at epos.cz petr.kristan at epos.cz
Tue Apr 8 19:05:02 CEST 2008


On Tue, Apr 08, 2008 at 05:19:34PM +0200, Jonas Maebe wrote:
> 
> On 08 Apr 2008, at 17:03, petr.kristan at epos.cz wrote:
> >On Tue, Apr 08, 2008 at 04:29:51PM +0200, Michael Van Canneyt wrote:
> >>
> >
> >>This is not correct, it makes sysutils dependent on (g)libc and  
> >>that is not
> >>allowed. The correct way of doing this is to make it a separate unit
> >>that links to libc, and fills all variables in it's initialization  
> >>section.
> >Ok. But where in rtl place this unit in the uses clause?
> 
> Nowhere. You'll have to manually add it to the uses-clause of your  
> programs, like the cwstring (widestring support for unix) and cthreads  
> (threading support for unix) units.
Here is attached separated clocale.pp. I think that it should be placed into rtl/unix directory.
Unit is tested only in Linux environment, but I assume that on other unices
will be necessary to add some $IFDEFs.

Finally a little question. I'am here new, do not know context and my
english is bad. But why rtl/win/sysutils.pp can depend on windows and
rtl/unix/sysutils.pp cannot depend on libc?

Petr

-- 
Ing. Petr Kristan
.
EPOS PRO s.r.o., Bozeny Nemcove 2625, 530 02 Pardubice
tel: +420 466335223    Czech Republic (Eastern Europe) 
fax: +420 466510709
-------------- next part --------------
{
    This file is part of the Free Pascal run time library.
    Copyright (c) 2005 by Florian Klaempfl,
    member of the Free Pascal development team.

    Init rtl formating variables based on libc locales

    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.
 **********************************************************************}

unit clocale;

{$mode objfpc}

interface

implementation

{$linklib c}

Uses
  SysUtils, unixtype, initc;

Const
  __LC_CTYPE    = 0;
  __LC_NUMERIC  = 1;
  __LC_TIME     = 2;
  __LC_COLLATE  = 3;
  __LC_MONETARY = 4;
  __LC_MESSAGES = 5;
  __LC_ALL      = 6;
  

 ABDAY_1 = (__LC_TIME shl 16);
 DAY_1 = (ABDAY_1)+7;
 ABMON_1 = (ABDAY_1)+14;
 MON_1 = (ABDAY_1)+26;
 AM_STR = (ABDAY_1)+38;
 PM_STR = (ABDAY_1)+39;
 D_T_FMT = (ABDAY_1)+40;
 D_FMT = (ABDAY_1)+41;
 T_FMT = (ABDAY_1)+42;
 T_FMT_AMPM = (ABDAY_1)+43;

 __DECIMAL_POINT = (__LC_NUMERIC shl 16);
 RADIXCHAR = __DECIMAL_POINT;
 __THOUSANDS_SEP = (__DECIMAL_POINT)+1;

 __INT_CURR_SYMBOL = (__LC_MONETARY shl 16);
 __CURRENCY_SYMBOL = (__INT_CURR_SYMBOL)+1;
 __MON_DECIMAL_POINT = (__INT_CURR_SYMBOL)+2;
 __MON_THOUSANDS_SEP = (__INT_CURR_SYMBOL)+3;
 __MON_GROUPING = (__INT_CURR_SYMBOL)+4;
 __POSITIVE_SIGN = (__INT_CURR_SYMBOL)+5;
 __NEGATIVE_SIGN = (__INT_CURR_SYMBOL)+6;
 __INT_FRAC_DIGITS = (__INT_CURR_SYMBOL)+7;
 __FRAC_DIGITS = (__INT_CURR_SYMBOL)+8;
 __P_CS_PRECEDES = (__INT_CURR_SYMBOL)+9;
 __P_SEP_BY_SPACE = (__INT_CURR_SYMBOL)+10;
 __N_CS_PRECEDES = (__INT_CURR_SYMBOL)+11;
 __N_SEP_BY_SPACE = (__INT_CURR_SYMBOL)+12;
 __P_SIGN_POSN = (__INT_CURR_SYMBOL)+13;
 __N_SIGN_POSN = (__INT_CURR_SYMBOL)+14;
 _NL_MONETARY_CRNCYSTR = (__INT_CURR_SYMBOL)+15;



function setlocale(category: cint; locale: pchar): pchar; cdecl; external clib name 'setlocale';
function nl_langinfo(__item: cint):Pchar;cdecl;external clib name 'nl_langinfo';

procedure GetFormatSettings;

  function GetLocaleStr(item: cint): string;
  begin
    GetLocaleStr := AnsiString(nl_langinfo(item));
  end;

  function GetLocaleChar(item: cint): char;
  begin
    GetLocaleChar := nl_langinfo(item)^;
  end;

  function FindSeparator(const s: string; Def: char): char;
  var
    i, l: integer;
  begin
    FindSeparator := Def;
    i := Pos('%', s);
    if i=0 then
      Exit;
    l := Length(s);
    inc(i);
    if (i<=l) and (s[i] in ['E', 'O']) then //possible modifier
      inc(i);
    inc(i); 
    if i<=l then
      FindSeparator := s[i];
  end;

  function TransformFormatStr(const s: string): string;
  var
    i, l: integer;
  begin
    TransformFormatStr := '';
    i := 1;
    l := Length(s);
    while i<=l do begin
      if s[i]='%' then begin
        inc(i);
        if (i<=l) and (s[i] in ['E', 'O']) then //ignore modifier
          inc(i);
        if i>l then
          Exit;
        case s[i] of
          'a': TransformFormatStr := TransformFormatStr + 'ddd';
          'A': TransformFormatStr := TransformFormatStr + 'dddd';
          'b': TransformFormatStr := TransformFormatStr + 'mmm';
          'B': TransformFormatStr := TransformFormatStr + 'mmmm';
          'c': TransformFormatStr := TransformFormatStr + 'c';
          //'C':
          'd': TransformFormatStr := TransformFormatStr + 'dd';
          'D': TransformFormatStr := TransformFormatStr + 'mm"/"dd"/"yy';
          'e': TransformFormatStr := TransformFormatStr + 'd';
          'F': TransformFormatStr := TransformFormatStr + 'yyyy-mm-dd';
          'g': TransformFormatStr := TransformFormatStr + 'yy';
          'G': TransformFormatStr := TransformFormatStr + 'yyyy';
          'h': TransformFormatStr := TransformFormatStr + 'mmm';
          'H': TransformFormatStr := TransformFormatStr + 'hh';
          'I': TransformFormatStr := TransformFormatStr + 'hhampm';
          //'j':
          'k': TransformFormatStr := TransformFormatStr + 'h';
          'l': TransformFormatStr := TransformFormatStr + 'hampm';
          'm': TransformFormatStr := TransformFormatStr + 'mm';
          'M': TransformFormatStr := TransformFormatStr + 'nn';
          'n': TransformFormatStr := TransformFormatStr + sLineBreak;
          'p': TransformFormatStr := TransformFormatStr + 'ampm';
          'P': TransformFormatStr := TransformFormatStr + 'ampm';
          'r': TransformFormatStr := TransformFormatStr + 'hhampm:nn:ss';
          'R': TransformFormatStr := TransformFormatStr + 'hh:nn';
          //'s':
          'S': TransformFormatStr := TransformFormatStr + 'ss';
          't': TransformFormatStr := TransformFormatStr + #9;
          'T': TransformFormatStr := TransformFormatStr + 'hh:nn:ss';
          //'u':
          //'U':
          //'V':
          //'w':
          //'W':
          'x': TransformFormatStr := TransformFormatStr + 'ddddd';
          'X': TransformFormatStr := TransformFormatStr + 't';
          'y': TransformFormatStr := TransformFormatStr + 'yy';
          'Y': TransformFormatStr := TransformFormatStr + 'yyyy';
          //'z':
          //'Z':
          '%': TransformFormatStr := TransformFormatStr + '%';
        end;
      end else
        TransformFormatStr := TransformFormatStr + s[i];
      inc(i);
    end;
  end;

const
  //                      sign  prec  sep
  NegFormatsTable: array [0..4, 0..1, 0..1] of byte = (
    ( (4, 15), (0, 14) ), //Parentheses surround the quantity and currency_symbol
    ( (5, 8), (1, 9) ), //The sign string precedes the quantity and currency_symbol
    ( (7, 10), (3, 11) ), //The sign string follows the quantity and currency_symbol
    ( (6, 13), (1, 9) ), //The sign string immediately precedes the currency_symbol
    ( (7, 10), (2, 12) )  //The sign string immediately follows the currency_symbol
  ); 
var
  i: integer;
  prec, sep, signp: byte;
begin
  setlocale(__LC_ALL,'');
  for i := 1 to 12 do
    begin
    ShortMonthNames[i]:=GetLocaleStr(ABMON_1+i-1);
    LongMonthNames[i]:=GetLocaleStr(MON_1+i-1);
    end;
  for i := 1 to 7 do
    begin
    ShortDayNames[i]:=GetLocaleStr(ABDAY_1+i-1);
    LongDayNames[i]:=GetLocaleStr(DAY_1+i-1);
    end;
  //Date stuff
  ShortDateFormat := GetLocaleStr(D_FMT);
  DateSeparator := FindSeparator(ShortDateFormat, DateSeparator);
  ShortDateFormat := TransformFormatStr(ShortDateFormat);
  LongDateFormat := GetLocaleStr(D_T_FMT);
  LongDateFormat := TransformFormatStr(LongDateFormat);
  //Time stuff
  TimeAMString := GetLocaleStr(AM_STR);
  TimePMString := GetLocaleStr(PM_STR);
  ShortTimeFormat := GetLocaleStr(T_FMT);
  TimeSeparator := FindSeparator(ShortTimeFormat, TimeSeparator);
  ShortTimeFormat := TransformFormatStr(ShortTimeFormat);
  LongTimeFormat := GetLocaleStr(T_FMT_AMPM);
  LongTimeFormat := TransformFormatStr(LongTimeFormat);
  //Currency stuff
  CurrencyString := GetLocaleStr(_NL_MONETARY_CRNCYSTR);
  CurrencyString := Copy(CurrencyString, 2, Length(CurrencyString));
  CurrencyDecimals := StrToIntDef(GetLocaleStr(__FRAC_DIGITS), CurrencyDecimals);
  prec := byte(GetLocaleChar(__P_CS_PRECEDES));
  sep := byte(GetLocaleChar(__P_SEP_BY_SPACE));
  if (prec<=1) and (sep<=1) then
    CurrencyFormat := byte(not boolean(prec)) + sep shl 1;
  prec := byte(GetLocaleChar(__N_CS_PRECEDES));
  sep := byte(GetLocaleChar(__N_SEP_BY_SPACE));
  signp := byte(GetLocaleChar(__N_SIGN_POSN));
  if (signp in [0..4]) and (prec in [0, 1]) and (sep in [0, 1]) then
    NegCurrFormat := NegFormatsTable[signp, prec, sep];
  //Number stuff
  ThousandSeparator:=GetLocaleChar(__THOUSANDS_SEP);
  DecimalSeparator:=GetLocaleChar(RADIXCHAR);
end;

initialization
  GetFormatSettings;

end.


More information about the fpc-devel mailing list