<> <> <> <> <<>> DIRECTORY PS, Atom USING [MakeAtom], Rope USING [Fetch, Size]; PSStringImpl: CEDAR PROGRAM IMPORTS PS, Atom, Rope ~ BEGIN OPEN PS; <> StringCreate: PUBLIC PROC [size: INT] RETURNS [String] ~ { IF size<0 THEN ERROR Error[rangecheck]; IF size IN StringIndex THEN { ref: StringRef ~ NEW[TEXT[size]]; FOR i: StringIndex IN[0..ref.maxLength) DO ref[i] _ VAL[0] ENDLOOP; RETURN[[ val: [executable: FALSE, variant: string[access: unlimited, start: 0, length: size]], ref: ref ]]; } ELSE ERROR Error[limitcheck]; }; StringAccess: PUBLIC PROC [string: String] RETURNS [Access] ~ { RETURN [string.val.access]; }; StringLength: PUBLIC PROC [string: String] RETURNS [INT] ~ { RETURN [string.val.length]; }; StringGet: PUBLIC PROC [string: String, index: INT] RETURNS [CHAR] ~ { IF index NOT IN [0..string.val.length) THEN ERROR Error[rangecheck]; RETURN [string.ref[string.val.start+index]]; }; StringPut: PUBLIC PROC [string: String, index: INT, x: CHAR] ~ { IF index NOT IN[0..string.val.length) THEN ERROR Error[rangecheck]; string.ref[string.val.start+index] _ x; }; StringGetInterval: PUBLIC PROC [string: String, index, count: INT] RETURNS [String] ~ { IF index NOT IN [0..string.val.length] THEN ERROR Error[rangecheck]; IF count NOT IN [0..(string.val.length-index)] THEN ERROR Error[rangecheck]; RETURN[[ val: [executable: string.val.executable, variant: string[ access: string.val.access, start: string.val.start+index, length: count]], ref: string.ref ]]; }; <> <> <> <<};>> <<>> <> <> <> <<};>> <<>> <> <> <> <<{>> <> <> <> <> <> <> <> <> <<]>> <<]];>> <<};>> <<};>> <<>> <> StringPutInterval: PUBLIC PROC [string: String, index: INT, interval: String] ~ { substring: String ~ StringGetInterval[string, index, StringLength[interval]]; <<***** use ByteBlt here? *****>> FOR i: INT IN[0..StringLength[substring]) DO StringPut[substring, i, StringGet[interval, i]]; ENDLOOP; }; StringCopy: PUBLIC PROC [string1, string2: String] RETURNS [String] ~ { substring2: String ~ StringGetInterval[string2, 0, StringLength[string1]]; StringPutInterval[substring2, 0, string1]; RETURN [substring2]; }; StringForAll: PUBLIC PROC [string: String, action: PROC [CHAR]] ~ { FOR index: INT IN [0..StringLength[string]) DO action[StringGet[string, index]]; ENDLOOP; }; StringEq: PUBLIC PROC [string1: String, string2: String] RETURNS [BOOL] ~ { IF StringLength[string1]#StringLength[string2] THEN RETURN [FALSE]; RETURN [StringCompare[string1, string2]=equal]; }; StringCompare: PUBLIC PROC [string1, string2: String] RETURNS [Comparison] ~ { length1: INT ~ StringLength[string1]; length2: INT ~ StringLength[string2]; FOR index: INT IN[0..MIN[length1, length2]) DO char1: CHAR ~ StringGet[string1, index]; char2: CHAR ~ StringGet[string2, index]; IF char1=char2 THEN NULL ELSE RETURN [IF char1 found _ TRUE; ENDLOOP; IF anchor THEN EXIT ELSE index _ index+1; ENDLOOP; }; StringFromRope: PUBLIC PROC [rope: ROPE, executable: BOOL] RETURNS [String] ~ { length: INT ~ Rope.Size[rope]; string: String ~ StringCreate[length]; FOR i: INT IN [0..length) DO StringPut[string, i, Rope.Fetch[rope, i]]; ENDLOOP; RETURN [string]; }; <> <> <> <> <> <> <> <<};>> <<>> <> <> <<};>> <<>> NameFromRope: PROC [rope: ROPE, executable: BOOL _ TRUE] RETURNS [Name] ~ { RETURN [[ val: [executable: executable, variant: name[]], ref: Atom.MakeAtom[rope] ]]; }; <> <> <> <> <> <> <> <> <<};>> <<>> END.