Merge: new `with` statement
[nit.git] / lib / standard / string.nit
index db43964..409b4ed 100644 (file)
@@ -531,6 +531,14 @@ abstract class Text
        #
        #     assert "abAB12<>&".escape_to_c         == "abAB12<>&"
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
+       #
+       # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
+       # Three digits are always used to avoid following digits to be interpreted as an element
+       # of the octal sequence.
+       #
+       #     assert "{0.ascii}{1.ascii}{8.ascii}{31.ascii}{32.ascii}".escape_to_c == "\\000\\001\\010\\037 "
+       #
+       # The exceptions are the common `\t` and `\n`.
        fun escape_to_c: String
        do
                var b = new FlatBuffer
@@ -541,7 +549,7 @@ abstract class Text
                        else if c == '\t' then
                                b.append("\\t")
                        else if c == '\0' then
-                               b.append("\\0")
+                               b.append("\\000")
                        else if c == '"' then
                                b.append("\\\"")
                        else if c == '\'' then
@@ -549,7 +557,17 @@ abstract class Text
                        else if c == '\\' then
                                b.append("\\\\")
                        else if c.ascii < 32 then
-                               b.append("\\{c.ascii.to_base(8, false)}")
+                               b.add('\\')
+                               var oct = c.ascii.to_base(8, false)
+                               # Force 3 octal digits since it is the
+                               # maximum allowed in the C specification
+                               if oct.length == 1 then
+                                       b.add('0')
+                                       b.add('0')
+                               else if oct.length == 2 then
+                                       b.add('0')
+                               end
+                               b.append(oct)
                        else
                                b.add(c)
                        end
@@ -846,6 +864,23 @@ abstract class FlatText
        # Real items, used as cache for to_cstring is called
        private var real_items: nullable NativeString = null
 
+       # Returns a char* starting at position `index_from`
+       #
+       # WARNING: If you choose to use this service, be careful of the following.
+       #
+       # Strings and NativeString are *ideally* always allocated through a Garbage Collector.
+       # Since the GC tracks the use of the pointer for the beginning of the char*, it may be
+       # deallocated at any moment, rendering the pointer returned by this function invalid.
+       # Any access to freed memory may very likely cause undefined behaviour or a crash.
+       # (Failure to do so will most certainly result in long and painful debugging hours)
+       #
+       # The only safe use of this pointer is if it is ephemeral (e.g. read in a C function
+       # then immediately return).
+       #
+       # As always, do not modify the content of the String in C code, if this is what you want
+       # copy locally the char* as Nit Strings are immutable.
+       private fun fast_cstring: NativeString is abstract
+
        redef var length: Int = 0
 
        redef fun output
@@ -1101,6 +1136,8 @@ class FlatString
                return native.to_s_with_length(self.length)
        end
 
+       redef fun fast_cstring do return items.fast_cstring(index_from)
+
        redef fun substring(from, count)
        do
                assert count >= 0
@@ -1549,6 +1586,8 @@ class FlatBuffer
 
        private var capacity: Int = 0
 
+       redef fun fast_cstring do return items.fast_cstring(0)
+
        redef fun substrings do return new FlatSubstringsIter(self)
 
        # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
@@ -2271,6 +2310,12 @@ extern class NativeString `{ char* `}
        # Creates a new NativeString with a capacity of `length`
        new(length: Int) is intern
 
+       # Returns a char* starting at `index`.
+       #
+       # WARNING: Unsafe for extern code, use only for temporary
+       # pointer manipulation purposes (e.g. write to file or such)
+       fun fast_cstring(index: Int): NativeString is intern
+
        # Get char at `index`.
        fun [](index: Int): Char is intern