X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/string.nit b/lib/standard/string.nit index e78f655..8db6a4e 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -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 @@ -538,8 +546,10 @@ abstract class Text var c = chars[i] if c == '\n' then b.append("\\n") + 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 @@ -547,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 @@ -844,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 @@ -1099,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 @@ -1547,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` @@ -1911,9 +1952,7 @@ end redef class Int # Wrapper of strerror C function - private fun strerror_ext: NativeString is extern `{ - return strerror(recv); - `} + private fun strerror_ext: NativeString is extern "strerror" # Returns a string describing error number fun strerror: String do return strerror_ext.to_s @@ -1953,6 +1992,10 @@ redef class Int # assert 1.to_s == "1" # assert (-123).to_s == "-123" redef fun to_s do + # Fast case for common numbers + if self == 0 then return "0" + if self == 1 then return "1" + var nslen = int_to_s_len var ns = new NativeString(nslen + 1) ns[nslen] = '\0' @@ -2180,6 +2223,48 @@ redef class Array[E] end end +redef class NativeArray[E] + # Join all the elements using `to_s` + # + # REQUIRE: `self isa NativeArray[String]` + # REQUIRE: all elements are initialized + fun native_to_s: String + do + assert self isa NativeArray[String] + var l = length + var na = self + var i = 0 + var sl = 0 + var mypos = 0 + while i < l do + sl += na[i].length + i += 1 + mypos += 1 + end + var ns = new NativeString(sl + 1) + ns[sl] = '\0' + i = 0 + var off = 0 + while i < mypos do + var tmp = na[i] + var tpl = tmp.length + if tmp isa FlatString then + tmp.items.copy_to(ns, tpl, tmp.index_from, off) + off += tpl + else + for j in tmp.substrings do + var s = j.as(FlatString) + var slen = s.length + s.items.copy_to(ns, slen, s.index_from, off) + off += slen + end + end + i += 1 + end + return ns.to_s_with_length(sl) + end +end + redef class Map[K,V] # Concatenate couple of 'key value'. # key and value are separated by `couple_sep`. @@ -2223,6 +2308,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