+const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0, CREATE_METHOD_TABLE(RegExp) };
+
+RegExpFlags regExpFlags(const UString& string)
+{
+ RegExpFlags flags = NoFlags;
+
+ for (unsigned i = 0; i < string.length(); ++i) {
+ switch (string[i]) {
+ case 'g':
+ if (flags & FlagGlobal)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagGlobal);
+ break;
+
+ case 'i':
+ if (flags & FlagIgnoreCase)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
+ break;
+
+ case 'm':
+ if (flags & FlagMultiline)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagMultiline);
+ break;
+
+ default:
+ return InvalidFlags;
+ }
+ }
+
+ return flags;
+}
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+class RegExpFunctionalTestCollector {
+ // This class is not thread safe.
+protected:
+ static const char* const s_fileName;
+
+public:
+ static RegExpFunctionalTestCollector* get();
+
+ ~RegExpFunctionalTestCollector();
+
+ void outputOneTest(RegExp*, UString, int, int*, int);
+ void clearRegExp(RegExp* regExp)
+ {
+ if (regExp == m_lastRegExp)
+ m_lastRegExp = 0;
+ }
+
+private:
+ RegExpFunctionalTestCollector();
+
+ void outputEscapedUString(const UString&, bool escapeSlash = false);
+
+ static RegExpFunctionalTestCollector* s_instance;
+ FILE* m_file;
+ RegExp* m_lastRegExp;
+};
+
+const char* const RegExpFunctionalTestCollector::s_fileName = "/tmp/RegExpTestsData";
+RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::s_instance = 0;
+
+RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::get()
+{
+ if (!s_instance)
+ s_instance = new RegExpFunctionalTestCollector();
+
+ return s_instance;
+}
+
+void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, UString s, int startOffset, int* ovector, int result)
+{
+ if ((!m_lastRegExp) || (m_lastRegExp != regExp)) {
+ m_lastRegExp = regExp;
+ fputc('/', m_file);
+ outputEscapedUString(regExp->pattern(), true);
+ fputc('/', m_file);
+ if (regExp->global())
+ fputc('g', m_file);
+ if (regExp->ignoreCase())
+ fputc('i', m_file);
+ if (regExp->multiline())
+ fputc('m', m_file);
+ fprintf(m_file, "\n");
+ }
+
+ fprintf(m_file, " \"");
+ outputEscapedUString(s);
+ fprintf(m_file, "\", %d, %d, (", startOffset, result);
+ for (unsigned i = 0; i <= regExp->numSubpatterns(); i++) {
+ int subpatternBegin = ovector[i * 2];
+ int subpatternEnd = ovector[i * 2 + 1];
+ if (subpatternBegin == -1)
+ subpatternEnd = -1;
+ fprintf(m_file, "%d, %d", subpatternBegin, subpatternEnd);
+ if (i < regExp->numSubpatterns())
+ fputs(", ", m_file);
+ }
+
+ fprintf(m_file, ")\n");
+ fflush(m_file);
+}
+
+RegExpFunctionalTestCollector::RegExpFunctionalTestCollector()
+{
+ m_file = fopen(s_fileName, "r+");
+ if (!m_file)
+ m_file = fopen(s_fileName, "w+");
+
+ fseek(m_file, 0L, SEEK_END);
+}
+
+RegExpFunctionalTestCollector::~RegExpFunctionalTestCollector()
+{
+ fclose(m_file);
+ s_instance = 0;
+}
+
+void RegExpFunctionalTestCollector::outputEscapedUString(const UString& s, bool escapeSlash)
+{
+ int len = s.length();
+
+ for (int i = 0; i < len; ++i) {
+ UChar c = s[i];
+
+ switch (c) {
+ case '\0':
+ fputs("\\0", m_file);
+ break;
+ case '\a':
+ fputs("\\a", m_file);
+ break;
+ case '\b':
+ fputs("\\b", m_file);
+ break;
+ case '\f':
+ fputs("\\f", m_file);
+ break;
+ case '\n':
+ fputs("\\n", m_file);
+ break;
+ case '\r':
+ fputs("\\r", m_file);
+ break;
+ case '\t':
+ fputs("\\t", m_file);
+ break;
+ case '\v':
+ fputs("\\v", m_file);
+ break;
+ case '/':
+ if (escapeSlash)
+ fputs("\\/", m_file);
+ else
+ fputs("/", m_file);
+ break;
+ case '\"':
+ fputs("\\\"", m_file);
+ break;
+ case '\\':
+ fputs("\\\\", m_file);
+ break;
+ case '\?':
+ fputs("\?", m_file);
+ break;
+ default:
+ if (c > 0x7f)
+ fprintf(m_file, "\\u%04x", c);
+ else
+ fputc(c, m_file);
+ break;
+ }
+ }
+}