home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / SmallEiffel 0.3.3 / SmallEiffel 68k / lib_std / string.e < prev   
Encoding:
Text File  |  1996-06-13  |  19.7 KB  |  1,049 lines  |  [TEXT/EDIT]

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