Escape " \ ', trigraphs and non printable characters using the rules of literal C strings and characters

assert "abAB12<>&".escape_to_c       == "abAB12<>&"
assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
assert "allo???!".escape_to_c        == "allo??\\?!"
assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)"
assert "??!??<??>??-".escape_to_c    == "?\\?!?\\?<?\\?>?\\?-"

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.code_point}{1.code_point}{8.code_point}{31.code_point}{32.code_point}".escape_to_c == "\\000\\001\\010\\037 "

The exceptions are the common \t and \n.

Property definitions

core $ Text :: escape_to_c
	# Escape `"` `\` `'`, trigraphs and non printable characters using the rules of literal C strings and characters
	#
	# ~~~
	# assert "abAB12<>&".escape_to_c       == "abAB12<>&"
	# assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
	# assert "allo???!".escape_to_c        == "allo??\\?!"
	# assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)"
	# assert "??!??<??>??-".escape_to_c    == "?\\?!?\\?<?\\?>?\\?-"
	# ~~~
	#
	# 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.code_point}{1.code_point}{8.code_point}{31.code_point}{32.code_point}".escape_to_c == "\\000\\001\\010\\037 "
	# ~~~
	#
	# The exceptions are the common `\t` and `\n`.
	fun escape_to_c: String
	do
		var b = new Buffer
		for i in [0..length[ do
			var c = chars[i]
			if c == '\n' then
				b.append("\\n")
			else if c == '\t' then
				b.append("\\t")
			else if c == '"' then
				b.append("\\\"")
			else if c == '\'' then
				b.append("\\\'")
			else if c == '\\' then
				b.append("\\\\")
			else if c == '?' then
				# Escape if it is the last question mark of a ANSI C trigraph.
				var j = i + 1
				if j < length then
					var next = chars[j]
					# We ignore `??'` because it will be escaped as `??\'`.
					if
						next == '!' or
						next == '(' or
						next == ')' or
						next == '-' or
						next == '/' or
						next == '<' or
						next == '=' or
						next == '>'
					then b.add('\\')
				end
				b.add('?')
			else if c.code_point < 32 then
				b.add('\\')
				var oct = c.code_point.to_base(8)
				# 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
		end
		return b.to_s
	end
lib/core/text/abstract_text.nit:664,2--733,4

core :: flat $ FlatText :: escape_to_c
	redef fun escape_to_c do
		var ln_extra = chars_to_escape_to_c
		if ln_extra == 0 then return self.to_s
		var its = _items
		var max = last_byte
		var nlen = _byte_length + ln_extra
		var nns = new CString(nlen)
		var pos = first_byte
		var opos = 0
		while pos <= max do
			var c = its[pos]
			# Special codes:
			#
			# Any byte with value < 32 is a control character
			# All their uses will be replaced by their octal
			# value in C.
			#
			# There are two exceptions however:
			#
			# * 0x09 => \t
			# * 0x0A => \n
			#
			# Aside from the code points above, the following are:
			#
			# * 0x22 => \"
			# * 0x27 => \'
			# * 0x5C => \\
			if c == u'\t' then
				nns[opos] = u'\\'
				nns[opos + 1] = u't'
				opos += 2
			else if c == u'\n' then
				nns[opos] = u'\\'
				nns[opos + 1] = u'n'
				opos += 2
			else if c == u'"' then
				nns[opos] = u'\\'
				nns[opos + 1] = u'"'
				opos += 2
			else if c == u'\'' then
				nns[opos] = u'\\'
				nns[opos + 1] = u'\''
				opos += 2
			else if c == u'\\' then
				nns[opos] = u'\\'
				nns[opos + 1] = u'\\'
				opos += 2
			else if c == u'?' then
				var j = pos + 1
				if j < length then
					var next = its[j]
					# We ignore `??'` because it will be escaped as `??\'`.
					if
						next == 0x21 or
						next == 0x28 or
						next == 0x29 or
						next == 0x2D or
						next == 0x2F or
						next == 0x3C or
						next == 0x3D or
						next == 0x3E
					then
						nns[opos] = 0x5C
						opos += 1
					end
				end
				nns[opos] = 0x3F
				opos += 1
			else if c < 32 then
				nns[opos] = u'\\'
				nns[opos + 1] = u'0'
				nns[opos + 2] = ((c & 0x38) >> 3) + u'0'
				nns[opos + 3] = (c & 0x07) + u'0'
				opos += 4
			else
				nns[opos] = c
				opos += 1
			end
			pos += 1
		end
		return nns.to_s_unsafe(nlen, copy=false, clean=false)
	end
lib/core/text/flat.nit:245,2--326,4