Browse Source

* Fix bugs 30950 & 29781

git-svn-id: trunk@36740 -
michael 8 years ago
parent
commit
32cdee6f5d
4 changed files with 406 additions and 517 deletions
  1. 1 0
      .gitattributes
  2. 392 0
      rtl/objpas/sysutils/fmtflt.inc
  3. 3 0
      rtl/objpas/sysutils/syshelp.inc
  4. 10 517
      rtl/objpas/sysutils/sysstr.inc

+ 1 - 0
.gitattributes

@@ -9743,6 +9743,7 @@ rtl/objpas/sysutils/filutil.inc svneol=native#text/plain
 rtl/objpas/sysutils/filutilh.inc svneol=native#text/plain
 rtl/objpas/sysutils/fina.inc svneol=native#text/plain
 rtl/objpas/sysutils/finah.inc svneol=native#text/plain
+rtl/objpas/sysutils/fmtflt.inc svneol=native#text/plain
 rtl/objpas/sysutils/intfh.inc svneol=native#text/plain
 rtl/objpas/sysutils/osutil.inc svneol=native#text/plain
 rtl/objpas/sysutils/osutilsh.inc svneol=native#text/plain

+ 392 - 0
rtl/objpas/sysutils/fmtflt.inc

@@ -0,0 +1,392 @@
+function IntFloatToTextFmt(Buf: FPChar; const Value; ValueType: TFloatValue; Format: FPChar; const AFormatSettings: TFormatSettings): Integer;
+
+Type
+  TPosArray = Array[0..3] of Integer;
+
+const
+  MaxPrecision = 18;  // Extended precision
+
+var
+  // Input in usable format
+  E : Extended;              // Value as extended.
+  FV: TFloatRec;             // Value as floatrec.
+  Section : String;          // Format can contain 3 sections, semicolon separated: Pos;Neg;Zero. This is the one to use.
+  SectionLength : Integer;   // Length of section.
+  // Calculated based on section. Static during output
+  ThousandSep: Boolean;      // Thousands separator detected in format ?
+  IsScientific: Boolean;     // Use Scientific notation ? (E detected in format)
+  DecimalPos: Integer;       // Position of decimal point in pattern.
+  FirstDigit: Integer;       // First actual digit in input (# or 0), relative to decimal point
+  LastDigit: Integer;        // Last required (0) digit, relative to decimal point
+  RequestedDigits: Integer;  // Number of requested digits, # and 0 alike
+  ExpSize : Integer;         // Number of digits in exponent
+  Available: Integer;        // Available digits in FV.
+  // These change during output loop
+  Current: Integer;          // Current digit in available digits
+  PadZeroes: Integer;        // Difference in requested digits before comma and exponent, needs to be padded with zeroes.
+  DistToDecimal: Integer;    // Place of current digit, relative to decimal point taking in account PadZeroes!
+
+  Procedure InitVars;
+
+  begin
+    if ValueType = fvCurrency then
+      E:=Currency(Value)
+    else
+      E:=Extended(Value);
+    Section:='';
+    SectionLength:=0;
+    ThousandSep:=false;
+    IsScientific:=false;
+    DecimalPos:=0;
+    FirstDigit:=MaxInt;
+    LastDigit:=0;
+    RequestedDigits:=0;
+    ExpSize:=0;
+    Available:=-1;
+  end;
+
+  procedure ToResult(const AChar: FChar); inline;
+  begin
+    Buf[Result]:=AChar;
+    Inc(Result);
+    // Writeln('->',AChar,'(',Ord(AChar),') : ',Result);
+  end;
+
+
+  procedure AddToResult(const AStr: FString);
+  var
+    I : Integer;
+  begin
+    For I:=1 to Length(AStr) do
+      ToResult(AStr[I]);
+  end;
+
+  procedure WriteDigit(ADigit: FChar);
+
+  // Write a digit to result, prepend with decimalseparator or append with 1000 separator
+
+  begin
+    if ADigit=#0 then exit;
+    // Writeln('WriteDigit: ',ADigit,', DistToDecimal: ',DistToDecimal);
+    Dec(DistToDecimal);
+    // -1 -> we've arrived behind the decimal
+    if (DistToDecimal=-1) then
+      begin
+      ToResult(AFormatSettings.DecimalSeparator);
+      ToResult(ADigit);
+      end
+    else
+      begin
+      // We're still before the decimal.
+      ToResult(ADigit);
+      if ThousandSep and ((DistToDecimal mod 3)=0) and (DistToDecimal>1) then
+        ToResult(AFormatSettings.ThousandSeparator);
+      end;
+  end;
+
+  Function GetDigit : FChar;
+
+  // Return next digit from available digits.
+  // May return #0 if none available.
+  // Will return '0' if applicable.
+
+  begin
+    // Writeln(' DistToDecimal <= LastDigit : ',DistToDecimal,' <  ',LastDigit,' have digit: ',Current<=Available, '(',Current,')');
+    Result:=#0;
+    if (Current<=Available) then
+      begin
+      Result:=FV.Digits[Current];
+      Inc(Current);
+      end
+    else if (DistToDecimal <= LastDigit) then
+      Dec(DistToDecimal)
+    else
+      Result:='0';
+    //  Writeln('GetDigit ->: ',Result);
+  end;
+
+  procedure CopyDigit;
+
+  // Copy a digit (#, 0) to the output with the correct value
+
+  begin
+    // Writeln('CopyDigit ');
+    if (PadZeroes=0) then
+      WriteDigit(GetDigit) // No shift needed, just copy what is available.
+    else if (PadZeroes<0) then
+      begin
+      // We must prepend zeroes
+      Inc(PadZeroes);
+      if (DistToDecimal<=FirstDigit) then
+        WriteDigit('0')
+      else
+        Dec(DistToDecimal);
+      end
+    else
+      begin
+      // We must append zeroes
+      while PadZeroes > 0 do
+        begin
+        WriteDigit(GetDigit);
+        Dec(PadZeroes);
+        end;
+      WriteDigit(GetDigit);
+      end;
+  end;
+
+  Function GetSections(Var SP : TPosArray) : Integer;
+
+  var
+    FL : Integer;
+    i : Integer;
+    C,Q : FChar;
+    inQuote : Boolean;
+
+  begin
+    Result:=1;
+    SP[1]:=-1;
+    SP[2]:=-1;
+    SP[3]:=-1;
+    inQuote:=False;
+    Q:=#0;
+    I:=0;
+    FL:=StrLen(Format);
+    while (I<FL) do
+      begin
+      C:=Format[I];
+      case C of
+      ';':
+        begin
+        if not InQuote then
+          begin
+          if Result>3 then
+            Raise Exception.Create('Invalid float format');
+          SP[Result]:=I+1;
+          Inc(Result);
+          end;
+        end;
+      '"','''':
+        begin
+        if InQuote then
+          InQuote:=C<>Q
+        else
+          begin
+          InQuote:=True;
+          Q:=C;
+          end;
+        end;
+      end;
+      Inc(I);
+      end;
+    if SP[Result]=-1 then
+      SP[Result]:=FL+1;
+  end;
+
+  Procedure AnalyzeFormat;
+
+  var
+    I,Len: Integer;
+    Q,C: FChar;
+    InQuote : Boolean;
+
+  begin
+    Len:=Length(Section);
+    I:=1;
+    InQuote:=False;
+    Q:=#0;
+    while (I<=Len) do
+      begin
+      C:=Section[i];
+      if C in ['"',''''] then
+        begin
+        if InQuote then
+          InQuote:=C<>Q
+        else
+          begin
+          InQuote:=True;
+          Q:=C;
+          end;
+        end
+      else if not InQuote then
+        case C of
+        '.':
+          if (DecimalPos=0) then
+            DecimalPos:=RequestedDigits+1;
+        ',':
+            ThousandSep:=AFormatSettings.ThousandSeparator<>#0;
+        'e', 'E':
+            begin
+            Inc(I);
+            if (I<Len) then
+              begin
+              C:=Section[i];
+              IsScientific:=C in ['-','+'];
+              if IsScientific then
+                while (I<Len) and (Section[i+1]='0') do
+                  begin
+                  Inc(ExpSize);
+                  Inc(I);
+                  end;
+              if ExpSize>4 then
+                ExpSize:=4;
+              end;
+            end;
+        '#':
+            Inc(RequestedDigits);
+        '0':
+            begin
+            if RequestedDigits<FirstDigit then
+              FirstDigit:=RequestedDigits+1;
+            Inc(RequestedDigits);
+            LastDigit:=RequestedDigits+1;
+            end;
+        end;
+      Inc(I);
+      end;
+    if DecimalPos=0 then
+      DecimalPos:=RequestedDigits+1;
+    // Writeln('LastDigit: ',DecimalPos,'-',LastDigit);
+    LastDigit:=DecimalPos-LastDigit;
+    if LastDigit>0 then
+      LastDigit:=0;
+    // Writeln('FirstDigit: ',DecimalPos,'-',FirstDigit);
+    FirstDigit:=DecimalPos-FirstDigit;
+    if FirstDigit<0 then
+      FirstDigit:=0;
+  end;
+
+  Function ValueOutSideScope : Boolean;
+  begin
+    With FV do
+     Result:=((Exponent >= 18) and (not IsScientific)) or (Exponent = $7FF) or (Exponent = $800)
+  end;
+
+  Procedure CalcRunVars;
+
+  Var
+    D,P: Integer;
+
+  begin
+    if IsScientific then
+      begin
+      P:=RequestedDigits;
+      D:=9999;
+      end
+    else
+      begin
+      P:=MaxPrecision;
+      D:=RequestedDigits-DecimalPos+1;
+      end;
+    FloatToDecimal(FV,Value,ValueType,P,D);
+    DistToDecimal:=DecimalPos-1;
+    if IsScientific then
+      PadZeroes:=0 // No padding.
+    else
+      begin
+      PadZeroes:=FV.Exponent-(DecimalPos-1);
+      if (PadZeroes>=0) then
+        DistToDecimal:=FV.Exponent
+      end;
+    // Writeln('PadZeroes : ',PadZeroes, ', DistToDecimal : ',DistToDecimal);
+    Available:=-1;
+    while (Available<High(FV.Digits)) and (FV.Digits[Available+1]<>#0) do
+      Inc(Available);
+    // Writeln('Available: ',Available);
+  end;
+
+
+  Function FormatExponent(ASign: FChar; aExponent: Integer) : FString;
+
+  begin
+    Result:=IntToStr(aExponent);
+    Result:=StringOfChar('0',ExpSize-Length(Result))+Result;
+    if (aExponent<0) then
+      Result:='-'+Result
+    else if (aExponent>0) and (aSign='+') then
+      Result:=aSign+Result;
+  end;
+
+var
+  I,S : Integer;
+  C,Q : FChar;
+  PA : TPosArray;
+  InLiteral : Boolean;
+
+begin
+  Result:=0;
+  Initvars;
+  // What section to use ?
+  if (E>0) then
+    S:=1
+  else if (E<0) then
+    S:=2
+  else
+    S:=3;
+  PA[0]:=0;
+  I:=GetSections(PA);
+  if (I<S) or (PA[S]-PA[S-1]=0) then
+    S:=1;
+  // Extract correct section
+  SectionLength:=PA[S]-PA[S-1]-1;
+  SetLength(Section,SectionLength);
+  Move(Format[PA[S-1]],Section[1],SizeOf(FChar)*SectionLength);
+  // Writeln('Section ',I,' : "',Section,'" ',SectionLength);
+  AnalyzeFormat;
+  // Writeln('RequestedDigits: ',RequestedDigits,', DecimalPos : ',DecimalPos,', LastDigit: ',LastDigit,', FirstDigit: ',FirstDigit);
+  CalcRunVars;
+  // If we cannot process value using current settings, fallback
+  if (SectionLength=0) or ValueOutSideScope then
+    Exit(FloatToText(FPChar(Buf), E, ffGeneral, 15, 0, AFormatSettings));
+  // Get Started
+  I:=1;
+  Current:=0;
+  Q:=' ';
+  InLiteral:=False;
+  if (FV.Negative) and (S=1) then
+    ToResult('-');
+  while (I<=SectionLength) do
+    begin
+    C:=Section[i];
+    // Writeln('Analyzing pos ',I,': "',C,'"');
+    If (C in ['"', '''']) then
+      begin
+      if InLiteral then
+        InLiteral:=C<>Q
+      else
+        begin
+        inLiteral:=True;
+        Q:=C;
+        end;
+      end
+    else if InLiteral then
+      ToResult(C)
+    else
+      case C of
+      '0', '#':
+        CopyDigit;
+      '.', ',':
+        ; // Do nothing, handled by CopyDigit
+      'e', 'E':
+        begin
+        ToResult(C); // Always needed
+        Inc(I);
+        if I<=Section.Length then
+          begin
+          C:=Section[I];
+          if (C in ['+','-']) then
+            begin
+            AddToResult(FormatExponent(C,FV.Exponent-DecimalPos+1));
+            // Skip rest
+            while (I<SectionLength) and (Section[i+1]='0') do
+              Inc(I);
+            end;
+          end;
+        end;
+      else
+        ToResult(C);
+      end;
+    Inc(i);
+    end;
+//  Writeln('Result  ',Result);
+end;
+

+ 3 - 0
rtl/objpas/sysutils/syshelp.inc

@@ -1507,6 +1507,7 @@ end;
 {$define FLOATTYPE:=Single}
 {$define TFloatRec:=TSingleRec}
 {$i syshelpf.inc}
+{$UNDEF TFloatRec}
 {$ENDIF FPC_HAS_TYPE_SINGLE}
 
 { ---------------------------------------------------------------------
@@ -1517,6 +1518,7 @@ end;
 {$define FLOATTYPE:=Double}
 {$define TFloatRec:=TDoubleRec}
 {$i syshelpf.inc}
+{$UNDEF TFloatRec}
 {$ENDIF FPC_HAS_TYPE_DOUBLE}
 
 { ---------------------------------------------------------------------
@@ -1528,6 +1530,7 @@ end;
 {$define FLOATTYPE:=Extended}
 {$define TFloatRec:=TExtended80Rec}
 {$i syshelpf.inc}
+{$UNDEF TFloatRec}
 {$ENDIF FPC_HAS_TYPE_EXTENDED}
 
 { ---------------------------------------------------------------------

+ 10 - 517
rtl/objpas/sysutils/sysstr.inc

@@ -2029,526 +2029,18 @@ begin
   Result:=FloatToTextFmt(Buffer,Value,Format,DefaultFormatSettings);
 end;
 
-Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar;FormatSettings : TFormatSettings): Integer;
+{$MACRO ON}
+{$define FPChar:=PAnsiChar}
+{$define FChar:=AnsiChar}
+{$define FString:=AnsiString}
 
-Var
-  Digits: String[40];                         { String Of Digits                 }
-  Exponent: String[8];                        { Exponent strin                   }
-  FmtStart, FmtStop: PChar;                   { Start And End Of relevant part   }
-                                              { Of format String                 }
-  ExpFmt, ExpSize: Integer;                   { Type And Length Of               }
-                                              { exponential format chosen        }
-  Placehold: Array[1..4] Of Integer;          { Number Of placeholders In All    }
-                                              { four Sections                    }
-  thousand: Boolean;                          { thousand separators?             }
-  UnexpectedDigits: Integer;                  { Number Of unexpected Digits that }
-                                              { have To be inserted before the   }
-                                              { First placeholder.               }
-  DigitExponent: Integer;                     { Exponent Of First digit In       }
-                                              { Digits Array.                    }
-
-  { Find end of format section starting at P. False, if empty }
-
-  Function GetSectionEnd(Var P: PChar): Boolean;
-  Var
-    C: Char;
-    SQ, DQ: Boolean;
-  Begin
-    Result := False;
-    SQ := False;
-    DQ := False;
-    C := P[0];
-    While (C<>#0) And ((C<>';') Or SQ Or DQ) Do
-      Begin
-      Result := True;
-      Case C Of
-        #34: If Not SQ Then DQ := Not DQ;
-        #39: If Not DQ Then SQ := Not SQ;
-      End;
-      Inc(P);
-      C := P[0];
-      End;
-  End;
-
-  { Find start and end of format section to apply. If section doesn't exist,
-    use section 1. If section 2 is used, the sign of value is ignored.       }
-
-  Procedure GetSectionRange(section: Integer);
-  Var
-    Sec: Array[1..3] Of PChar;
-    SecOk: Array[1..3] Of Boolean;
-  Begin
-    Sec[1] := format;
-    SecOk[1] := GetSectionEnd(Sec[1]);
-    If section > 1 Then
-      Begin
-      Sec[2] := Sec[1];
-      If Sec[2][0] <> #0 Then
-        Inc(Sec[2]);
-      SecOk[2] := GetSectionEnd(Sec[2]);
-      If section > 2 Then
-        Begin
-        Sec[3] := Sec[2];
-        If Sec[3][0] <> #0 Then
-          Inc(Sec[3]);
-        SecOk[3] := GetSectionEnd(Sec[3]);
-        End;
-      End;
-    If Not SecOk[1] Then
-      FmtStart := Nil
-    Else
-      Begin
-      If Not SecOk[section] Then
-        section := 1
-      Else If section = 2 Then
-        Value := -Value;   { Remove sign }
-      If section = 1 Then FmtStart := format Else
-        Begin
-        FmtStart := Sec[section - 1];
-        Inc(FmtStart);
-        End;
-      FmtStop := Sec[section];
-      End;
-  End;
-
-  { Find format section ranging from FmtStart to FmtStop. }
-
-  Procedure GetFormatOptions;
-  Var
-    Fmt: PChar;
-    SQ, DQ: Boolean;
-    area: Integer;
-  Begin
-    SQ := False;
-    DQ := False;
-    Fmt := FmtStart;
-    ExpFmt := 0;
-    area := 1;
-    thousand := False;
-    Placehold[1] := 0;
-    Placehold[2] := 0;
-    Placehold[3] := 0;
-    Placehold[4] := 0;
-    While Fmt < FmtStop Do
-      Begin
-      Case Fmt[0] Of
-        #34:
-          Begin
-          If Not SQ Then
-            DQ := Not DQ;
-          Inc(Fmt);
-          End;
-        #39:
-          Begin
-          If Not DQ Then
-            SQ := Not SQ;
-          Inc(Fmt);
-          End;
-      Else
-       { if not in quotes, then interpret}
-        If Not (SQ Or DQ) Then
-          Begin
-          Case Fmt[0] Of
-            '0':
-              Begin
-              Case area Of
-                1:
-                  area := 2;
-                4:
-                  Begin
-                  area := 3;
-                  Inc(Placehold[3], Placehold[4]);
-                  Placehold[4] := 0;
-                  End;
-              End;
-              Inc(Placehold[area]);
-              Inc(Fmt);
-              End;
-
-            '#':
-              Begin
-              If area=3 Then
-                area:=4;
-              Inc(Placehold[area]);
-              Inc(Fmt);
-              End;
-            '.':
-              Begin
-              If area<3 Then
-                area:=3;
-              Inc(Fmt);
-              End;
-            ',':
-              Begin
-              thousand := DefaultFormatSettings.ThousandSeparator<>#0;
-              Inc(Fmt);
-              End;
-            'e', 'E':
-              If ExpFmt = 0 Then
-                Begin
-                If (Fmt[0]='E') Then
-                  ExpFmt:=1
-                Else
-                  ExpFmt := 3;
-                Inc(Fmt);
-                If (Fmt<FmtStop) Then
-                  Begin
-                  Case Fmt[0] Of
-                    '+':
-                      Begin
-                      End;
-                    '-':
-                      Inc(ExpFmt);
-                  Else
-                    ExpFmt := 0;
-                  End;
-                  If ExpFmt <> 0 Then
-                    Begin
-                    Inc(Fmt);
-                    ExpSize := 0;
-                    While (Fmt<FmtStop) And
-                          (ExpSize<4) And
-                          (Fmt[0] In ['0'..'9']) Do
-                      Begin
-                      Inc(ExpSize);
-                      Inc(Fmt);
-                      End;
-                    End;
-                  End
-                Else
-                  { just e/E without subsequent +/- -> not exponential format,
-                    but we have to simply print e/E literally }
-                  ExpFmt:=0;
-                End
-              Else
-                Inc(Fmt);
-          Else { Case }
-            Inc(Fmt);
-          End; { Case }
-          End  { Begin }
-        Else
-          Inc(Fmt);
-      End; { Case }
-      End; { While .. Begin }
-  End;
-
-  Procedure FloatToStr;
+{$I fmtflt.inc}
 
-  Var
-    I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
-
-  Begin
-    If ExpFmt = 0 Then
-      Begin
-      { Fixpoint }
-      Decimals:=Placehold[3]+Placehold[4];
-      Width:=Placehold[1]+Placehold[2]+Decimals;
-      If (Decimals=0) Then
-        Str(Value:Width:0,Digits)
-      Else if Value>=0 then
-        Str(Value:Width+1:Decimals,Digits)
-      else
-        Str(Value:Width+2:Decimals,Digits);
-      len:=Length(Digits);
-      { Find the decimal point }
-      If (Decimals=0) Then
-        DecimalPoint:=len+1
-      Else
-        DecimalPoint:=len-Decimals;
-      { If value is very small, and no decimal places
-        are desired, remove the leading 0.            }
-      If (Abs(Value) < 1) And (Placehold[2] = 0) Then
-        Begin
-        If (Placehold[1]=0) Then
-          Delete(Digits,DecimalPoint-1,1)
-        Else
-          Digits[DecimalPoint-1]:=' ';
-        End;
-      { Convert optional zeroes to spaces. }
-      I:=len;
-      J:=DecimalPoint+Placehold[3];
-      While (I>J) And (Digits[I]='0') Do
-        Begin
-        Digits[I] := ' ';
-        Dec(I);
-        End;
-      { If integer value and no obligatory decimal
-        places, remove decimal point. }
-      If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
-          Digits[DecimalPoint] := ' ';
-      { Convert spaces left from obligatory decimal point to zeroes.
-        MVC : If - sign is encountered, replace it too, and put at position 1}
-      I:=DecimalPoint-Placehold[2];
-      J:=0;
-      While (I<DecimalPoint) And (Digits[I] in [' ','-']) Do
-        Begin
-        If Digits[i]='-' then
-          J:=I;
-        Digits[I] := '0';
-        Inc(I);
-        End;
-      If (J<>0) then
-        Digits[1]:='-';
-      If (Digits[1]='-') then
-        Begin
-        I:=1;
-        While (I<=length(Digits)) And (Not (Digits[I] in ['1'..'9'])) Do
-          Inc(I);
-        If (I>length(Digits)) then
-          Begin
-          Digits:=Copy(Digits, 2, Length(Digits));
-          Dec(DecimalPoint);
-          End;
-        End;
-      Exp := 0;
-      End
-    Else
-      Begin
-      { Scientific: exactly <Width> Digits With <Precision> Decimals
-        And adjusted Exponent. }
-      If Placehold[1]+Placehold[2]=0 Then
-        Placehold[1]:=1;
-      Decimals := Placehold[3] + Placehold[4];
-      Width:=Placehold[1]+Placehold[2]+Decimals;
-      { depending on the maximally supported precision, the exponent field }
-      { is longer/shorter                                                  }
-{$ifdef FPC_HAS_TYPE_EXTENDED}
-      Str(Value:Width+8,Digits);
-{$else FPC_HAS_TYPE_EXTENDED}
-{$ifdef FPC_HAS_TYPE_DOUBLE}
-      Str(Value:Width+7,Digits);
-{$else FPC_HAS_TYPE_DOUBLE}
-      Str(Value:Width+6,Digits);
-{$endif FPC_HAS_TYPE_DOUBLE}
-{$endif FPC_HAS_TYPE_EXTENDED}
-
-      { Find and cut out exponent. Always the
-        last 6 characters in the string.
-        -> 0000E+0000
-        *** No, not always the last 6 characters, this depends on
-            the maximally supported precision (JM)}
-      I:=Pos('E',Digits);
-      Val(Copy(Digits,I+1,255),Exp,J);
-      Exp:=Exp+1-(Placehold[1]+Placehold[2]);
-      Delete(Digits, I, 255);
-      { Str() always returns at least one digit after the decimal point.
-        If we don't want it, we have to remove it. }
-      If (Decimals=0) And (Placehold[1]+Placehold[2]<= 1) Then
-        Begin
-        If (Digits[4]>='5') Then
-          Begin
-          Inc(Digits[2]);
-          If (Digits[2]>'9') Then
-            Begin
-            Digits[2] := '1';
-            Inc(Exp);
-            End;
-          End;
-        Delete(Digits, 3, 2);
-        DecimalPoint := Length(Digits) + 1;
-        End
-      Else
-        Begin
-        { Move decimal point at the desired position }
-        Delete(Digits, 3, 1);
-        DecimalPoint:=2+Placehold[1]+Placehold[2];
-        If (Decimals<>0) Then
-          Insert('.',Digits,DecimalPoint);
-        End;
-
-      { Convert optional zeroes to spaces. }
-      I := Length(Digits);
-      J := DecimalPoint + Placehold[3];
-      While (I > J) And (Digits[I] = '0') Do
-        Begin
-        Digits[I] := ' ';
-        Dec(I);
-        End;
-
-      { If integer number and no obligatory decimal paces, remove decimal point }
-
-      If (DecimalPoint<Length(Digits)) And
-         (Digits[DecimalPoint+1]=' ') Then
-          Digits[DecimalPoint]:=' ';
-      If (Digits[1]=' ') Then
-        Begin
-        Delete(Digits, 1, 1);
-        Dec(DecimalPoint);
-        End;
-      { Calculate exponent string }
-      Str(Abs(Exp), Exponent);
-      While Length(Exponent)<ExpSize Do
-        Insert('0',Exponent,1);
-      If Exp >= 0 Then
-        Begin
-        If (ExpFmt In [1,3]) Then
-          Insert('+', Exponent, 1);
-        End
-      Else
-        Insert('-',Exponent,1);
-      If (ExpFmt<3) Then
-        Insert('E',Exponent,1)
-      Else
-        Insert('e',Exponent,1);
-      End;
-    DigitExponent:=DecimalPoint-2;
-    I:=1;
-    While (I<=Length(Digits)) and (Digits[i] in [' ','-']) do
-      begin
-      Dec(DigitExponent);
-      Inc(i);
-      end;
-    UnexpectedDigits:=DecimalPoint-1-(Placehold[1]+Placehold[2]);
-  End;
-
-  Function PutResult: LongInt;
-
-  Var
-    SQ, DQ: Boolean;
-    Fmt, Buf: PChar;
-    Dig, N: Integer;
-
-  Begin
-    SQ := False;
-    DQ := False;
-    Fmt := FmtStart;
-    Buf := Buffer;
-    Dig := 1;
-    While (Fmt<FmtStop) Do
-      Begin
-//      WriteLn('Treating : "',Fmt[0],'"');
-      Case Fmt[0] Of
-        #34:
-          Begin
-          If Not SQ Then
-            DQ := Not DQ;
-          Inc(Fmt);
-          End;
-        #39:
-          Begin
-          If Not DQ Then
-            SQ := Not SQ;
-          Inc(Fmt);
-          End;
-      Else
-        If Not (SQ Or DQ) Then
-          Begin
-          Case Fmt[0] Of
-            '0', '#', '.':
-              Begin
-              If (Dig=1) And (UnexpectedDigits>0) Then
-                Begin
-                { Everything unexpected is written before the first digit }
-                For N := 1 To UnexpectedDigits Do
-                  Begin
-                    if (Digits[N]<>' ') Then
-                    begin
-                      Buf[0] := Digits[N];
-                      Inc(Buf);
-                    end;
-                  If thousand And (Not (Digits[N] in [' ','-'])) Then
-                    Begin
-                    If (DigitExponent Mod 3 = 0) And (DigitExponent>0) Then
-                      Begin
-                      Buf[0] := FormatSettings.ThousandSeparator;
-                      Inc(Buf);
-                      End;
-                    Dec(DigitExponent);
-                    End;
-                  End;
-                Inc(Dig, UnexpectedDigits);
-                End;
-              If (Digits[Dig]<>' ') Then
-                Begin
-                If (Digits[Dig]='.') Then
-                  Buf[0] := FormatSettings.DecimalSeparator
-                Else
-                  Buf[0] := Digits[Dig];
-                Inc(Buf);
-                If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) and (Digits[Dig]<>'-') Then
-                  Begin
-                  Buf[0] := FormatSettings.ThousandSeparator;
-                  Inc(Buf);
-                  End;
-                End;
-              if Digits[Dig]<>'-' then
-                Dec(DigitExponent);
-              Inc(Dig);
-              Inc(Fmt);
-              End;
-            'e', 'E':
-              Begin
-              If ExpFmt <> 0 Then
-                Begin
-                Inc(Fmt);
-                If Fmt < FmtStop Then
-                  Begin
-                  If Fmt[0] In ['+', '-'] Then
-                    Begin
-                    Inc(Fmt, ExpSize);
-                    For N:=1 To Length(Exponent) Do
-                      Buf[N-1] := Exponent[N];
-                    Inc(Buf,Length(Exponent));
-                    ExpFmt:=0;
-                    End;
-                  Inc(Fmt);
-                  End;
-                End
-              Else
-                Begin
-                { No legal exponential format.
-                  Simply write the 'E' to the result. }
-                Buf[0] := Fmt[0];
-                Inc(Buf);
-                Inc(Fmt);
-                End;
-              End;
-          Else { Case }
-            { Usual character }
-            If (Fmt[0]<>',') Then
-              Begin
-              Buf[0] := Fmt[0];
-              Inc(Buf);
-              End;
-            Inc(Fmt);
-          End; { Case }
-          End
-        Else { IF }
-          Begin
-          { Character inside single or double quotes }
-          Buf[0] := Fmt[0];
-          Inc(Buf);
-          Inc(Fmt);
-          End;
-      End; { Case }
-    End; { While .. Begin }
-    Result:=PtrUInt(Buf)-PtrUInt(Buffer);
-  End;
-
-Begin
-  If (Value>0) Then
-    GetSectionRange(1)
-  Else If (Value<0) Then
-    GetSectionRange(2)
-  Else
-    GetSectionRange(3);
-  If FmtStart = Nil Then
-    Begin
-    Result := FloatToText(Buffer, Value, ffGeneral, 15, 4, FormatSettings);
-    End
-  Else
-    Begin
-    GetFormatOptions;
-    If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then
-      Result := FloatToText(Buffer, Value, ffGeneral, 15, 4, FormatSettings)
-    Else
-      Begin
-      FloatToStr;
-      Result := PutResult;
-      End;
-    End;
-End;
+Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar; FormatSettings : TFormatSettings): Integer;
 
+begin
+  Result:=IntFloatToTextFmt(Buffer,Value,fvExtended,Format,FormatSettings);
+end;
 
 Procedure FloatToDecimal(Out Result: TFloatRec; const Value; ValueType: TFloatValue; Precision, Decimals : integer);
 var
@@ -2556,6 +2048,7 @@ var
   InfNan: string[3];
   Error, N, L, Start, C: Integer;
   GotNonZeroBeforeDot, BeforeDot : boolean;
+
 begin
   case ValueType of
     fvExtended: