1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef CPCD_PARSER_HPP
26 #define CPCD_PARSER_HPP
27 
28 #include "Vector.hpp"
29 #include "Properties.hpp"
30 #include "InputStream.hpp"
31 
32 class ParserImpl;
33 template<class T> struct ParserRow;
34 
35 //#define PARSER_DEBUG
36 #ifdef PARSER_DEBUG
37 #include "NdbOut.hpp"
38 #define DEBUG(x) \
39   ndbout_c("%s:%d:%s", __FILE__, __LINE__, x);
40 #else
41 #define DEBUG(x)
42 #endif
43 
44 /**
45  * A generic parser
46  */
47 template<class T>
48 class Parser {
49 public:
50   /**
51    * Status for parser
52    */
53   enum ParserStatus {
54     Ok                     = 0,
55     Eof                    = 1,
56     NoLine                 = 2,
57     EmptyLine              = 3,
58     UnknownCommand         = 4,
59     UnknownArgument        = 5,
60     TypeMismatch           = 6,
61     InvalidArgumentFormat  = 7,
62     UnknownArgumentType    = 8,
63     CommandWithoutFunction = 9,
64     ArgumentGivenTwice     = 10,
65     ExternalStop           = 11,
66     MissingMandatoryArgument = 12
67   };
68 
69   /**
70    * Context for parse
71    */
72   class Context {
73   public:
Context()74     Context() { m_mutex= NULL; }
75     ParserStatus m_status;
76     const ParserRow<T> * m_currentCmd;
77     const ParserRow<T> * m_currentArg;
78     char * m_currentToken;
79     STATIC_CONST(MaxParseBytes = 512);
80     char m_tokenBuffer[ MaxParseBytes ];
81     NdbMutex *m_mutex;
82 
83     Vector<const ParserRow<T> *> m_aliasUsed;
84   };
85 
86   /**
87    * Initialize parser
88    */
89   Parser(const ParserRow<T> rows[], class InputStream & in);
90   ~Parser();
91 
92   /**
93    * Run parser
94    */
95   bool run(Context &, T &, volatile bool * stop = 0) const;
96 
97   /**
98    * Parse only one entry and return Properties object representing
99    * the message
100    */
101   const Properties *parse(Context &, T &);
102 
103 private:
104   ParserImpl * impl;
105 };
106 
107 template<class T>
108 struct ParserRow {
109 public:
110   enum Type { Cmd, Arg, CmdAlias, ArgAlias, End }; // Put new types before end
111   enum ArgType { String, Int, Properties };
112   enum ArgRequired { Mandatory, Optional };
113   enum ArgMinMax { CheckMinMax, IgnoreMinMax };
114 
115   const char * name;
116   const char * realName;
117   Type type;
118   ArgType argType;
119   ArgRequired argRequired;
120   ArgMinMax argMinMax;
121   int minVal;
122   int maxVal;
123   void (T::* function)(typename Parser<T>::Context & ctx,
124 		       const class Properties& args);
125   const char * description;
126   void *user_value;
127 };
128 
129 /**
130  * The void* equivalent implementation
131  */
132 class ParserImpl {
133 public:
134   class Dummy {};
135   typedef ParserRow<Dummy> DummyRow;
136   typedef Parser<Dummy>::Context Context;
137 
138 
139   ParserImpl(const DummyRow rows[], class InputStream & in);
140   ~ParserImpl();
141 
142   bool run(Context *ctx, const class Properties **, volatile bool *) const ;
143 
144   static const DummyRow* matchCommand(Context*, const char*, const DummyRow*);
145   static const DummyRow* matchArg(Context*, const char *, const DummyRow *);
146   static bool parseArg(Context*, char*, const DummyRow*, Properties*);
147   static bool checkMandatory(Context*, const Properties*);
148 private:
149   const DummyRow * const m_rows;
150   class InputStream & input;
151 
152   void check_parser_rows(const DummyRow* rows) const;
153 };
154 
155 template<class T>
156 inline
Parser(const ParserRow<T> rows[],class InputStream & in)157 Parser<T>::Parser(const ParserRow<T> rows[], class InputStream & in) {
158   impl = new ParserImpl((ParserImpl::DummyRow *)rows, in);
159 }
160 
161 template<class T>
162 inline
~Parser()163 Parser<T>::~Parser(){
164   delete impl;
165 }
166 
167 template<class T>
168 inline
169 bool
run(Context & ctx,T & t,volatile bool * stop) const170 Parser<T>::run(Context & ctx, T & t, volatile bool * stop) const {
171   const Properties * p;
172   DEBUG("Executing Parser<T>::run");
173   if(impl->run((ParserImpl::Context*)&ctx, &p, stop)){
174     const ParserRow<T> * cmd = ctx.m_currentCmd; // Cast to correct type
175     if(cmd == 0){
176       /**
177        * Should happen if run returns true
178        */
179       abort();
180     }
181 
182     for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++){
183       const ParserRow<T> * alias = ctx.m_aliasUsed[i];
184       if(alias->function != 0){
185 	/**
186 	 * Report alias usage with callback (if specified by user)
187 	 */
188 	DEBUG("Alias usage with callback");
189 	(t.* alias->function)(ctx, * p);
190       }
191     }
192 
193     if(cmd->function == 0){
194       ctx.m_status = CommandWithoutFunction;
195       DEBUG("CommandWithoutFunction");
196       delete p;
197       return false;
198     }
199     (t.* cmd->function)(ctx, * p); // Call the function
200     delete p;
201     return true;
202   }
203   DEBUG("");
204   return false;
205 }
206 
207 template<class T>
208 inline
209 const Properties *
parse(Context & ctx,T & t)210 Parser<T>::parse(Context &ctx, T &t) {
211   const Properties * p;
212   volatile bool stop = false;
213   DEBUG("Executing Parser<T>::parse");
214 
215   if(impl->run((ParserImpl::Context*)&ctx, &p, &stop)){
216     const ParserRow<T> * cmd = ctx.m_currentCmd; // Cast to correct type
217     if(cmd == 0){
218       /**
219        * Should happen if run returns true
220        */
221       abort();
222     }
223 
224     for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++){
225       const ParserRow<T> * alias = ctx.m_aliasUsed[i];
226       if(alias->function != 0){
227 	/**
228 	 * Report alias usage with callback (if specified by user)
229 	 */
230 	DEBUG("Alias usage with callback");
231 	(t.* alias->function)(ctx, * p);
232       }
233     }
234 
235     if(cmd->function == 0){
236       DEBUG("CommandWithoutFunction");
237       ctx.m_status = CommandWithoutFunction;
238       return p;
239     }
240     return p;
241   }
242   DEBUG("");
243   return NULL;
244 }
245 
246 #endif
247