-----------------------------------------------------------
--                   Eiffel/S libraries                  --
-----------------------------------------------------------
--               Copyright (C) 1991 - 1993               --
--                           by                          --
--                   SiG Computer GmbH                   --
--                  All rights reserved                  --
-----------------------------------------------------------
-- Release : 1.3 - October 1993                          --
-----------------------------------------------------------
-- Authors : Lambert Strether & Michael Schweitzer       --
-----------------------------------------------------------
  
class   STRING

inherit
    COMPARABLE
        redefine
            infix "<", compare
    end

    HASHABLE
        redefine
            hash_code
    end

    ANY
        redefine
            is_equal, copy
        select
            is_equal, copy
    end
-----------------------------------------------------------
creation {ANY}
    make, adapt
-----------------------------------------------------------
feature {ANY}   -- Features which modify the string
-----------------------------------------------------------

    make (nr_blanks : INTEGER)  is
                        -- Initialize string with `nr_blanks'
                        -- blanks
        require
            non_negative_size : nr_blanks >= 0
        do
            !!special.make (nr_blanks + 1)
            count := nr_blanks
            fill_with (' ')
        ensure
            filled_with_blanks : count = nr_blanks
                                 -- All characters are blanks.
        end
-----------------------------------------------------------

    adapt (s : STRING) is
                        -- Initialize Current's text from
                        -- string s.
        require
            good_string : s /= Void
        do
            !!special.make (0)
            special.copy (s.special)
            count  := s.count
            h_code := -1
        ensure
            same_text : -- The text of Current is the same as the text of 's'.
        end
-----------------------------------------------------------

    copy (other : STRING) is
                        -- Copy `other' onto Current including
                        -- `other''s character sequence.

        do
            if special = Void then
                !!special.make (0)
            end

            special.copy (other.special)
            count  := other.count
            h_code := -1
        end
-----------------------------------------------------------

    fill_with (c : CHARACTER) is
                        -- Fill entire string with character `c'
        require
            not_null_char : c /= '%U'
        do
            special.fill_with (c, count)
            h_code := -1
        ensure
            filled : -- All characters are equal to 'c'.
        end
-----------------------------------------------------------

    append (other : STRING) is
                        -- Append `other' to Current
        require
            argument_not_void : other /= Void

        local
            new_count : INTEGER
            new_spec  : ES3_SPEC [CHARACTER]
        do
            if other.count /= 0 then
                new_count := count + other.count
                !!new_spec.make (new_count + 1)

                if count /= 0 then
                    new_spec.puts (special.store, 0)
                end

                new_spec.puts (other.special.store, count)
                special := new_spec
                count   := new_count
                h_code  := -1
            end
        ensure
            appended : -- 'other' has been appended to Current.
        end
-----------------------------------------------------------

    prepend (other : STRING) is
                        -- Prepend `other' to Current
        require
            argument_not_void : other /= Void

        local
            new_count : INTEGER
            new_spec  : ES3_SPEC [CHARACTER]
        do
            if other.count /= 0 then
                new_count := count + other.count
                !!new_spec.make (new_count + 1)
                new_spec.puts (other.special.store, 0)

                if count /= 0 then
                    new_spec.puts (special.store, other.count)
                end
                special := new_spec
                count   := new_count
                h_code := -1
            end
        ensure
            prepended : -- 'other' has been prepended to Current.
        end
-----------------------------------------------------------

    put (ch : CHARACTER, index : INTEGER) is
                        -- Put `ch' at position `index'.

        require
            inside_bounds : 1 <= index and then index <= count
            not_null_char : ch /= '%U'
        local
            new : ES3_SPEC [CHARACTER]
        do
            if ch = '%U' then
                special.resize (index + 1)
                count := index
            end
            special.put (ch, index - 1)
            h_code := -1
        ensure
            in_place : item (index) = ch
        end
-----------------------------------------------------------

    insert (ch : CHARACTER, index : INTEGER) is
                        -- Insert `ch' AFTER position `index'.

        require
            valid_position : 0 <= index and then index <= count
        do
            special.resize (count + 2)
            special.move (index, count, 1)
            count := count + 1
            put (ch, index + 1)
        ensure
            inserted : item (index + 1) = ch
        end
