home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / eiffel / smalleif.97 / se.t / SmallEiffel / lib_std / string.e < prev   
Encoding:
Text File  |  1996-05-02  |  18.1 KB  |  981 lines

  1. -- Part of SmallEiffel -- Read DISCLAIMER file -- Copyright (C) 
  2. -- Dominique COLNET and Suzanne COLLIN -- colnet@loria.fr
  3. --
  4. class STRING
  5. --
  6. -- Characters strings. 
  7. --
  8.  
  9. inherit
  10.    COMPARABLE 
  11.       redefine 
  12.      hash_code, is_equal, infix "<", compare, copy,
  13.      print_on
  14.       end;
  15.    
  16. creation {ANY}
  17.    make, copy, blank
  18.  
  19. feature {NONE}
  20.    
  21.    storage: POINTER;
  22.      -- The place where characters are stored.
  23.    
  24. feature {ANY}
  25.    
  26.    count: INTEGER;
  27.      -- String length.
  28.    
  29.    capacity: INTEGER;
  30.      -- Capacity of the `storage'.
  31.    
  32. feature {ANY} -- Creation / Modification :
  33.    
  34.    make(needed_capacity: INTEGER) is
  35.      -- Initialize the string to have at least a `needed_capacity'
  36.      -- space of storage.
  37.       require
  38.      needed_capacity >= 0;
  39.       do
  40.      count := 0;
  41.      if needed_capacity > 0 then
  42.         if capacity < needed_capacity then
  43.            if capacity = 0 then
  44.           c_inline_c("C->_storage=(char *)%
  45.                   %malloc((size_t)a1);");
  46.            else
  47.           c_inline_c("C->_storage=(char *)%
  48.                  %realloc(C->_storage,(size_t)a1);");
  49.            end;
  50.            capacity := needed_capacity;
  51.         end;
  52.      end;
  53.       ensure
  54.      needed_capacity <= capacity;
  55.      count = 0
  56.       end;
  57.  
  58.    blank(nr_blanks: INTEGER) is
  59.      -- Initialize string with `nr_blanks' blanks.
  60.       require
  61.      nr_blanks >= 0;
  62.       do
  63.      make(nr_blanks);
  64.      count := nr_blanks;
  65.      fill_with(' ');
  66.       ensure
  67.      count = nr_blanks;
  68.      occurrences_of(' ') = count
  69.       end;
  70.  
  71. feature {ANY} -- No Modification of the receiver :
  72.    
  73.    empty: BOOLEAN is
  74.      -- Has string length 0?
  75.       do
  76.      Result := (count = 0)
  77.       end;
  78.  
  79.    infix "@", item(index: INTEGER): CHARACTER is
  80.      -- Character at position `index'.
  81.       require
  82.      valid_index(index)
  83.       do
  84.      c_inline_c("R=(C->_storage)[a1-1];");
  85.       end;
  86.  
  87.    valid_index(index: INTEGER): BOOLEAN is
  88.      -- True when `index' is valid (ie inside actual bounds).
  89.       do
  90.      Result := 1 <= index and then index <= count;
  91.       ensure      
  92.      Result = (1 <= index and index <= count)
  93.       end;
  94.    
  95.    hash_code: INTEGER is
  96.       local
  97.      i: INTEGER;
  98.       do
  99.      from  
  100.         i := count;
  101.         if i > 5 then
  102.            i := 5;
  103.         end;
  104.      until
  105.         i = 0
  106.      loop
  107.         Result := Result + item(i).code;
  108.         i := i - 1;
  109.      end;
  110.       end;
  111.  
  112.    infix "<" (other: STRING): BOOLEAN is
  113.      -- Is Current less than `other' ?
  114.       local
  115.      i: INTEGER;
  116.       do
  117.      from  
  118.         i := 1;
  119.      until
  120.         count < i or else other.count < i 
  121.         or else item(i) /= other.item(i)
  122.      loop
  123.         i := i + 1;
  124.      end;
  125.      if count < i then
  126.         Result := other.count >= i;
  127.      elseif other.count < i then
  128.         Result := false;
  129.      else
  130.         Result := item(i) < other.item(i);
  131.      end;
  132.       end;
  133.  
  134.    compare(other: STRING): INTEGER is
  135.       local
  136.      i: INTEGER;
  137.       do
  138.      from  
  139.         i := 1;
  140.      until
  141.         count < i or else other.count < i 
  142.         or else item(i) /= other.item(i)
  143.      loop
  144.         i := i + 1;
  145.      end;
  146.      if count < i then
  147.         if other.count < i then
  148.            Result := 0;
  149.         else
  150.            Result := -1;
  151.         end;
  152.      elseif other.count < i then
  153.         Result := +1;
  154.      elseif item(i) < other.item(i) then
  155.         Result := -1;
  156.      else
  157.         Result := +1;
  158.      end;
  159.       end;
  160.     
  161.    same_as(other: STRING): BOOLEAN is
  162.      -- No difference is done between upper and lower case.
  163.       local
  164.      i: INTEGER;
  165.       do
  166.      if other = Current then
  167.         Result := true;
  168.      else     
  169.         if other.count /= count then
  170.            Result := false;
  171.         else
  172.            from  
  173.           i := count;
  174.            until
  175.           (i = 0) or else (not item(i).same_as(other @ i))
  176.            loop
  177.           i := i - 1;
  178.            end;
  179.            Result := (i = 0);
  180.         end;
  181.      end;
  182.       end;
  183.    
  184.    is_equal(other: STRING): BOOLEAN is
  185.      -- Has Current the same text as `other'?
  186.       require else
  187.      true
  188.       local
  189.      i: INTEGER;
  190.       do
  191.      if Current = other then
  192.         Result := true;
  193.      else
  194.         from
  195.            i := count;
  196.            Result := (i = other.count);
  197.         until
  198.            not Result or i = 0
  199.         loop
  200.            Result := item(i) = other.item(i);
  201.            i := i - 1;
  202.         end;
  203.      end;
  204.       end;
  205.    
  206.    index_of (ch: CHARACTER): INTEGER is
  207.      -- Give the index of the first occurrence `ch'.
  208.      -- Answer `count + 1' when `ch' is not inside.
  209.       do
  210.      from  
  211.         Result := 1;
  212.      until
  213.         (Result > count) or else (ch = item(Result))
  214.      loop
  215.         Result := Result + 1;
  216.      end;
  217.       ensure
  218.      (Result /= count + 1) implies (item(Result) = ch);
  219.       end;
  220.    
  221.    has(ch: CHARACTER): BOOLEAN is
  222.      -- True if `ch' is in the STRING.
  223.       do
  224.      Result := index_of(ch) /= (count + 1);
  225.       end;
  226.    
  227.    occurrences_of(c: CHARACTER): INTEGER is
  228.      -- How many character `c' in the receiver.
  229.       local
  230.      i: INTEGER;
  231.       do
  232.      from  
  233.         i := count;
  234.      until
  235.         i = 0
  236.      loop
  237.         if c = item(i) then
  238.            Result := Result + 1;
  239.         end;
  240.         i := i - 1;
  241.      end;
  242.       ensure
  243.      Result >= 0
  244.       end;
  245.    
  246.    has_suffix(s: STRING): BOOLEAN is
  247.      -- True if suffix of Current is `s'.
  248.       require
  249.      s /= Void;
  250.       local
  251.      i1, i2: INTEGER;
  252.       do
  253.      if s.count <= count then
  254.         from  
  255.            i1 := count - s.count + 1;
  256.            i2 := 1;
  257.         until
  258.            i1 > count or else
  259.            i2 > s.count or else
  260.            item(i1) /= s.item(i2)
  261.         loop
  262.            i1 := i1 + 1;
  263.            i2 := i2 + 1;
  264.         end;
  265.         Result := i1 > count; 
  266.      end;
  267.       end;
  268.    
  269.    has_prefix(p: STRING): BOOLEAN is
  270.      -- True if prefix of Current is `p'.
  271.       require
  272.      p /= Void;
  273.       local
  274.      i: INTEGER;
  275.       do
  276.      if p.count <= count then
  277.         from  
  278.            i := p.count;
  279.         until
  280.            i = 0 or else item(i) /= p.item(i)
  281.         loop
  282.            i := i - 1;
  283.         end;
  284.         Result := i = 0; 
  285.      end;
  286.       end;
  287.    
  288. feature {ANY} -- Modification :
  289.    
  290.    clear is
  291.      -- Clear out the current STRING.
  292.      -- Note : internal `storage' memory not released.
  293.       do
  294.      count := 0;
  295.       ensure
  296.      count = 0;
  297.       end;
  298.    
  299.    copy(other: STRING) is
  300.      -- Copy `other' onto Current.
  301.       local
  302.      i: INTEGER;
  303.       do
  304.      i := other.count;
  305.      count := i;
  306.      if i > 0 then
  307.         if capacity < i then
  308.            if capacity = 0 then
  309.           c_inline_c("C->_storage=(char *)%
  310.                  %malloc((size_t)_i);");
  311.            else
  312.           c_inline_c("C->_storage=(char *)%
  313.                  %realloc(C->_storage,(size_t)_i);");
  314.            end;
  315.            capacity := i;
  316.         end;
  317.         from
  318.         until
  319.            i = 0
  320.         loop
  321.            put(other.item(i),i);
  322.            i := i - 1;
  323.         end;
  324.      end;
  325.       ensure then
  326.      count = other.count
  327.       end;
  328.  
  329.    fill_with(c: CHARACTER) is
  330.      -- Fill entire string with character `c'
  331.       local
  332.      i: INTEGER;
  333.       do
  334.      from  
  335.         i := count
  336.      until
  337.         i = 0
  338.      loop
  339.         put(c,i);
  340.         i := i - 1;
  341.      end;
  342.       end;
  343.    
  344.    append(other: STRING) is
  345.      -- Append `other' to Current.
  346.       require
  347.      other /= Void
  348.       local
  349.      i: INTEGER;
  350.       do
  351.      from  
  352.         i := 1;
  353.      until
  354.         i > other.count
  355.      loop
  356.         extend(other @ i);
  357.         i := i + 1;
  358.      end;
  359.       end;
  360.    
  361.    prepend(other: STRING) is
  362.      -- Prepend `other' to Current
  363.       require
  364.      other /= Void
  365.       local
  366.      i, old_count: INTEGER;
  367.       do
  368.      old_count := count;
  369.      from  
  370.         i := other.count;
  371.      until
  372.         i = 0
  373.      loop
  374.         extend(' ');
  375.         i := i - 1;
  376.      end;
  377.      from  
  378.         i := count;
  379.      until
  380.         old_count = 0
  381.      loop
  382.         put(item(old_count),i);
  383.         i := i - 1;
  384.         old_count := old_count - 1;
  385.      end;
  386.      from  
  387.         i := other.count
  388.      until
  389.         i = 0
  390.      loop
  391.         put(other @ i,i);
  392.         i := i - 1;
  393.      end;
  394.       ensure 
  395.      count = other.count + old count
  396.       end;
  397.    
  398.    put(ch: CHARACTER; index: INTEGER) is
  399.      -- Put `ch' at position `index'.
  400.       require
  401.      valid_index(index)
  402.       do
  403.      c_inline_c("(C->_storage)[a2-1]=a1;");
  404.       ensure
  405.      item (index) = ch
  406.       end;
  407.    
  408.    swap(i1, i2: INTEGER) is
  409.       require
  410.      valid_index(i1);
  411.      valid_index(i2)
  412.       local
  413.      tmp: CHARACTER;
  414.       do
  415.      tmp := item(i1);
  416.      put(item(i2),i1);
  417.      put(tmp,i2);
  418.       ensure
  419.      item(i1) = old item(i2);
  420.      item(i2) = old item(i1);
  421.       end;
  422.    
  423.    insert(ch: CHARACTER; index: INTEGER) is
  424.      -- Insert `ch' after position `index'.
  425.       require
  426.      0 <= index and index <= count;
  427.       local
  428.      i: INTEGER;
  429.       do
  430.      from  
  431.         i := count;
  432.         extend(' ');
  433.      until
  434.         i = index
  435.      loop
  436.         put(item(i),i + 1);
  437.         i := i - 1;
  438.      end;
  439.      put(ch,index + 1);
  440.       ensure
  441.      item (index + 1) = ch
  442.       end;
  443.  
  444.    shrink(low, up: INTEGER) is
  445.      -- Keep only the slice `low' .. `up' or nothing
  446.      -- when the slice is empty.
  447.       require
  448.      1 <= low;
  449.      low <= count;
  450.      1 <= up;
  451.      up <= count;
  452.       local
  453.      i, i2: INTEGER;
  454.       do
  455.      if up < low then
  456.         clear;
  457.      elseif low = 1 then
  458.         count := up;
  459.      else
  460.         from  
  461.            i := 1;
  462.            i2 := low;
  463.         until
  464.            i2 > up
  465.         loop
  466.            put(item(i2),i);
  467.            i := i + 1;
  468.            i2 := i2 + 1;
  469.         end;
  470.         count := i - 1;
  471.      end;
  472.       ensure
  473.      up > low implies count = up - low + 1;
  474.       end;
  475.    
  476.    remove(index: INTEGER) is
  477.      -- Remove character at position `index'.
  478.       require
  479.      valid_index(index)
  480.       do
  481.      remove_between(index,index);
  482.       ensure
  483.      count = (old count) - 1
  484.       end;
  485.  
  486.    add_first(ch: CHARACTER) is
  487.      -- Add `ch' at first position.
  488.       local
  489.      i: INTEGER;
  490.       do
  491.      from  
  492.         extend(' ');
  493.         i := count;
  494.      until
  495.         i = 1
  496.      loop
  497.         put(item(i - 1),i);
  498.         i := i - 1;
  499.      end;
  500.      put(ch,1);
  501.       ensure
  502.      count = 1 + old count;
  503.      item(1) = ch
  504.       end;
  505.  
  506.    add_last, extend(ch: CHARACTER) is
  507.      -- Append `ch' to string
  508.       do
  509.      count := count + 1;
  510.      if capacity < count then
  511.         if capacity = 0 then
  512.            capacity := 16;
  513.            c_inline_c("C->_storage=(char *)%
  514.                %malloc((size_t)C->_capacity);");
  515.         else
  516.            capacity := capacity + 16;
  517.            c_inline_c("C->_storage=(char *)realloc(%
  518.               %C->_storage,(size_t)C->_capacity);");
  519.         end;
  520.      end;
  521.      put(ch,count);
  522.       ensure
  523.      count = 1 + old count;
  524.      item (count) = ch;
  525.       end;
  526.  
  527.    precede(ch: CHARACTER) is
  528.      -- Prepend `ch' to string
  529.       local
  530.      i: INTEGER;
  531.       do
  532.      from  
  533.         extend(' ');
  534.         i := count;
  535.      until
  536.         i = 1
  537.      loop
  538.         put(item(i-1),i);
  539.         i := i - 1;
  540.      end;
  541.      put(ch,1);
  542.       ensure
  543.      item (1) = ch
  544.       end;
  545.     
  546.    to_lower is
  547.      -- Convert all characters to lower case.
  548.       local
  549.      i: INTEGER;
  550.       do
  551.      from  
  552.         i := count;
  553.      until
  554.         i = 0
  555.      loop
  556.         put(item(i).to_lower,i);
  557.         i := i - 1;
  558.      end;
  559.       end;
  560.    
  561.    to_upper is
  562.      -- Convert all characters to upper case.
  563.       local
  564.      i: INTEGER;
  565.       do
  566.      from  
  567.         i := count;
  568.      until
  569.         i = 0
  570.      loop
  571.         put(item(i).to_upper,i);
  572.         i := i - 1;
  573.      end;
  574.       end;
  575.     
  576.    remove_first(nb: INTEGER) is
  577.      -- Remove `nb' first characters.
  578.       require
  579.      nb >= 0; 
  580.      count >= nb;
  581.       do
  582.      if nb > 0 then
  583.         remove_between(1, nb)
  584.      end;
  585.       ensure
  586.      count = (old count) - nb
  587.       end; 
  588.    
  589.    remove_last(nb: INTEGER) is
  590.      -- Remove `nb' last characters.
  591.       require
  592.      0 <= nb;
  593.      nb <= count;
  594.       do
  595.      count := count - nb;
  596.       ensure
  597.      count = old count - nb
  598.       end; 
  599.    
  600.    remove_between(low, up : INTEGER) is
  601.      -- Remove character between positions `low' and `up'.
  602.       require
  603.      valid_index(low);
  604.      valid_index(up);
  605.      low <= up
  606.       local
  607.      i : INTEGER;
  608.       do
  609.      from  
  610.         i := up;
  611.      until
  612.         i >= count
  613.      loop
  614.         put(item(i + 1), low + i - up);
  615.         i := i + 1;
  616.      end;
  617.      count := count - (up - low + 1);
  618.       ensure
  619.      count = (old count) - (up - low + 1)
  620.       end;
  621.  
  622.    remove_suffix(s: STRING) is
  623.       -- Remove the suffix `s' of current string.
  624.       require
  625.      has_suffix(s);
  626.       do
  627.      remove_last(s.count);
  628.       ensure
  629.      old count = count + s.count
  630.       end;
  631.  
  632.    remove_prefix(s: STRING) is
  633.       -- Remove the prefix `s' of current string.
  634.       require
  635.      has_prefix(s);
  636.       do
  637.      remove_first(s.count);
  638.       ensure
  639.      old count = count + s.count
  640.       end;
  641.  
  642. feature {ANY}   -- Features which don't modify the string
  643.  
  644.    first: CHARACTER is
  645.       require
  646.      not empty;
  647.       do
  648.      Result := item(1);
  649.       end;
  650.  
  651.    last: CHARACTER is
  652.       require
  653.      not empty;
  654.       do
  655.      Result := item(count);
  656.       end;
  657.  
  658. feature {ANY} -- Conversion :
  659.  
  660.    to_integer: INTEGER is
  661.      -- Current must looks like an INTEGER.
  662.       local
  663.      i, state: INTEGER;
  664.      cc: CHARACTER;
  665.      minus: BOOLEAN;
  666.       do
  667.      -- state 0 : nothing read.
  668.      -- state 1 : "+" or "-" read.
  669.      -- state 2 : in the number.
  670.      -- state 3 : after the number.
  671.      -- state 4 : error.
  672.      from
  673.         i := 1;
  674.      until
  675.         i > count or else state = 4
  676.      loop
  677.         cc := item(i);
  678.         inspect 
  679.            state
  680.         when 0 then
  681.            if cc.is_separator then
  682.            elseif cc = '+' then
  683.           state := 1;
  684.            elseif cc = '-' then
  685.           minus := true;
  686.           state := 1;
  687.            elseif cc.is_digit then
  688.           Result := cc.value;
  689.           state := 2;
  690.            else
  691.           state := 4;
  692.            end;
  693.         when 1 then
  694.            if cc.is_separator then
  695.            elseif cc.is_digit then
  696.           Result := cc.value;
  697.           state := 2;
  698.            else
  699.           state := 4;
  700.            end;
  701.         when 2 then
  702.            if cc.is_digit then
  703.           Result := (Result * 10) + cc.value;
  704.            elseif cc.is_separator then
  705.           state := 3;
  706.            else
  707.           state := 4;
  708.            end;
  709.         else -- state = 3
  710.            if cc.is_separator then
  711.            else 
  712.           state := 4;
  713.            end;
  714.         end;
  715.         i := i + 1;
  716.      end;
  717.      if state = 4 then
  718.         std_error.put_string("STRING.to_integer: %"");
  719.         std_error.put_string(Current);
  720.         std_error.put_string("%" is not an INTEGER.%N");
  721.      elseif minus then
  722.         Result := - Result;
  723.      end;
  724.       end; 
  725.    
  726.    to_real: REAL is
  727.      -- Conversion to the corresponding REAL value. 
  728.      -- The string must looks like a REAL (or like an 
  729.      -- INTEGER because fractionnal part is optional).
  730.       do
  731.      Result := to_double.to_real;
  732.       end;
  733.    
  734.    to_double: DOUBLE is
  735.      -- Conversion to the corresponding DOUBLE value. 
  736.      -- The string must looks like a DOUBLE, like 
  737.      -- a REAL (or like an INTEGER because fractionnal 
  738.      -- part is optional).
  739.       require
  740.      count >= 1;
  741.       local
  742.      i, j, integral_part, state: INTEGER;
  743.      cc: CHARACTER;
  744.      minus: BOOLEAN;
  745.       do
  746.      -- state 0 : nothing read.
  747.      -- state 1 : "+" or "-" read.
  748.      -- state 2 : in the `integral_part'.
  749.      -- state 3 : in the fractionnal part.
  750.      -- state 4 : after the fractionnal part.
  751.      -- state 5 : error.
  752.      from
  753.         i := 1;
  754.      until
  755.         i > count or else state > 2
  756.      loop
  757.         cc := item(i);
  758.         inspect 
  759.            state
  760.         when 0 then
  761.            if cc.is_separator then
  762.            elseif cc = '+' then
  763.           state := 1;
  764.            elseif cc = '-' then
  765.           minus := true;
  766.           state := 1;
  767.            elseif cc.is_digit then
  768.           integral_part := cc.value;
  769.           state := 2;
  770.            elseif cc = '.' then
  771.           state := 4;
  772.            else
  773.           state := 5;
  774.            end;
  775.         when 1 then
  776.            if cc.is_separator then
  777.            elseif cc.is_digit then
  778.           integral_part := cc.value;
  779.           state := 2;
  780.            else
  781.           state := 5;
  782.            end;
  783.         else -- state = 2 
  784.            if cc.is_digit then
  785.           integral_part := (integral_part * 10) + cc.value;
  786.            elseif cc.is_separator then
  787.           state := 4;
  788.            elseif cc ='.' then
  789.           state := 4;
  790.            else
  791.           state := 5;
  792.            end;
  793.         end;
  794.         i := i + 1;
  795.      end;
  796.      from  
  797.         j := count;
  798.      invariant
  799.         Result < 1;
  800.      until
  801.         j < i or else state > 4
  802.      loop
  803.         cc := item(j);
  804.         inspect 
  805.            state
  806.         when 3 then
  807.            if cc.is_digit then
  808.           Result := (Result + cc.value) / 10;
  809.            else
  810.           state := 5;
  811.            end;
  812.         else -- state = 4
  813.            if cc.is_separator then
  814.            elseif cc.is_digit then
  815.           Result := cc.value.to_real / 10;
  816.           state := 3;
  817.            else
  818.           state := 5;
  819.            end;
  820.         end;
  821.         j := j - 1;
  822.      end;
  823.      if state >= 5 then
  824.         std_error.put_string("STRING.to_real: %"");
  825.         std_error.put_string(Current);
  826.         std_error.put_string("%" is not a REAL.%N");
  827.      elseif minus then
  828.         Result := -(Result + integral_part);
  829.      else
  830.         Result := Result + integral_part;
  831.      end;
  832.       end; 
  833.  
  834. feature {ANY} -- Printing :
  835.    
  836.    print_on(file: STD_FILE_WRITE) is
  837.       local
  838.      i: INTEGER;
  839.       do
  840.      file.put_character('%"');
  841.      from  
  842.         i := 1;
  843.      until
  844.         i > count
  845.      loop
  846.         file.put_character(item(i));
  847.         i := i +1;
  848.      end;
  849.      file.put_character('%"');
  850.       end;
  851.    
  852. feature {ANY} -- Other features :
  853.    
  854.    substring(low, up: INTEGER): STRING is
  855.      -- Create a new string initialized with range `low'.. `up'.  
  856.       require
  857.      1 <= low;
  858.      low <= up; 
  859.      up <= count;
  860.       local
  861.      i: INTEGER;
  862.       do
  863.      from  
  864.         !!Result.make(up - low + 1);
  865.         i := low;
  866.      until
  867.         i > up
  868.      loop
  869.         Result.extend(item(i));
  870.         i := i + 1;
  871.      end;
  872.       end;
  873.    
  874.    reverse is
  875.       -- Reverse the string.
  876.       local
  877.      i1, i2: INTEGER;
  878.       do
  879.      from  
  880.         i1 := 1;
  881.         i2 := count;
  882.      until
  883.         i1 >= i2
  884.      loop
  885.         swap(i1,i2);
  886.         i1 := i1 + 1;
  887.         i2 := i2 - 1;
  888.      end;
  889.       end;
  890.    
  891.    remove_all_occurrences(ch: CHARACTER) is
  892.      -- Remove all occurrences of `ch'.
  893.       local
  894.      i, j: INTEGER;
  895.       do
  896.      from  
  897.         i := 1;
  898.         j := 1;
  899.      until
  900.         i > count
  901.      loop
  902.         if item(i) /= ch then
  903.            put(item(i),j);
  904.            j := j + 1;
  905.         end;
  906.         i := i + 1;
  907.      end;
  908.      count := j - 1; 
  909.       ensure
  910.      count = old count - old occurrences_of(ch)
  911.       end;
  912.    
  913.    split: ARRAY[STRING] is
  914.      -- Split the string into an array of words.
  915.      -- Uses `is_separator' of CHARACTER to find words.
  916.      -- Gives Void or a not empty array.
  917.       local     
  918.      state, i: INTEGER;
  919.      -- state = 0 : waiting next word.
  920.      -- state = 1 : inside a new word.
  921.      c: CHARACTER;
  922.       do
  923.      if count > 0 then
  924.         from
  925.            i := 1;
  926.         until
  927.            i > count
  928.         loop
  929.            c := item(i);
  930.            if state = 0 then
  931.           if not c.is_separator then
  932.              tmp_string.clear;
  933.              tmp_string.extend(c);
  934.              state := 1;
  935.           end;
  936.            else
  937.           if not c.is_separator then
  938.              tmp_string.extend(c);
  939.           end;
  940.           if c.is_separator or else i = count then
  941.              if Result = Void then
  942.             Result := <<clone(tmp_string)>>;
  943.              else
  944.             Result.add_last(clone(tmp_string));
  945.              end;
  946.              state := 0;
  947.           end;
  948.            end;
  949.            i := i + 1;
  950.         end;
  951.      end;
  952.       ensure
  953.      Result /= Void implies not Result.empty;
  954.       end;
  955.    
  956.    to_external: POINTER is
  957.      -- Gives address of a copy of the contents of the string
  958.      -- adding null character at end (for C use). 
  959.      -- NOTE: do a malloc(`count' + 1), thus it is not an access 
  960.      -- to `storage'.
  961.       do
  962.      c_inline_c("R=(char *)malloc((C->_count)+1);%N%
  963.             %memcpy(R,C->_storage,C->_count);%N%
  964.             %((char *)R)[C->_count]='\0';");
  965.       end;
  966.    
  967. feature {NONE}
  968.    
  969.    tmp_string: STRING is "ABCDEFGHIJKLMN...";
  970.    
  971. invariant
  972.    
  973.    0 <= count;
  974.  
  975.    0 <= capacity;
  976.  
  977.    count <= capacity;
  978.    
  979. end -- class STRING
  980.  
  981.