File : g-spitbo.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT LIBRARY COMPONENTS                          --
   4 --                                                                          --
   5 --                         G N A T . S P I T B O L                          --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --                     Copyright (C) 1998-2012, AdaCore                     --
  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 Ada.Strings;               use Ada.Strings;
  33 with Ada.Strings.Unbounded.Aux; use Ada.Strings.Unbounded.Aux;
  34 
  35 with GNAT.Debug_Utilities;      use GNAT.Debug_Utilities;
  36 with GNAT.IO;                   use GNAT.IO;
  37 
  38 with System.String_Hash;
  39 
  40 with Ada.Unchecked_Deallocation;
  41 
  42 package body GNAT.Spitbol is
  43 
  44    ---------
  45    -- "&" --
  46    ---------
  47 
  48    function "&" (Num : Integer; Str : String)  return String is
  49    begin
  50       return S (Num) & Str;
  51    end "&";
  52 
  53    function "&" (Str : String;  Num : Integer) return String is
  54    begin
  55       return Str & S (Num);
  56    end "&";
  57 
  58    function "&" (Num : Integer; Str : VString) return VString is
  59    begin
  60       return S (Num) & Str;
  61    end "&";
  62 
  63    function "&" (Str : VString; Num : Integer) return VString is
  64    begin
  65       return Str & S (Num);
  66    end "&";
  67 
  68    ----------
  69    -- Char --
  70    ----------
  71 
  72    function Char (Num : Natural) return Character is
  73    begin
  74       return Character'Val (Num);
  75    end Char;
  76 
  77    ----------
  78    -- Lpad --
  79    ----------
  80 
  81    function Lpad
  82      (Str : VString;
  83       Len : Natural;
  84       Pad : Character := ' ') return VString
  85    is
  86    begin
  87       if Length (Str) >= Len then
  88          return Str;
  89       else
  90          return Tail (Str, Len, Pad);
  91       end if;
  92    end Lpad;
  93 
  94    function Lpad
  95      (Str : String;
  96       Len : Natural;
  97       Pad : Character := ' ') return VString
  98    is
  99    begin
 100       if Str'Length >= Len then
 101          return V (Str);
 102 
 103       else
 104          declare
 105             R : String (1 .. Len);
 106 
 107          begin
 108             for J in 1 .. Len - Str'Length loop
 109                R (J) := Pad;
 110             end loop;
 111 
 112             R (Len - Str'Length + 1 .. Len) := Str;
 113             return V (R);
 114          end;
 115       end if;
 116    end Lpad;
 117 
 118    procedure Lpad
 119      (Str  : in out VString;
 120       Len  : Natural;
 121       Pad  : Character := ' ')
 122    is
 123    begin
 124       if Length (Str) >= Len then
 125          return;
 126       else
 127          Tail (Str, Len, Pad);
 128       end if;
 129    end Lpad;
 130 
 131    -------
 132    -- N --
 133    -------
 134 
 135    function N (Str : VString) return Integer is
 136       S : Big_String_Access;
 137       L : Natural;
 138    begin
 139       Get_String (Str, S, L);
 140       return Integer'Value (S (1 .. L));
 141    end N;
 142 
 143    --------------------
 144    -- Reverse_String --
 145    --------------------
 146 
 147    function Reverse_String (Str : VString) return VString is
 148       S : Big_String_Access;
 149       L : Natural;
 150 
 151    begin
 152       Get_String (Str, S, L);
 153 
 154       declare
 155          Result : String (1 .. L);
 156 
 157       begin
 158          for J in 1 .. L loop
 159             Result (J) := S (L + 1 - J);
 160          end loop;
 161 
 162          return V (Result);
 163       end;
 164    end Reverse_String;
 165 
 166    function Reverse_String (Str : String) return VString is
 167       Result : String (1 .. Str'Length);
 168 
 169    begin
 170       for J in 1 .. Str'Length loop
 171          Result (J) := Str (Str'Last + 1 - J);
 172       end loop;
 173 
 174       return V (Result);
 175    end Reverse_String;
 176 
 177    procedure Reverse_String (Str : in out VString) is
 178       S : Big_String_Access;
 179       L : Natural;
 180 
 181    begin
 182       Get_String (Str, S, L);
 183 
 184       declare
 185          Result : String (1 .. L);
 186 
 187       begin
 188          for J in 1 .. L loop
 189             Result (J) := S (L + 1 - J);
 190          end loop;
 191 
 192          Set_Unbounded_String (Str, Result);
 193       end;
 194    end Reverse_String;
 195 
 196    ----------
 197    -- Rpad --
 198    ----------
 199 
 200    function Rpad
 201      (Str : VString;
 202       Len : Natural;
 203       Pad : Character := ' ') return VString
 204    is
 205    begin
 206       if Length (Str) >= Len then
 207          return Str;
 208       else
 209          return Head (Str, Len, Pad);
 210       end if;
 211    end Rpad;
 212 
 213    function Rpad
 214      (Str : String;
 215       Len : Natural;
 216       Pad : Character := ' ') return VString
 217    is
 218    begin
 219       if Str'Length >= Len then
 220          return V (Str);
 221 
 222       else
 223          declare
 224             R : String (1 .. Len);
 225 
 226          begin
 227             for J in Str'Length + 1 .. Len loop
 228                R (J) := Pad;
 229             end loop;
 230 
 231             R (1 .. Str'Length) := Str;
 232             return V (R);
 233          end;
 234       end if;
 235    end Rpad;
 236 
 237    procedure Rpad
 238      (Str  : in out VString;
 239       Len  : Natural;
 240       Pad  : Character := ' ')
 241    is
 242    begin
 243       if Length (Str) >= Len then
 244          return;
 245 
 246       else
 247          Head (Str, Len, Pad);
 248       end if;
 249    end Rpad;
 250 
 251    -------
 252    -- S --
 253    -------
 254 
 255    function S (Num : Integer) return String is
 256       Buf : String (1 .. 30);
 257       Ptr : Natural := Buf'Last + 1;
 258       Val : Natural := abs (Num);
 259 
 260    begin
 261       loop
 262          Ptr := Ptr - 1;
 263          Buf (Ptr) := Character'Val (Val mod 10 + Character'Pos ('0'));
 264          Val := Val / 10;
 265          exit when Val = 0;
 266       end loop;
 267 
 268       if Num < 0 then
 269          Ptr := Ptr - 1;
 270          Buf (Ptr) := '-';
 271       end if;
 272 
 273       return Buf (Ptr .. Buf'Last);
 274    end S;
 275 
 276    ------------
 277    -- Substr --
 278    ------------
 279 
 280    function Substr
 281      (Str   : VString;
 282       Start : Positive;
 283       Len   : Natural) return VString
 284    is
 285       S : Big_String_Access;
 286       L : Natural;
 287 
 288    begin
 289       Get_String (Str, S, L);
 290 
 291       if Start > L then
 292          raise Index_Error;
 293       elsif Start + Len - 1 > L then
 294          raise Length_Error;
 295       else
 296          return V (S (Start .. Start + Len - 1));
 297       end if;
 298    end Substr;
 299 
 300    function Substr
 301      (Str   : String;
 302       Start : Positive;
 303       Len   : Natural) return VString
 304    is
 305    begin
 306       if Start > Str'Length then
 307          raise Index_Error;
 308       elsif Start + Len - 1 > Str'Length then
 309          raise Length_Error;
 310       else
 311          return
 312            V (Str (Str'First + Start - 1 .. Str'First + Start + Len - 2));
 313       end if;
 314    end Substr;
 315 
 316    -----------
 317    -- Table --
 318    -----------
 319 
 320    package body Table is
 321 
 322       procedure Free is new
 323         Ada.Unchecked_Deallocation (Hash_Element, Hash_Element_Ptr);
 324 
 325       -----------------------
 326       -- Local Subprograms --
 327       -----------------------
 328 
 329       function Hash is new System.String_Hash.Hash
 330         (Character, String, Unsigned_32);
 331 
 332       ------------
 333       -- Adjust --
 334       ------------
 335 
 336       procedure Adjust (Object : in out Table) is
 337          Ptr1 : Hash_Element_Ptr;
 338          Ptr2 : Hash_Element_Ptr;
 339 
 340       begin
 341          for J in Object.Elmts'Range loop
 342             Ptr1 := Object.Elmts (J)'Unrestricted_Access;
 343 
 344             if Ptr1.Name /= null then
 345                loop
 346                   Ptr1.Name := new String'(Ptr1.Name.all);
 347                   exit when Ptr1.Next = null;
 348                   Ptr2 := Ptr1.Next;
 349                   Ptr1.Next := new Hash_Element'(Ptr2.all);
 350                   Ptr1 := Ptr1.Next;
 351                end loop;
 352             end if;
 353          end loop;
 354       end Adjust;
 355 
 356       -----------
 357       -- Clear --
 358       -----------
 359 
 360       procedure Clear (T : in out Table) is
 361          Ptr1 : Hash_Element_Ptr;
 362          Ptr2 : Hash_Element_Ptr;
 363 
 364       begin
 365          for J in T.Elmts'Range loop
 366             if T.Elmts (J).Name /= null then
 367                Free (T.Elmts (J).Name);
 368                T.Elmts (J).Value := Null_Value;
 369 
 370                Ptr1 := T.Elmts (J).Next;
 371                T.Elmts (J).Next := null;
 372 
 373                while Ptr1 /= null loop
 374                   Ptr2 := Ptr1.Next;
 375                   Free (Ptr1.Name);
 376                   Free (Ptr1);
 377                   Ptr1 := Ptr2;
 378                end loop;
 379             end if;
 380          end loop;
 381       end Clear;
 382 
 383       ----------------------
 384       -- Convert_To_Array --
 385       ----------------------
 386 
 387       function Convert_To_Array (T : Table) return Table_Array is
 388          Num_Elmts : Natural := 0;
 389          Elmt      : Hash_Element_Ptr;
 390 
 391       begin
 392          for J in T.Elmts'Range loop
 393             Elmt := T.Elmts (J)'Unrestricted_Access;
 394 
 395             if Elmt.Name /= null then
 396                loop
 397                   Num_Elmts := Num_Elmts + 1;
 398                   Elmt := Elmt.Next;
 399                   exit when Elmt = null;
 400                end loop;
 401             end if;
 402          end loop;
 403 
 404          declare
 405             TA  : Table_Array (1 .. Num_Elmts);
 406             P   : Natural := 1;
 407 
 408          begin
 409             for J in T.Elmts'Range loop
 410                Elmt := T.Elmts (J)'Unrestricted_Access;
 411 
 412                if Elmt.Name /= null then
 413                   loop
 414                      Set_Unbounded_String (TA (P).Name, Elmt.Name.all);
 415                      TA (P).Value := Elmt.Value;
 416                      P := P + 1;
 417                      Elmt := Elmt.Next;
 418                      exit when Elmt = null;
 419                   end loop;
 420                end if;
 421             end loop;
 422 
 423             return TA;
 424          end;
 425       end Convert_To_Array;
 426 
 427       ----------
 428       -- Copy --
 429       ----------
 430 
 431       procedure Copy (From : Table; To : in out Table) is
 432          Elmt : Hash_Element_Ptr;
 433 
 434       begin
 435          Clear (To);
 436 
 437          for J in From.Elmts'Range loop
 438             Elmt := From.Elmts (J)'Unrestricted_Access;
 439             if Elmt.Name /= null then
 440                loop
 441                   Set (To, Elmt.Name.all, Elmt.Value);
 442                   Elmt := Elmt.Next;
 443                   exit when Elmt = null;
 444                end loop;
 445             end if;
 446          end loop;
 447       end Copy;
 448 
 449       ------------
 450       -- Delete --
 451       ------------
 452 
 453       procedure Delete (T : in out Table; Name : Character) is
 454       begin
 455          Delete (T, String'(1 => Name));
 456       end Delete;
 457 
 458       procedure Delete (T : in out Table; Name  : VString) is
 459          S : Big_String_Access;
 460          L : Natural;
 461       begin
 462          Get_String (Name, S, L);
 463          Delete (T, S (1 .. L));
 464       end Delete;
 465 
 466       procedure Delete (T : in out Table; Name  : String) is
 467          Slot : constant Unsigned_32 := Hash (Name) mod T.N + 1;
 468          Elmt : Hash_Element_Ptr := T.Elmts (Slot)'Unrestricted_Access;
 469          Next : Hash_Element_Ptr;
 470 
 471       begin
 472          if Elmt.Name = null then
 473             null;
 474 
 475          elsif Elmt.Name.all = Name then
 476             Free (Elmt.Name);
 477 
 478             if Elmt.Next = null then
 479                Elmt.Value := Null_Value;
 480                return;
 481 
 482             else
 483                Next := Elmt.Next;
 484                Elmt.Name  := Next.Name;
 485                Elmt.Value := Next.Value;
 486                Elmt.Next  := Next.Next;
 487                Free (Next);
 488                return;
 489             end if;
 490 
 491          else
 492             loop
 493                Next := Elmt.Next;
 494 
 495                if Next = null then
 496                   return;
 497 
 498                elsif Next.Name.all = Name then
 499                   Free (Next.Name);
 500                   Elmt.Next := Next.Next;
 501                   Free (Next);
 502                   return;
 503 
 504                else
 505                   Elmt := Next;
 506                end if;
 507             end loop;
 508          end if;
 509       end Delete;
 510 
 511       ----------
 512       -- Dump --
 513       ----------
 514 
 515       procedure Dump (T : Table; Str : String := "Table") is
 516          Num_Elmts : Natural := 0;
 517          Elmt      : Hash_Element_Ptr;
 518 
 519       begin
 520          for J in T.Elmts'Range loop
 521             Elmt := T.Elmts (J)'Unrestricted_Access;
 522 
 523             if Elmt.Name /= null then
 524                loop
 525                   Num_Elmts := Num_Elmts + 1;
 526                   Put_Line
 527                     (Str & '<' & Image (Elmt.Name.all) & "> = " &
 528                      Img (Elmt.Value));
 529                   Elmt := Elmt.Next;
 530                   exit when Elmt = null;
 531                end loop;
 532             end if;
 533          end loop;
 534 
 535          if Num_Elmts = 0 then
 536             Put_Line (Str & " is empty");
 537          end if;
 538       end Dump;
 539 
 540       procedure Dump (T : Table_Array; Str : String := "Table_Array") is
 541       begin
 542          if T'Length = 0 then
 543             Put_Line (Str & " is empty");
 544 
 545          else
 546             for J in T'Range loop
 547                Put_Line
 548                  (Str & '(' & Image (To_String (T (J).Name)) & ") = " &
 549                   Img (T (J).Value));
 550             end loop;
 551          end if;
 552       end Dump;
 553 
 554       --------------
 555       -- Finalize --
 556       --------------
 557 
 558       procedure Finalize (Object : in out Table) is
 559          Ptr1 : Hash_Element_Ptr;
 560          Ptr2 : Hash_Element_Ptr;
 561 
 562       begin
 563          for J in Object.Elmts'Range loop
 564             Ptr1 := Object.Elmts (J).Next;
 565             Free (Object.Elmts (J).Name);
 566             while Ptr1 /= null loop
 567                Ptr2 := Ptr1.Next;
 568                Free (Ptr1.Name);
 569                Free (Ptr1);
 570                Ptr1 := Ptr2;
 571             end loop;
 572          end loop;
 573       end Finalize;
 574 
 575       ---------
 576       -- Get --
 577       ---------
 578 
 579       function Get (T : Table; Name : Character) return Value_Type is
 580       begin
 581          return Get (T, String'(1 => Name));
 582       end Get;
 583 
 584       function Get (T : Table; Name : VString) return Value_Type is
 585          S : Big_String_Access;
 586          L : Natural;
 587       begin
 588          Get_String (Name, S, L);
 589          return Get (T, S (1 .. L));
 590       end Get;
 591 
 592       function Get (T : Table; Name : String) return Value_Type is
 593          Slot : constant Unsigned_32 := Hash (Name) mod T.N + 1;
 594          Elmt : Hash_Element_Ptr := T.Elmts (Slot)'Unrestricted_Access;
 595 
 596       begin
 597          if Elmt.Name = null then
 598             return Null_Value;
 599 
 600          else
 601             loop
 602                if Name = Elmt.Name.all then
 603                   return Elmt.Value;
 604 
 605                else
 606                   Elmt := Elmt.Next;
 607 
 608                   if Elmt = null then
 609                      return Null_Value;
 610                   end if;
 611                end if;
 612             end loop;
 613          end if;
 614       end Get;
 615 
 616       -------------
 617       -- Present --
 618       -------------
 619 
 620       function Present (T : Table; Name : Character) return Boolean is
 621       begin
 622          return Present (T, String'(1 => Name));
 623       end Present;
 624 
 625       function Present (T : Table; Name : VString) return Boolean is
 626          S : Big_String_Access;
 627          L : Natural;
 628       begin
 629          Get_String (Name, S, L);
 630          return Present (T, S (1 .. L));
 631       end Present;
 632 
 633       function Present (T : Table; Name : String) return Boolean is
 634          Slot : constant Unsigned_32 := Hash (Name) mod T.N + 1;
 635          Elmt : Hash_Element_Ptr := T.Elmts (Slot)'Unrestricted_Access;
 636 
 637       begin
 638          if Elmt.Name = null then
 639             return False;
 640 
 641          else
 642             loop
 643                if Name = Elmt.Name.all then
 644                   return True;
 645 
 646                else
 647                   Elmt := Elmt.Next;
 648 
 649                   if Elmt = null then
 650                      return False;
 651                   end if;
 652                end if;
 653             end loop;
 654          end if;
 655       end Present;
 656 
 657       ---------
 658       -- Set --
 659       ---------
 660 
 661       procedure Set (T : in out Table; Name : VString; Value : Value_Type) is
 662          S : Big_String_Access;
 663          L : Natural;
 664       begin
 665          Get_String (Name, S, L);
 666          Set (T, S (1 .. L), Value);
 667       end Set;
 668 
 669       procedure Set (T : in out Table; Name : Character; Value : Value_Type) is
 670       begin
 671          Set (T, String'(1 => Name), Value);
 672       end Set;
 673 
 674       procedure Set
 675         (T     : in out Table;
 676          Name  : String;
 677          Value : Value_Type)
 678       is
 679       begin
 680          if Value = Null_Value then
 681             Delete (T, Name);
 682 
 683          else
 684             declare
 685                Slot : constant Unsigned_32 := Hash (Name) mod T.N + 1;
 686                Elmt : Hash_Element_Ptr := T.Elmts (Slot)'Unrestricted_Access;
 687 
 688                subtype String1 is String (1 .. Name'Length);
 689 
 690             begin
 691                if Elmt.Name = null then
 692                   Elmt.Name  := new String'(String1 (Name));
 693                   Elmt.Value := Value;
 694                   return;
 695 
 696                else
 697                   loop
 698                      if Name = Elmt.Name.all then
 699                         Elmt.Value := Value;
 700                         return;
 701 
 702                      elsif Elmt.Next = null then
 703                         Elmt.Next := new Hash_Element'(
 704                                        Name  => new String'(String1 (Name)),
 705                                        Value => Value,
 706                                        Next  => null);
 707                         return;
 708 
 709                      else
 710                         Elmt := Elmt.Next;
 711                      end if;
 712                   end loop;
 713                end if;
 714             end;
 715          end if;
 716       end Set;
 717    end Table;
 718 
 719    ----------
 720    -- Trim --
 721    ----------
 722 
 723    function Trim (Str : VString) return VString is
 724    begin
 725       return Trim (Str, Right);
 726    end Trim;
 727 
 728    function Trim (Str : String) return VString is
 729    begin
 730       for J in reverse Str'Range loop
 731          if Str (J) /= ' ' then
 732             return V (Str (Str'First .. J));
 733          end if;
 734       end loop;
 735 
 736       return Nul;
 737    end Trim;
 738 
 739    procedure Trim (Str : in out VString) is
 740    begin
 741       Trim (Str, Right);
 742    end Trim;
 743 
 744    -------
 745    -- V --
 746    -------
 747 
 748    function V (Num : Integer) return VString is
 749       Buf : String (1 .. 30);
 750       Ptr : Natural := Buf'Last + 1;
 751       Val : Natural := abs (Num);
 752 
 753    begin
 754       loop
 755          Ptr := Ptr - 1;
 756          Buf (Ptr) := Character'Val (Val mod 10 + Character'Pos ('0'));
 757          Val := Val / 10;
 758          exit when Val = 0;
 759       end loop;
 760 
 761       if Num < 0 then
 762          Ptr := Ptr - 1;
 763          Buf (Ptr) := '-';
 764       end if;
 765 
 766       return V (Buf (Ptr .. Buf'Last));
 767    end V;
 768 
 769 end GNAT.Spitbol;