From db6463b32267b3d7c8f7f134833b17add403d0ff Mon Sep 17 00:00:00 2001 From: Murray Cumming Date: Thu, 30 Mar 2006 12:19:58 +0000 Subject: Use a default value, to show that it can be done. 2006-03-30 Murray Cumming * examples/options/main.cc: Use a default value, to show that it can be done. 2006-03-30 Armin Burgmeier * glib/src/optiongroup.ccg: default_c_arg(): Set the initial value of the C argument to the value the C++ argument has, to avoid that glibmm resets arguments to zero that were not given on the command line. --- ChangeLog | 14 +++- examples/options/main.cc | 30 ++++---- glib/src/optiongroup.ccg | 196 ++++++++++++++++++++++++++++++++++------------- glib/src/optiongroup.hg | 29 ++++--- 4 files changed, 188 insertions(+), 81 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1833e93c..e1d0184b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,18 @@ +2006-03-30 Murray Cumming + + * examples/options/main.cc: Use a default value, to show that it + can be done. + +2006-03-30 Armin Burgmeier + + * glib/src/optiongroup.ccg: default_c_arg(): Set the initial + value of the C argument to the value the C++ argument has, to avoid + that glibmm resets arguments to zero that were not given on the + command line. + 2.8.5: -2006-02-27 Cedric Gustin +2006-02-27 Cedric Gustin * README.win32: Updated for glibmm-2.8 (MS Visual Studio 2005). * glib/glibmm/ustring.h: Tag npos with GLIBMM_API, in order to diff --git a/examples/options/main.cc b/examples/options/main.cc index ac055b94..f4a40efb 100644 --- a/examples/options/main.cc +++ b/examples/options/main.cc @@ -28,7 +28,7 @@ public: virtual bool on_pre_parse(Glib::OptionContext& context, Glib::OptionGroup& group); virtual bool on_post_parse(Glib::OptionContext& context, Glib::OptionGroup& group); virtual void on_error(Glib::OptionContext& context, Glib::OptionGroup& group); - + //These int instances should live as long as the OptionGroup to which they are added, //and as long as the OptionContext to which those OptionGroups are added. int m_arg_foo; @@ -47,24 +47,25 @@ ExampleOptionGroup::ExampleOptionGroup() entry1.set_short_name('f'); entry1.set_description("The Foo"); add_entry(entry1, m_arg_foo); - + Glib::OptionEntry entry2; entry2.set_long_name("file"); entry2.set_short_name('F'); entry2.set_description("The Filename"); add_entry_filename(entry2, m_arg_filename); - + Glib::OptionEntry entry3; entry3.set_long_name("goo"); entry3.set_short_name('g'); entry3.set_description("The Goo"); + m_arg_goo = "default-goo-value"; //We can choose a default to be used if the user doesn't specify this option. add_entry(entry3, m_arg_goo); - + Glib::OptionEntry entry4; entry4.set_long_name("activate_something"); entry4.set_description("Activate something"); add_entry(entry4, m_arg_boolean); - + Glib::OptionEntry entry5; entry5.set_long_name("list"); entry5.set_short_name('l'); @@ -74,13 +75,17 @@ ExampleOptionGroup::ExampleOptionGroup() bool ExampleOptionGroup::on_pre_parse(Glib::OptionContext& context, Glib::OptionGroup& group) { - //This is called before the m_arg_* instances are given their values. + // This is called before the m_arg_* instances are given their values. + // You do not need to override this method. This is just here to show you how, + // in case you want to do any extra processing. return Glib::OptionGroup::on_pre_parse(context, group); } bool ExampleOptionGroup::on_post_parse(Glib::OptionContext& context, Glib::OptionGroup& group) { - //This is called after the m_arg_* instances are given their values. + // This is called before the m_arg_* instances are given their values. + // You do not need to override this method. This is just here to show you how, + // in case you want to do any extra processing. return Glib::OptionGroup::on_post_parse(context, group); } @@ -88,7 +93,6 @@ void ExampleOptionGroup::on_error(Glib::OptionContext& context, Glib::OptionGrou { Glib::OptionGroup::on_error(context, group); } - int main(int argc, char** argv) @@ -96,14 +100,14 @@ int main(int argc, char** argv) //This example should be executed like so: //./example --foo=1 --bar=2 --goo=abc //./example --help - + Glib::init(); - + Glib::OptionContext context; - + ExampleOptionGroup group; context.set_main_group(group); - + try { context.parse(argc, argv); @@ -118,7 +122,7 @@ int main(int argc, char** argv) " filename = " << group.m_arg_filename << std::endl << " activate_something = " << (group.m_arg_boolean ? "enabled" : "disabled") << std::endl << " goo = " << group.m_arg_goo << std::endl; - + //This one shows the results of multiple instance of the same option, such as --list=1 --list=a --list=b std::cout << " list = "; for(Glib::OptionGroup::vecustrings::const_iterator iter = group.m_arg_list.begin(); iter != group.m_arg_list.end(); ++iter) diff --git a/glib/src/optiongroup.ccg b/glib/src/optiongroup.ccg index 77d3c713..e2f5cb34 100644 --- a/glib/src/optiongroup.ccg +++ b/glib/src/optiongroup.ccg @@ -22,6 +22,7 @@ #include #include //#include +#include // g_malloc #include namespace Glib @@ -37,7 +38,7 @@ static gboolean g_callback_pre_parse(GOptionContext* context, GOptionGroup* /* g { OptionContext cppContext(context, false /* take_ownership */); //OptionGroup cppGroup(group, true /* take_copy */); //Maybe this should be option_group. - + OptionGroup* option_group = static_cast(data); if(option_group) return option_group->on_pre_parse(cppContext, *option_group); @@ -49,7 +50,7 @@ static gboolean g_callback_post_parse(GOptionContext* context, GOptionGroup* /* { OptionContext cppContext(context, false /* take_ownership */); //OptionGroup cppGroup(group, true /* take_copy */); //Maybe this should be option_group. - + OptionGroup* option_group = static_cast(data); if(option_group) { @@ -63,7 +64,7 @@ static void g_callback_error(GOptionContext* context, GOptionGroup* /* group */, { OptionContext cppContext(context, false /* take_ownership */); //OptionGroup cppGroup(group); //Maybe this should be option_group. - + OptionGroup* option_group = static_cast(data); if(option_group) return option_group->on_error(cppContext, *option_group); @@ -99,7 +100,7 @@ OptionGroup::~OptionGroup() CppOptionEntry& cpp_entry = iter->second; cpp_entry.release_c_arg(); } - + if(has_ownership_) { g_option_group_free(gobj()); @@ -110,15 +111,15 @@ OptionGroup::~OptionGroup() void OptionGroup::add_entry(const OptionEntry& entry) { //It does not copy the entry, so it needs to live as long as the group. - + //g_option_group_add_entries takes an array, with the last item in the array having a null long_name. //Hopefully this will be properly documented eventually - see bug # - + //Create a temporary array, just so we can give the correct thing to g_option_group_add_entries: GOptionEntry array[2]; array[0] = *(entry.gobj()); //Copy contents. GLIBMM_INITIALIZE_STRUCT(array[1], GOptionEntry); - + g_option_group_add_entries(gobj(), array); } @@ -157,10 +158,11 @@ void OptionGroup::add_entry_with_wrapper(const OptionEntry& entry, GOptionArg ar const Glib::ustring name = entry.get_long_name(); type_map_entries::iterator iterFind = map_entries_.find(name); if( iterFind == map_entries_.end() ) //If we have not added this entry already - { + { CppOptionEntry cppEntry; cppEntry.carg_type_ = arg_type; cppEntry.allocate_c_arg(); + cppEntry.set_c_arg_default(cpp_arg); cppEntry.cpparg_ = cpp_arg; @@ -171,36 +173,35 @@ void OptionGroup::add_entry_with_wrapper(const OptionEntry& entry, GOptionArg ar cppEntry.entry_->gobj()->arg = arg_type; cppEntry.entry_->gobj()->arg_data = cppEntry.carg_; - + //Remember the C++/C mapping so that we can use it later: map_entries_[name] = cppEntry; add_entry(*(cppEntry.entry_)); } } - + bool OptionGroup::on_pre_parse(OptionContext& /* context */, OptionGroup& /* group */) { - return true; } bool OptionGroup::on_post_parse(OptionContext& /* context */, OptionGroup& /* group */) { //Call this at the start of overrides. - + //TODO: Maybe put this in the C callback: - + //The C args have now been given values by GOption. //Convert C values to C++ values: - + for(type_map_entries::iterator iter = map_entries_.begin(); iter != map_entries_.end(); ++iter) { CppOptionEntry& cpp_entry = iter->second; cpp_entry.convert_c_to_cpp(); } - + return true; } @@ -212,20 +213,24 @@ void OptionGroup::on_error(OptionContext& /* context */, OptionGroup& /* group * OptionGroup::CppOptionEntry::CppOptionEntry() : carg_type_(G_OPTION_ARG_NONE), carg_(0), cpparg_(0), entry_(0) {} - + void OptionGroup::CppOptionEntry::allocate_c_arg() { //Create an instance of the appropriate C type. //This will be destroyed in the OptionGroup destructor. + // + //We must also call set_c_arg_default() to give these C types the specified defaults based on the C++-typed arguments. switch(carg_type_) { case G_OPTION_ARG_STRING: //The char* will be for UTF8 strins. case G_OPTION_ARG_FILENAME: //The char* will be for strings in the current locale's encoding. { char** typed_arg = new char*; - *typed_arg = 0; //The C code will allocate a char* and put it here, for us to g_free() later. + //The C code will allocate a char* and put it here, for us to g_free() later. + //Alternatively, set_c_arg_default() might allocate a char*, and the C code might or might not free and replace that. + *typed_arg = 0; carg_ = typed_arg; - + break; } case G_OPTION_ARG_INT: @@ -233,7 +238,7 @@ void OptionGroup::CppOptionEntry::allocate_c_arg() int* typed_arg = new int; *typed_arg = 0; carg_ = typed_arg; - + break; } case G_OPTION_ARG_STRING_ARRAY: @@ -242,7 +247,7 @@ void OptionGroup::CppOptionEntry::allocate_c_arg() char*** typed_arg = new char**; *typed_arg = 0; carg_ = typed_arg; - + break; } case G_OPTION_ARG_NONE: /* Actually a boolean. */ @@ -250,7 +255,88 @@ void OptionGroup::CppOptionEntry::allocate_c_arg() gboolean* typed_arg = new gboolean; *typed_arg = 0; carg_ = typed_arg; - + + break; + } + default: + { + break; + } + } +} + +void OptionGroup::CppOptionEntry::set_c_arg_default(void* cpp_arg) +{ + switch(carg_type_) + { + case G_OPTION_ARG_INT: + { + *static_cast(carg_) = *static_cast(cpp_arg); + break; + } + case G_OPTION_ARG_NONE: + { + *static_cast(carg_) = *static_cast(cpp_arg); + break; + } + case G_OPTION_ARG_STRING: + { + Glib::ustring* typed_cpp_arg = static_cast(cpp_arg); + if(typed_cpp_arg && !typed_cpp_arg->empty()) + { + const char** typed_c_arg = static_cast(carg_); + *typed_c_arg = g_strdup(typed_cpp_arg->c_str()); //Freed in release_c_arg(). + } + break; + } + case G_OPTION_ARG_FILENAME: + { + std::string* typed_cpp_arg = static_cast(cpp_arg); + if(typed_cpp_arg && !typed_cpp_arg->empty()) + { + const char** typed_c_arg = static_cast(carg_); + *typed_c_arg = g_strdup(typed_cpp_arg->c_str()); //Freed in release_c_arg(). + } + break; + } + case G_OPTION_ARG_STRING_ARRAY: + { + std::vector* typed_cpp_arg = static_cast*>(cpp_arg); + if(typed_cpp_arg) + { + std::vector& vec = *typed_cpp_arg; + const char** array = static_cast( g_malloc(sizeof(gchar*) * (vec.size() + 1)) ); + + for(std::vector::size_type i = 0; i < vec.size(); ++i) + { + array[i] = g_strdup( vec[i].c_str() ); + } + + array[vec.size()] = 0; + + const char*** typed_c_arg = static_cast(carg_); + *typed_c_arg = array; + } + break; + } + case G_OPTION_ARG_FILENAME_ARRAY: + { + std::vector* typed_cpp_arg = static_cast*>(cpp_arg); + if(typed_cpp_arg) + { + std::vector& vec = *typed_cpp_arg; + const char** array = static_cast( g_malloc(sizeof(gchar*) * (vec.size() + 1)) ); + + for(std::vector::size_type i = 0; i < vec.size(); ++i) + { + array[i] = g_strdup( vec[i].c_str() ); + } + + array[vec.size()] = 0; + + const char*** typed_c_arg = static_cast(carg_); + *typed_c_arg = array; + } break; } default: @@ -271,15 +357,15 @@ void OptionGroup::CppOptionEntry::release_c_arg() case G_OPTION_ARG_STRING: case G_OPTION_ARG_FILENAME: { - char** typed_arg = (char**)carg_; + char** typed_arg = static_cast(carg_); g_free(*typed_arg); //Free the char* string at type_arg, which was allocated by the C code. delete typed_arg; //Delete the char** that we allocated in allocate_c_arg; - + break; } case G_OPTION_ARG_INT: { - int* typed_arg = (int*)carg_; + int* typed_arg = static_cast(carg_); delete typed_arg; break; @@ -292,23 +378,23 @@ void OptionGroup::CppOptionEntry::release_c_arg() } case G_OPTION_ARG_NONE: /* Actually a boolean. */ { - gboolean* typed_arg = (gboolean*)carg_; + gboolean* typed_arg = static_cast(carg_); delete typed_arg; break; } default: { - /* TODO: - G_OPTION_ARG_CALLBACK, -*/ + /* TODO: + G_OPTION_ARG_CALLBACK, + */ break; } } - + carg_ = 0; } - + if(entry_) delete entry_; } @@ -319,44 +405,44 @@ void OptionGroup::CppOptionEntry::convert_c_to_cpp() { case G_OPTION_ARG_STRING: { - char** typed_arg = (char**)carg_; - Glib::ustring* typed_cpp_arg = (Glib::ustring*)cpparg_; + char** typed_arg = static_cast(carg_); + Glib::ustring* typed_cpp_arg = static_cast(cpparg_); if(typed_arg && typed_cpp_arg) { char* pch = *typed_arg; (*typed_cpp_arg) = Glib::convert_const_gchar_ptr_to_ustring(pch); - + break; } } case G_OPTION_ARG_FILENAME: { - char** typed_arg = (char**)carg_; - std::string* typed_cpp_arg = (std::string*)cpparg_; + char** typed_arg = static_cast(carg_); + std::string* typed_cpp_arg = static_cast(cpparg_); if(typed_arg && typed_cpp_arg) { char* pch = *typed_arg; (*typed_cpp_arg) = Glib::convert_const_gchar_ptr_to_stdstring(pch); - + break; } } case G_OPTION_ARG_INT: { - *((int*)cpparg_) = *((int*)carg_); + *((int*)cpparg_) = *(static_cast(carg_)); break; } case G_OPTION_ARG_STRING_ARRAY: { - char*** typed_arg = (char***)carg_; - vecustrings* typed_cpp_arg = (vecustrings*)cpparg_; + char*** typed_arg = static_cast(carg_); + vecustrings* typed_cpp_arg = static_cast(cpparg_); if(typed_arg && typed_cpp_arg) { typed_cpp_arg->clear(); - + //The C array seems to be null-terminated. //Glib::StringArrayHandle array_handle(*typed_arg, Glib::OWNERSHIP_NONE); - + //The SUN Forte compiler complains about this: // "optiongroup.cc", line 354: Error: Cannot assign Glib::ArrayHandle> to std::vector without @@ -369,14 +455,14 @@ void OptionGroup::CppOptionEntry::convert_c_to_cpp() // cxx: Error: ../../glib/glibmm/containerhandle_shared.h, line 149: the operand // of a pointer dynamic_cast must be a pointer to a complete class type // return dynamic_cast(Glib::wrap_auto(cobj, false /* take_copy */)); - + //for(Glib::StringArrayHandle::iterator iter = array_handle.begin(); iter != array_handle.end(); ++iter) //{ // typed_cpp_arg->push_back(*iter); //} - + //So we do this: - + char** char_array_next = *typed_arg; while(char_array_next && *char_array_next) { @@ -384,19 +470,19 @@ void OptionGroup::CppOptionEntry::convert_c_to_cpp() ++char_array_next; } } - + break; } case G_OPTION_ARG_FILENAME_ARRAY: { - char*** typed_arg = (char***)carg_; - vecustrings* typed_cpp_arg = (vecustrings*)cpparg_; + char*** typed_arg = static_cast(carg_); + vecustrings* typed_cpp_arg = static_cast(cpparg_); if(typed_arg && typed_cpp_arg) { typed_cpp_arg->clear(); - + //See comments above about the SUN Forte and Tru64 compilers. - + char** char_array_next = *typed_arg; while(char_array_next && *char_array_next) { @@ -404,20 +490,20 @@ void OptionGroup::CppOptionEntry::convert_c_to_cpp() ++char_array_next; } } - + break; } case G_OPTION_ARG_NONE: /* Actually a boolean. */ { - *((bool*)cpparg_) = *((gboolean*)carg_); + *(static_cast(cpparg_)) = *(static_cast(carg_)); break; } default: { /* TODO: - G_OPTION_ARG_CALLBACK, - */ - break; + G_OPTION_ARG_CALLBACK, + */ + break; } } } @@ -427,6 +513,6 @@ GOptionGroup* OptionGroup::gobj_give_ownership() has_ownership_ = false; return gobj(); } - + } // namespace Glib diff --git a/glib/src/optiongroup.hg b/glib/src/optiongroup.hg index f2ef9d44..2bdcb2e7 100644 --- a/glib/src/optiongroup.hg +++ b/glib/src/optiongroup.hg @@ -61,21 +61,21 @@ public: virtual bool on_post_parse(OptionContext& context, OptionGroup& group); virtual void on_error(OptionContext& context, OptionGroup& group); _IGNORE(g_option_group_set_parse_hooks, g_option_group_set_error_hook) - + void add_entry(const OptionEntry& entry); _IGNORE(g_option_group_add_entries) - - + + typedef std::vector vecustrings; typedef std::vector vecstrings; - + void add_entry(const OptionEntry& entry, bool& arg); void add_entry(const OptionEntry& entry, int& arg); void add_entry(const OptionEntry& entry, Glib::ustring& arg); void add_entry_filename(const OptionEntry& entry, std::string& arg); void add_entry(const OptionEntry& entry, vecustrings& arg); void add_entry_filename(const OptionEntry& entry, vecstrings& arg); - + /* TODO: void g_option_group_set_translate_func (GOptionGroup *group, GTranslateFunc func, @@ -83,36 +83,41 @@ void g_option_group_set_translate_func (GOptionGroup *group, GDestroyNotify destroy_notify); */ _WRAP_METHOD(void set_translation_domain(const Glib::ustring& domain), g_option_group_set_translation_domain) - + GOptionGroup* gobj() { return gobject_; } const GOptionGroup* gobj() const { return gobject_; } GOptionGroup* gobj_give_ownership(); - + protected: +#ifndef DOXYGEN_SHOULD_SKIP_THIS + /** This is not public API. It is an implementation detail. + */ class CppOptionEntry { public: CppOptionEntry(); - + void allocate_c_arg(); + void set_c_arg_default(void* cpp_arg); void convert_c_to_cpp(); void release_c_arg(); - + GOptionArg carg_type_; void* carg_; void* cpparg_; OptionEntry* entry_; }; - + void add_entry_with_wrapper(const OptionEntry& entry, GOptionArg arg_type, void* cpp_arg); - + //Map of entry names to CppOptionEntry: typedef std::map type_map_entries; type_map_entries map_entries_; - + GOptionGroup* gobject_; bool has_ownership_; //Whether the gobject_ belongs to this C++ instance. +#endif //DOXYGEN_SHOULD_SKIP_THIS }; } // namespace Glib -- cgit v1.2.1