home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / lib_std / string.e < prev    next >
Text File  |  1999-06-05  |  39KB  |  1,524 lines

  1. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  2. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  3. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  4. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  5. -- this header is kept unaltered, and a notification of the changes is added.
  6. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  7. -- another product.
  8. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  9. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  10. --                       http://SmallEiffel.loria.fr
  11. --
  12. class STRING
  13.    --
  14.    -- Resizable character STRINGs. 
  15.    --
  16.    
  17. inherit
  18.    HASHABLE;
  19.    COMPARABLE 
  20.       redefine 
  21.          is_equal, compare, three_way_comparison, copy, 
  22.          out_in_tagged_out_memory, fill_tagged_out_memory
  23.       end;
  24.    
  25. creation make, copy, blank, from_external, from_external_copy,
  26.    make_from_string
  27.  
  28. feature {STRING}
  29.    
  30.    storage: NATIVE_ARRAY[CHARACTER];
  31.          -- The place where characters are stored.
  32.    
  33. feature 
  34.    
  35.    count: INTEGER;
  36.          -- String length.
  37.    
  38.    capacity: INTEGER;
  39.          -- Capacity of the `storage'.
  40.    
  41. feature -- Creation / Modification :
  42.    
  43.    make(needed_capacity: INTEGER) is
  44.          -- Initialize the string to have at least `needed_capacity'
  45.          -- characters of storage.
  46.       require
  47.           non_negative_size: needed_capacity >= 0;
  48.       do
  49.          if needed_capacity > 0 then
  50.             if capacity < needed_capacity then
  51.                storage := storage.calloc(needed_capacity);
  52.                capacity := needed_capacity;
  53.             end;
  54.          end;
  55.          count := 0;
  56.       ensure
  57.          needed_capacity <= capacity;
  58.          empty_string: count = 0
  59.       end;
  60.  
  61.    blank(nr_blanks: INTEGER) is
  62.          -- Initialize string with `nr_blanks' blanks.
  63.       require
  64.          nr_blanks >= 0;
  65.       do
  66.          make(nr_blanks);
  67.          count := nr_blanks;
  68.          fill_with(' ');
  69.       ensure
  70.          count = nr_blanks;
  71.          occurrences_of(' ') = count
  72.       end;
  73.  
  74. feature -- Testing :
  75.    
  76.    empty: BOOLEAN is
  77.          -- Has string length 0?
  78.       do
  79.          Result := (count = 0)
  80.       end;
  81.  
  82.    item, infix "@" (index: INTEGER): CHARACTER is
  83.          -- Character at position `index'.
  84.       require
  85.          valid_index(index)
  86.       do
  87.          Result := storage.item(index - 1);
  88.       end;
  89.  
  90.    valid_index(index: INTEGER): BOOLEAN is
  91.          -- True when `index' is valid (i.e., inside actual bounds).
  92.       do
  93.          Result := 1 <= index and then index <= count;
  94.       ensure
  95.          Result = (1 <= index and then index <= count)
  96.       end;
  97.    
  98.    hash_code: INTEGER is
  99.       local
  100.          i: INTEGER;
  101.       do
  102.          i := count;
  103.          if i > 5 then
  104.             Result := i * item(i).code;
  105.             i := 5;
  106.          end;
  107.          from until i <= 0 loop
  108.             Result := Result + item(i).code;
  109.             i := i - 1;
  110.          end;
  111.          Result := Result * count;
  112.       end;
  113.  
  114.    infix "<" (other: like Current): BOOLEAN is
  115.          -- Is Current less than `other' ?
  116.       local
  117.          i: INTEGER;
  118.       do
  119.          from  
  120.             i := 1;
  121.          until
  122.             count < i or else other.count < i 
  123.             or else item(i) /= other.item(i)
  124.          loop
  125.             i := i + 1;
  126.          end;
  127.          if count < i then
  128.             Result := other.count >= i;
  129.          elseif other.count < i then
  130.             Result := false;
  131.          else
  132.             Result := item(i) < other.item(i);
  133.          end;
  134.       end;
  135.  
  136.    compare, three_way_comparison(other: like Current): INTEGER is
  137.       local
  138.          i: INTEGER;
  139.       do
  140.          from  
  141.             i := 1;
  142.          until
  143.             count < i or else other.count < i 
  144.             or else item(i) /= other.item(i)
  145.          loop
  146.             i := i + 1;
  147.          end;
  148.          if count < i then
  149.             if other.count < i then
  150.             else
  151.                Result := -1;
  152.             end;
  153.          elseif other.count < i then
  154.             Result := 1;
  155.          elseif item(i) < other.item(i) then
  156.             Result := -1;
  157.          else
  158.             Result := 1;
  159.          end;
  160.       end;
  161.  
  162.    same_as(other: STRING): BOOLEAN is
  163.          -- Case insensitive `is_equal'.
  164.       require
  165.          other /= Void
  166.       local
  167.          s1, s2: like storage;
  168.          i: INTEGER;
  169.       do
  170.          i := count;
  171.          if i = other.count then
  172.             from
  173.                i := i - 1;
  174.                s1 := storage;
  175.                s2 := other.storage;
  176.                Result := true;
  177.             until
  178.                i < 0
  179.             loop
  180.                if s1.item(i).same_as(s2.item(i)) then
  181.                   i := i - 1;
  182.                else
  183.                   i := -1;
  184.                   Result := false;
  185.                end;
  186.             end;
  187.          end;
  188.       end;
  189.    
  190.    is_equal(other: like Current): BOOLEAN is
  191.          -- Has Current the same text as `other' ?
  192.       do
  193.          if count = other.count then
  194.             Result := storage.fast_memcmp(other.storage,count);
  195.          end;
  196.       end;
  197.    
  198.    index_of(ch: CHARACTER): INTEGER is
  199.          -- Gives the index of the first occurrence `ch' or 
  200.          -- `count + 1' if none.
  201.       do
  202.          Result := 1 + storage.fast_index_of(ch,count - 1);
  203.       ensure
  204.          (Result /= count + 1) implies (item(Result) = ch);
  205.       end;
  206.    
  207.    index_of_string(other: STRING): INTEGER is
  208.          -- Position of the first occurrence of `other'
  209.          -- or `count + 1' if none.
  210.       require
  211.          not other.empty
  212.       local
  213.          stop: BOOLEAN;
  214.          i1, i2, i3: INTEGER;
  215.       do
  216.          from
  217.             i1 := 1;
  218.             i2 := other.count;
  219.             i3 := i2;
  220.          invariant
  221.             i3 = i2 - i1 + 1; 
  222.          variant
  223.             count - i1 + 1
  224.          until
  225.             Result /= 0
  226.          loop
  227.             if i2 > count then
  228.                Result := count + 1;
  229.             else
  230.                from
  231.                   stop := false;
  232.                invariant
  233.                   i3 = i2 - i1 + 1
  234.                variant
  235.                   (i3 + i2)
  236.                until
  237.                   stop
  238.                loop
  239.                   if i3 = 0 then
  240.                      stop := true;
  241.                      Result := i1;
  242.                   elseif other.item(i3) /= item(i2) then
  243.                      stop := true;
  244.                   end;
  245.                   i3 := i3 - 1;
  246.                   i2 := i2 - 1;
  247.                end;
  248.             end;
  249.             i1 := i1 + 1;
  250.             i3 := other.count;
  251.             i2 := i1 + i3 - 1;
  252.          end;
  253.       end;
  254.  
  255.    has(ch: CHARACTER): BOOLEAN is
  256.          -- True if `ch' is in the STRING.
  257.       do
  258.          Result := storage.fast_has(ch,count - 1);
  259.       end;
  260.  
  261.    has_string(other: STRING): BOOLEAN is
  262.          -- True if `other' is in the STRING.
  263.       do
  264.          Result := index_of_string(other) /= (count + 1);
  265.       end;
  266.  
  267.    occurrences_of, occurrences(c: CHARACTER): INTEGER is
  268.          -- Number of times character `c' appears in the string.
  269.       do
  270.          Result := storage.fast_nb_occurrences(c,count - 1);
  271.       ensure
  272.          Result >= 0
  273.       end;
  274.    
  275.    has_suffix(s: STRING): BOOLEAN is
  276.          -- True if suffix of Current is `s'.
  277.       require
  278.          s /= Void
  279.       local
  280.          i1, i2: INTEGER;
  281.       do
  282.          if s.count <= count then
  283.             from  
  284.                i1 := count - s.count + 1;
  285.                i2 := 1;
  286.             until
  287.                i1 > count or else
  288.                i2 > s.count or else
  289.                item(i1) /= s.item(i2)
  290.             loop
  291.                i1 := i1 + 1;
  292.                i2 := i2 + 1;
  293.             end;
  294.             Result := i1 > count; 
  295.          end;
  296.       end;
  297.    
  298.    has_prefix(p: STRING): BOOLEAN is
  299.          -- True if prefix of Current is `p'.
  300.       require
  301.          p /= Void;
  302.       local
  303.          i: INTEGER;
  304.       do
  305.          if p.count <= count then
  306.             from  
  307.                i := p.count;
  308.             until
  309.                i = 0 or else item(i) /= p.item(i)
  310.             loop
  311.                i := i - 1;
  312.             end;
  313.             Result := i = 0; 
  314.          end;
  315.       end;
  316.  
  317.    replace_all(old_character, new_character: like item) is
  318.          -- Replace all occurrences of the element `old_character' by 
  319.          -- `new_character'.
  320.       do
  321.          storage.fast_replace_all(old_character,new_character,count - 1);
  322.       ensure
  323.          count = old count;
  324.          occurrences_of(old_character) = 0
  325.       end;
  326.  
  327.    is_integer: BOOLEAN is
  328.       -- Can contents be read as an INTEGER ?
  329.       local
  330.          i, state: INTEGER;
  331.          cc: CHARACTER;
  332.       do
  333.          -- state 0 : nothing read.
  334.          -- state 1 : "+" or "-" read.
  335.          -- state 2 : in the number.
  336.          -- state 3 : after the number.
  337.          -- state 4 : error.
  338.          from
  339.             i := 1;
  340.          until
  341.             i > count or else state = 4
  342.          loop
  343.             cc := item(i);
  344.             inspect 
  345.                state
  346.             when 0 then
  347.                if cc.is_separator then
  348.                elseif cc = '+' then
  349.                   state := 1;
  350.                elseif cc = '-' then
  351.                   state := 1;
  352.                elseif cc.is_digit then
  353.                   state := 2;
  354.                   Result := true;
  355.                else
  356.                   state := 4;
  357.                   Result := false;
  358.                end;
  359.             when 1 then
  360.                if cc.is_separator then
  361.                elseif cc.is_digit then
  362.                   state := 2;
  363.                   Result := true;
  364.                else
  365.                   state := 4;
  366.                   Result := false;
  367.                end;
  368.             when 2 then
  369.                if cc.is_digit then
  370.                elseif cc.is_separator then
  371.                   state := 3;
  372.                else
  373.                   state := 4;
  374.                   Result := false;
  375.                end;
  376.             when 3 then
  377.                if cc.is_separator then
  378.                else 
  379.                   state := 4;
  380.                   Result := false;
  381.                end;
  382.             end;
  383.             i := i + 1;
  384.          end;
  385.       end; 
  386.  
  387.    is_real: BOOLEAN is
  388.          -- Contents can be read as a REAL.
  389.       local
  390.          d: DOUBLE;
  391.       do
  392.          if is_double then
  393.             d := to_double
  394.             if Minimum_real <= d and then d <= Maximum_real then
  395.                Result := true
  396.                -- This gives only approximate accuracy; the comparison 
  397.                -- is not accurate to nearly as many significant figures
  398.                -- as are displayed for the limits.
  399.             end
  400.          end
  401.       end
  402.  
  403.    is_double: BOOLEAN is
  404.          -- Contents can be read as a DOUBLE.
  405.       local
  406.          i, state: INTEGER;
  407.          cc: CHARACTER;
  408.          begun: BOOLEAN;
  409.       do
  410.          -- state 0 : nothing read.
  411.          -- state 1 : "+" or "-" read.
  412.          -- state 2 : in the number.
  413.          -- state 3 : decimal point read
  414.          -- state 4 : in fractional part
  415.          -- state 5 : read 'E' or 'e' for scientific notation
  416.          -- state 6 : read "-" sign of exponent
  417.          -- state 7 : in exponent
  418.          -- state 8 : after the number.
  419.          -- state 9 : error.
  420.          from
  421.             i := 1;
  422.          until
  423.             i > count or else state = 9
  424.          loop
  425.             cc := item(i);
  426.             inspect 
  427.                state
  428.             when 0 then
  429.                if cc.is_separator then
  430.                elseif cc = '+' then
  431.                   state := 1;
  432.                elseif cc = '-' then
  433.                   state := 1;
  434.                elseif cc.is_digit then
  435.                   state := 2;
  436.                   Result := true;
  437.                elseif cc = '.' then
  438.                   state := 3
  439.                else
  440.                   state := 9;
  441.                   Result := false;
  442.                end;
  443.             when 1 then
  444.                if cc.is_separator then
  445.                elseif cc.is_digit then
  446.                   state := 2;
  447.                   Result := true;
  448.                elseif cc = '.' then
  449.                   state := 3
  450.                else
  451.                   state := 9;
  452.                   Result := false;
  453.                end;
  454.             when 2 then
  455.                if cc.is_digit then
  456.                   begun := true
  457.                elseif cc = '.' then
  458.                   state := 3
  459.                else
  460.                   state := 9;
  461.                   Result := false;
  462.                end;
  463.             when 3 then
  464.                if cc.is_separator then
  465.                   state := 8;
  466.                elseif cc.is_digit then
  467.                   state := 4
  468.                   Result := true;
  469.                   begun := true
  470.                else
  471.                   state := 9
  472.                   Result := false
  473.                end
  474.             when 4 then
  475.                if cc.is_digit then
  476.                   begun := true
  477.                elseif cc.is_separator then
  478.                   state := 8;
  479.                elseif (cc = 'e' or cc = 'E') and begun then
  480.                   state := 5
  481.                else
  482.                   state := 9;
  483.                   Result := false;
  484.                end;
  485.             when 5 then
  486.                if cc = '-' then
  487.                   state := 6
  488.                elseif cc.is_digit then
  489.                   state := 7
  490.                else
  491.                   state := 9;
  492.                   Result := false;
  493.                end;
  494.             when 6 then
  495.                if cc.is_digit then
  496.                   state := 7
  497.                else
  498.                   state := 9;
  499.                   Result := false;
  500.                end;
  501.             when 7 then
  502.                if cc.is_digit then
  503.                elseif cc.is_separator then
  504.                   state := 8
  505.                else
  506.                   state := 9;
  507.                   Result := false;
  508.                end;
  509.             when 8 then
  510.                if cc.is_separator then
  511.                else 
  512.                   state := 9;
  513.                   Result := false;
  514.                end;
  515.             end;
  516.             i := i + 1;
  517.          end;
  518.          if state < 3 then
  519.             -- exclude integers
  520.             Result := false
  521.          end
  522.          -- We should check the value is within the system limits, but
  523.          -- I can't see how to do that without trying to convert it.
  524.       end; 
  525.  
  526.    is_bit: BOOLEAN is
  527.          -- True when the contents is a sequence of bits (i.e., mixed 
  528.          -- characters `0' and characters `1').
  529.       local
  530.          i: INTEGER;
  531.       do
  532.          from
  533.             i := count;
  534.             Result := true;
  535.          until
  536.             not Result or else i = 0
  537.          loop
  538.             Result := item(i).is_bit;
  539.             i := i - 1;
  540.          end;
  541.       ensure
  542.          Result = (count = occurrences_of('0') + occurrences_of('1'))
  543.       end;
  544.  
  545. feature -- Modification :
  546.    
  547.    clear, wipe_out is
  548.          -- Clear out the current STRING.
  549.          -- Note : internal `storage' memory is neither released nor shrunk.
  550.       do
  551.          count := 0;
  552.       ensure
  553.          count = 0;
  554.       end;
  555.    
  556.    copy(other: like Current) is
  557.          -- Copy `other' onto Current.
  558.       do
  559.          count := other.count;
  560.          if count > 0 then
  561.             if capacity < count then
  562.                storage := storage.calloc(count);
  563.                capacity := count;
  564.             end;
  565.             storage.copy_from(other.storage,count-1);
  566.          end;
  567.       ensure then
  568.          count = other.count
  569.       end;
  570.  
  571.    fill, fill_with(c: CHARACTER) is
  572.          -- Replace every character with `c'.
  573.       do
  574.          storage.set_all_with(c,count - 1);
  575.       ensure
  576.          occurrences_of(c) = count
  577.       end;
  578.    
  579.    fill_blank is 
  580.          -- Fill entire string with blanks
  581.       do  
  582.          fill_with(' ');
  583.       ensure
  584.          occurrences_of(' ') = count
  585.       end;     
  586.  
  587.    append, append_string(other: STRING) is
  588.          -- Append `other' to Current.
  589.       require
  590.          other /= Void
  591.       local
  592.          other_count, needed_capacity: INTEGER;
  593.       do
  594.          other_count := other.count;
  595.          needed_capacity := count + other_count;
  596.          if capacity < needed_capacity then
  597.             if capacity = 0 then
  598.                capacity := needed_capacity;
  599.                storage := storage.calloc(capacity);
  600.             else
  601.                storage := storage.realloc(capacity,needed_capacity);
  602.                capacity := needed_capacity;
  603.             end;
  604.          end;
  605.          storage.copy_at(count,other.storage,other_count);
  606.          count := needed_capacity;
  607.       end;
  608.  
  609.    prepend(other: STRING) is
  610.          -- Prepend `other' to Current
  611.       require
  612.          other /= Void
  613.       local
  614.          i, old_count: INTEGER;
  615.       do
  616.          old_count := count;
  617.          from  
  618.             i := other.count;
  619.          until
  620.             i = 0
  621.          loop
  622.             extend(' ');
  623.             i := i - 1;
  624.          end;
  625.          from  
  626.             i := count;
  627.          until
  628.             old_count = 0
  629.          loop
  630.             put(item(old_count),i);
  631.             i := i - 1;
  632.             old_count := old_count - 1;
  633.          end;
  634.          from  
  635.             i := other.count
  636.          until
  637.             i = 0
  638.          loop
  639.             put(other.item(i),i);
  640.             i := i - 1;
  641.          end;
  642.       ensure 
  643.          count = other.count + old count
  644.       end;
  645.  
  646.    infix "+" (other: STRING): STRING is
  647.          -- Create a new STRING which is the concatenation of 
  648.          -- `Current' and `other'.
  649.       require
  650.          other /= Void
  651.       do
  652.          !!Result.make(count + other.count);
  653.          Result.append(Current);
  654.          Result.append(other);
  655.       ensure
  656.          Result.count = count + other.count
  657.       end;
  658.    
  659.    put(ch: CHARACTER; index: INTEGER) is
  660.          -- Put `ch' at position `index'.
  661.       require
  662.          valid_index(index)
  663.       do
  664.          storage.put(ch,index - 1);
  665.       ensure
  666.          item (index) = ch
  667.       end;
  668.    
  669.    swap(i1, i2: INTEGER) is
  670.       require
  671.          valid_index(i1);
  672.          valid_index(i2)
  673.       local
  674.          tmp: CHARACTER;
  675.       do
  676.          tmp := item(i1);
  677.          put(item(i2),i1);
  678.          put(tmp,i2);
  679.       ensure
  680.          item(i1) = old item(i2);
  681.          item(i2) = old item(i1);
  682.       end;
  683.    
  684.    insert(ch: CHARACTER; index: INTEGER) is
  685.          -- Insert `ch' after position `index'.
  686.       require
  687.          0 <= index and index <= count;
  688.       local
  689.          i: INTEGER;
  690.       do
  691.          from  
  692.             i := count;
  693.             extend(' ');
  694.          until
  695.             i = index
  696.          loop
  697.             put(item(i),i + 1);
  698.             i := i - 1;
  699.          end;
  700.          put(ch,index + 1);
  701.       ensure
  702.          item (index + 1) = ch
  703.       end;
  704.  
  705.    shrink(low, up: INTEGER) is
  706.          -- Keep only the slice `low' .. `up' or nothing
  707.          -- when the slice is empty.
  708.       require
  709.          1 <= low;
  710.          low <= count;
  711.          1 <= up;
  712.          up <= count;
  713.       local
  714.          i, i2: INTEGER;
  715.       do
  716.          if up < low then
  717.             clear;
  718.          elseif low = 1 then
  719.             count := up;
  720.          else
  721.             from  
  722.                i := 1;
  723.                i2 := low;
  724.             until
  725.                i2 > up
  726.             loop
  727.                put(item(i2),i);
  728.                i := i + 1;
  729.                i2 := i2 + 1;
  730.             end;
  731.             count := i - 1;
  732.          end;
  733.       ensure
  734.          up > low implies count = up - low + 1;
  735.       end;
  736.    
  737.    remove(index: INTEGER) is
  738.          -- Remove character at position `index'.
  739.       require
  740.          valid_index(index)
  741.       do
  742.          remove_between(index,index);
  743.       ensure
  744.          count = (old count) - 1
  745.       end;
  746.  
  747.    add_first(ch: CHARACTER) is
  748.          -- Add `ch' at first position.
  749.       local
  750.          i: INTEGER;
  751.       do
  752.          from  
  753.             extend(' ');
  754.             i := count;
  755.          until
  756.             i = 1
  757.          loop
  758.             put(item(i - 1),i);
  759.             i := i - 1;
  760.          end;
  761.          put(ch,1);
  762.       ensure
  763.          count = 1 + old count;
  764.          item(1) = ch
  765.       end;
  766.  
  767.    add_last, extend, append_character(ch: CHARACTER) is
  768.          -- Append `ch' to string
  769.       local
  770.          new_capacity: INTEGER;
  771.       do
  772.          if capacity > count then
  773.          elseif capacity = 0 then
  774.             capacity := 32;
  775.             storage := storage.calloc(capacity);
  776.          else
  777.             new_capacity := 2 * capacity;
  778.             storage := storage.realloc(capacity,new_capacity);
  779.             capacity := new_capacity;
  780.          end;
  781.          storage.put(ch,count);
  782.          count := count + 1;
  783.       ensure
  784.          count = 1 + old count;
  785.          item (count) = ch
  786.       end;
  787.  
  788.    precede(ch: CHARACTER) is
  789.          -- Prepend `ch' to string
  790.       local
  791.          i: INTEGER;
  792.       do
  793.          from  
  794.             extend(' ');
  795.             i := count;
  796.          until
  797.             i = 1
  798.          loop
  799.             put(item(i-1),i);
  800.             i := i - 1;
  801.          end;
  802.          put(ch,1);
  803.       ensure
  804.          item (1) = ch
  805.       end;
  806.  
  807.    to_lower is
  808.          -- Convert all characters to lower case.
  809.       local
  810.          i: INTEGER;
  811.       do
  812.          from  
  813.             i := count;
  814.          until
  815.             i = 0
  816.          loop
  817.             put(item(i).to_lower,i);
  818.             i := i - 1;
  819.          end;
  820.       end;
  821.    
  822.    to_upper is
  823.          -- Convert all characters to upper case.
  824.       local
  825.          i: INTEGER;
  826.       do
  827.          from  
  828.             i := count;
  829.          until
  830.             i = 0
  831.          loop
  832.             put(item(i).to_upper,i);
  833.             i := i - 1;
  834.          end;
  835.       end;
  836.  
  837.    remove_first(nb: INTEGER) is
  838.          -- Remove `nb' first characters.
  839.       require
  840.          nb >= 0; 
  841.          count >= nb;
  842.       do
  843.          if nb > 0 then
  844.             remove_between(1, nb)
  845.          end;
  846.       ensure
  847.          count = (old count) - nb
  848.       end; 
  849.    
  850.    remove_last(nb: INTEGER) is
  851.          -- Remove `nb' last characters.
  852.       require
  853.          0 <= nb;
  854.          nb <= count;
  855.       do
  856.          count := count - nb;
  857.       ensure
  858.          count = old count - nb
  859.       end; 
  860.    
  861.    remove_between(low, up : INTEGER) is
  862.          -- Remove character between positions `low' and `up'.
  863.       require
  864.          valid_index(low);
  865.          valid_index(up);
  866.          low <= up
  867.       local
  868.          i : INTEGER;
  869.       do
  870.          from  
  871.             i := up;
  872.          until
  873.             i >= count
  874.          loop
  875.             put(item(i + 1), low + i - up);
  876.             i := i + 1;
  877.          end;
  878.          count := count - (up - low + 1);
  879.       ensure
  880.          count = (old count) - (up - low + 1)
  881.       end;
  882.  
  883.    remove_suffix(s: STRING) is
  884.       -- Remove the suffix `s' of current string.
  885.       require
  886.          has_suffix(s);
  887.       do
  888.          remove_last(s.count);
  889.       ensure
  890.          old count = count + s.count
  891.       end;
  892.  
  893.    remove_prefix(s: STRING) is
  894.       -- Remove the prefix `s' of current string.
  895.       require
  896.          has_prefix(s);
  897.       do
  898.          remove_first(s.count);
  899.       ensure
  900.          old count = count + s.count
  901.       end;
  902.  
  903.    left_adjust is
  904.          -- Remove leading blanks.
  905.       local
  906.          i: INTEGER;
  907.       do
  908.          from
  909.          until
  910.             i + 1 > count or else item(i + 1) /= ' '
  911.          loop
  912.             i := i + 1;
  913.          end;
  914.          remove_first(i);
  915.       ensure
  916.          stripped: empty or else item (1) /= ' '
  917.       end;
  918.  
  919.    right_adjust is
  920.          -- Remove trailing blanks.
  921.       do
  922.          from
  923.          until
  924.             count = 0 or else item(count) /= ' '
  925.          loop
  926.             count := count - 1;
  927.          end
  928.       ensure
  929.          stripped: empty or else item (count) /= ' '
  930.       end;
  931.  
  932. feature -- Features which don't modify the string
  933.  
  934.    first: CHARACTER is
  935.       require
  936.          not empty
  937.       do
  938.          Result := storage.item(0);
  939.       end;
  940.  
  941.    last: CHARACTER is
  942.       require
  943.          not empty;
  944.       do
  945.          Result := item(count);
  946.       end;
  947.  
  948. feature -- Conversion :
  949.  
  950.    to_integer: INTEGER is
  951.          -- Current must looks like an INTEGER.
  952.       require
  953.          is_integer
  954.       local
  955.          i, state: INTEGER;
  956.          cc: CHARACTER;
  957.          minus: BOOLEAN;
  958.       do
  959.          -- state 0 : nothing read.
  960.          -- state 1 : "+" or "-" read.
  961.          -- state 2 : in the number.
  962.          -- state 3 : after the number.
  963.          -- state 4 : error.
  964.          from
  965.             i := 1;
  966.          until
  967.             i > count 
  968.          loop
  969.             cc := item(i);
  970.             inspect 
  971.                state
  972.             when 0 then
  973.                if cc.is_separator then
  974.                elseif cc = '+' then
  975.                   state := 1;
  976.                elseif cc = '-' then
  977.                   minus := true;
  978.                   state := 1;
  979.                else
  980.                   check
  981.                      cc.is_digit
  982.                   end;
  983.                   Result := cc.value;
  984.                   state := 2;
  985.                end;
  986.             when 1 then
  987.                if cc.is_separator then
  988.                else
  989.                   check
  990.                      cc.is_digit
  991.                   end;
  992.                   Result := cc.value;
  993.                   state := 2;
  994.                end;
  995.             when 2 then
  996.                if cc.is_digit then
  997.                   Result := (Result * 10) + cc.value;
  998.                else
  999.                   check
  1000.                      cc.is_separator
  1001.                   end;
  1002.                   state := 3;
  1003.                end;
  1004.             when 3 then
  1005.                check
  1006.                   cc.is_separator
  1007.                end;
  1008.             end;
  1009.             i := i + 1;
  1010.          end;
  1011.          if minus then
  1012.             Result := - Result;
  1013.          end;
  1014.       end; 
  1015.  
  1016.    to_real: REAL is
  1017.          -- Conversion to the corresponding REAL value. 
  1018.          -- The string must looks like a REAL (or like an 
  1019.          -- INTEGER because fractionnal part is optional).
  1020.       require
  1021.          is_integer or is_real
  1022.       do
  1023.          Result := to_double.to_real;
  1024.       end;
  1025.    
  1026.    to_double: DOUBLE is
  1027.          -- Conversion to the corresponding DOUBLE value. 
  1028.          -- The string must looks like a DOUBLE, like 
  1029.          -- a REAL (or like an INTEGER because fractionnal 
  1030.          -- part is optional).
  1031.       require
  1032.          is_integer or is_real
  1033.       local
  1034.          negative: BOOLEAN;
  1035.          p: POINTER;
  1036.       do
  1037.          tmp_string.copy(Current);
  1038.          tmp_string.left_adjust;
  1039.          if tmp_string.first = '-' then
  1040.             negative := true;
  1041.             tmp_string.remove_first(1);
  1042.          elseif tmp_string.first = '+' then
  1043.             tmp_string.remove_first(1);
  1044.          end;
  1045.          tmp_string.left_adjust;
  1046.          p := tmp_string.to_external;
  1047.          Result := se_string2double(p);
  1048.          if negative then
  1049.             Result := -Result;
  1050.          end;
  1051.       end;
  1052.  
  1053.    binary_to_integer: INTEGER is
  1054.          -- Assume there is enougth space in the INTEGER to store
  1055.          -- the corresponding decimal value.
  1056.       require
  1057.          is_bit;
  1058.          count <= Integer_bits
  1059.       local
  1060.          i: INTEGER;
  1061.       do
  1062.          from
  1063.             i := 1;
  1064.          until
  1065.             i > count
  1066.          loop
  1067.             if item(i) = '1' then
  1068.                Result := (2 * Result) + 1;
  1069.             else
  1070.                Result := 2 * Result;
  1071.             end;
  1072.             i := i + 1;
  1073.          end;
  1074.       end;
  1075.  
  1076.    to_hexadecimal is
  1077.          -- Convert Current bit sequence into the corresponding 
  1078.          -- hexadecimal notation.
  1079.       require
  1080.          is_bit
  1081.       local
  1082.          i, k, new_count: INTEGER;
  1083.          value: INTEGER;
  1084.       do
  1085.          from
  1086.             i := 1;
  1087.             k := count \\ 4;
  1088.             if k > 0 then
  1089.                new_count := 1;
  1090.             end;
  1091.          until
  1092.             k = 0
  1093.          loop
  1094.             value := value * 2 + item(i).value;
  1095.             i := i + 1;
  1096.             k := k - 1;
  1097.          end;
  1098.          if new_count > 0 then
  1099.             put(value.hexadecimal_digit,new_count);
  1100.          end;
  1101.          from
  1102.          until
  1103.             i > count 
  1104.          loop
  1105.             from
  1106.                value := item(i).value;
  1107.                i := i + 1;
  1108.                k := 3;
  1109.             until
  1110.                k = 0
  1111.             loop
  1112.                value := value * 2 + item(i).value;
  1113.                i := i + 1;
  1114.                k := k - 1;
  1115.             end;
  1116.             new_count := new_count + 1;
  1117.             put(value.hexadecimal_digit,new_count);
  1118.          end;
  1119.          count := new_count;
  1120.       end;
  1121.  
  1122. feature -- Printing :
  1123.    
  1124.    out_in_tagged_out_memory is
  1125.       do
  1126.          tagged_out_memory.append(Current); 
  1127.       end;
  1128.    
  1129.    fill_tagged_out_memory is
  1130.       do
  1131.          tagged_out_memory.append("count: "); 
  1132.          count.append_in(tagged_out_memory);
  1133.          tagged_out_memory.append("capacity: "); 
  1134.          capacity.append_in(tagged_out_memory);
  1135.          tagged_out_memory.append("storage: %""); 
  1136.          tagged_out_memory.append(Current); 
  1137.          tagged_out_memory.extend('%"'); 
  1138.       end;
  1139.    
  1140. feature -- Other features :
  1141.    
  1142.    substring(low, up: INTEGER): like Current is
  1143.          -- Create a new string initialized with range `low'.. `up'.  
  1144.       require
  1145.          1 <= low;
  1146.          low <= up; 
  1147.          up <= count;
  1148.       local
  1149.          i: INTEGER;
  1150.       do
  1151.          from  
  1152.             !!Result.make(up - low + 1);
  1153.             i := low;
  1154.          until
  1155.             i > up
  1156.          loop
  1157.             Result.extend(item(i));
  1158.             i := i + 1;
  1159.          end;
  1160.       end;
  1161.    
  1162.    extend_multiple(c: CHARACTER; n: INTEGER) is
  1163.          -- Extend Current with `n' times character `c'.
  1164.       require
  1165.          n >= 0
  1166.       local
  1167.          i: INTEGER;
  1168.       do
  1169.          from
  1170.             i := n;
  1171.          until
  1172.             i = 0
  1173.          loop
  1174.             extend(c);
  1175.             i := i - 1;
  1176.          end;
  1177.       ensure
  1178.          count = n + old count
  1179.       end;
  1180.  
  1181.    precede_multiple(c: CHARACTER; n: INTEGER) is
  1182.          -- Prepend `n' times character `c' to Current.
  1183.       require
  1184.          n >= 0
  1185.       local
  1186.          old_count: INTEGER;
  1187.       do
  1188.          if n > 0 then
  1189.             old_count := count;
  1190.             if old_count = 0 then
  1191.                extend_multiple(c,n);
  1192.             else
  1193.                extend_multiple('%U',n);
  1194.                storage.move(0,old_count - 1,n);
  1195.                storage.set_all_with(c,n - 1);
  1196.             end;
  1197.          end;
  1198.       ensure
  1199.          count = n + old count
  1200.       end;
  1201.  
  1202.    extend_to_count(c: CHARACTER; needed_count: INTEGER) is
  1203.          -- Extend Current with `c' until `needed_count' is reached.
  1204.          -- Do nothing if `needed_count' is already greater or equal 
  1205.          -- to `count'.
  1206.       require
  1207.          needed_count >= 0
  1208.       local
  1209.          offset: INTEGER;
  1210.       do
  1211.          from
  1212.             offset := needed_count - count;
  1213.          until
  1214.             offset <= 0
  1215.          loop
  1216.             extend(c);
  1217.             offset := offset - 1;
  1218.          end;
  1219.       ensure
  1220.          count >= needed_count
  1221.       end;
  1222.  
  1223.    precede_to_count(c: CHARACTER; needed_count: INTEGER) is
  1224.          -- Prepend `c' to Current until `needed_count' is reached.
  1225.          -- Do nothing if `needed_count' is already greater or equal 
  1226.          -- to `count'.
  1227.       require
  1228.          needed_count >= 0
  1229.       local
  1230.          offset, old_count: INTEGER;
  1231.       do
  1232.          old_count := count;
  1233.          offset := needed_count - old_count;
  1234.          if offset > 0 then
  1235.             extend_to_count('%U',needed_count);
  1236.             storage.move(0,old_count - 1,offset);
  1237.             storage.set_all_with(c,offset - 1);
  1238.          end;
  1239.       ensure
  1240.          count >= needed_count
  1241.       end;
  1242.  
  1243.    reverse is
  1244.          -- Reverse the string.
  1245.       local
  1246.          i1, i2: INTEGER;
  1247.       do
  1248.          from  
  1249.             i1 := 1;
  1250.             i2 := count;
  1251.          until
  1252.             i1 >= i2
  1253.          loop
  1254.             swap(i1,i2);
  1255.             i1 := i1 + 1;
  1256.             i2 := i2 - 1;
  1257.          end;
  1258.       end;
  1259.    
  1260.    remove_all_occurrences(ch: CHARACTER) is
  1261.          -- Remove all occurrences of `ch'.
  1262.       local
  1263.          i, j: INTEGER;
  1264.       do
  1265.          from  
  1266.             i := 1;
  1267.             j := 1;
  1268.          until
  1269.             i > count
  1270.          loop
  1271.             if item(i) /= ch then
  1272.                put(item(i),j);
  1273.                j := j + 1;
  1274.             end;
  1275.             i := i + 1;
  1276.          end;
  1277.          count := j - 1; 
  1278.       ensure
  1279.          count = old count - old occurrences_of(ch)
  1280.       end;
  1281.  
  1282.    substring_index(other: STRING; start: INTEGER): INTEGER is
  1283.          -- Position of first occurrence of `other' at or after 
  1284.          -- `start';
  1285.          -- 0 if none.
  1286.       require
  1287.          start_large_enough: start >= 1;
  1288.          start_small_enough: start <= count;
  1289.          string_exist: other /= Void
  1290.       local
  1291.          i, s: INTEGER;
  1292.       do
  1293.          from
  1294.             s := start;
  1295.          until
  1296.             Result /= 0 or else (s + other.count - 1) > count
  1297.          loop
  1298.             from
  1299.                i := 1;
  1300.             until
  1301.                i > other.count or else item(s + i - 1) /= other.item(i)
  1302.             loop
  1303.                i := i + 1;
  1304.             end;
  1305.             if i > other.count then
  1306.                Result := s;
  1307.             else
  1308.                s := s + 1
  1309.             end;
  1310.          end;
  1311.       end;
  1312.  
  1313. feature -- Splitting a STRING :
  1314.    
  1315.    split: ARRAY[STRING] is
  1316.          -- Split the string into an array of words.
  1317.          -- Uses `is_separator' of CHARACTER to find words.
  1318.          -- Gives Void or a non empty array.
  1319.       do
  1320.          if count > 0 then
  1321.             split_buffer.clear;
  1322.             split_in(split_buffer);
  1323.             if not split_buffer.empty then
  1324.                Result := split_buffer.twin;
  1325.             end;
  1326.          end;
  1327.       ensure
  1328.          Result /= Void implies not Result.empty
  1329.       end;
  1330.  
  1331.    split_in(words: COLLECTION[STRING]) is
  1332.          -- Same jobs as `split' but result is appended in `words'.
  1333.       require
  1334.          words /= Void
  1335.       local 
  1336.          state, i: INTEGER;
  1337.          -- state = 0 : waiting next word.
  1338.          -- state = 1 : inside a new word.
  1339.          c: CHARACTER;
  1340.       do
  1341.          if count > 0 then
  1342.             from
  1343.                i := 1;
  1344.             until
  1345.                i > count
  1346.             loop
  1347.                c := item(i);
  1348.                if state = 0 then
  1349.                   if not c.is_separator then
  1350.                      tmp_string.clear;
  1351.                      tmp_string.extend(c);
  1352.                      state := 1;
  1353.                   end;
  1354.                else
  1355.                   if not c.is_separator then
  1356.                      tmp_string.extend(c);
  1357.                   else
  1358.                      words.add_last(tmp_string.twin);
  1359.                      state := 0;
  1360.                   end;
  1361.                end;
  1362.                i := i + 1;
  1363.             end;
  1364.             if state = 1 then 
  1365.                words.add_last(tmp_string.twin);
  1366.             end;
  1367.          end;
  1368.       ensure
  1369.          words.count >= old (words.count)
  1370.       end;
  1371.  
  1372. feature -- Other feature :
  1373.  
  1374.    set_last(ch: CHARACTER) is
  1375.       do
  1376.          if count = 0 or else item(count) /= ch then
  1377.             extend(ch);
  1378.          end;
  1379.       ensure
  1380.          last = ch
  1381.       end;
  1382.  
  1383. feature -- Interfacing with C string :
  1384.    
  1385.    to_external: POINTER is
  1386.          -- Gives C access to the internal `storage' (may be dangerous).
  1387.          -- To be compatible with C, a null character is added at the end 
  1388.          -- of the internal `storage'. This extra null character is not 
  1389.          -- part of the Eiffel STRING. 
  1390.       do
  1391.          if capacity > count then
  1392.             count := count + 1;
  1393.             if item(count) /= '%U' then
  1394.                put('%U',count);
  1395.             end;
  1396.          else
  1397.             extend('%U');
  1398.          end;
  1399.          count := count - 1;
  1400.          Result := storage.to_pointer;
  1401.       ensure
  1402.          count = old count;
  1403.          Result.is_not_null
  1404.       end;
  1405.  
  1406.    from_external(p: POINTER) is
  1407.          -- Internal `storage' is set using `p' (may be dangerous because
  1408.          -- the external C string `p' is not duplicated).
  1409.          -- Assume `p' has a null character at the end in order to 
  1410.          -- compute the Eiffel `count'. This extra null character
  1411.          -- is not part of the Eiffel STRING.
  1412.          -- Also consider `from_external_copy' to choose the most appropriate. 
  1413.       require
  1414.          p.is_not_null
  1415.       do
  1416.          from
  1417.             storage := storage.from_pointer(p);
  1418.             count := 0;
  1419.          until
  1420.             storage.item(count) = '%U'
  1421.          loop
  1422.             count := count + 1;
  1423.          end;
  1424.          capacity := count + 1;
  1425.       ensure
  1426.          capacity = count + 1;
  1427.          p = to_external
  1428.       end;
  1429.  
  1430.    from_external_copy(p: POINTER) is
  1431.          -- Internal `storage' is set using a copy of `p'.
  1432.          -- Assume `p' has a null character at the end in order to 
  1433.          -- compute the Eiffel `count'. This extra null character
  1434.          -- is not part of the Eiffel STRING.
  1435.          -- Also consider `from_external' to choose the most appropriate.
  1436.       local
  1437.          s: like storage;
  1438.       do
  1439.          from_external(p);
  1440.          s := s.calloc(capacity);
  1441.          s.copy_from(storage,capacity);
  1442.          storage := s;
  1443.       end;
  1444.  
  1445. feature -- Other feature here for ELKS'95 compatibility :
  1446.  
  1447.    make_from_string(s: STRING) is
  1448.          -- Initialize from the characters of `s'.
  1449.          -- (Useful in proper descendants of class STRING, to 
  1450.          -- initialize a string-like object from a manifest string.)
  1451.       require
  1452.          s /= Void
  1453.       local
  1454.          i, sc: INTEGER;
  1455.       do
  1456.          from
  1457.             sc := s.count;
  1458.             make(sc);
  1459.          until
  1460.             i = sc
  1461.          loop
  1462.             i := i + 1;
  1463.             extend(s.item(i));
  1464.          end;
  1465.       ensure
  1466.          count = s.count
  1467.       end;
  1468.  
  1469.    head(n: INTEGER) is
  1470.       -- Remove all characters except fo the first `n'.
  1471.       -- Do nothing if n >= count.
  1472.       require
  1473.          n >= 0
  1474.       do
  1475.          if n < count then
  1476.             remove_last(count - n);
  1477.          end;
  1478.       ensure
  1479.          count = n.min(old count)
  1480.       end;
  1481.    
  1482.    tail(n: INTEGER) is
  1483.       -- Remove all characters except for the last `n'.
  1484.       -- Do nothing if n >= count.
  1485.       require
  1486.          n >= 0
  1487.       do
  1488.          if n < count then
  1489.             remove_first(count - n);
  1490.          end;
  1491.       ensure
  1492.          count = n.min(old count)
  1493.       end;
  1494.  
  1495. feature {STRING}
  1496.  
  1497.    se_string2double(number_view: POINTER):DOUBLE is
  1498.       external "SmallEiffel"
  1499.       end; 
  1500.  
  1501. feature {NONE}
  1502.    
  1503.    tmp_string: STRING is 
  1504.       once
  1505.          !!Result.make(256);
  1506.       end;
  1507.  
  1508. feature {NONE}
  1509.  
  1510.    split_buffer: ARRAY[STRING] is
  1511.       once
  1512.          !!Result.with_capacity(4,1);
  1513.       end;
  1514.  
  1515. invariant
  1516.  
  1517.    0 <= count;
  1518.  
  1519.    count <= capacity;
  1520.  
  1521.    capacity > 0 implies storage.is_not_null;
  1522.    
  1523. end -- STRING
  1524.