This creates a fresh copy of the given 0-terminated buffer. */
recording::string *
-recording::context::new_string (const char *text)
+recording::context::new_string (const char *text, bool escaped)
{
if (!text)
return NULL;
- recording::string *result = new string (this, text);
+ recording::string *result = new string (this, text, escaped);
record (result);
return result;
}
/* Constructor for gcc::jit::recording::string::string, allocating a
copy of the given text using new char[]. */
-recording::string::string (context *ctxt, const char *text)
- : memento (ctxt)
+recording::string::string (context *ctxt, const char *text, bool escaped)
+: memento (ctxt),
+ m_escaped (escaped)
{
m_len = strlen (text);
m_buffer = new char[m_len + 1];
recording::string *
recording::string::make_debug_string ()
{
- /* Hack to avoid infinite recursion into strings when logging all
- mementos: don't re-escape strings: */
- if (m_buffer[0] == '"')
+ /* Avoid infinite recursion into strings when logging all mementos:
+ don't re-escape strings: */
+ if (m_escaped)
return this;
/* Wrap in quotes and do escaping etc */
for (size_t i = 0; i < m_len ; i++)
{
char ch = m_buffer[i];
- if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
- APPEND('\\');
- APPEND(ch);
+ switch (ch)
+ {
+ default:
+ APPEND(ch);
+ break;
+ case '\t':
+ APPEND('\\');
+ APPEND('t');
+ break;
+ case '\n':
+ APPEND('\\');
+ APPEND('n');
+ break;
+ case '\\':
+ case '"':
+ APPEND('\\');
+ APPEND(ch);
+ break;
+ }
}
APPEND('"'); /* closing quote */
#undef APPEND
tmp[len] = '\0'; /* nil termintator */
- string *result = m_ctxt->new_string (tmp);
+ string *result = m_ctxt->new_string (tmp, true);
delete[] tmp;
return result;
void disassociate_from_playback ();
string *
- new_string (const char *text);
+ new_string (const char *text, bool escaped = false);
location *
new_location (const char *filename,
class string : public memento
{
public:
- string (context *ctxt, const char *text);
+ string (context *ctxt, const char *text, bool escaped);
~string ();
const char *c_str () { return m_buffer; }
private:
size_t m_len;
char *m_buffer;
+
+ /* Flag to track if this string is the result of string::make_debug_string,
+ to avoid infinite recursion when logging all mementos: don't re-escape
+ such strings. */
+ bool m_escaped;
};
class location : public memento
"((struct node *)ptr->next)->next");
}
+ /* Check string literal escaping. */
+ {
+ CHECK_RVALUE_DEBUG_STRING
+ (gcc_jit_context_new_string_literal (ctxt, ""),
+ "\"\"");
+ CHECK_RVALUE_DEBUG_STRING
+ (gcc_jit_context_new_string_literal (ctxt, "foo"),
+ "\"foo\"");
+ CHECK_RVALUE_DEBUG_STRING
+ (gcc_jit_context_new_string_literal (ctxt, "\""),
+ "\"\\\"\"");
+ CHECK_RVALUE_DEBUG_STRING
+ (gcc_jit_context_new_string_literal (ctxt, "line 1\nline 2\n"),
+ "\"line 1\\nline 2\\n\"");
+ CHECK_RVALUE_DEBUG_STRING
+ (gcc_jit_context_new_string_literal (ctxt, "foo\tbar"),
+ "\"foo\\tbar\"");
+ }
+
+#undef CHECK_RVALUE_DEBUG_STRING
#undef CHECK_LVALUE_DEBUG_STRING
}