File : a-wtgeau.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT RUN-TIME COMPONENTS                         --
   4 --                                                                          --
   5 --         A D A . W I D E _ T E X T _ I O . G E N E R I C _ A U X          --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 1992-2014, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  17 --                                                                          --
  18 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 -- You should have received a copy of the GNU General Public License and    --
  23 -- a copy of the GCC Runtime Library Exception along with this program;     --
  24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  25 -- <http://www.gnu.org/licenses/>.                                          --
  26 --                                                                          --
  27 -- GNAT was originally developed  by the GNAT team at  New York University. --
  28 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  29 --                                                                          --
  30 ------------------------------------------------------------------------------
  31 
  32 with Interfaces.C_Streams; use Interfaces.C_Streams;
  33 with System.File_IO;
  34 with System.File_Control_Block;
  35 
  36 package body Ada.Wide_Text_IO.Generic_Aux is
  37 
  38    package FIO renames System.File_IO;
  39    package FCB renames System.File_Control_Block;
  40    subtype AP is FCB.AFCB_Ptr;
  41 
  42    ------------------------
  43    -- Check_End_Of_Field --
  44    ------------------------
  45 
  46    procedure Check_End_Of_Field
  47      (Buf   : String;
  48       Stop  : Integer;
  49       Ptr   : Integer;
  50       Width : Field)
  51    is
  52    begin
  53       if Ptr > Stop then
  54          return;
  55 
  56       elsif Width = 0 then
  57          raise Data_Error;
  58 
  59       else
  60          for J in Ptr .. Stop loop
  61             if not Is_Blank (Buf (J)) then
  62                raise Data_Error;
  63             end if;
  64          end loop;
  65       end if;
  66    end Check_End_Of_Field;
  67 
  68    -----------------------
  69    -- Check_On_One_Line --
  70    -----------------------
  71 
  72    procedure Check_On_One_Line
  73      (File   : File_Type;
  74       Length : Integer)
  75    is
  76    begin
  77       FIO.Check_Write_Status (AP (File));
  78 
  79       if File.Line_Length /= 0 then
  80          if Count (Length) > File.Line_Length then
  81             raise Layout_Error;
  82          elsif File.Col + Count (Length) > File.Line_Length + 1 then
  83             New_Line (File);
  84          end if;
  85       end if;
  86    end Check_On_One_Line;
  87 
  88    --------------
  89    -- Is_Blank --
  90    --------------
  91 
  92    function Is_Blank (C : Character) return Boolean is
  93    begin
  94       return C = ' ' or else C = ASCII.HT;
  95    end Is_Blank;
  96 
  97    ----------
  98    -- Load --
  99    ----------
 100 
 101    procedure Load
 102      (File   : File_Type;
 103       Buf    : out String;
 104       Ptr    : in out Integer;
 105       Char   : Character;
 106       Loaded : out Boolean)
 107    is
 108       ch : int;
 109 
 110    begin
 111       if File.Before_Wide_Character then
 112          Loaded := False;
 113          return;
 114 
 115       else
 116          ch := Getc (File);
 117 
 118          if ch = Character'Pos (Char) then
 119             Store_Char (File, ch, Buf, Ptr);
 120             Loaded := True;
 121          else
 122             Ungetc (ch, File);
 123             Loaded := False;
 124          end if;
 125       end if;
 126    end Load;
 127 
 128    procedure Load
 129      (File   : File_Type;
 130       Buf    : out String;
 131       Ptr    : in out Integer;
 132       Char   : Character)
 133    is
 134       ch : int;
 135 
 136    begin
 137       if File.Before_Wide_Character then
 138          null;
 139 
 140       else
 141          ch := Getc (File);
 142 
 143          if ch = Character'Pos (Char) then
 144             Store_Char (File, ch, Buf, Ptr);
 145          else
 146             Ungetc (ch, File);
 147          end if;
 148       end if;
 149    end Load;
 150 
 151    procedure Load
 152      (File   : File_Type;
 153       Buf    : out String;
 154       Ptr    : in out Integer;
 155       Char1  : Character;
 156       Char2  : Character;
 157       Loaded : out Boolean)
 158    is
 159       ch : int;
 160 
 161    begin
 162       if File.Before_Wide_Character then
 163          Loaded := False;
 164          return;
 165 
 166       else
 167          ch := Getc (File);
 168 
 169          if ch = Character'Pos (Char1)
 170            or else ch = Character'Pos (Char2)
 171          then
 172             Store_Char (File, ch, Buf, Ptr);
 173             Loaded := True;
 174          else
 175             Ungetc (ch, File);
 176             Loaded := False;
 177          end if;
 178       end if;
 179    end Load;
 180 
 181    procedure Load
 182      (File   : File_Type;
 183       Buf    : out String;
 184       Ptr    : in out Integer;
 185       Char1  : Character;
 186       Char2  : Character)
 187    is
 188       ch : int;
 189 
 190    begin
 191       if File.Before_Wide_Character then
 192          null;
 193 
 194       else
 195          ch := Getc (File);
 196 
 197          if ch = Character'Pos (Char1)
 198            or else ch = Character'Pos (Char2)
 199          then
 200             Store_Char (File, ch, Buf, Ptr);
 201          else
 202             Ungetc (ch, File);
 203          end if;
 204       end if;
 205    end Load;
 206 
 207    -----------------
 208    -- Load_Digits --
 209    -----------------
 210 
 211    procedure Load_Digits
 212      (File   : File_Type;
 213       Buf    : out String;
 214       Ptr    : in out Integer;
 215       Loaded : out Boolean)
 216    is
 217       ch          : int;
 218       After_Digit : Boolean;
 219 
 220    begin
 221       if File.Before_Wide_Character then
 222          Loaded := False;
 223          return;
 224 
 225       else
 226          ch := Getc (File);
 227 
 228          if ch not in Character'Pos ('0') .. Character'Pos ('9') then
 229             Loaded := False;
 230 
 231          else
 232             Loaded := True;
 233             After_Digit := True;
 234 
 235             loop
 236                Store_Char (File, ch, Buf, Ptr);
 237                ch := Getc (File);
 238 
 239                if ch in Character'Pos ('0') .. Character'Pos ('9') then
 240                   After_Digit := True;
 241 
 242                elsif ch = Character'Pos ('_') and then After_Digit then
 243                   After_Digit := False;
 244 
 245                else
 246                   exit;
 247                end if;
 248             end loop;
 249          end if;
 250 
 251          Ungetc (ch, File);
 252       end if;
 253    end Load_Digits;
 254 
 255    procedure Load_Digits
 256      (File   : File_Type;
 257       Buf    : out String;
 258       Ptr    : in out Integer)
 259    is
 260       ch          : int;
 261       After_Digit : Boolean;
 262 
 263    begin
 264       if File.Before_Wide_Character then
 265          return;
 266 
 267       else
 268          ch := Getc (File);
 269 
 270          if ch in Character'Pos ('0') .. Character'Pos ('9') then
 271             After_Digit := True;
 272 
 273             loop
 274                Store_Char (File, ch, Buf, Ptr);
 275                ch := Getc (File);
 276 
 277                if ch in Character'Pos ('0') .. Character'Pos ('9') then
 278                   After_Digit := True;
 279 
 280                elsif ch = Character'Pos ('_') and then After_Digit then
 281                   After_Digit := False;
 282 
 283                else
 284                   exit;
 285                end if;
 286             end loop;
 287          end if;
 288 
 289          Ungetc (ch, File);
 290       end if;
 291    end Load_Digits;
 292 
 293    --------------------------
 294    -- Load_Extended_Digits --
 295    --------------------------
 296 
 297    procedure Load_Extended_Digits
 298      (File   : File_Type;
 299       Buf    : out String;
 300       Ptr    : in out Integer;
 301       Loaded : out Boolean)
 302    is
 303       ch          : int;
 304       After_Digit : Boolean := False;
 305 
 306    begin
 307       if File.Before_Wide_Character then
 308          Loaded := False;
 309          return;
 310 
 311       else
 312          Loaded := False;
 313 
 314          loop
 315             ch := Getc (File);
 316 
 317             if ch in Character'Pos ('0') .. Character'Pos ('9')
 318                  or else
 319                ch in Character'Pos ('a') .. Character'Pos ('f')
 320                  or else
 321                ch in Character'Pos ('A') .. Character'Pos ('F')
 322             then
 323                After_Digit := True;
 324 
 325             elsif ch = Character'Pos ('_') and then After_Digit then
 326                After_Digit := False;
 327 
 328             else
 329                exit;
 330             end if;
 331 
 332             Store_Char (File, ch, Buf, Ptr);
 333             Loaded := True;
 334          end loop;
 335 
 336          Ungetc (ch, File);
 337       end if;
 338    end Load_Extended_Digits;
 339 
 340    procedure Load_Extended_Digits
 341      (File   : File_Type;
 342       Buf    : out String;
 343       Ptr    : in out Integer)
 344    is
 345       Junk : Boolean;
 346       pragma Unreferenced (Junk);
 347    begin
 348       Load_Extended_Digits (File, Buf, Ptr, Junk);
 349    end Load_Extended_Digits;
 350 
 351    ---------------
 352    -- Load_Skip --
 353    ---------------
 354 
 355    procedure Load_Skip (File  : File_Type) is
 356       C : Character;
 357 
 358    begin
 359       FIO.Check_Read_Status (AP (File));
 360 
 361       --  We need to explicitly test for the case of being before a wide
 362       --  character (greater than 16#7F#). Since no such character can
 363       --  ever legitimately be a valid numeric character, we can
 364       --  immediately signal Data_Error.
 365 
 366       if File.Before_Wide_Character then
 367          raise Data_Error;
 368       end if;
 369 
 370       --  Otherwise loop till we find a non-blank character (note that as
 371       --  usual in Wide_Text_IO, blank includes horizontal tab). Note that
 372       --  Get_Character deals with Before_LM/Before_LM_PM flags appropriately.
 373 
 374       loop
 375          Get_Character (File, C);
 376          exit when not Is_Blank (C);
 377       end loop;
 378 
 379       Ungetc (Character'Pos (C), File);
 380       File.Col := File.Col - 1;
 381    end Load_Skip;
 382 
 383    ----------------
 384    -- Load_Width --
 385    ----------------
 386 
 387    procedure Load_Width
 388      (File  : File_Type;
 389       Width : Field;
 390       Buf   : out String;
 391       Ptr   : in out Integer)
 392    is
 393       ch : int;
 394       WC : Wide_Character;
 395 
 396       Bad_Wide_C : Boolean := False;
 397       --  Set True if one of the characters read is not in range of type
 398       --  Character. This is always a Data_Error, but we do not signal it
 399       --  right away, since we have to read the full number of characters.
 400 
 401    begin
 402       FIO.Check_Read_Status (AP (File));
 403 
 404       --  If we are immediately before a line mark, then we have no characters.
 405       --  This is always a data error, so we may as well raise it right away.
 406 
 407       if File.Before_LM then
 408          raise Data_Error;
 409 
 410       else
 411          for J in 1 .. Width loop
 412             if File.Before_Wide_Character then
 413                Bad_Wide_C := True;
 414                Store_Char (File, 0, Buf, Ptr);
 415                File.Before_Wide_Character := False;
 416 
 417             else
 418                ch := Getc (File);
 419 
 420                if ch = EOF then
 421                   exit;
 422 
 423                elsif ch = LM then
 424                   Ungetc (ch, File);
 425                   exit;
 426 
 427                else
 428                   WC := Get_Wide_Char (Character'Val (ch), File);
 429                   ch := Wide_Character'Pos (WC);
 430 
 431                   if ch > 255 then
 432                      Bad_Wide_C := True;
 433                      ch := 0;
 434                   end if;
 435 
 436                   Store_Char (File, ch, Buf, Ptr);
 437                end if;
 438             end if;
 439          end loop;
 440 
 441          if Bad_Wide_C then
 442             raise Data_Error;
 443          end if;
 444       end if;
 445    end Load_Width;
 446 
 447    --------------
 448    -- Put_Item --
 449    --------------
 450 
 451    procedure Put_Item (File : File_Type; Str : String) is
 452    begin
 453       Check_On_One_Line (File, Str'Length);
 454 
 455       for J in Str'Range loop
 456          Put (File, Wide_Character'Val (Character'Pos (Str (J))));
 457       end loop;
 458    end Put_Item;
 459 
 460    ----------------
 461    -- Store_Char --
 462    ----------------
 463 
 464    procedure Store_Char
 465      (File : File_Type;
 466       ch   : Integer;
 467       Buf  : out String;
 468       Ptr  : in out Integer)
 469    is
 470    begin
 471       File.Col := File.Col + 1;
 472 
 473       if Ptr = Buf'Last then
 474          raise Data_Error;
 475       else
 476          Ptr := Ptr + 1;
 477          Buf (Ptr) := Character'Val (ch);
 478       end if;
 479    end Store_Char;
 480 
 481    -----------------
 482    -- String_Skip --
 483    -----------------
 484 
 485    procedure String_Skip (Str : String; Ptr : out Integer) is
 486    begin
 487       --  Routines calling String_Skip malfunction if Str'Last = Positive'Last.
 488       --  It's too much trouble to make this silly case work, so we just raise
 489       --  Program_Error with an appropriate message. We raise Program_Error
 490       --  rather than Constraint_Error because we don't want this case to be
 491       --  converted to Data_Error.
 492 
 493       if Str'Last = Positive'Last then
 494          raise Program_Error with
 495            "string upper bound is Positive'Last, not supported";
 496       end if;
 497 
 498       --  Normal case where Str'Last < Positive'Last
 499 
 500       Ptr := Str'First;
 501 
 502       loop
 503          if Ptr > Str'Last then
 504             raise End_Error;
 505 
 506          elsif not Is_Blank (Str (Ptr)) then
 507             return;
 508 
 509          else
 510             Ptr := Ptr + 1;
 511          end if;
 512       end loop;
 513    end String_Skip;
 514 
 515    ------------
 516    -- Ungetc --
 517    ------------
 518 
 519    procedure Ungetc (ch : int; File : File_Type) is
 520    begin
 521       if ch /= EOF then
 522          if ungetc (ch, File.Stream) = EOF then
 523             raise Device_Error;
 524          end if;
 525       end if;
 526    end Ungetc;
 527 
 528 end Ada.Wide_Text_IO.Generic_Aux;