|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 15976 (0x3e68)
Types: TextFile
Names: »B«
└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
└─⟦5cb1d1d7f⟧ »DATA«
└─⟦3b1ee7bd8⟧
└─⟦this⟧
with Unchecked_Deallocation;
with Lists, Stack_Pkg;
package body String_Pkg is
--| Overview:
--| The implementation for most operations is fairly straightforward.
--| The interesting aspects involve the allocation and deallocation of
--| heap space. This is done as follows:
--|
--| 1. A stack of accesses to lists of string_type values is set up
--| so that the top of the stack always refers to a list of values
--| that were allocated since the last invocation of mark.
--| The stack is called scopes, referring to the dynamic scopes
--| defined by the invocations of mark and release.
--| There is an implicit invocation of mark when the
--| package body is elaborated; this is implemented with an explicit
--| invocation in the package initialization code.
--|
--| 2. At each invocation of mark, a pointer to an empty list
--| is pushed onto the stack.
--|
--| 3. At each invocation of release, all of the values in the
--| list referred to by the pointer at the top of the stack are
--| returned to the heap. Then the list, and the pointer to it,
--| are returned to the heap. Finally, the stack is popped.
package String_List_Pkg is new Lists (String_Type);
subtype String_List is String_List_Pkg.List;
type String_List_Ptr is access String_List;
package Scope_Stack_Pkg is new Stack_Pkg (String_List_Ptr);
subtype Scope_Stack is Scope_Stack_Pkg.Stack;
use String_List_Pkg;
use Scope_Stack_Pkg;
Scopes : Scope_Stack; -- See package body overview.
-- Utility functions/procedures:
function Enter (S : in String_Type) return String_Type;
--| Raises: illegal_alloc
--| Effects:
--| Stores s, the address of s.all, in current scope list (top(scopes)),
--| and returns s. Useful for functions that create and return new
--| string_type values.
--| Raises illegal_alloc if the scopes stack is empty.
function Match_String
(S1, S2 : in String; Start : in Positive := 1) return Natural;
--| Raises: no_match
--| Effects:
--| Returns the minimum index, i, in s1'range such that
--| s1(i..i + s2'length - 1) = s2. Returns 0 if no such index.
--| Requires:
--| s1'first = 1.
-- Constructors:
function Create (S : in String) return String_Type is
subtype Constr_Str is String (1 .. S'Length);
Dec_S : Constr_Str := S;
begin
return Enter (new Constr_Str'(Dec_S));
-- DECada bug; above code (and decl of dec_s) replaces the following:
-- return enter(new constr_str'(s));
end Create;
function "&" (S1, S2 : in String_Type) return String_Type is
begin
if Is_Empty (S1) then
return Enter (Make_Persistent (S2));
end if;
if Is_Empty (S2) then
return Enter (Make_Persistent (S1));
end if;
return Create (S1.all & S2.all);
end "&";
function "&" (S1 : in String_Type; S2 : in String) return String_Type is
begin
if S1 = null then
return Create (S2);
end if;
return Create (S1.all & S2);
end "&";
function "&" (S1 : in String; S2 : in String_Type) return String_Type is
begin
if S2 = null then
return Create (S1);
end if;
return Create (S1 & S2.all);
end "&";
function Substr (S : in String_Type; I : in Positive; Len : in Natural)
return String_Type is
begin
if Len = 0 then
return null;
end if;
return Create (S (I .. (I + Len - 1)));
exception
when Constraint_Error =>
-- on array fetch or null deref
raise Bounds;
end Substr;
function Splice (S : in String_Type; I : in Positive; Len : in Natural)
return String_Type is
begin
if Len = 0 then
return Enter (Make_Persistent (S));
end if;
if I + Len - 1 > Length (S) then
raise Bounds;
end if;
return Create (S (1 .. (I - 1)) & S ((I + Len) .. Length (S)));
end Splice;
function Insert (S1, S2 : in String_Type; I : in Positive)
return String_Type is
begin
if I > Length (S1) then
raise Bounds;
end if;
if Is_Empty (S2) then
return Create (S1.all);
end if;
return Create (S1 (1 .. (I - 1)) & S2.all & S1 (I .. S1'Last));
end Insert;
function Insert (S1 : in String_Type; S2 : in String; I : in Positive)
return String_Type is
begin
if I > Length (S1) then
raise Bounds;
end if;
return Create (S1 (1 .. (I - 1)) & S2 & S1 (I .. S1'Last));
end Insert;
function Insert (S1 : in String; S2 : in String_Type; I : in Positive)
return String_Type is
begin
if not (I in S1'Range) then
raise Bounds;
end if;
if S2 = null then
return Create (S1);
end if;
return Create (S1 (S1'First .. (I - 1)) & S2.all & S1 (I .. S1'Last));
end Insert;
function Lower (S : in String) return String_Type is
S2 : String_Type := Create (S);
procedure Lc (C : in out Character) is
begin
if ('A' <= C) and then (C <= 'Z') then
C := Character'Val (Character'Pos (C) - Character'Pos ('A') +
Character'Pos ('a'));
end if;
end Lc;
begin
for I in S2'Range loop
Lc (S2 (I));
end loop;
return S2;
end Lower;
function Lower (S : in String_Type) return String_Type is
begin
if S = null then
return null;
end if;
return Lower (S.all);
end Lower;
function Upper (S : in String) return String_Type is
S2 : String_Type := Create (S);
procedure Uc (C : in out Character) is
begin
if ('a' <= C) and then (C <= 'z') then
C := Character'Val (Character'Pos (C) - Character'Pos ('a') +
Character'Pos ('A'));
end if;
end Uc;
begin
for I in S2'Range loop
Uc (S2 (I));
end loop;
return S2;
end Upper;
function Upper (S : in String_Type) return String_Type is
begin
if S = null then
return null;
end if;
return Upper (S.all);
end Upper;
-- Heap Management:
function Make_Persistent (S : in String_Type) return String_Type is
subtype Constr_Str is String (1 .. Length (S));
begin
if S = null or else S.all = "" then
return null;
else
return new Constr_Str'(S.all);
end if;
end Make_Persistent;
function Make_Persistent (S : in String) return String_Type is
subtype Constr_Str is String (1 .. S'Length);
begin
if S = "" then
return null;
else
return new Constr_Str'(S);
end if;
end Make_Persistent;
procedure Real_Flush is new Unchecked_Deallocation (String, String_Type);
--| Effect:
--| Return space used by argument to heap. Does nothing if null.
--| Notes:
--| This procedure is actually the body for the flush procedure,
--| but a generic instantiation cannot be used as a body for another
--| procedure. You tell me why.
procedure Flush (S : in out String_Type) is
begin
if S /= null then
Real_Flush (S);
end if;
-- Actually, the if isn't needed; however, DECada compiler chokes
-- on deallocation of null.
end Flush;
procedure Mark is
begin
Push (Scopes, new String_List'(Create));
end Mark;
procedure Release is
procedure Flush_List_Ptr is new Unchecked_Deallocation
(String_List, String_List_Ptr);
Iter : String_List_Pkg.Listiter;
Top_List : String_List_Ptr;
S : String_Type;
begin
Pop (Scopes, Top_List);
Iter := Makelistiter (Top_List.all);
while More (Iter) loop
Next (Iter, S);
Flush (S);
-- real_flush is bad, DECada bug
-- real_flush(s);
end loop;
Destroy (Top_List.all);
Flush_List_Ptr (Top_List);
exception
when Empty_Stack =>
raise Illegal_Dealloc;
end Release;
-- Queries:
function Is_Empty (S : in String_Type) return Boolean is
begin
return (S = null) or else (S.all = "");
end Is_Empty;
function Length (S : in String_Type) return Natural is
begin
if S = null then
return 0;
end if;
return (S.all'Length);
end Length;
function Value (S : in String_Type) return String is
subtype Null_Range is Positive range 1 .. 0;
subtype Null_String is String (Null_Range);
begin
if S = null then
return Null_String'("");
end if;
return S.all;
end Value;
function Fetch (S : in String_Type; I : in Positive) return Character is
begin
if Is_Empty (S) or else (not (I in S'Range)) then
raise Bounds;
end if;
return S (I);
end Fetch;
function Equal (S1, S2 : in String_Type) return Boolean is
begin
if Is_Empty (S1) then
return Is_Empty (S2);
end if;
return (S2 /= null) and then (S1.all = S2.all);
-- The above code replaces the following. (DECada buggy)
-- return s1.all = s2.all;
-- exception
-- end EQUAL;
end Equal;
function Equal (S1 : in String_Type; S2 : in String) return Boolean is
begin
if S1 = null then
return S2 = "";
end if;
return S1.all = S2;
end Equal;
function Equal (S1 : in String; S2 : in String_Type) return Boolean is
begin
if S2 = null then
return S1 = "";
end if;
return S1 = S2.all;
end Equal;
function "<" (S1 : in String_Type; S2 : in String_Type) return Boolean is
begin
if Is_Empty (S1) then
return (not Is_Empty (S2));
else
return (S1.all < S2);
end if;
-- Got rid of the following code: (Think that DECada is buggy)
--return s1.all < s2.all;
--exception
--when constraint_error => -- on null deref
--return (not is_empty(s2));
-- one of them must be empty
end "<";
function "<" (S1 : in String_Type; S2 : in String) return Boolean is
begin
if S1 = null then
return S2 /= "";
end if;
return S1.all < S2;
end "<";
function "<" (S1 : in String; S2 : in String_Type) return Boolean is
begin
if S2 = null then
return False;
end if;
return S1 < S2.all;
end "<";
function "<=" (S1 : in String_Type; S2 : in String_Type) return Boolean is
begin
if Is_Empty (S1) then
return True;
end if;
return (S1.all <= S2);
-- Replaces the following: (I think DECada is buggy)
--return s1.all <= s2.all;
--exception
--when constraint_error => -- on null deref
--return is_empty(s1); -- one must be empty, so s1<=s2 iff s1 = ""
end "<=";
function "<=" (S1 : in String_Type; S2 : in String) return Boolean is
begin
if S1 = null then
return True;
end if;
return S1.all <= S2;
end "<=";
function "<=" (S1 : in String; S2 : in String_Type) return Boolean is
begin
if S2 = null then
return S1 = "";
end if;
return S1 <= S2.all;
end "<=";
function Match_C (S : in String_Type;
C : in Character;
Start : in Positive := 1) return Natural is
begin
if S = null then
return 0;
end if;
for I in Start .. S.all'Last loop
if S (I) = C then
return I;
end if;
end loop;
return 0;
end Match_C;
function Match_Not_C
(S : in String_Type; C : in Character; Start : in Positive := 1)
return Natural is
begin
if S = null then
return 0;
end if;
for I in Start .. S.all'Last loop
if S (I) /= C then
return I;
end if;
end loop;
return 0;
end Match_Not_C;
function Match_S (S1, S2 : in String_Type; Start : in Positive := 1)
return Natural is
begin
if (S1 = null) or else (S2 = null) then
return 0;
end if;
return Match_String (S1.all, S2.all, Start);
end Match_S;
function Match_S
(S1 : in String_Type; S2 : in String; Start : in Positive := 1)
return Natural is
begin
if S1 = null then
return 0;
end if;
return Match_String (S1.all, S2, Start);
end Match_S;
function Match_Any (S, Any : in String_Type; Start : in Positive := 1)
return Natural is
begin
if Any = null then
raise Any_Empty;
end if;
return Match_Any (S, Any.all, Start);
end Match_Any;
function Match_Any
(S : in String_Type; Any : in String; Start : in Positive := 1)
return Natural is
begin
if Any = "" then
raise Any_Empty;
end if;
if S = null then
return 0;
end if;
for I in Start .. S.all'Last loop
for J in Any'Range loop
if S (I) = Any (J) then
return I;
end if;
end loop;
end loop;
return 0;
end Match_Any;
function Match_None (S, None : in String_Type; Start : in Positive := 1)
return Natural is
begin
if Is_Empty (S) then
return 0;
end if;
if Is_Empty (None) then
return 1;
end if;
return Match_None (S, None.all, Start);
end Match_None;
function Match_None
(S : in String_Type; None : in String; Start : in Positive := 1)
return Natural is
Found : Boolean;
begin
if Is_Empty (S) then
return 0;
end if;
for I in Start .. S.all'Last loop
Found := True;
for J in None'Range loop
if S (I) = None (J) then
Found := False;
exit;
end if;
end loop;
if Found then
return I;
end if;
end loop;
return 0;
end Match_None;
-- Utilities:
function Enter (S : in String_Type) return String_Type is
begin
Top (Scopes).all := Attach (Top (Scopes).all, S);
return S;
exception
when Empty_Stack =>
raise Illegal_Alloc;
end Enter;
function Match_String
(S1, S2 : in String; Start : in Positive := 1) return Natural is
Offset : Natural;
begin
Offset := S2'Length - 1;
for I in Start .. (S1'Last - Offset) loop
if S1 (I .. (I + Offset)) = S2 then
return I;
end if;
end loop;
return 0;
exception
when Constraint_Error =>
-- on offset := s2'length (= 0)
return 0;
end Match_String;
begin
-- Initialize the scopes stack with an implicit mark.
Scopes := Create;
Mark;
end String_Pkg;