home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Environments / Small Eiffel 0.4.8 / lib_std / string.e < prev   
Encoding:
Text File  |  1997-04-13  |  21.6 KB  |  1,159 lines  |  [TEXT/ttxt]

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