home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
LIBRARY
/
STR.SA
< prev
next >
Wrap
Text File
|
1995-02-05
|
30KB
|
791 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
-- str.sa: Strings.
-------------------------------------------------------------------
class STR < $IS_EQ{STR}, $IS_LT{STR}, $HASH is
-- Strings.
-- Strings are represented as arrays of characters. Every character
-- is significant.
--
-- References: Gonnet and Baeza-Yates, "Handbook of Algorithms and
-- Data Structures", Addison Wesley, 1991.
private include AREF{CHAR} aget->aget;
-- Make modification routines private.
private shared buf:FSTR; -- Character buffer.
create:SAME is
-- An empty string. (Occasionally useful in constructs like
-- `#STR + foo').
return "" end;
create_from_file(nm:STR):SAME is
-- Open the file named `nm' in the current directory, create a
-- string containing its contents and then close the file. Return
-- void if there is no such file.
fd::=C_STR::c_str_file_open(nm);
if fd<0 then return void end;
sz::=C_STR::c_str_file_size(fd);
r::=new(sz);
C_STR::c_str_file_in_str(fd,r,0,sz);
C_STR::c_str_file_close(fd);
return r end;
create_from_file_range(nm:STR,st,sz:INT):SAME is
-- Open the file named `nm' in the current directory, create a
-- string containing `sz' characters starting at `st'. Fill in
-- the remainder with '\0' if the file is too small. Return
-- void if there is no such file.
fd::=C_STR::c_str_file_open(nm);
if fd<0 then return void end;
fsz::=C_STR::c_str_file_size(fd);
r::=new(sz);
if st+sz<fsz then C_STR::c_str_file_in_str(fd,r,st,sz);
else C_STR::c_str_file_in_str(fd,r,st,fsz-st) end;
C_STR::c_str_file_close(fd);
return r end;
create_from_c_string(s:EXT_OB):SAME is
-- Create a Sather string from a C pointer. Needless to say,
-- use this with caution.
if void(s) then return void end;
len::=C_STR::strlen(s);
r::=new(len);
ext::=C_STR::strcpy(r,s);
return r;
end;
create_from_memory_area(s:EXT_OB,len:INT):SAME is
-- Create a Sather string from a memory area of size
-- 'len' bytes starting at 's'. Needless to say,
-- use this with caution.
if void(s) or len<=0 then return void end;
r::=new(len);
ext::=C_STR::memcpy(r,s,len);
return r;
end;
size:INT is
-- The number of characters in self. 0 if self is void.
-- if void(self) then return 0 else return asize end end; -- NLP
if void(self) then return 0 end; return asize; end; -- NLP
length:INT is
-- The number of characters in self. 0 if self is void.
-- Another name for `size'.
-- if void(self) then return 0 else return asize end end; -- NLP
if void(self) then return 0 end; return asize; end; -- NLP
char(i:INT):CHAR
-- The character at index `i' of self.
pre i.is_bet(0,asize-1) is
return [i] end;
elt!:CHAR is
-- Yield the characters of self in order.
-- Self may be void.
if ~void(self) then loop yield aelt! end end end;
elt!(beg:INT):CHAR is
-- Yield the characters of self in order starting at `beg'.
-- Self may be void.
if ~void(self) then loop yield aelt!(beg) end end end;
ind!:INT is
-- Yield the indices of the characters of self in order.
-- Self may be void.
if ~void(self) then loop yield aind! end end end;
acopyn(s:FSTR,n:INT) pre n <= s.length is
-- copy "n" chars from "s" into "self".
loop aset!(s[n.times!]) end;
end;
acopyn(s:STR,n:INT) pre n <= s.length is
-- copy "n" chars from "s" into "self".
loop aset!(s[n.times!]) end;
end;
from_fstr(s:FSTR):SAME is
-- A new string with the characters currently held in `s'.
-- Returns empty string if emtpy. Modified MBK.
sz ::= s.size; -- save it.
if sz=0 then return "" end;
r::=new(sz);
r.acopyn(s,sz);
-- loop r.aset!(s.elt!) end;
return r end;
fstr:FSTR is
-- An FSTR with the same characters as self.
-- if size=0 then return void; end;
-- r::=#FSTR(size);
-- loop r:=r.push(elt!); end;
-- return r;
-- end;
return #FSTR(self); end;
plus(s:SAME):SAME is
-- A new string obtained by appending `s' to self.
-- Either self or `s' may be void. Sped up, MBK.
-- if size=0 then return s -- NLP
-- else -- NLP
-- sz ::= s.size; -- NLP
-- if sz=0 then return self -- NLP
-- else r::=new(asize+sz); r.acopyn(self,asize); -- NLP
-- r.acopy(asize,s); return r end -- NLP
-- end; -- NLP
if size=0 then return s; end; -- NLP
sz ::= s.size; -- NLP
if sz=0 then return self; end; -- NLP
r::=new(asize+sz); r.acopyn(self,asize); -- NLP
r.acopy(asize,s); return r; -- NLP
end;
plus(b:BOOL):SAME is
-- A new string obtained by appending the value of `b'
-- to self. Self may be void.
if void(self) then
if b then return "true" else return "false" end
elsif b then return self+"true"
-- else return self+"false" end end; -- NLP
end; return self+"false"; end; -- NLP
plus(c:CHAR):SAME is
-- A new string obtained by appending `c' to self.
-- Self may be void.
r:SAME;
if void(self) then r:=new(1)
else r:=new(asize+1); r.acopy(self) end;
r[size]:=c; return r end;
plus(i:INT):SAME is
-- A new string obtained by appending `i' to self.
-- Self may be void.
buf.clear; if ~void(self) then buf:=buf+self end;
buf:=i.str_in(buf); return from_fstr(buf) end;
plus(f:FLT):SAME is
-- A new string obtained by appending `f' to self.
-- Self may be void.
buf.clear; if ~void(self) then buf := buf+self; end;
return(from_fstr(buf+(f.str))); end;
plus(f:FLTD):SAME is
-- A new string obtained by appending `f' to self.
-- Self may be void.
buf.clear; if ~void(self) then buf := buf+self; end;
return(from_fstr(buf+(f.str))); end;
plus(s:FSTR):SAME is
-- A new string obtained by appending `s' to self.
-- Either self or `s' may be void.
if s.size=0 then return self
elsif size=0 then return s.str
-- else r::=new(size+s.size); -- NLP
end; r::=new(size+s.size); -- NLP
r.acopy(self); loop r.aset!(size,s.elt!) end;
-- return r end end; -- NLP
return r; end; -- NLP
append(s:SAME):SAME is
-- A new string obtained by appending `s' to self.
-- Either self or `s' may be void.
return plus(s) end;
append(s1,s2:SAME):SAME is
-- A new string obtained by appending `s1' and `s2' to self.
-- Any of the strings may be void.
if size=0 then return s1+s2
elsif s1.size=0 then return self+s2
elsif s2.size=0 then return self+s1
-- else r::=new(asize+s1.asize+s2.asize); -- NLP
end; r::=new(asize+s1.asize+s2.asize); -- NLP
r.acopy(self); r.acopy(asize,s1);
-- r.acopy(asize+s1.asize,s2); return r end end; -- NLP
r.acopy(asize+s1.asize,s2); return r; end; -- NLP
append(s1,s2,s3:SAME):SAME is
-- A new string obtained by appending `s1', `s2', and `s3' to self.
-- Any of the strings may be void.
if size=0 then return s1.append(s2,s3)
elsif s1.size=0 then return self.append(s2,s3)
elsif s2.size=0 then return self.append(s1,s3)
elsif s3.size=0 then return self.append(s1,s2)
-- else r::=new(asize+s1.asize+s2.asize+s3.asize); -- NLP
end; r::=new(asize+s1.asize+s2.asize+s3.asize); -- NLP
r.acopy(self); r.acopy(asize,s1);
r.acopy(asize+s1.asize,s2); r.acopy(asize+s1.asize+s2.asize,s3);
-- return r end end; -- NLP
return r; end; -- NLP
append(s1,s2,s3,s4:SAME):SAME is
-- A new string obtained by appending `s1', `s2', `s3', and
-- `s4' to self. Any of the strings may be void.
if size=0 then return s1.append(s2,s3,s4)
elsif s1.size=0 then return self.append(s2,s3,s4)
elsif s2.size=0 then return self.append(s1,s3,s4)
elsif s3.size=0 then return self.append(s1,s2,s4)
elsif s4.size=0 then return self.append(s1,s2,s3)
-- else r::=new(asize+s1.asize+s2.asize+s3.asize+s4.asize); -- NLP
end; r::=new(asize+s1.asize+s2.asize+s3.asize+s4.asize); -- NLP
r.acopy(self); r.acopy(asize,s2); r.acopy(asize+s1.asize,s2);
r.acopy(asize+s1.asize+s2.asize,s3);
r.acopy(asize+s1.asize+s2.asize+s3.asize,s4);
-- return r end end; -- NLP
return r; end; -- NLP
str:STR is
return self; end;
pretty:STR is
-- Pretty print self. This surrounds the string with
-- a pair of double quotes. Any non-printing characters or double
-- quotes are replaced by their special codes or the octal
-- representation.
buf.clear; buf:=buf+'\"';
loop c::=elt!;
if c.is_print and c/='\"' and c/='\\' then buf:=buf+c
else buf:=buf + '\\';
case c
when '\a' then buf:=buf+'a' when '\b' then buf:=buf+'b'
when '\f' then buf:=buf+'f' when '\n' then buf:=buf+'n'
when '\r' then buf:=buf+'r' when '\t' then buf:=buf+'t'
when '\v' then buf:=buf+'v' when '\\' then buf:=buf+'\\'
when '\"' then buf:=buf+'\"'
else s::=c.int.octal_str;
buf:=buf+s.tail(s.size-2) end end end;
buf:=buf+'\"'; return buf.str end;
as_literal:STR is
-- Returns the string described by self assuming it is in "string
-- literal" form. This means it must begin and end with double
-- quotes and must not contain any non-printing characters.
-- The returned string eliminates the initial and final double
-- quotes and converts any escape codes to the corresponding
-- characters. self may consist of several double-quote enclosed
-- strings separated by whitespace. In this case the strings are
-- concatenated together. If self is not in correct string literal
-- format, returns void.
if void(self) or [0]/='\"' or [size-1]/='\"' then return void end;
buf.clear; esc,oct,qt:BOOL; oval:INT;
loop c::=aelt!(1,size-2);
if qt then -- We're between concatted strings.
if c='\"' then qt:=false
elsif ~c.is_space then return void end;
else
if oct then -- we're in an octal escape code
if c.is_octal_digit then oval:=oval*8+c.octal_digit_value
else buf:=buf+oval.char; oct:=false; esc:=false end end;
if ~oct then
if esc then -- we've seen only a '\'
case c
when 'a' then buf:=buf+'\a'; esc:=false
when 'b' then buf:=buf+'\b'; esc:=false
when 'f' then buf:=buf+'\f'; esc:=false
when 'n' then buf:=buf+'\n'; esc:=false
when 'r' then buf:=buf+'\r'; esc:=false
when 't' then buf:=buf+'\t'; esc:=false
when 'v' then buf:=buf+'\v'; esc:=false
when '\\' then buf:=buf+'\\'; esc:=false
when '\"' then buf:=buf+'\"'; esc:=false
when '\'' then buf:=buf+'\''; esc:=false
when 0,1,2,3,4,5,6,7 then
oct:=true; oval:=c.octal_digit_value
else return void end; -- illegal escape code
elsif c='\\' then esc:=true
elsif c='\"' then qt:=true
elsif c.is_print then buf:=buf+c
else return void end; -- Illegal character
end end end;
if ~qt then return void -- Must close internal quotes.
elsif oct then buf:=buf+oval.char -- Ended with octal code.
elsif esc then return void end; -- Ended with '\'
return buf.str end;
is_empty:BOOL is
-- True if self has no characters.
-- Self may be void.
return (void(self)) or (asize=0) end;
private is_eq_helper(s:SAME,i:INT):BOOL is
-- Matt Kennel, INLS. The reason for this
-- function's existence is that it will be overridden
-- by "memcmp" in MACROS.
loop if aelt!/=s.aelt! then return false end; end;
return true;
end;
is_eq(s:SAME):BOOL is
-- True if `s' equals self. Either may be void.
if void(self) then
if void(s) then return true
elsif s.asize=0 then return true
else return false end;
elsif void(s) then
if asize=0 then return true else return false end
elsif asize/=s.asize then return false
-- else -- NLP
end; -- NLP
return is_eq_helper(s,asize);
-- end; -- NLP
end;
is_neq(s:SAME):BOOL is
-- True if `s' is not equal to self. Either may be void.
return ~is_eq(s) end;
is_lt(s:SAME):BOOL is
-- True if self is lexicographically before `s'.
-- Void is taken to be before everything else.
if size=0 then
if s.size/=0 then return true else return false end
elsif s.size=0 then return false
else
loop c::=aelt!; sc::=s.aelt!;
if c.is_gt(sc) then return false
elsif c.is_lt(sc) then return true end end;
if size<s.size then return true
-- else return false end end end; -- NLP
end; end; return false; end; -- NLP
is_leq(s:SAME):BOOL is
-- True if self is lexicographically before `s' or equal to it.
-- Either may be void.
if size=0 then return true
elsif s.size=0 then return false
else
loop c::=aelt!; sc::=s.aelt!;
if c.is_gt(sc) then return false
elsif c.is_lt(sc) then return true end end;
if size<=s.size then return true
-- else return false end end end; -- NLP
end; end; return false; end; -- NLP
is_gt(s:SAME):BOOL is
-- True if `s' is lexicographically before self.
-- Either may be void.
return s.is_lt(self) end;
is_geq(s:SAME):BOOL is
-- True if `s' is lexicographically before self or equal to it.
-- Either may be void.
return s.is_leq(self) end;
is_upper:BOOL is
-- True if each alphabetic character of self is upper case.
-- Self may be void.
loop if ~elt!.is_upper then return false end end;
return true end;
is_lower:BOOL is
-- True if each alphabetic character of self is lower case.
-- Self may be void.
loop if ~elt!.is_lower then return false end end;
return true end;
upper:SAME is
-- A copy of self with each character in upper case.
-- Self may be void.
if void(self) then return void end;
r::=new(asize);
loop r.aset!(aelt!.upper) end; return r end;
lower:SAME is
-- A copy of self with each character in lower case.
-- Self may be void.
if void(self) then return void end;
r::=new(asize);
loop r.aset!(aelt!.lower) end; return r end;
capitalize:SAME is
-- A copy of self with each word capitalized.
-- Self may be void.
if void(self) then return void end;
r::=new(asize);
sp::=true; -- True if previous char was punct.
loop c::=aelt!;
if sp then c:=c.upper end;
if c.is_punct or c.is_space then sp:=true else sp:=false end;
r.aset!(c) end;
return r end;
head(i:INT):SAME
-- The first `i' characters of self.
-- Self may be void if i=0.
pre i.is_bet(0,size) is
if void(self) then return void end;
r::=new(i); r.acopy(self); return r end;
tail(i:INT):SAME
-- The last `i' characters of self.
-- Self may be void if i=0.
pre i.is_bet(0,size) is
if void(self) then return self end;
r::=new(i); r.acopy(0,i,asize-i,self); return r end;
substring(beg,num:INT):SAME
-- The substring with `num' charcters whose first character has
-- index `beg'. Self may be void if beg=0 and num=0.
pre num>=0 and beg.is_bet(0,size-num) is
if void(self) then return void end;
r::=new(num); r.acopy(0,num,beg,self); return r end;
reverse:SAME is
-- A string whose characters are the reverse of those in self.
-- Self may be void.
if void(self) then return void end;
r::=new(asize);
loop r.aset!(aelt!(asize-1,asize,-1)) end;
return r end;
repeat(i:INT):SAME
-- Self repeated `i' times. Self may be void.
pre i>=0 is
if void(self) then return void end;
r::=new(asize*i);
loop r.acopy(0.step!(i,asize),self) end; return r end;
contains(c:CHAR):BOOL is
-- True if `c' appears in self. Self may be void.
loop if elt!=c then return true end end;
return false end;
count(c:CHAR):INT is
-- The number of times `c' appears in self.
-- Self may be void.
r::=0; loop if elt!=c then r:=r+1 end end;
return r end;
count(s:STR):INT is
-- The number of times a character in `s' appears in self.
-- Self may be void.
if void(self) or void(s) then return 0 end;
r::=0; loop if s.contains(elt!) then r:=r+1 end end;
return r end;
search(c:CHAR):INT is
-- The index of the first appearance of `c' in self or -1 if absent.
-- Self may be void.
loop r::=ind!; if [r]=c then return r end end;
return -1 end;
search(c:CHAR,st:INT):INT is
-- The index of the first appearance of `c' at location `st' or
-- greater in self or -1 if absent.
-- Self may be void.
loop r::=st.upto!(size-1); if [r]=c then return r end end;
return -1 end;
replace(o,n:CHAR):SAME is
-- A new string with each occurance of `o' replaced by `n'.
-- Self may be void.
if void(self) then return void end;
r::=new(asize);
loop c::=aelt!; if c=o then c:=n end;
r.aset!(c) end;
return r end;
remove(c:CHAR):SAME is
-- Self with all occurances of `c' removed.
-- Self may be void.
if void(self) then return void end;
ns::=asize-count(c);
if ns=0 then return void end;
r::=new(ns);
loop sc::=aelt!;
if ~(sc=c) then r.aset!(sc) end end;
return r end;
contains_chars_from(s:STR):BOOL is
-- True if any of the characters in self are contained in `s'.
-- Either may be void.
loop if s.contains(elt!) then return true end end;
return false end;
count_chars_from(s:SAME):INT is
-- The number of characters in self which are contained in `s'.
-- Either may be void.
r::=0; loop if s.contains(elt!) then r:=r+1 end end;
return r end;
search_chars_from(s:SAME):INT is
-- The index of the first appearance in self of a character
-- contained in `s' or -1 if none.
-- Self or `s' may be void.
loop r::=ind!; if s.contains([r]) then return r end end;
return -1 end;
replace_chars_from(set:SAME,n:CHAR):SAME is
-- A new string with character contained in `set' replaced by
-- `n'. Self may be void.
if void(self) then return void end;
r::=new(asize);
loop c::=aelt!; if set.contains(c) then c:=n end;
r.aset!(c) end;
return r end;
remove_chars_from(s:SAME):SAME is
-- Self with all characters which are contained in `s' removed.
-- Either may be void.
if void(self) then return void end;
if void(s) then return self end;
ns::=asize-count(s); if ns=0 then return self end;
r::=new(ns);
loop c::=aelt!;
if ~s.contains(c) then r.aset!(c) end end;
return r end;
is_prefix(s:SAME):BOOL is
-- true is s is a prefix of self.
if length<s.length then return false; end;
loop if (elt!/=s.elt!) then return false; end; end;
return true; end;
mismatch(s:SAME):INT is
-- The index of the first character of self which differs from `s'.
-- -1 if self is a prefix of `s'. Either may be void.
if void(self) then return -1 end;
if void(s) then return 0 end;
r:INT;
loop r:=ind!; if [r]/=s.aelt! then return r end end;
if r=asize-1 then return -1 end;
return r end;
search(s:SAME):INT is
-- The index of the leftmost substring of self which matches `s'.
-- -1 if none. Uses simple algorithm which has good performance
-- unless the strings are special (eg. many repeated values).
-- Either string may be void. (Void matches void at 0).
if void(s) then return 0 end;
if void(self) then return -1 end;
loop r::=0.upto!(asize-s.asize); match::=true;
loop if aelt!(r)/=s.aelt! then
match:=false; break! end end;
if match=true then return r end end;
return -1 end;
cursor:STR_CURSOR is
-- A cursor into self.
return STR_CURSOR::create(self) end;
hash1:INT is
-- An inexpensive to compute hash function of self.
-- Gives an INT with rightmost 24 bits.
-- Void gives 0.
-- r::=0; loop i::=ind!;
-- r:=r.bxor([i].int.lshift(i.band(15))) end;
-- return r end;
-- code changed by MBK. This has to go fast,
-- it's frequently called by the compiler code.
-- Guess what. The above hash function really sucks rocks.
-- we get lots and lots of clustering. The compiler's
-- run time is dependent on how fast and how good
-- you can make string hashing
-- go. This next one isn't great either. We should make one
-- as strong as reasonable random number generators.
-- Those numbers are just 'random' integers between 0 and 2^24-1
-- that I picked up behind a dark alley.
--
if void(self) then return 0 end;
r::=11764026;
i::= asize-1;
loop
while!(i>=0);
c:INT := [i].int;
case (r+c).band(7)
when 0 then r:=r.bxor(11522134) + c.bxor(15272649);
when 1 then r:=r.bxor(9981388) + c.bxor(12787561);
when 2 then r:=r.bxor(15610134) + c.bxor(4403230);
when 3 then r:=r.bxor(14196234) + c.bxor(796322);
when 4 then r:=r.bxor(8840397) + c.bxor(12349404);
when 5 then r:=r.bxor(1542914) + c.bxor(5506856);
when 6 then r:=r.bxor(10970939) + c.bxor(10613913);
when 7 then r:=r.bxor(6979311) + c.bxor(12690462);
end;
i := i-1;
end;
return r.band(16777215); -- 2^24-1
end;
private const coeff1:ARRAY{INT} := |11522134,9981388,15610134,14196234,
8840397,1524914,10970939,6979311|;
private const coeff2:ARRAY{INT} := |15272649,12787561,4403230,796322,
12349404,5506856,10613913,12690462|;
hash2:INT is
-- code changed by MBK. This has to go fast,
-- it's frequently called by the compiler code.
-- Guess what. The original hash function really sucks rocks.
-- we get lots and lots of clustering. The compiler's
-- run time is dependent on how fast and how good
-- you can make string hashing
-- go. This next one isn't great either. We should make one
-- as strong as reasonable random number generators.
-- Those numbers are just 'random' integers between 0 and 2^24-1
-- that I picked up behind a dark alley.
if void(self) then return 0 end;
r::=11764026;
i::= asize-1;
loop
while!(i>=0);
c:INT := [i].int;
z:INT := (r+c).band(7);
r := r.bxor(coeff1[z]) + c.bxor(coeff2[z]);
i := i-1;
end;
return r.band(16777215); -- 2^24-1
end;
hash3: INT is
-- An not-quite-so inexpensive to compute hash function of self.
-- Void gives 0. Changed from original, MBK.
-- Original gave very yucky collision avalanching in the compiler
-- implementation. I'm sick of half-assed hash functions.
if void(self) then return 0 end;
i::= asize-1;
r:INT:=532415.uplus([i].int);
-- 532415 = 'A' * (2^13-1)
i := i-1;
loop while!(i >= 3);
fourchars :INT:= ([i].int).lshift(24);
fourchars := fourchars.bor(([i-1].int).lshift(16));
fourchars := fourchars.bor(([i-2].int).lshift(8));
fourchars := fourchars.bor([i-3].int);
r := (r.utimes(1664525)).uplus(1013904223).uplus(fourchars);
-- Motivated by Numerical Recipes in C, p. 284. A linear
-- congruential PRNG plus 4 characters as the hash salt.
-- r := (r.utimes(8191)).uplus([i].int);
-- negative. That one was even worse than the original.
i := i-4;
end;
if (i < 0) then return r; end;
c:INT;
case i
when 2 then
c := ([2].int).lshift(16).bor(
([1].int).lshift(8).bor(
([0].int)));
when 1 then
c := ([1].int).lshift(8).bor(([0].int));
when 0 then
c := ([0]).int;
end;
r := (r.utimes(1664525)).uplus(1013904223).uplus(c);
return r;
end;
hash:INT is
-- Keep It Simple, Stupid.
if void(self) then return 0 end;
if (asize = 0) then return 0 end;
i::= asize-1;
r:INT:=532415.uplus([i].int);
-- 532415 = 'A' * (2^13-1)
i := i-1;
loop while!(i>=0);
r := (r.utimes(1664525)).uplus(1013904223).uplus([i].int);
i := i-1
end;
return r;
end;
left(i:INT):SAME is
-- A string of at least `i' characters in which self
-- is left-justified and padded with spaces on the right.
-- Returns self if i<=size.
if i<=size then return self end;
if void(self) then return " ".repeat(i) end;
r::=new(i); r.acopy(self);
loop r.aset!(asize, ' ') end;
return r end;
right(i:INT):SAME is
-- A string of at least `i' characters in which self
-- is right-justified and padded with spaces on the left.
-- Returns self if i<=size.
if i<=size then return self end;
if void(self) then return " ".repeat(i) end;
r::=new(i); r.acopy(i-asize,self);
loop r.aset!(0, i-asize, ' ') end;
return r end;
center(i:INT):SAME is
-- A string of at least `i' characters in which self
-- is centered and padded with spaces on the left and right.
-- Returns self if i<=size.
if i<=size then return self end;
if void(self) then return " ".repeat(i) end;
r::=new(i);
lp::=(i-asize)/2; -- Size of left padding.
r.acopy(lp,self);
loop r.aset!(0, lp, ' ') end;
loop r.aset!(lp+asize, ' ') end;
return r end;
separate!(s:STR!):STR is
-- On the first iteration just outputs `s', on successive
-- iterations it outputs self followed by `s'. Useful for
-- forming lists,
-- Eg: loop #OUT + ", ".separate!(a.elt!) end;
yield s; loop yield self + s end end;
concat_all(a: ARRAY{SAME}): SAME is
-- Concatinate all array of STRING. Separator is '\0'.
r: SAME;
l: INT := a.size;
loop i ::= 0.upto!(l - 2);
r := r + a[i] + '\0';
end; -- loop
return r + a[l - 1];
end;
end; -- class STR
-------------------------------------------------------------------
external class C_STR is
-- Interface to C functions supporting STR.
c_str_file_open(s:STR):INT; -- Try to open the file named `s'
-- for reading and return the file descriptor. -1 for failure.
c_str_file_size(fd:INT):INT; -- The size in characters of the
-- file described by descriptor `fd'.
c_str_file_in_str(fd:INT,s:STR,st,sz:INT); -- Fill in the string `s'
-- with the characters from the file described by `fd' starting
-- at character `st' and going for `sz' chars (which should be
-- the length of `s'). THIS SHOULD NOT BE CALLED OUTSIDE OF
-- STR (to avoid breaking the immutability property of strings).
c_str_file_in_fstr(fd:INT,s:FSTR,st,sz,bst:INT); -- Insert into
-- the string buffer `s' characters from the file described by
-- `fd' starting at character `st' and going for `sz' chars. Start
-- inserting at character `bst' of the buffer (there must be
-- room!).
c_str_file_close(fd:INT); -- Close the file described by the
-- descriptor `fd'.
c_str_create_astr(i:INT, s:STR): EXT_OB; -- Split concatinate
-- strings separated by '\0' into array of string in C.
strlen(s:EXT_OB):INT;
strcpy(s1:STR,s2:EXT_OB):EXT_OB;
memcpy(r:STR,s:EXT_OB,i:INT):EXT_OB;
end; -- external class C_STR
-------------------------------------------------------------------