lib: remove class StringCapable
[nit.git] / lib / standard / string.nit
index e5a1581..48cb238 100644 (file)
@@ -30,7 +30,6 @@ intrude import collection::array
 # High-level abstraction for all text representations
 abstract class Text
        super Comparable
-       super StringCapable
 
        redef type OTHER: Text
 
@@ -181,8 +180,25 @@ abstract class Text
        #
        #     assert "abcd".has_substring("bc",1)            ==  true
        #     assert "abcd".has_substring("bc",2)            ==  false
+       #
+       # Returns true iff all characters of `str` are presents
+       # at the expected index in `self.`
+       # The first character of `str` being at `pos`, the second
+       # character being at `pos+1` and so on...
+       #
+       # This means that all characters of `str` need to be inside `self`.
+       #
+       #     assert "abcd".has_substring("xab", -1)         == false
+       #     assert "abcd".has_substring("cdx", 2)          == false
+       #
+       # And that the empty string is always a valid substring.
+       #
+       #     assert "abcd".has_substring("", 2)             == true
+       #     assert "abcd".has_substring("", 200)           == true
        fun has_substring(str: String, pos: Int): Bool
        do
+               if str.is_empty then return true
+               if pos < 0 or pos + str.length > length then return false
                var myiter = self.chars.iterator_from(pos)
                var itsiter = str.chars.iterator
                while myiter.is_ok and itsiter.is_ok do
@@ -477,6 +493,50 @@ abstract class Text
        #     assert "\n\"'\\\{\}".escape_to_nit      == "\\n\\\"\\'\\\\\\\{\\\}"
        fun escape_to_nit: String do return escape_more_to_c("\{\}")
 
