aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonan Desplanques <desplanques@adacore.com>2022-12-07 17:37:21 +0100
committerMarc Poulhiès <poulhies@adacore.com>2023-01-03 10:29:53 +0100
commitd3f50f75aa3e5054b28074c029d36c1cbce2d0cb (patch)
treeb6e65bbf1239805f5f77bb9b8a5393423ef2ecee
parent32841e7e8480cb16d34f60feda226e4f582c3186 (diff)
downloadgcc-d3f50f75aa3e5054b28074c029d36c1cbce2d0cb.zip
gcc-d3f50f75aa3e5054b28074c029d36c1cbce2d0cb.tar.gz
gcc-d3f50f75aa3e5054b28074c029d36c1cbce2d0cb.tar.bz2
ada: Fix format string parsing in GNAT.Formatted_String
Before this patch, format strings ending with "%%" (two consecutive percent signs) caused GNAT.Formatted_String."-" to give the wrong output, and cause the various GNAT.Formatted_String."&" to raise exceptions with misleading error messages. Also before this patch, a bug in GNAT.Formatted_String."-" caused characters from the format string to be dropped. Calling GNAT.Formatted_String."-" on an instance of GNAT.Formatted_String.Formatted_String caused subsequent uses of that instance to return wrong results. In addition to fixing the parsing of format strings, this patch centralizes the detection of format specifiers in a unique procedure. gcc/ada/ * libgnat/g-forstr.adb (Advance_And_Accumulate_Until_Next_Specifier): New procedure. ("-"): Replace inline code with call to Advance_And_Accumulate_Until_Next_Specifier. (Next_Format): likewise.
-rw-r--r--gcc/ada/libgnat/g-forstr.adb67
1 files changed, 36 insertions, 31 deletions
diff --git a/gcc/ada/libgnat/g-forstr.adb b/gcc/ada/libgnat/g-forstr.adb
index 8821de6..8353e2c 100644
--- a/gcc/ada/libgnat/g-forstr.adb
+++ b/gcc/ada/libgnat/g-forstr.adb
@@ -77,6 +77,12 @@ package body GNAT.Formatted_String is
Value_Needed : Natural range 0 .. 2 := 0;
end record;
+ procedure Advance_And_Accumulate_Until_Next_Specifier
+ (Format : Formatted_String);
+ -- Advance Format.D.Index until either the next format specifier is
+ -- encountered, or the end of Format.D.Format is reached. The characters
+ -- advanced over are appended to Format.D.Result.
+
procedure Next_Format
(Format : Formatted_String;
F_Spec : out F_Data;
@@ -139,29 +145,13 @@ package body GNAT.Formatted_String is
---------
function "-" (Format : Formatted_String) return String is
- F : String renames Format.D.Format;
- J : Natural renames Format.D.Index;
- R : Unbounded_String := Format.D.Result;
-
begin
-- Make sure we get the remaining character up to the next unhandled
-- format specifier.
- while (J <= F'Length and then F (J) /= '%')
- or else (J < F'Length - 1 and then F (J + 1) = '%')
- loop
- Append (R, F (J));
-
- -- If we have two consecutive %, skip the second one
-
- if F (J) = '%' and then J < F'Length - 1 and then F (J + 1) = '%' then
- J := J + 1;
- end if;
-
- J := J + 1;
- end loop;
+ Advance_And_Accumulate_Until_Next_Specifier (Format);
- return To_String (R);
+ return To_String (Format.D.Result);
end "-";
---------
@@ -318,6 +308,33 @@ package body GNAT.Formatted_String is
F.D.Ref_Count := F.D.Ref_Count + 1;
end Adjust;
+ -------------------------------------------------
+ -- Advance_And_Accumulate_Until_Next_Specifier --
+ -------------------------------------------------
+
+ procedure Advance_And_Accumulate_Until_Next_Specifier
+ (Format : Formatted_String)
+ is
+ begin
+ loop
+ if Format.D.Index > Format.D.Format'Last then
+ exit;
+ end if;
+
+ if Format.D.Format (Format.D.Index) /= '%' then
+ Append (Format.D.Result, Format.D.Format (Format.D.Index));
+ Format.D.Index := Format.D.Index + 1;
+ elsif Format.D.Index + 1 <= Format.D.Format'Last
+ and then Format.D.Format (Format.D.Index + 1) = '%'
+ then
+ Append (Format.D.Result, '%');
+ Format.D.Index := Format.D.Index + 2;
+ else
+ exit;
+ end if;
+ end loop;
+ end Advance_And_Accumulate_Until_Next_Specifier;
+
--------------------
-- Decimal_Format --
--------------------
@@ -505,19 +522,7 @@ package body GNAT.Formatted_String is
-- Got to next %
- while (J <= F'Last and then F (J) /= '%')
- or else (J < F'Last - 1 and then F (J + 1) = '%')
- loop
- Append (Format.D.Result, F (J));
-
- -- If we have two consecutive %, skip the second one
-
- if F (J) = '%' and then J < F'Last - 1 and then F (J + 1) = '%' then
- J := J + 1;
- end if;
-
- J := J + 1;
- end loop;
+ Advance_And_Accumulate_Until_Next_Specifier (Format);
if J >= F'Last or else F (J) /= '%' then
raise Format_Error with "no format specifier found for parameter"