]> git.saurik.com Git - cycript.git/blobdiff - Output.cpp
Also use CXType walker to for function prototypes.
[cycript.git] / Output.cpp
index 2c2ef36ab2785acb3db7e8eabe722ff8bf0fe62a..50cc836c822ef5b5ff26a74a687d72f598c0783f 100644 (file)
 
 #include "Syntax.hpp"
 
-void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) {
-    bool single;
-    if (c)
-        single = false;
+enum CYStringType {
+    CYStringTypeSingle,
+    CYStringTypeDouble,
+    CYStringTypeTemplate,
+};
+
+void CYStringify(std::ostringstream &str, const char *data, size_t size, CYStringifyMode mode) {
+    if (size == 0) {
+        str << "\"\"";
+        return;
+    }
+
+    unsigned quot(0), apos(0), tick(0), line(0);
+    for (const char *value(data), *end(data + size); value != end; ++value)
+        switch (*value) {
+            case '"': ++quot; break;
+            case '\'': ++apos; break;
+            case '`': ++tick; break;
+            case '$': ++tick; break;
+            case '\n': ++line; break;
+        }
+
+    bool split;
+    if (mode != CYStringifyModeCycript)
+        split = false;
     else {
-        unsigned quot(0), apos(0);
-        for (const char *value(data), *end(data + size); value != end; ++value)
-            if (*value == '"')
-                ++quot;
-            else if (*value == '\'')
-                ++apos;
-
-        single = quot > apos;
+        double ratio(double(line) / size);
+        split = size > 10 && line > 2 && ratio > 0.005 && ratio < 0.10;
     }
 
-    str << (single ? '\'' : '"');
+    CYStringType type;
+    if (mode == CYStringifyModeNative)
+        type = CYStringTypeDouble;
+    else if (split)
+        type = CYStringTypeTemplate;
+    else if (quot > apos)
+        type = CYStringTypeSingle;
+    else
+        type = CYStringTypeDouble;
+
+    bool parens(split && mode != CYStringifyModeNative && type != CYStringTypeTemplate);
+    if (parens)
+        str << '(';
+
+    char border;
+    switch (type) {
+        case CYStringTypeSingle: border = '\''; break;
+        case CYStringTypeDouble: border = '"'; break;
+        case CYStringTypeTemplate: border = '`'; break;
+    }
+
+    str << border;
+
+    bool space(false);
 
     for (const char *value(data), *end(data + size); value != end; ++value)
-        switch (uint8_t next = *value) {
+        if (*value == ' ') {
+            space = true;
+            str << ' ';
+        } else { switch (uint8_t next = *value) {
             case '\\': str << "\\\\"; break;
             case '\b': str << "\\b"; break;
             case '\f': str << "\\f"; break;
-            case '\n': str << "\\n"; break;
             case '\r': str << "\\r"; break;
             case '\t': str << "\\t"; break;
             case '\v': str << "\\v"; break;
 
+            case '\a':
+                if (mode == CYStringifyModeNative)
+                    str << "\\a";
+                else goto simple;
+            break;
+
+            case '\n':
+                if (!split)
+                    str << "\\n";
+                /*else if (mode == CYStringifyModeNative)
+                    str << border << "\\\n" << border;*/
+                else if (type != CYStringTypeTemplate)
+                    str << border << '+' << border;
+                else if (!space)
+                    str << '\n';
+                else
+                    str << "\\n\\\n";
+            break;
+
+            case '$':
+                if (type == CYStringTypeTemplate)
+                    str << "\\$";
+                else goto simple;
+            break;
+
+            case '`':
+                if (type == CYStringTypeTemplate)
+                    str << "\\`";
+                else goto simple;
+            break;
+
             case '"':
-                if (!single)
+                if (type == CYStringTypeDouble)
                     str << "\\\"";
                 else goto simple;
             break;
 
             case '\'':
-                if (single)
+                if (type == CYStringTypeSingle)
                     str << "\\'";
                 else goto simple;
             break;
 
             case '\0':
-                if (value[1] >= '0' && value[1] <= '9')
+                if (mode != CYStringifyModeNative && value[1] >= '0' && value[1] <= '9')
                     str << "\\x00";
                 else
                     str << "\\0";
@@ -74,6 +145,8 @@ void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c)
             default:
                 if (next >= 0x20 && next < 0x7f) simple:
                     str << *value;
+                else if (mode == CYStringifyModeNative)
+                    str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value & 0xff);
                 else {
                     unsigned levels(1);
                     if ((next & 0x80) != 0)
@@ -93,9 +166,12 @@ void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c)
                         str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
                     }
                 }
-        }
+        } space = false; }
 
-    str << (single ? '\'' : '"');
+    str << border;
+
+    if (parens)
+        str << ')';
 }
 
 void CYNumerify(std::ostringstream &str, double value) {
@@ -948,7 +1024,7 @@ void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) co
 
 void CYString::Output(CYOutput &out, CYFlags flags) const {
     std::ostringstream str;
-    CYStringify(str, value_, size_);
+    CYStringify(str, value_, size_, CYStringifyModeLegacy);
     out << str.str().c_str();
 }
 
@@ -1109,6 +1185,15 @@ void CYTypeError::Output(CYOutput &out) const {
     out << "@error";
 }
 
+void CYTypeFloating::Output(CYOutput &out) const {
+    switch (length_) {
+        case 0: out << "float"; break;
+        case 1: out << "double"; break;
+        case 2: out << "long" << ' ' << "double"; break;
+        default: _assert(false);
+    }
+}
+
 void CYTypeInt128::Output(CYOutput &out) const {
     switch (signing_) {
         case CYTypeNeutral: break;