-----------------------------------------------------------

    remove (index : INTEGER) is
                        -- Remove character at position `index'.

        require
            inside_bounds : 1 <= index and then index <= count
        do
            special.move (index, count, -1)
            special.resize (count)
            count  := count - 1
            h_code := -1
        ensure
            removed   : -- The character at position 'index' has been removed.
            shortened : count = (old count) - 1
        end
-----------------------------------------------------------

    extend (ch : CHARACTER) is
                        -- Append `ch' to string
        require
            not_null_char : ch /= '%U'
        do
            insert (ch, count)
        ensure
            extended : item (count) = ch
        end
-----------------------------------------------------------

    precede (ch : CHARACTER) is
                        -- Prepend `ch' to string
        require
            not_null_char : ch /= '%U'
        do
            insert (ch, 0)
        ensure
            preceded : item (1) = ch
        end
-----------------------------------------------------------

    to_upper is
                        -- Convert text to upper case
        do
            special.sv_lit
            rt_to_upper (special.store)
            h_code := -1
        ensure
            all_upper : -- The text is now in upper case.
        end
-----------------------------------------------------------

    to_lower is
                        -- Convert text to lower case
        do
            special.sv_lit
            rt_to_lower (special.store)
            h_code := -1
        ensure
            all_lower : -- The text is now in lower case.
        end
-----------------------------------------------------------
feature {ANY}   -- Features which don't modify the string
-----------------------------------------------------------

    count : INTEGER     -- String length

-----------------------------------------------------------

    empty : BOOLEAN is
                        -- Has string length 0?
        do
            Result := (count = 0)
        end
-----------------------------------------------------------

    hash_code : INTEGER is

        do
            if h_code = -1 then
                h_code := rt_hash (special.store)
            end

            Result := h_code
        end
-----------------------------------------------------------

    infix "<" (other : STRING) : BOOLEAN is
                        -- Is Current less than `other'?
        do
            Result := rt_less (special.store, other.special.store)
        end
-----------------------------------------------------------

    compare (other : STRING) : INTEGER is

        do
            Result := rt_compare (special.store, other.special.store)
        end
-----------------------------------------------------------

    is_equal (other : STRING) : BOOLEAN is
                        -- Has Current the same text as `other'?
        do
            Result := (count = other.count) and then
                      special.is_equal (other.special)
        end
-----------------------------------------------------------

    infix "@", item (index : INTEGER) : CHARACTER is
                        -- Character at position `index'.
        require
            inside_bounds : 1 <= index and then index <= count
        do
            Result := special.item (index - 1)
        end
-----------------------------------------------------------

    to_external : POINTER is

        do
            Result := special.store
        end
-----------------------------------------------------------
feature {ANY}   -- Other features
-----------------------------------------------------------

    substring (from_index, to_index : INTEGER) : STRING is
                        -- Create a string which contains exactly
                        -- the char's from `from_index' to `to_index'
                        -- of Current (inclusive).
        require
            sub_interval : 1          <= from_index and then
                           from_index <= to_index   and then
                           to_index   <= count

        do
            !!Result.make (to_index - from_index + 1)
            Result.special.puts (special.gets (from_index - 1, to_index - 1), 
                                                                            0)
        end
-----------------------------------------------------------
feature {NONE, STRING} 
-----------------------------------------------------------

    special : ES3_SPEC [CHARACTER]
    h_code  : INTEGER               -- Hash code.
-----------------------------------------------------------

    set_special (sp : ES3_SPEC [CHARACTER]) is

        require
            special_not_void : sp /= Void
        do
            special := sp
            count   := sp.count - 1
            h_code  := -1
        end
-----------------------------------------------------------

    rt_to_upper (sp : POINTER) is

        external "C" -- changed by x_c_cwc
        alias    "RTC2_to_upper"
        end
-----------------------------------------------------------

    rt_to_lower (sp : POINTER) is

        external "C" -- changed by x_c_cwc
        alias    "RTC2_to_lower"
        end
-----------------------------------------------------------

    rt_hash (sp : POINTER) : INTEGER is

        external "C" -- changed by x_c_cwc
        alias    "RTC2_hash"
        end
-----------------------------------------------------------

    rt_less (sp1, sp2 : POINTER) : BOOLEAN is

        external "C" -- changed by x_c_cwc
        alias    "RTC2_less"
        end
-----------------------------------------------------------

    rt_compare (sp1, sp2 : POINTER) : INTEGER is

        external "C" -- changed by x_c_cwc
        alias    "RTC2_compare"
        end
-----------------------------------------------------------

end -- class STRING