+       # Escape to POSIX Shell (sh).
+       #
+       # Abort if the text contains a null byte.
+       #
+       #     assert "\n\"'\\\{\}0".escape_to_sh == "'\n\"'\\''\\\{\}0'"
+       fun escape_to_sh: String do
+               var b = new FlatBuffer
+               b.chars.add '\''
+               for i in [0..length[ do
+                       var c = chars[i]
+                       if c == '\'' then
+                               b.append("'\\''")
+                       else
+                               assert without_null_byte: c != '\0'
+                               b.add(c)
+                       end
+               end
+               b.chars.add '\''
+               return b.to_s
+       end
+
+       # Escape to include in a Makefile
+       #
+       # Unfortunately, some characters are not escapable in Makefile.
+       # These characters are `;`, `|`, `\`, and the non-printable ones.
+       # They will be rendered as `"?{hex}"`.
+       fun escape_to_mk: String do
+               var b = new FlatBuffer
+               for i in [0..length[ do
+                       var c = chars[i]
+                       if c == '$' then
+                               b.append("$$")
+                       else if c == ':' or c == ' ' or c == '#' then
+                               b.add('\\')
+                               b.add(c)
+                       else if c.ascii < 32 or c == ';' or c == '|' or c == '\\' or c == '=' then
+                               b.append("?{c.ascii.to_base(16, false)}")
+                       else
+                               b.add(c)
+                       end
+               end
+               return b.to_s
+       end
+
        # Return a string where Nit escape sequences are transformed.
        #
        #     var s = "\\n"
@@ -720,11 +780,6 @@ private abstract class StringCharView
 
        private var target: SELFTYPE
 
-       private init(tgt: SELFTYPE)
-       do
-               target = tgt
-       end
-
        redef fun is_empty do return target.is_empty
 
        redef fun length do return target.length
@@ -766,6 +821,8 @@ abstract class String
 
        fun insert_at(s: String, pos: Int): SELFTYPE is abstract
 
+       redef fun substrings: Iterator[String] is abstract
+
        # Returns a reversed version of self
        #
        #     assert "hello".reversed  == "olleh"
@@ -896,8 +953,6 @@ private class FlatSubstringsIter
 
        var tgt: nullable FlatText
 
-       init(tgt: FlatText) do self.tgt = tgt
-
        redef fun item do
                assert is_ok
                return tgt.as(not null)
@@ -936,7 +991,7 @@ class FlatString
 
        redef fun reversed
        do
-               var native = calloc_string(self.length + 1)
+               var native = new NativeString(self.length + 1)
                var length = self.length
                var items = self.items
                var pos = 0
@@ -974,7 +1029,7 @@ class FlatString
 
        redef fun to_upper
        do
-               var outstr = calloc_string(self.length + 1)
+               var outstr = new NativeString(self.length + 1)
                var out_index = 0
 
                var myitems = self.items
@@ -994,7 +1049,7 @@ class FlatString
 
        redef fun to_lower
        do
-               var outstr = calloc_string(self.length + 1)
+               var outstr = new NativeString(self.length + 1)
                var out_index = 0
 
                var myitems = self.items
@@ -1039,7 +1094,7 @@ class FlatString
                if real_items != null then
                        return real_items.as(not null)
                else
-                       var newItems = calloc_string(length + 1)
+                       var newItems = new NativeString(length + 1)
                        self.items.copy_to(newItems, length, index_from, 0)
                        newItems[length] = '\0'
                        self.real_items = newItems
@@ -1117,7 +1172,7 @@ class FlatString
 
                var total_length = my_length + its_length
 
-               var target_string = calloc_string(my_length + its_length + 1)
+               var target_string = new NativeString(my_length + its_length + 1)
 
                self.items.copy_to(target_string, my_length, index_from, 0)
                if s isa FlatString then
@@ -1148,7 +1203,7 @@ class FlatString
 
                var my_items = self.items
 
-               var target_string = calloc_string((final_length) + 1)
+               var target_string = new NativeString(final_length + 1)
 
                target_string[final_length] = '\0'
 
@@ -1446,7 +1501,7 @@ class FlatBuffer
                # The COW flag can be set at false here, since
                # it does a copy of the current `Buffer`
                written = false
-               var a = calloc_string(c+1)
+               var a = new NativeString(c+1)
                if length > 0 then items.copy_to(a, length, 0, 0)
                items = a
                capacity = c
@@ -1462,7 +1517,7 @@ class FlatBuffer
        redef fun to_cstring
        do
                if is_dirty then
-                       var new_native = calloc_string(length + 1)
+                       var new_native = new NativeString(length + 1)
                        new_native[length] = '\0'
                        if length > 0 then items.copy_to(new_native, length, 0, 0)
                        real_items = new_native
@@ -1478,7 +1533,7 @@ class FlatBuffer
        do
                capacity = s.length + 1
                length = s.length
-               items = calloc_string(capacity)
+               items = new NativeString(capacity)
                if s isa FlatString then
                        s.items.copy_to(items, length, s.index_from, 0)
                else if s isa FlatBuffer then
@@ -1498,7 +1553,7 @@ class FlatBuffer
        do
                assert cap >= 0
                # _items = new NativeString.calloc(cap)
-               items = calloc_string(cap+1)
+               items = new NativeString(cap+1)
                capacity = cap
                length = 0
        end
@@ -1555,7 +1610,7 @@ class FlatBuffer
        redef fun reverse
        do
                written = false
-               var ns = calloc_string(capacity)
+               var ns = new NativeString(capacity)
                var si = length - 1
                var ni = 0
                var it = items
@@ -1626,7 +1681,6 @@ end
 
 private class FlatBufferCharView
        super BufferCharView
-       super StringCapable
 
        redef type SELFTYPE: FlatBuffer
 
@@ -2062,7 +2116,6 @@ end
 
 # Native strings are simple C char *
 extern class NativeString `{ char* `}
-       super StringCapable
        # Creates a new NativeString with a capacity of `length`
        new(length: Int) is intern
        fun [](index: Int): Char is intern
@@ -2088,26 +2141,21 @@ extern class NativeString `{ char* `}
        do
                assert length >= 0
                var str = new FlatString.with_infos(self, length, 0, length - 1)
-               str.real_items = self
                return str
        end
 
        fun to_s_with_copy: FlatString
        do
                var length = cstring_length
-               var new_self = calloc_string(length + 1)
+               var new_self = new NativeString(length + 1)
                copy_to(new_self, length, 0, 0)
                var str = new FlatString.with_infos(new_self, length, 0, length - 1)
-               str.real_items = self
+               new_self[length] = '\0'
+               str.real_items = new_self
                return str
        end
 end
 
-# StringCapable objects can create native strings
-interface StringCapable
-       protected fun calloc_string(size: Int): NativeString is intern
-end
-
 redef class Sys
        private var args_cache: nullable Sequence[String]