149 lines
6.3 KiB
Ada
149 lines
6.3 KiB
Ada
|
------------------------------------------------------------------------------
|
||
|
-- --
|
||
|
-- GNAT RUN-TIME COMPONENTS --
|
||
|
-- --
|
||
|
-- ADA.STRINGS.TEXT_OUTPUT.BUFFERS --
|
||
|
-- --
|
||
|
-- B o d y --
|
||
|
-- --
|
||
|
-- Copyright (C) 2020, Free Software Foundation, Inc. --
|
||
|
-- --
|
||
|
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||
|
-- terms of the GNU General Public License as published by the Free Soft- --
|
||
|
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||
|
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||
|
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||
|
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||
|
-- --
|
||
|
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||
|
-- additional permissions described in the GCC Runtime Library Exception, --
|
||
|
-- version 3.1, as published by the Free Software Foundation. --
|
||
|
-- --
|
||
|
-- You should have received a copy of the GNU General Public License and --
|
||
|
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||
|
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||
|
-- <http://www.gnu.org/licenses/>. --
|
||
|
-- --
|
||
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
||
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
||
|
-- --
|
||
|
------------------------------------------------------------------------------
|
||
|
|
||
|
with Unchecked_Deallocation;
|
||
|
with Ada.Strings.UTF_Encoding.Strings;
|
||
|
with Ada.Strings.UTF_Encoding.Wide_Strings;
|
||
|
with Ada.Strings.UTF_Encoding.Wide_Wide_Strings;
|
||
|
package body Ada.Strings.Text_Output.Buffers is
|
||
|
|
||
|
type Chunk_Access is access all Chunk;
|
||
|
|
||
|
function New_Buffer
|
||
|
(Indent_Amount : Natural := Default_Indent_Amount;
|
||
|
Chunk_Length : Positive := Default_Chunk_Length) return Buffer
|
||
|
is
|
||
|
begin
|
||
|
return Result : Buffer (Chunk_Length) do
|
||
|
Result.Indent_Amount := Indent_Amount;
|
||
|
Result.Cur_Chunk := Result.Initial_Chunk'Unchecked_Access;
|
||
|
end return;
|
||
|
end New_Buffer;
|
||
|
|
||
|
-- We need type conversions of Chunk_Access values in the following two
|
||
|
-- procedures, because the one in Text_Output has Storage_Size => 0,
|
||
|
-- because Text_Output is Pure. We do not run afoul of 13.11.2(16/3),
|
||
|
-- which requires the allocation and deallocation to have the same pool,
|
||
|
-- because the allocation in Full_Method and the deallocation in Destroy
|
||
|
-- use the same access type, and therefore the same pool.
|
||
|
|
||
|
procedure Destroy (S : in out Buffer) is
|
||
|
procedure Free is new Unchecked_Deallocation (Chunk, Chunk_Access);
|
||
|
Cur : Chunk_Access := Chunk_Access (S.Initial_Chunk.Next);
|
||
|
begin
|
||
|
while Cur /= null loop
|
||
|
declare
|
||
|
Temp : constant Chunk_Access := Chunk_Access (Cur.Next);
|
||
|
begin
|
||
|
Free (Cur);
|
||
|
Cur := Temp;
|
||
|
end;
|
||
|
end loop;
|
||
|
|
||
|
S.Cur_Chunk := null;
|
||
|
end Destroy;
|
||
|
|
||
|
overriding procedure Full_Method (S : in out Buffer) is
|
||
|
begin
|
||
|
pragma Assert (S.Cur_Chunk.Next = null);
|
||
|
pragma Assert (S.Last = S.Cur_Chunk.Chars'Length);
|
||
|
S.Cur_Chunk.Next :=
|
||
|
Text_Output.Chunk_Access (Chunk_Access'(new Chunk (S.Chunk_Length)));
|
||
|
S.Cur_Chunk := S.Cur_Chunk.Next;
|
||
|
S.Num_Extra_Chunks := @ + 1;
|
||
|
S.Last := 0;
|
||
|
end Full_Method;
|
||
|
|
||
|
function UTF_8_Length (S : Buffer'Class) return Natural is
|
||
|
begin
|
||
|
return S.Num_Extra_Chunks * S.Chunk_Length + S.Last;
|
||
|
end UTF_8_Length;
|
||
|
|
||
|
procedure Get_UTF_8
|
||
|
(S : Buffer'Class; Result : out UTF_8_Lines)
|
||
|
is
|
||
|
Cur : access constant Chunk := S.Initial_Chunk'Access;
|
||
|
First : Positive := 1;
|
||
|
begin
|
||
|
loop
|
||
|
if Cur.Next = null then
|
||
|
pragma Assert (Result'Last = First + S.Last - 1);
|
||
|
Result (First .. Result'Last) := Cur.Chars (1 .. S.Last);
|
||
|
exit;
|
||
|
end if;
|
||
|
|
||
|
pragma Assert (S.Chunk_Length = Cur.Chars'Length);
|
||
|
Result (First .. First + S.Chunk_Length - 1) := Cur.Chars;
|
||
|
First := First + S.Chunk_Length;
|
||
|
Cur := Cur.Next;
|
||
|
end loop;
|
||
|
end Get_UTF_8;
|
||
|
|
||
|
function Get_UTF_8 (S : Buffer'Class) return UTF_8_Lines is
|
||
|
begin
|
||
|
return Result : String (1 .. UTF_8_Length (S)) do
|
||
|
Get_UTF_8 (S, Result);
|
||
|
end return;
|
||
|
end Get_UTF_8;
|
||
|
|
||
|
function Get (S : Buffer'Class) return String is
|
||
|
begin
|
||
|
-- If all characters are 7 bits, we don't need to decode;
|
||
|
-- this is an optimization.
|
||
|
|
||
|
-- Otherwise, if all are 8 bits, we need to decode to get Latin-1.
|
||
|
-- Otherwise, the result is implementation defined, so we return a
|
||
|
-- String encoded as UTF-8. (Note that the AI says "if any character
|
||
|
-- in the sequence is not defined in Character, the result is
|
||
|
-- implementation-defined", so we are not obliged to decode ANY
|
||
|
-- Latin-1 characters if ANY character is bigger than 8 bits.
|
||
|
|
||
|
if S.All_7_Bits then
|
||
|
return Get_UTF_8 (S);
|
||
|
elsif S.All_8_Bits then
|
||
|
return UTF_Encoding.Strings.Decode (Get_UTF_8 (S));
|
||
|
else
|
||
|
return Get_UTF_8 (S);
|
||
|
end if;
|
||
|
end Get;
|
||
|
|
||
|
function Wide_Get (S : Buffer'Class) return Wide_String is
|
||
|
begin
|
||
|
return UTF_Encoding.Wide_Strings.Decode (Get_UTF_8 (S));
|
||
|
end Wide_Get;
|
||
|
|
||
|
function Wide_Wide_Get (S : Buffer'Class) return Wide_Wide_String is
|
||
|
begin
|
||
|
return UTF_Encoding.Wide_Wide_Strings.Decode (Get_UTF_8 (S));
|
||
|
end Wide_Wide_Get;
|
||
|
|
||
|
end Ada.Strings.Text_Output.Buffers;
|