PACKAGE BODY VStrings IS ------------------------------------------------------------------ --| Body of ADT to handle strings of variable length. --| Maximum length must be at least 1. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: September 1995 ------------------------------------------------------------------ -- local function FUNCTION Maximum(L, R: Positive) RETURN Positive IS BEGIN IF L > R THEN RETURN L; ELSE RETURN R; END IF; END Maximum; FUNCTION Length(S : VString) RETURN Natural IS BEGIN RETURN S.CurrentLength; END Length; FUNCTION MaxLength(S : VString) RETURN Positive IS BEGIN RETURN S.MaxLength; END MaxLength; FUNCTION Value(S : VString) RETURN String IS BEGIN IF S.CurrentLength = 0 THEN RETURN ""; ELSE RETURN S.StringPart(1 .. S.CurrentLength); END IF; END Value; FUNCTION Tail(S : VString) RETURN VString IS Result: VString(S.MaxLength); CurrLength: Natural; BEGIN CurrLength := S.CurrentLength; IF CurrLength = 0 THEN RAISE EmptyString; ELSIF CurrLength = 1 THEN RETURN Result; -- other fields default ELSE Result.CurrentLength := CurrLength - 1; Result.StringPart(1..CurrLength-1) := S.StringPart(2..CurrLength); RETURN Result; END IF; END Tail; FUNCTION Head(S : VString) RETURN Character IS BEGIN IF S.CurrentLength = 0 THEN RAISE EmptyString; ELSE RETURN S.StringPart(1); END IF; END Head; FUNCTION IsEmpty(S : VString) RETURN Boolean IS BEGIN RETURN S.CurrentLength = 0; END IsEmpty; FUNCTION MakeVString(S : String; MaxLength : Positive) RETURN VString IS Result: VString(MaxLength); BEGIN IF S'Length > MaxLength THEN RAISE StringOverflow; ELSE Result.CurrentLength := S'Length; Result.StringPart(1..S'Length) := S; END IF; RETURN Result; END MakeVString; FUNCTION EmptyVString(MaxLength : Positive) RETURN VString IS Result: VString(MaxLength); BEGIN RETURN Result; -- CurrentLength, StringPart both defaulted END EmptyVString; FUNCTION MakeVString(C: Character; MaxLength: Positive) RETURN VString IS Result: VString(MaxLength); BEGIN Result.CurrentLength := 1; Result.StringPart(1) := C; RETURN Result; END MakeVString; FUNCTION "&" (S1, S2 : VString) RETURN VString IS Max: Positive := Maximum(S1.MaxLength, S2.MaxLength); CurrLength: Natural; Result: VString(Max); BEGIN CurrLength := S1.CurrentLength + S2.CurrentLength; IF CurrLength > Max THEN RAISE StringOverflow; ELSE Result.CurrentLength := CurrLength; Result.StringPart(1..CurrLength) := Value(S1) & Value(S2); END IF; RETURN Result; END "&"; FUNCTION "&" (S1 : VString; C : Character) RETURN VString IS Result: VString(S1.MaxLength); CurrLength: Natural; BEGIN CurrLength := S1.CurrentLength; IF CurrLength + 1 > S1.MaxLength THEN RAISE StringOverflow; ELSE Result.CurrentLength := CurrLength + 1; Result.StringPart(1..CurrLength + 1) := Value(S1) & C; RETURN Result; END IF; END "&"; FUNCTION "&" (C : Character; S1 : VString) RETURN VString IS Result: VString(S1.MaxLength); CurrLength: Natural; BEGIN CurrLength := S1.CurrentLength; IF CurrLength + 1 > S1.MaxLength THEN RAISE StringOverflow; ELSE Result.CurrentLength := CurrLength + 1; Result.StringPart(1..CurrLength + 1) := C & Value(S1); RETURN Result; END IF; END "&"; FUNCTION "&" (S1 : VString; S : String) RETURN VString IS Max: Positive := S1.MaxLength; CurrLength: Natural; Result: VString(Max); BEGIN CurrLength := S1.CurrentLength + S'Length; IF CurrLength > Max THEN RAISE StringOverflow; ELSE Result.CurrentLength := CurrLength; Result.StringPart(1..CurrLength) := Value(S1) & S; END IF; RETURN Result; END "&"; FUNCTION "&" (S : String; S1 : VString) RETURN VString IS Max: Positive := S1.MaxLength; CurrLength: Natural; Result: VString(Max); BEGIN CurrLength := S1.CurrentLength + S'Length; IF CurrLength > Max THEN RAISE StringOverflow; ELSE Result.CurrentLength := CurrLength; Result.StringPart(1..CurrLength) := S & Value(S1); END IF; RETURN Result; END "&"; FUNCTION "<=" (S1, S2 : VString) RETURN Boolean IS BEGIN RETURN Value(S1) <= Value(S2); END "<="; FUNCTION "<" (S1, S2 : VString) RETURN Boolean IS BEGIN RETURN Value(S1) < Value(S2); END "<"; FUNCTION ">=" (S1, S2 : VString) RETURN Boolean IS BEGIN RETURN Value(S1) >= Value(S2); END ">="; FUNCTION ">" (S1, S2 : VString) RETURN Boolean IS BEGIN RETURN Value(S1) > Value(S2); END ">"; FUNCTION Locate(Sub : String; Within : VString) RETURN Natural IS Result : Natural; LSub : Natural; LWithin : Natural; BEGIN LSub := Sub'Length; LWithin := Within.CurrentLength; Result := 0; IF LSub > 0 AND LWithin > 0 AND LSub <= LWithin THEN FOR Start IN 1 .. (LWithin - LSub + 1) LOOP IF Sub = Within.StringPart(Start .. (Start + LSub - 1)) THEN Result := Start; EXIT; END IF; END LOOP; END IF; RETURN Result; END Locate; FUNCTION Locate(Sub : VString; Within : VString) RETURN Natural IS BEGIN RETURN Locate(Value(Sub), Within); END Locate; FUNCTION Locate(C : Character; Within : VString) RETURN Natural IS Temp : String(1..1); BEGIN Temp(1) := C; RETURN Locate(Temp, Within); END Locate; FUNCTION Slice(S : VString; Start, Finish : Positive) RETURN VString IS Result: VString(S.MaxLength); BEGIN IF Start > Length(S) OR Finish > Length(S) THEN RAISE InvalidArguments; ELSIF Start > Finish THEN RETURN Result; -- empty; consistent with Ada slice ELSE Result.CurrentLength := Finish - Start + 1; Result.StringPart(1..Result.CurrentLength) := S.StringPart(Start..Finish); RETURN Result; END IF; END Slice; END VStrings;