1 /*
2    Copyright (c) 2014, 2015 Oracle and/or its affiliates. All rights reserved.
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 ABSTRACT_OPTION_INCLUDED
26 #define ABSTRACT_OPTION_INCLUDED
27 
28 #include <string>
29 #include <vector>
30 #include "my_getopt.h"
31 #include "i_option_changed_listener.h"
32 #include "i_callable.h"
33 
34 
35 namespace Mysql{
36 namespace Tools{
37 namespace Base{
38 namespace Options{
39 
40 class Abstract_options_provider;
41 
42 /**
43   Abstract base with common option functionalities.
44  */
45 template<typename T_type> class Abstract_option : public I_option
46 {
47 public:
48   virtual ~Abstract_option();
49 
50   /**
51     Adds new callback for this option for option_parsed() event to callback
52     chain.
53     I_Callable can be replaced with std::Function<void(char*)> once we get
54     one.
55    */
56   T_type* add_callback(Mysql::I_callable<void, char*>* callback);
57 
58   /**
59     Sets optid to given character to make possible usage of short option
60     alternative.
61    */
62   T_type* set_short_character(char code);
63 
64 protected:
65   /**
66     Constructs new option.
67     @param value Pointer to object to receive option value.
68     @param var_type my_getopt internal option type.
69     @param name Name of option. It is used in command line option name as
70       --name.
71     @param desription Description of option to be printed in --help.
72     @param default_value default value to be supplied to internal option
73       data structure.
74    */
75   Abstract_option(void* value, ulong var_type, std::string name,
76     std::string description, uint64 default_value);
77 
78   /**
79     Returns my_getopt internal option data structure representing this option.
80     To be used by Abstract_options_provider when preparing options array to
81     return.
82    */
83   my_option get_my_option();
84 
85   /**
86     Method to set listener on option changed events.
87     For use from Abstract_options_provider class only.
88    */
89   void set_option_changed_listener(I_option_changed_listener* listener);
90 
91   my_option m_option_structure;
92 
93 private:
94   void call_callbacks(char* argument);
95 
96   std::vector<Mysql::I_callable<void, char*>*> m_callbacks;
97   I_option_changed_listener* m_option_changed_listener;
98 
99   friend class Abstract_options_provider;
100 };
101 
~Abstract_option()102 template<typename T_type> Abstract_option<T_type>::~Abstract_option()
103 {
104   my_free((void*)this->m_option_structure.name);
105   my_free((void*)this->m_option_structure.comment);
106 
107   for (std::vector<Mysql::I_callable<void, char*>*>::iterator
108     it= this->m_callbacks.begin();
109     it != this->m_callbacks.end();
110     it++)
111   {
112     delete *it;
113   }
114 }
115 
add_callback(Mysql::I_callable<void,char * > * callback)116 template<typename T_type> T_type* Abstract_option<T_type>::add_callback(
117   Mysql::I_callable<void, char*>* callback)
118 {
119   this->m_callbacks.push_back(callback);
120   return (T_type*)this;
121 }
122 
set_short_character(char code)123 template<typename T_type> T_type* Abstract_option<T_type>::set_short_character(
124   char code)
125 {
126   // Change optid to new one
127   uint32 old_optid= this->m_option_structure.id;
128   this->m_option_structure.id= (int)code;
129 
130   // Inform that it has changed
131   if (this->m_option_changed_listener != NULL)
132   {
133     this->m_option_changed_listener->notify_option_optid_changed(
134       this, old_optid);
135   }
136 
137   return (T_type*)this;
138 }
139 
Abstract_option(void * value,ulong var_type,std::string name,std::string description,uint64 default_value)140 template<typename T_type> Abstract_option<T_type>::Abstract_option(void* value,
141     ulong var_type, std::string name, std::string description,
142     uint64 default_value)
143   : m_option_changed_listener(NULL)
144 {
145   this->m_option_structure.block_size= 0;
146   this->m_option_structure.max_value= 0;
147   this->m_option_structure.min_value= 0;
148   this->m_option_structure.sub_size= 0;
149   this->m_option_structure.typelib= NULL;
150   this->m_option_structure.u_max_value= NULL;
151 
152   this->m_option_structure.app_type= this;
153   this->m_option_structure.arg_type= REQUIRED_ARG;
154   this->m_option_structure.comment= my_strdup(
155     PSI_NOT_INSTRUMENTED, description.c_str(), MYF(MY_FAE));
156   // This in future can be changed to atomic operation (compare_and_exchange)
157   this->m_option_structure.id= Abstract_option::last_optid;
158   Abstract_option::last_optid++;
159   ;
160   this->m_option_structure.def_value= default_value;
161 
162   this->m_option_structure.name= my_strdup(
163     PSI_NOT_INSTRUMENTED, name.c_str(), MYF(MY_FAE));
164   /*
165    TODO mbabij 15-04-2014: this is based on previous usages of my_option.
166    Everyone sets this the same as my_option::value, explain why.
167    */
168   this->m_option_structure.u_max_value= value;
169 
170   this->m_option_structure.value= value;
171   this->m_option_structure.var_type= var_type;
172 }
173 
get_my_option()174 template<typename T_type> my_option Abstract_option<T_type>::get_my_option()
175 {
176   return this->m_option_structure;
177 }
178 
179 template<typename T_type> void
set_option_changed_listener(I_option_changed_listener * listener)180   Abstract_option<T_type>::set_option_changed_listener(
181     I_option_changed_listener* listener)
182 {
183   DBUG_ASSERT(this->m_option_changed_listener == NULL);
184 
185   this->m_option_changed_listener= listener;
186 }
187 
call_callbacks(char * argument)188 template<typename T_type> void Abstract_option<T_type>::call_callbacks(
189   char* argument)
190 {
191   std::vector<Mysql::I_callable<void, char*>*>::iterator callback_it;
192   for (callback_it= this->m_callbacks.begin();
193     callback_it != this->m_callbacks.end(); callback_it++)
194   {
195     (**callback_it)(argument);
196   }
197 }
198 
199 }
200 }
201 }
202 }
203 
204 #endif
205