public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Marc Poulhi?s <dkm@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r13-4968] ada: Fix format string parsing in GNAT.Formatted_String
Date: Tue,  3 Jan 2023 09:34:24 +0000 (GMT)	[thread overview]
Message-ID: <20230103093424.9A9EC3858C36@sourceware.org> (raw)

https://gcc.gnu.org/g:d3f50f75aa3e5054b28074c029d36c1cbce2d0cb

commit r13-4968-gd3f50f75aa3e5054b28074c029d36c1cbce2d0cb
Author: Ronan Desplanques <desplanques@adacore.com>
Date:   Wed Dec 7 17:37:21 2022 +0100

    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.

Diff:
---
 gcc/ada/libgnat/g-forstr.adb | 67 ++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/gcc/ada/libgnat/g-forstr.adb b/gcc/ada/libgnat/g-forstr.adb
index 8821de6f280..8353e2c4ad8 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"

                 reply	other threads:[~2023-01-03  9:34 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230103093424.9A9EC3858C36@sourceware.org \
    --to=dkm@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).