 c447e5cf15
			
		
	
	c447e5cf15
	
	
	
		
			
			See script directory for method. The script to run in the top level MaxScale directory is called maxscale-uncrustify.sh, which uses another script, list-src, from the same directory (so you need to set your PATH). The uncrustify version was 0.66.
		
			
				
	
	
		
			457 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			457 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2016 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2022-01-01
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| 
 | |
| #include "testreader.hh"
 | |
| #include <algorithm>
 | |
| #include <map>
 | |
| #include <iostream>
 | |
| 
 | |
| using std::istream;
 | |
| using std::string;
 | |
| using std::map;
 | |
| 
 | |
| namespace
 | |
| {
 | |
| 
 | |
| enum skip_action_t
 | |
| {
 | |
|     SKIP_NOTHING,       // Skip nothing.
 | |
|     SKIP_BLOCK,         // Skip until the end of next { ... }
 | |
|     SKIP_DELIMITER,     // Skip the new delimiter.
 | |
|     SKIP_LINE,          // Skip current line.
 | |
|     SKIP_NEXT_STATEMENT,// Skip statement starting on line following this line.
 | |
|     SKIP_STATEMENT,     // Skip statment starting on this line.
 | |
|     SKIP_TERMINATE,     // Cannot handle this, terminate.
 | |
| };
 | |
| 
 | |
| typedef std::map<std::string, skip_action_t> KeywordActionMapping;
 | |
| 
 | |
| static KeywordActionMapping mtl_keywords;
 | |
| static KeywordActionMapping plsql_keywords;
 | |
| 
 | |
| void init_keywords()
 | |
| {
 | |
|     struct Keyword
 | |
|     {
 | |
|         const char*   z_keyword;
 | |
|         skip_action_t action;
 | |
|     };
 | |
| 
 | |
|     static const Keyword MTL_KEYWORDS[] =
 | |
|     {
 | |
|         {"append_file",                SKIP_LINE          },
 | |
|         {"cat_file",                   SKIP_LINE          },
 | |
|         {"change_user",                SKIP_LINE          },
 | |
|         {"character_set",              SKIP_LINE          },
 | |
|         {"chmod",                      SKIP_LINE          },
 | |
|         {"connect",                    SKIP_LINE          },
 | |
|         {"connection",                 SKIP_LINE          },
 | |
|         {"copy_file",                  SKIP_LINE          },
 | |
|         {"dec",                        SKIP_LINE          },
 | |
|         {"delimiter",                  SKIP_DELIMITER     },
 | |
|         {"die",                        SKIP_LINE          },
 | |
|         {"diff_files",                 SKIP_LINE          },
 | |
|         {"dirty_close",                SKIP_LINE          },
 | |
|         {"disable_abort_on_error",     SKIP_LINE          },
 | |
|         {"disable_connect_log",        SKIP_LINE          },
 | |
|         {"disable_info",               SKIP_LINE          },
 | |
|         {"disable_metadata",           SKIP_LINE          },
 | |
|         {"disable_parsing",            SKIP_LINE          },
 | |
|         {"disable_ps_protocol",        SKIP_LINE          },
 | |
|         {"disable_query_log",          SKIP_LINE          },
 | |
|         {"disable_reconnect",          SKIP_LINE          },
 | |
|         {"disable_result_log",         SKIP_LINE          },
 | |
|         {"disable_rpl_parse",          SKIP_LINE          },
 | |
|         {"disable_session_track_info", SKIP_LINE          },
 | |
|         {"disable_warnings",           SKIP_LINE          },
 | |
|         {"disconnect",                 SKIP_LINE          },
 | |
|         {"echo",                       SKIP_LINE          },
 | |
|         {"enable_abort_on_error",      SKIP_LINE          },
 | |
|         {"enable_connect_log",         SKIP_LINE          },
 | |
|         {"enable_info",                SKIP_LINE          },
 | |
|         {"enable_metadata",            SKIP_LINE          },
 | |
|         {"enable_parsing",             SKIP_LINE          },
 | |
|         {"enable_ps_protocol",         SKIP_LINE          },
 | |
|         {"enable_query_log",           SKIP_LINE          },
 | |
|         {"enable_reconnect",           SKIP_LINE          },
 | |
|         {"enable_result_log",          SKIP_LINE          },
 | |
|         {"enable_rpl_parse",           SKIP_LINE          },
 | |
|         {"enable_session_track_info",  SKIP_LINE          },
 | |
|         {"enable_warnings",            SKIP_LINE          },
 | |
|         {"end_timer",                  SKIP_LINE          },
 | |
|         {"error",                      SKIP_NEXT_STATEMENT},
 | |
|         {"eval",                       SKIP_STATEMENT     },
 | |
|         {"exec",                       SKIP_LINE          },
 | |
|         {"file_exists",                SKIP_LINE          },
 | |
|         {"horizontal_results",         SKIP_LINE          },
 | |
|         {"inc",                        SKIP_LINE          },
 | |
|         {"let",                        SKIP_LINE          },
 | |
|         {"let",                        SKIP_LINE          },
 | |
|         {"list_files",                 SKIP_LINE          },
 | |
|         {"list_files_append_file",     SKIP_LINE          },
 | |
|         {"list_files_write_file",      SKIP_LINE          },
 | |
|         {"lowercase_result",           SKIP_LINE          },
 | |
|         {"mkdir",                      SKIP_LINE          },
 | |
|         {"move_file",                  SKIP_LINE          },
 | |
|         {"output",                     SKIP_LINE          },
 | |
|         {"perl",                       SKIP_TERMINATE     },
 | |
|         {"ping",                       SKIP_LINE          },
 | |
|         {"print",                      SKIP_LINE          },
 | |
|         {"query",                      SKIP_LINE          },
 | |
|         {"query_get_value",            SKIP_LINE          },
 | |
|         {"query_horizontal",           SKIP_LINE          },
 | |
|         {"query_vertical",             SKIP_LINE          },
 | |
|         {"real_sleep",                 SKIP_LINE          },
 | |
|         {"reap",                       SKIP_LINE          },
 | |
|         {"remove_file",                SKIP_LINE          },
 | |
|         {"remove_files_wildcard",      SKIP_LINE          },
 | |
|         {"replace_column",             SKIP_LINE          },
 | |
|         {"replace_regex",              SKIP_LINE          },
 | |
|         {"replace_result",             SKIP_LINE          },
 | |
|         {"require",                    SKIP_LINE          },
 | |
|         {"reset_connection",           SKIP_LINE          },
 | |
|         {"result",                     SKIP_LINE          },
 | |
|         {"result_format",              SKIP_LINE          },
 | |
|         {"rmdir",                      SKIP_LINE          },
 | |
|         {"same_master_pos",            SKIP_LINE          },
 | |
|         {"send",                       SKIP_LINE          },
 | |
|         {"send_eval",                  SKIP_LINE          },
 | |
|         {"send_quit",                  SKIP_LINE          },
 | |
|         {"send_shutdown",              SKIP_LINE          },
 | |
|         {"skip",                       SKIP_LINE          },
 | |
|         {"sleep",                      SKIP_LINE          },
 | |
|         {"sorted_result",              SKIP_LINE          },
 | |
|         {"source",                     SKIP_LINE          },
 | |
|         {"start_timer",                SKIP_LINE          },
 | |
|         {"sync_slave_with_master",     SKIP_LINE          },
 | |
|         {"sync_with_master",           SKIP_LINE          },
 | |
|         {"system",                     SKIP_LINE          },
 | |
|         {"vertical_results",           SKIP_LINE          },
 | |
|         {"write_file",                 SKIP_LINE          },
 | |
|     };
 | |
| 
 | |
|     const size_t N_MTL_KEYWORDS = sizeof(MTL_KEYWORDS) / sizeof(MTL_KEYWORDS[0]);
 | |
| 
 | |
|     for (size_t i = 0; i < N_MTL_KEYWORDS; ++i)
 | |
|     {
 | |
|         mtl_keywords[MTL_KEYWORDS[i].z_keyword] = MTL_KEYWORDS[i].action;
 | |
|     }
 | |
| 
 | |
|     static const Keyword PLSQL_KEYWORDS[] =
 | |
|     {
 | |
|         {"exit",  SKIP_LINE },
 | |
|         {"if",    SKIP_BLOCK},
 | |
|         {"while", SKIP_BLOCK},
 | |
|     };
 | |
| 
 | |
|     const size_t N_PLSQL_KEYWORDS = sizeof(PLSQL_KEYWORDS) / sizeof(PLSQL_KEYWORDS[0]);
 | |
| 
 | |
|     for (size_t i = 0; i < N_PLSQL_KEYWORDS; ++i)
 | |
|     {
 | |
|         plsql_keywords[PLSQL_KEYWORDS[i].z_keyword] = PLSQL_KEYWORDS[i].action;
 | |
|     }
 | |
| }
 | |
| 
 | |
| skip_action_t get_action(const string& keyword, const string& delimiter)
 | |
| {
 | |
|     skip_action_t action = SKIP_NOTHING;
 | |
| 
 | |
|     string key(keyword);
 | |
|     std::transform(key.begin(), key.end(), key.begin(), ::tolower);
 | |
| 
 | |
|     if (key == "delimiter")
 | |
|     {
 | |
|         // DELIMITER is directly understood by the parser so it needs to
 | |
|         // be handled explicitly.
 | |
|         action = SKIP_DELIMITER;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         KeywordActionMapping::iterator i = mtl_keywords.find(key);
 | |
| 
 | |
|         if (i != mtl_keywords.end())
 | |
|         {
 | |
|             action = i->second;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ((action == SKIP_NOTHING) && (delimiter == ";"))
 | |
|     {
 | |
|         // Some mysqltest keywords, such as "while", "exit" and "if" are also
 | |
|         // PL/SQL keywords. We assume they can only be used in the former role,
 | |
|         // if the delimiter is ";".
 | |
|         KeywordActionMapping::iterator i = plsql_keywords.find(key);
 | |
| 
 | |
|         if (i != plsql_keywords.end())
 | |
|         {
 | |
|             action = i->second;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return action;
 | |
| }
 | |
| 
 | |
| inline void ltrim(std::string& s)
 | |
| {
 | |
|     s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
 | |
| }
 | |
| 
 | |
| inline void rtrim(std::string& s)
 | |
| {
 | |
|     s.erase(std::find_if(s.rbegin(),
 | |
|                          s.rend(),
 | |
|                          std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
 | |
|             s.end());
 | |
| }
 | |
| 
 | |
| void trim(std::string& s)
 | |
| {
 | |
|     ltrim(s);
 | |
|     rtrim(s);
 | |
| }
 | |
| }
 | |
| 
 | |
| namespace maxscale
 | |
| {
 | |
| 
 | |
| TestReader::TestReader(istream& in,
 | |
|                        size_t   line)
 | |
|     : m_in(in)
 | |
|     , m_line(line)
 | |
|     , m_delimiter(";")
 | |
| {
 | |
|     init();
 | |
| }
 | |
| 
 | |
| TestReader::result_t TestReader::get_statement(std::string& stmt)
 | |
| {
 | |
|     bool error = false;     // Whether an error has occurred.
 | |
|     bool found = false;     // Whether we have found a statement.
 | |
|     bool skip = false;      // Whether next statement should be skipped.
 | |
| 
 | |
|     stmt.clear();
 | |
| 
 | |
|     string line;
 | |
| 
 | |
|     while (!error && !found && std::getline(m_in, line))
 | |
|     {
 | |
|         trim(line);
 | |
| 
 | |
|         m_line++;
 | |
| 
 | |
|         if (!line.empty() && (line.at(0) != '#'))
 | |
|         {
 | |
|             // Ignore comment lines.
 | |
|             if ((line.substr(0, 3) == "-- ") || (line.substr(0, 1) == "#"))
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (!skip)
 | |
|             {
 | |
|                 if (line.substr(0, 2) == "--")
 | |
|                 {
 | |
|                     line = line.substr(2);
 | |
|                     trim(line);
 | |
|                 }
 | |
| 
 | |
|                 string::iterator i = std::find_if(line.begin(),
 | |
|                                                   line.end(),
 | |
|                                                   std::ptr_fun<int, int>(std::isspace));
 | |
|                 string keyword = line.substr(0, i - line.begin());
 | |
| 
 | |
|                 skip_action_t action = get_action(keyword, m_delimiter);
 | |
| 
 | |
|                 switch (action)
 | |
|                 {
 | |
|                 case SKIP_NOTHING:
 | |
|                     break;
 | |
| 
 | |
|                 case SKIP_BLOCK:
 | |
|                     skip_block();
 | |
|                     continue;
 | |
| 
 | |
|                 case SKIP_DELIMITER:
 | |
|                     line = line.substr(i - line.begin());
 | |
|                     trim(line);
 | |
|                     if (line.length() > 0)
 | |
|                     {
 | |
|                         if (line.length() >= m_delimiter.length())
 | |
|                         {
 | |
|                             if (line.substr(line.length() - m_delimiter.length()) == m_delimiter)
 | |
|                             {
 | |
|                                 m_delimiter = line.substr(0, line.length() - m_delimiter.length());
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 m_delimiter = line;
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             m_delimiter = line;
 | |
|                         }
 | |
|                     }
 | |
|                     continue;
 | |
| 
 | |
|                 case SKIP_LINE:
 | |
|                     continue;
 | |
| 
 | |
|                 case SKIP_NEXT_STATEMENT:
 | |
|                     skip = true;
 | |
|                     continue;
 | |
| 
 | |
|                 case SKIP_STATEMENT:
 | |
|                     skip = true;
 | |
|                     break;
 | |
| 
 | |
|                 case SKIP_TERMINATE:
 | |
|                     MXS_ERROR("Cannot handle line %u: %s", (unsigned)m_line, line.c_str());
 | |
|                     error = true;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             stmt += line;
 | |
| 
 | |
|             // Look for a ';'. If we are dealing with a one line test statment
 | |
|             // the delimiter will in practice be ';' and if it is a multi-line
 | |
|             // test statement then the test-script delimiter will be something
 | |
|             // else than ';' and ';' will be the delimiter used in the multi-line
 | |
|             // statement.
 | |
|             string::size_type i = line.find(";");
 | |
| 
 | |
|             if (i != string::npos)
 | |
|             {
 | |
|                 // Is there a "-- " or "#" after the delimiter?
 | |
|                 if ((line.find("-- ", i) != string::npos)
 | |
|                     || (line.find("#", i) != string::npos))
 | |
|                 {
 | |
|                     // If so, add a newline. Otherwise the rest of the
 | |
|                     // statement would be included in the comment.
 | |
|                     stmt += "\n";
 | |
|                 }
 | |
| 
 | |
|                 // This is somewhat fragile as a ";", "#" or "-- " inside a
 | |
|                 // string will trigger this behaviour...
 | |
|             }
 | |
| 
 | |
|             string c;
 | |
| 
 | |
|             if (line.length() >= m_delimiter.length())
 | |
|             {
 | |
|                 c = line.substr(line.length() - m_delimiter.length());
 | |
|             }
 | |
| 
 | |
|             if (c == m_delimiter)
 | |
|             {
 | |
|                 if (c != ";")
 | |
|                 {
 | |
|                     // If the delimiter was something else but ';' we need to
 | |
|                     // remove that before giving the line to the classifiers.
 | |
|                     stmt.erase(stmt.length() - m_delimiter.length());
 | |
|                 }
 | |
| 
 | |
|                 if (!skip)
 | |
|                 {
 | |
|                     found = true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     skip = false;
 | |
|                     stmt.clear();
 | |
|                 }
 | |
|             }
 | |
|             else if (!skip)
 | |
|             {
 | |
|                 stmt += " ";
 | |
|             }
 | |
|         }
 | |
|         else if (line.substr(0, 7) == "--error")
 | |
|         {
 | |
|             // Next statement is supposed to fail, no need to check.
 | |
|             skip = true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     result_t result;
 | |
| 
 | |
|     if (error)
 | |
|     {
 | |
|         result = RESULT_ERROR;
 | |
|     }
 | |
|     else if (found)
 | |
|     {
 | |
|         result = RESULT_STMT;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         result = RESULT_EOF;
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| // static
 | |
| void TestReader::init()
 | |
| {
 | |
|     static bool inited = false;
 | |
| 
 | |
|     if (!inited)
 | |
|     {
 | |
|         inited = true;
 | |
| 
 | |
|         init_keywords();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void TestReader::skip_block()
 | |
| {
 | |
|     int c;
 | |
| 
 | |
|     // Find first '{'
 | |
|     while (m_in && ((c = m_in.get()) != '{'))
 | |
|     {
 | |
|         if (c == '\n')
 | |
|         {
 | |
|             ++m_line;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     int n = 1;
 | |
| 
 | |
|     while ((n > 0) && m_in)
 | |
|     {
 | |
|         c = m_in.get();
 | |
| 
 | |
|         switch (c)
 | |
|         {
 | |
|         case '{':
 | |
|             ++n;
 | |
|             break;
 | |
| 
 | |
|         case '}':
 | |
|             --n;
 | |
|             break;
 | |
| 
 | |
|         case '\n':
 | |
|             ++m_line;
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             ;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| }
 |