home *** CD-ROM | disk | FTP | other *** search
- -- Part of SmallEiffel -- Read DISCLAIMER file -- Copyright (C)
- -- Dominique COLNET and Suzanne COLLIN -- colnet@loria.fr
- --
- class STRING
- --
- -- Characters strings.
- --
-
- inherit
- COMPARABLE
- redefine
- hash_code, is_equal, infix "<", compare, copy,
- print_on
- end;
-
- creation {ANY}
- make, copy, blank
-
- feature {NONE}
-
- storage: POINTER;
- -- The place where characters are stored.
-
- feature {ANY}
-
- count: INTEGER;
- -- String length.
-
- capacity: INTEGER;
- -- Capacity of the `storage'.
-
- feature {ANY} -- Creation / Modification :
-
- make(needed_capacity: INTEGER) is
- -- Initialize the string to have at least a `needed_capacity'
- -- space of storage.
- require
- needed_capacity >= 0;
- do
- count := 0;
- if needed_capacity > 0 then
- if capacity < needed_capacity then
- if capacity = 0 then
- c_inline_c("C->_storage=(char *)%
- %malloc((size_t)a1);");
- else
- c_inline_c("C->_storage=(char *)%
- %realloc(C->_storage,(size_t)a1);");
- end;
- capacity := needed_capacity;
- end;
- end;
- ensure
- needed_capacity <= capacity;
- count = 0
- end;
-
- blank(nr_blanks: INTEGER) is
- -- Initialize string with `nr_blanks' blanks.
- require
- nr_blanks >= 0;
- do
- make(nr_blanks);
- count := nr_blanks;
- fill_with(' ');
- ensure
- count = nr_blanks;
- occurrences_of(' ') = count
- end;
-
- feature {ANY} -- No Modification of the receiver :
-
- empty: BOOLEAN is
- -- Has string length 0?
- do
- Result := (count = 0)
- end;
-
- infix "@", item(index: INTEGER): CHARACTER is
- -- Character at position `index'.
- require
- valid_index(index)
- do
- c_inline_c("R=(C->_storage)[a1-1];");
- end;
-
- valid_index(index: INTEGER): BOOLEAN is
- -- True when `index' is valid (ie inside actual bounds).
- do
- Result := 1 <= index and then index <= count;
- ensure
- Result = (1 <= index and index <= count)
- end;
-
- hash_code: INTEGER is
- local
- i: INTEGER;
- do
- from
- i := count;
- if i > 5 then
- i := 5;
- end;
- until
- i = 0
- loop
- Result := Result + item(i).code;
- i := i - 1;
- end;
- end;
-
- infix "<" (other: STRING): BOOLEAN is
- -- Is Current less than `other' ?
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- count < i or else other.count < i
- or else item(i) /= other.item(i)
- loop
- i := i + 1;
- end;
- if count < i then
- Result := other.count >= i;
- elseif other.count < i then
- Result := false;
- else
- Result := item(i) < other.item(i);
- end;
- end;
-
- compare(other: STRING): INTEGER is
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- count < i or else other.count < i
- or else item(i) /= other.item(i)
- loop
- i := i + 1;
- end;
- if count < i then
- if other.count < i then
- Result := 0;
- else
- Result := -1;
- end;
- elseif other.count < i then
- Result := +1;
- elseif item(i) < other.item(i) then
- Result := -1;
- else
- Result := +1;
- end;
- end;
-
- same_as(other: STRING): BOOLEAN is
- -- No difference is done between upper and lower case.
- local
- i: INTEGER;
- do
- if other = Current then
- Result := true;
- else
- if other.count /= count then
- Result := false;
- else
- from
- i := count;
- until
- (i = 0) or else (not item(i).same_as(other @ i))
- loop
- i := i - 1;
- end;
- Result := (i = 0);
- end;
- end;
- end;
-
- is_equal(other: STRING): BOOLEAN is
- -- Has Current the same text as `other'?
- require else
- true
- local
- i: INTEGER;
- do
- if Current = other then
- Result := true;
- else
- from
- i := count;
- Result := (i = other.count);
- until
- not Result or i = 0
- loop
- Result := item(i) = other.item(i);
- i := i - 1;
- end;
- end;
- end;
-
- index_of (ch: CHARACTER): INTEGER is
- -- Give the index of the first occurrence `ch'.
- -- Answer `count + 1' when `ch' is not inside.
- do
- from
- Result := 1;
- until
- (Result > count) or else (ch = item(Result))
- loop
- Result := Result + 1;
- end;
- ensure
- (Result /= count + 1) implies (item(Result) = ch);
- end;
-
- has(ch: CHARACTER): BOOLEAN is
- -- True if `ch' is in the STRING.
- do
- Result := index_of(ch) /= (count + 1);
- end;
-
- occurrences_of(c: CHARACTER): INTEGER is
- -- How many character `c' in the receiver.
- local
- i: INTEGER;
- do
- from
- i := count;
- until
- i = 0
- loop
- if c = item(i) then
- Result := Result + 1;
- end;
- i := i - 1;
- end;
- ensure
- Result >= 0
- end;
-
- has_suffix(s: STRING): BOOLEAN is
- -- True if suffix of Current is `s'.
- require
- s /= Void;
- local
- i1, i2: INTEGER;
- do
- if s.count <= count then
- from
- i1 := count - s.count + 1;
- i2 := 1;
- until
- i1 > count or else
- i2 > s.count or else
- item(i1) /= s.item(i2)
- loop
- i1 := i1 + 1;
- i2 := i2 + 1;
- end;
- Result := i1 > count;
- end;
- end;
-
- has_prefix(p: STRING): BOOLEAN is
- -- True if prefix of Current is `p'.
- require
- p /= Void;
- local
- i: INTEGER;
- do
- if p.count <= count then
- from
- i := p.count;
- until
- i = 0 or else item(i) /= p.item(i)
- loop
- i := i - 1;
- end;
- Result := i = 0;
- end;
- end;
-
- feature {ANY} -- Modification :
-
- clear is
- -- Clear out the current STRING.
- -- Note : internal `storage' memory not released.
- do
- count := 0;
- ensure
- count = 0;
- end;
-
- copy(other: STRING) is
- -- Copy `other' onto Current.
- local
- i: INTEGER;
- do
- i := other.count;
- count := i;
- if i > 0 then
- if capacity < i then
- if capacity = 0 then
- c_inline_c("C->_storage=(char *)%
- %malloc((size_t)_i);");
- else
- c_inline_c("C->_storage=(char *)%
- %realloc(C->_storage,(size_t)_i);");
- end;
- capacity := i;
- end;
- from
- until
- i = 0
- loop
- put(other.item(i),i);
- i := i - 1;
- end;
- end;
- ensure then
- count = other.count
- end;
-
- fill_with(c: CHARACTER) is
- -- Fill entire string with character `c'
- local
- i: INTEGER;
- do
- from
- i := count
- until
- i = 0
- loop
- put(c,i);
- i := i - 1;
- end;
- end;
-
- append(other: STRING) is
- -- Append `other' to Current.
- require
- other /= Void
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- i > other.count
- loop
- extend(other @ i);
- i := i + 1;
- end;
- end;
-
- prepend(other: STRING) is
- -- Prepend `other' to Current
- require
- other /= Void
- local
- i, old_count: INTEGER;
- do
- old_count := count;
- from
- i := other.count;
- until
- i = 0
- loop
- extend(' ');
- i := i - 1;
- end;
- from
- i := count;
- until
- old_count = 0
- loop
- put(item(old_count),i);
- i := i - 1;
- old_count := old_count - 1;
- end;
- from
- i := other.count
- until
- i = 0
- loop
- put(other @ i,i);
- i := i - 1;
- end;
- ensure
- count = other.count + old count
- end;
-
- put(ch: CHARACTER; index: INTEGER) is
- -- Put `ch' at position `index'.
- require
- valid_index(index)
- do
- c_inline_c("(C->_storage)[a2-1]=a1;");
- ensure
- item (index) = ch
- end;
-
- swap(i1, i2: INTEGER) is
- require
- valid_index(i1);
- valid_index(i2)
- local
- tmp: CHARACTER;
- do
- tmp := item(i1);
- put(item(i2),i1);
- put(tmp,i2);
- ensure
- item(i1) = old item(i2);
- item(i2) = old item(i1);
- end;
-
- insert(ch: CHARACTER; index: INTEGER) is
- -- Insert `ch' after position `index'.
- require
- 0 <= index and index <= count;
- local
- i: INTEGER;
- do
- from
- i := count;
- extend(' ');
- until
- i = index
- loop
- put(item(i),i + 1);
- i := i - 1;
- end;
- put(ch,index + 1);
- ensure
- item (index + 1) = ch
- end;
-
- shrink(low, up: INTEGER) is
- -- Keep only the slice `low' .. `up' or nothing
- -- when the slice is empty.
- require
- 1 <= low;
- low <= count;
- 1 <= up;
- up <= count;
- local
- i, i2: INTEGER;
- do
- if up < low then
- clear;
- elseif low = 1 then
- count := up;
- else
- from
- i := 1;
- i2 := low;
- until
- i2 > up
- loop
- put(item(i2),i);
- i := i + 1;
- i2 := i2 + 1;
- end;
- count := i - 1;
- end;
- ensure
- up > low implies count = up - low + 1;
- end;
-
- remove(index: INTEGER) is
- -- Remove character at position `index'.
- require
- valid_index(index)
- do
- remove_between(index,index);
- ensure
- count = (old count) - 1
- end;
-
- add_first(ch: CHARACTER) is
- -- Add `ch' at first position.
- local
- i: INTEGER;
- do
- from
- extend(' ');
- i := count;
- until
- i = 1
- loop
- put(item(i - 1),i);
- i := i - 1;
- end;
- put(ch,1);
- ensure
- count = 1 + old count;
- item(1) = ch
- end;
-
- add_last, extend(ch: CHARACTER) is
- -- Append `ch' to string
- do
- count := count + 1;
- if capacity < count then
- if capacity = 0 then
- capacity := 16;
- c_inline_c("C->_storage=(char *)%
- %malloc((size_t)C->_capacity);");
- else
- capacity := capacity + 16;
- c_inline_c("C->_storage=(char *)realloc(%
- %C->_storage,(size_t)C->_capacity);");
- end;
- end;
- put(ch,count);
- ensure
- count = 1 + old count;
- item (count) = ch;
- end;
-
- precede(ch: CHARACTER) is
- -- Prepend `ch' to string
- local
- i: INTEGER;
- do
- from
- extend(' ');
- i := count;
- until
- i = 1
- loop
- put(item(i-1),i);
- i := i - 1;
- end;
- put(ch,1);
- ensure
- item (1) = ch
- end;
-
- to_lower is
- -- Convert all characters to lower case.
- local
- i: INTEGER;
- do
- from
- i := count;
- until
- i = 0
- loop
- put(item(i).to_lower,i);
- i := i - 1;
- end;
- end;
-
- to_upper is
- -- Convert all characters to upper case.
- local
- i: INTEGER;
- do
- from
- i := count;
- until
- i = 0
- loop
- put(item(i).to_upper,i);
- i := i - 1;
- end;
- end;
-
- remove_first(nb: INTEGER) is
- -- Remove `nb' first characters.
- require
- nb >= 0;
- count >= nb;
- do
- if nb > 0 then
- remove_between(1, nb)
- end;
- ensure
- count = (old count) - nb
- end;
-
- remove_last(nb: INTEGER) is
- -- Remove `nb' last characters.
- require
- 0 <= nb;
- nb <= count;
- do
- count := count - nb;
- ensure
- count = old count - nb
- end;
-
- remove_between(low, up : INTEGER) is
- -- Remove character between positions `low' and `up'.
- require
- valid_index(low);
- valid_index(up);
- low <= up
- local
- i : INTEGER;
- do
- from
- i := up;
- until
- i >= count
- loop
- put(item(i + 1), low + i - up);
- i := i + 1;
- end;
- count := count - (up - low + 1);
- ensure
- count = (old count) - (up - low + 1)
- end;
-
- remove_suffix(s: STRING) is
- -- Remove the suffix `s' of current string.
- require
- has_suffix(s);
- do
- remove_last(s.count);
- ensure
- old count = count + s.count
- end;
-
- remove_prefix(s: STRING) is
- -- Remove the prefix `s' of current string.
- require
- has_prefix(s);
- do
- remove_first(s.count);
- ensure
- old count = count + s.count
- end;
-
- feature {ANY} -- Features which don't modify the string
-
- first: CHARACTER is
- require
- not empty;
- do
- Result := item(1);
- end;
-
- last: CHARACTER is
- require
- not empty;
- do
- Result := item(count);
- end;
-
- feature {ANY} -- Conversion :
-
- to_integer: INTEGER is
- -- Current must looks like an INTEGER.
- local
- i, state: INTEGER;
- cc: CHARACTER;
- minus: BOOLEAN;
- do
- -- state 0 : nothing read.
- -- state 1 : "+" or "-" read.
- -- state 2 : in the number.
- -- state 3 : after the number.
- -- state 4 : error.
- from
- i := 1;
- until
- i > count or else state = 4
- loop
- cc := item(i);
- inspect
- state
- when 0 then
- if cc.is_separator then
- elseif cc = '+' then
- state := 1;
- elseif cc = '-' then
- minus := true;
- state := 1;
- elseif cc.is_digit then
- Result := cc.value;
- state := 2;
- else
- state := 4;
- end;
- when 1 then
- if cc.is_separator then
- elseif cc.is_digit then
- Result := cc.value;
- state := 2;
- else
- state := 4;
- end;
- when 2 then
- if cc.is_digit then
- Result := (Result * 10) + cc.value;
- elseif cc.is_separator then
- state := 3;
- else
- state := 4;
- end;
- else -- state = 3
- if cc.is_separator then
- else
- state := 4;
- end;
- end;
- i := i + 1;
- end;
- if state = 4 then
- std_error.put_string("STRING.to_integer: %"");
- std_error.put_string(Current);
- std_error.put_string("%" is not an INTEGER.%N");
- elseif minus then
- Result := - Result;
- end;
- end;
-
- to_real: REAL is
- -- Conversion to the corresponding REAL value.
- -- The string must looks like a REAL (or like an
- -- INTEGER because fractionnal part is optional).
- do
- Result := to_double.to_real;
- end;
-
- to_double: DOUBLE is
- -- Conversion to the corresponding DOUBLE value.
- -- The string must looks like a DOUBLE, like
- -- a REAL (or like an INTEGER because fractionnal
- -- part is optional).
- require
- count >= 1;
- local
- i, j, integral_part, state: INTEGER;
- cc: CHARACTER;
- minus: BOOLEAN;
- do
- -- state 0 : nothing read.
- -- state 1 : "+" or "-" read.
- -- state 2 : in the `integral_part'.
- -- state 3 : in the fractionnal part.
- -- state 4 : after the fractionnal part.
- -- state 5 : error.
- from
- i := 1;
- until
- i > count or else state > 2
- loop
- cc := item(i);
- inspect
- state
- when 0 then
- if cc.is_separator then
- elseif cc = '+' then
- state := 1;
- elseif cc = '-' then
- minus := true;
- state := 1;
- elseif cc.is_digit then
- integral_part := cc.value;
- state := 2;
- elseif cc = '.' then
- state := 4;
- else
- state := 5;
- end;
- when 1 then
- if cc.is_separator then
- elseif cc.is_digit then
- integral_part := cc.value;
- state := 2;
- else
- state := 5;
- end;
- else -- state = 2
- if cc.is_digit then
- integral_part := (integral_part * 10) + cc.value;
- elseif cc.is_separator then
- state := 4;
- elseif cc ='.' then
- state := 4;
- else
- state := 5;
- end;
- end;
- i := i + 1;
- end;
- from
- j := count;
- invariant
- Result < 1;
- until
- j < i or else state > 4
- loop
- cc := item(j);
- inspect
- state
- when 3 then
- if cc.is_digit then
- Result := (Result + cc.value) / 10;
- else
- state := 5;
- end;
- else -- state = 4
- if cc.is_separator then
- elseif cc.is_digit then
- Result := cc.value.to_real / 10;
- state := 3;
- else
- state := 5;
- end;
- end;
- j := j - 1;
- end;
- if state >= 5 then
- std_error.put_string("STRING.to_real: %"");
- std_error.put_string(Current);
- std_error.put_string("%" is not a REAL.%N");
- elseif minus then
- Result := -(Result + integral_part);
- else
- Result := Result + integral_part;
- end;
- end;
-
- feature {ANY} -- Printing :
-
- print_on(file: STD_FILE_WRITE) is
- local
- i: INTEGER;
- do
- file.put_character('%"');
- from
- i := 1;
- until
- i > count
- loop
- file.put_character(item(i));
- i := i +1;
- end;
- file.put_character('%"');
- end;
-
- feature {ANY} -- Other features :
-
- substring(low, up: INTEGER): STRING is
- -- Create a new string initialized with range `low'.. `up'.
- require
- 1 <= low;
- low <= up;
- up <= count;
- local
- i: INTEGER;
- do
- from
- !!Result.make(up - low + 1);
- i := low;
- until
- i > up
- loop
- Result.extend(item(i));
- i := i + 1;
- end;
- end;
-
- reverse is
- -- Reverse the string.
- local
- i1, i2: INTEGER;
- do
- from
- i1 := 1;
- i2 := count;
- until
- i1 >= i2
- loop
- swap(i1,i2);
- i1 := i1 + 1;
- i2 := i2 - 1;
- end;
- end;
-
- remove_all_occurrences(ch: CHARACTER) is
- -- Remove all occurrences of `ch'.
- local
- i, j: INTEGER;
- do
- from
- i := 1;
- j := 1;
- until
- i > count
- loop
- if item(i) /= ch then
- put(item(i),j);
- j := j + 1;
- end;
- i := i + 1;
- end;
- count := j - 1;
- ensure
- count = old count - old occurrences_of(ch)
- end;
-
- split: ARRAY[STRING] is
- -- Split the string into an array of words.
- -- Uses `is_separator' of CHARACTER to find words.
- -- Gives Void or a not empty array.
- local
- state, i: INTEGER;
- -- state = 0 : waiting next word.
- -- state = 1 : inside a new word.
- c: CHARACTER;
- do
- if count > 0 then
- from
- i := 1;
- until
- i > count
- loop
- c := item(i);
- if state = 0 then
- if not c.is_separator then
- tmp_string.clear;
- tmp_string.extend(c);
- state := 1;
- end;
- else
- if not c.is_separator then
- tmp_string.extend(c);
- end;
- if c.is_separator or else i = count then
- if Result = Void then
- Result := <<clone(tmp_string)>>;
- else
- Result.add_last(clone(tmp_string));
- end;
- state := 0;
- end;
- end;
- i := i + 1;
- end;
- end;
- ensure
- Result /= Void implies not Result.empty;
- end;
-
- to_external: POINTER is
- -- Gives address of a copy of the contents of the string
- -- adding null character at end (for C use).
- -- NOTE: do a malloc(`count' + 1), thus it is not an access
- -- to `storage'.
- do
- c_inline_c("R=(char *)malloc((C->_count)+1);%N%
- %memcpy(R,C->_storage,C->_count);%N%
- %((char *)R)[C->_count]='\0';");
- end;
-
- feature {NONE}
-
- tmp_string: STRING is "ABCDEFGHIJKLMN...";
-
- invariant
-
- 0 <= count;
-
- 0 <= capacity;
-
- count <= capacity;
-
- end -- class STRING
-
-