1 // Generated by gmmproc 2.64.2 -- DO NOT MODIFY!
2 
3 
4 #include <glibmm.h>
5 
6 #include <glibmm/optiongroup.h>
7 #include <glibmm/private/optiongroup_p.h>
8 
9 
10 /* Copyright (C) 2002 The gtkmm Development Team
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include <glibmm/optionentry.h>
27 #include <glibmm/optioncontext.h>
28 #include <glibmm/utility.h>
29 #include <glibmm/exceptionhandler.h>
30 //#include <glibmm/containers.h>
31 #include <glib.h> // g_malloc
32 #include <cstring> // std::memset()
33 
34 namespace Glib
35 {
36 
37 namespace // anonymous
38 {
39 
40 // A pointer to an OptionArgCallback instance is stored in CppOptionEntry::cpparg_
41 // when a callback function shall parse the command option's value.
42 class OptionArgCallback
43 {
44 public:
OptionArgCallback(const OptionGroup::SlotOptionArgString & slot)45   explicit OptionArgCallback(const OptionGroup::SlotOptionArgString& slot)
46   : slot_string_(new OptionGroup::SlotOptionArgString(slot)), slot_filename_(nullptr)
47   {
48   }
49 
OptionArgCallback(const OptionGroup::SlotOptionArgFilename & slot)50   explicit OptionArgCallback(const OptionGroup::SlotOptionArgFilename& slot)
51   : slot_string_(nullptr), slot_filename_(new OptionGroup::SlotOptionArgFilename(slot))
52   {
53   }
54 
is_filename_option() const55   bool is_filename_option() const { return slot_filename_ != nullptr; }
56 
get_slot_string() const57   const OptionGroup::SlotOptionArgString* get_slot_string() const { return slot_string_; }
58 
get_slot_filename() const59   const OptionGroup::SlotOptionArgFilename* get_slot_filename() const { return slot_filename_; }
60 
~OptionArgCallback()61   ~OptionArgCallback()
62   {
63     delete slot_string_;
64     delete slot_filename_;
65   }
66 
67 private:
68   // One of these slot pointers is 0 and the other one points to a slot.
69   OptionGroup::SlotOptionArgString* slot_string_;
70   OptionGroup::SlotOptionArgFilename* slot_filename_;
71 
72   // Not copyable
73   OptionArgCallback(const OptionArgCallback&);
74   OptionArgCallback& operator=(const OptionArgCallback&);
75 };
76 
77 extern "C" {
78 
79 static gboolean
g_callback_pre_parse(GOptionContext * context,GOptionGroup *,gpointer data,GError ** error)80 g_callback_pre_parse(
81   GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** error)
82 {
83   OptionContext cppContext(context, false /* take_ownership */);
84 
85   auto option_group = static_cast<OptionGroup*>(data);
86   if (!option_group)
87   {
88     OptionError(OptionError::FAILED, "Glib::OptionGroup: g_callback_pre_parse(): "
89                                      "No OptionGroup pointer available")
90       .propagate(error);
91     return false;
92   }
93 
94   try
95   {
96     return option_group->on_pre_parse(cppContext, *option_group);
97   }
98   catch (Glib::Error& err)
99   {
100     err.propagate(error);
101   }
102   catch (...)
103   {
104     Glib::exception_handlers_invoke();
105   }
106   return false;
107 }
108 
109 static void
g_callback_error(GOptionContext * context,GOptionGroup *,gpointer data,GError **)110 g_callback_error(
111   GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** /* TODO error */)
112 {
113   // TODO GError** error is input data containing information on an error that
114   // has occurred before this function is called. When API can be broken,
115   // the function prototype of on_error ought to be changed to
116   // void on_error(OptionContext& context, Error& error).
117 
118   OptionContext cppContext(context, false /* take_ownership */);
119 
120   auto option_group = static_cast<OptionGroup*>(data);
121   if (option_group)
122     return option_group->on_error(cppContext, *option_group);
123 }
124 
125 const gchar*
OptionGroup_Translate_glibmm_callback(const gchar * string,gpointer data)126 OptionGroup_Translate_glibmm_callback(const gchar* string, gpointer data)
127 {
128   Glib::OptionGroup::SlotTranslate* the_slot = static_cast<Glib::OptionGroup::SlotTranslate*>(data);
129 
130   try
131   {
132     // The C docs says that the char* belongs to Glib.
133     return g_strdup((*the_slot)(Glib::ustring(string)).c_str());
134   }
135   catch (...)
136   {
137     Glib::exception_handlers_invoke();
138   }
139 
140   return nullptr;
141 }
142 
143 static void
OptionGroup_Translate_glibmm_callback_destroy(void * data)144 OptionGroup_Translate_glibmm_callback_destroy(void* data)
145 {
146   delete static_cast<Glib::OptionGroup::SlotTranslate*>(data);
147 }
148 
149 } /* extern "C" */
150 
151 } // anonymous namespace
152 
153 // static
154 gboolean
post_parse_callback(GOptionContext * context,GOptionGroup *,gpointer data,GError ** error)155 OptionGroup::post_parse_callback(
156   GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** error)
157 {
158   OptionContext cppContext(context, false /* take_ownership */);
159 
160   OptionGroup* option_group = static_cast<OptionGroup*>(data);
161   if (!option_group)
162   {
163     OptionError(OptionError::FAILED, "Glib::OptionGroup::post_parse_callback(): "
164                                      "No OptionGroup pointer available")
165       .propagate(error);
166     return false;
167   }
168 
169   // The C args have now been given values by g_option_context_parse().
170   // Convert C values to C++ values:
171   for (auto& the_pair : option_group->map_entries_)
172   {
173     auto& cpp_entry = the_pair.second;
174     cpp_entry.convert_c_to_cpp();
175   }
176 
177   try
178   {
179     return option_group->on_post_parse(cppContext, *option_group);
180   }
181   catch (Glib::Error& err)
182   {
183     err.propagate(error);
184   }
185   catch (...)
186   {
187     Glib::exception_handlers_invoke();
188   }
189   return false;
190 }
191 
192 // static
193 gboolean
option_arg_callback(const gchar * option_name,const gchar * value,gpointer data,GError ** error)194 OptionGroup::option_arg_callback(
195   const gchar* option_name, const gchar* value, gpointer data, GError** error)
196 {
197   const Glib::ustring cpp_option_name(option_name);
198   const OptionGroup* const option_group = static_cast<const OptionGroup*>(data);
199   if (!option_group)
200   {
201     OptionError(OptionError::FAILED, "Glib::OptionGroup::option_arg_callback(): "
202                                      "No OptionGroup pointer available for option " +
203                                        cpp_option_name)
204       .propagate(error);
205     return false;
206   }
207 
208   // option_name is either a single dash followed by a single letter (for a
209   // short name) or two dashes followed by a long option name.
210   OptionGroup::type_map_entries::const_iterator iterFind = option_group->map_entries_.end();
211   if (option_name[1] == '-')
212   {
213     // Long option name.
214     const auto long_option_name = Glib::ustring(option_name + 2);
215     iterFind = option_group->map_entries_.find(long_option_name);
216   }
217   else
218   {
219     // Short option name.
220     const auto short_option_name = option_name[1];
221     for (iterFind = option_group->map_entries_.begin();
222          iterFind != option_group->map_entries_.end(); ++iterFind)
223     {
224       const auto& cppOptionEntry = iterFind->second;
225       if (cppOptionEntry.entry_ && cppOptionEntry.entry_->get_short_name() == short_option_name)
226         break;
227     }
228   }
229 
230   if (iterFind == option_group->map_entries_.end())
231   {
232     OptionError(OptionError::UNKNOWN_OPTION, "Glib::OptionGroup::option_arg_callback(): "
233                                              "Unknown option " +
234                                                cpp_option_name)
235       .propagate(error);
236     return false;
237   }
238 
239   const auto& cppOptionEntry = iterFind->second;
240   if (cppOptionEntry.carg_type_ != G_OPTION_ARG_CALLBACK)
241   {
242     OptionError(OptionError::FAILED, "Glib::OptionGroup::option_arg_callback() "
243                                      "called for non-callback option " +
244                                        cpp_option_name)
245       .propagate(error);
246     return false;
247   }
248 
249   const bool has_value = (value != nullptr);
250   const OptionArgCallback* const option_arg =
251     static_cast<const OptionArgCallback*>(cppOptionEntry.cpparg_);
252   try
253   {
254     if (option_arg->is_filename_option())
255     {
256       const auto the_slot = option_arg->get_slot_filename();
257       const std::string cpp_value(value ? value : "");
258       return (*the_slot)(cpp_option_name, cpp_value, has_value);
259     }
260     else
261     {
262       const auto the_slot = option_arg->get_slot_string();
263       const Glib::ustring cpp_value(value ? value : "");
264       return (*the_slot)(cpp_option_name, cpp_value, has_value);
265     }
266   }
267   catch (Glib::Error& err)
268   {
269     err.propagate(error);
270   }
271   catch (...)
272   {
273     Glib::exception_handlers_invoke();
274   }
275   return false;
276 }
277 
OptionGroup(const Glib::ustring & name,const Glib::ustring & description,const Glib::ustring & help_description)278 OptionGroup::OptionGroup(const Glib::ustring& name, const Glib::ustring& description,
279   const Glib::ustring& help_description)
280 : gobject_(g_option_group_new(name.c_str(), description.c_str(), help_description.c_str(),
281     this /* user_data */, nullptr /* destroy_func */)),
282   has_ownership_(true)
283 {
284   // g_callback_pre_parse(), post_parse_callback(), g_callback_error(), and
285   // option_arg_callback() depend on user_data being this. The first three
286   // functions get a GOptionGroup*, but it would not be correct to use it for
287   // creating a new OptionGroup. They must call their virtual functions in the
288   // original OptionGroup instance.
289 
290   // Connect callbacks, so that derived classes can override the virtual methods:
291   g_option_group_set_parse_hooks(gobj(), &g_callback_pre_parse, &post_parse_callback);
292   g_option_group_set_error_hook(gobj(), &g_callback_error);
293 }
294 
OptionGroup(GOptionGroup * castitem)295 OptionGroup::OptionGroup(GOptionGroup* castitem) : gobject_(castitem), has_ownership_(true)
296 {
297   // Always takes ownership - never takes copy.
298 }
299 
OptionGroup(OptionGroup && other)300 OptionGroup::OptionGroup(OptionGroup&& other) noexcept
301   : map_entries_(std::move(other.map_entries_)),
302     gobject_(std::move(other.gobject_)),
303     has_ownership_(std::move(other.has_ownership_))
304 {
305   other.gobject_ = nullptr;
306   other.has_ownership_ = false;
307 }
308 
309 OptionGroup&
operator =(OptionGroup && other)310 OptionGroup::operator=(OptionGroup&& other) noexcept
311 {
312   release_gobject();
313 
314   map_entries_ = std::move(other.map_entries_);
315   gobject_ = std::move(other.gobject_);
316   has_ownership_ = std::move(other.has_ownership_);
317 
318   other.gobject_ = nullptr;
319   other.has_ownership_ = false;
320 
321   return *this;
322 }
323 
324 void
release_gobject()325 OptionGroup::release_gobject() noexcept
326 {
327   // Free any C types that were allocated during add_entry():
328   for (auto& the_pair : map_entries_)
329   {
330     auto& cpp_entry = the_pair.second;
331     cpp_entry.release_c_arg();
332   }
333 
334   if (has_ownership_ && gobject_)
335   {
336     g_option_group_unref(gobj());
337     gobject_ = nullptr;
338   }
339 }
340 
~OptionGroup()341 OptionGroup::~OptionGroup()
342 {
343   release_gobject();
344 }
345 
346 void
add_entry(const OptionEntry & entry)347 OptionGroup::add_entry(const OptionEntry& entry)
348 {
349   // It does not copy the entry, so it needs to live as long as the group.
350 
351   // g_option_group_add_entries takes an array, with the last item in the array having a null
352   // long_name.
353   // Hopefully this will be properly documented eventually - see bug #
354 
355   // Create a temporary array, just so we can give the correct thing to g_option_group_add_entries:
356   GOptionEntry array[2];
357   array[0] = *(entry.gobj()); // Copy contents.
358   std::memset(&array[1], 0, sizeof(GOptionEntry));
359 
360   g_option_group_add_entries(gobj(), array);
361 }
362 
363 void
add_entry(const OptionEntry & entry,bool & arg)364 OptionGroup::add_entry(const OptionEntry& entry, bool& arg)
365 {
366   add_entry_with_wrapper(entry,
367     G_OPTION_ARG_NONE /* Actually a boolean on/off, depending on whether the argument name was given, without argument parameters. */,
368     &arg);
369 }
370 
371 void
add_entry(const OptionEntry & entry,int & arg)372 OptionGroup::add_entry(const OptionEntry& entry, int& arg)
373 {
374   add_entry_with_wrapper(entry, G_OPTION_ARG_INT, &arg);
375 }
376 
377 void
add_entry(const OptionEntry & entry,double & arg)378 OptionGroup::add_entry(const OptionEntry& entry, double& arg)
379 {
380   add_entry_with_wrapper(entry, G_OPTION_ARG_DOUBLE, &arg);
381 }
382 
383 void
add_entry(const OptionEntry & entry,Glib::ustring & arg)384 OptionGroup::add_entry(const OptionEntry& entry, Glib::ustring& arg)
385 {
386   add_entry_with_wrapper(entry, G_OPTION_ARG_STRING, &arg);
387 }
388 
389 void
add_entry(const OptionEntry & entry,vecustrings & arg)390 OptionGroup::add_entry(const OptionEntry& entry, vecustrings& arg)
391 {
392   add_entry_with_wrapper(entry, G_OPTION_ARG_STRING_ARRAY, &arg);
393 }
394 
395 void
add_entry_filename(const OptionEntry & entry,std::string & arg)396 OptionGroup::add_entry_filename(const OptionEntry& entry, std::string& arg)
397 {
398   add_entry_with_wrapper(entry, G_OPTION_ARG_FILENAME, &arg);
399 }
400 
401 void
add_entry_filename(const OptionEntry & entry,vecstrings & arg)402 OptionGroup::add_entry_filename(const OptionEntry& entry, vecstrings& arg)
403 {
404   add_entry_with_wrapper(entry, G_OPTION_ARG_FILENAME_ARRAY, &arg);
405 }
406 
407 // When the command argument value is to be parsed by a user-supplied function
408 // (indicated by G_OPTION_ARG_CALLBACK), the FLAG_FILENAME in 'entry' is ignored.
409 // set_c_arg_default() clears or sets it as required in a copy of 'entry'.
410 //
411 // The glib API is inconsistent here. The choice between UTF-8 and filename
412 // encoding is done with G_OPTION_ARG_STRING, G_OPTION_ARG_FILENAME,
413 // G_OPTION_ARG_STRING_ARRAY, and G_OPTION_ARG_FILENAME_ARRAY, which in glibmm
414 // are set by OptionGroup::add_entry[_filename]. But when a callback function
415 // is chosen, there is only G_OPTION_ARG_CALLBACK, and the encoding is chosen
416 // with G_OPTION_FLAG_FILENAME. We do this automatiically in set_c_arg_default().
417 // Other option flags are set by OptionEntry::set_flags().
418 
419 void
add_entry(const OptionEntry & entry,const SlotOptionArgString & slot)420 OptionGroup::add_entry(const OptionEntry& entry, const SlotOptionArgString& slot)
421 {
422   // The OptionArgCallback is deleted in release_c_arg().
423   add_entry_with_wrapper(entry, G_OPTION_ARG_CALLBACK, new OptionArgCallback(slot));
424 }
425 
426 void
add_entry_filename(const OptionEntry & entry,const SlotOptionArgFilename & slot)427 OptionGroup::add_entry_filename(const OptionEntry& entry, const SlotOptionArgFilename& slot)
428 {
429   // The OptionArgCallback is deleted in release_c_arg().
430   add_entry_with_wrapper(entry, G_OPTION_ARG_CALLBACK, new OptionArgCallback(slot));
431 }
432 
433 void
add_entry_with_wrapper(const OptionEntry & entry,GOptionArg arg_type,void * cpp_arg)434 OptionGroup::add_entry_with_wrapper(const OptionEntry& entry, GOptionArg arg_type, void* cpp_arg)
435 {
436   const auto name = entry.get_long_name();
437   type_map_entries::iterator iterFind = map_entries_.find(name);
438   if (iterFind == map_entries_.end()) // If we have not added this entry already
439   {
440     CppOptionEntry cppEntry;
441     // g_option_group_add_entry() does not take its own copy, so we must keep the instance alive.
442     cppEntry.entry_ = new OptionEntry(entry);
443     // cppEntry.entry_ is deleted in release_c_arg(), via the destructor.
444 
445     // Several options can refer to the same C++ variable,
446     // typically a pair of --enable-x / --disable-x options.
447     // Only one C variable shall be allocated for them.
448     // See https://bugzilla.gnome.org/show_bug.cgi?id=744854.
449     bool is_duplicate = false;
450     void* carg = nullptr;
451     if (arg_type != G_OPTION_ARG_CALLBACK)
452     {
453       for (type_map_entries::iterator iter = map_entries_.begin(); iter != map_entries_.end();
454            ++iter)
455       {
456         const auto& cpp_entry = iter->second;
457         if (cpp_entry.cpparg_ == cpp_arg && cpp_entry.carg_type_ == arg_type && cpp_entry.carg_)
458         {
459           is_duplicate = true;
460           carg = cpp_entry.carg_;
461           break;
462         }
463       }
464     }
465 
466     cppEntry.carg_type_ = arg_type;
467     if (!is_duplicate)
468     {
469       cppEntry.allocate_c_arg();
470       cppEntry.set_c_arg_default(cpp_arg);
471       carg = cppEntry.carg_;
472     }
473     cppEntry.cpparg_ = cpp_arg;
474 
475     // Give the information to the C API:
476     cppEntry.entry_->gobj()->arg = arg_type;
477     cppEntry.entry_->gobj()->arg_data = carg;
478 
479     // Remember the C++/C mapping so that we can use it later:
480     map_entries_[name] = cppEntry;
481 
482     add_entry(*(cppEntry.entry_));
483   }
484   else if (arg_type == G_OPTION_ARG_CALLBACK)
485   {
486     // Delete the OptionArgCallback instance that was allocated by add_entry()
487     // or add_entry_filename().
488     auto option_arg = static_cast<OptionArgCallback*>(cpp_arg);
489     delete option_arg;
490   }
491 }
492 
493 bool
on_pre_parse(OptionContext &,OptionGroup &)494 OptionGroup::on_pre_parse(OptionContext& /* context */, OptionGroup& /* group */)
495 {
496   return true;
497 }
498 
499 bool
on_post_parse(OptionContext &,OptionGroup &)500 OptionGroup::on_post_parse(OptionContext& /* context */, OptionGroup& /* group */)
501 {
502   return true;
503 }
504 
505 void
on_error(OptionContext &,OptionGroup &)506 OptionGroup::on_error(OptionContext& /* context */, OptionGroup& /* group */)
507 {
508 }
509 
510 void
set_translate_func(const SlotTranslate & slot)511 OptionGroup::set_translate_func(const SlotTranslate& slot)
512 {
513   // Create a copy of the slot. A pointer to this will be passed through the
514   // callback's data parameter.  It will be deleted when
515   // OptionGroup_Translate_glibmm_callback_destroy() is called.
516   auto slot_copy = new SlotTranslate(slot);
517   g_option_group_set_translate_func(gobj(), &OptionGroup_Translate_glibmm_callback, slot_copy,
518     &OptionGroup_Translate_glibmm_callback_destroy);
519 }
520 
CppOptionEntry()521 OptionGroup::CppOptionEntry::CppOptionEntry()
522 : carg_type_(G_OPTION_ARG_NONE), carg_(nullptr), cpparg_(nullptr), entry_(nullptr)
523 {
524 }
525 
526 void
allocate_c_arg()527 OptionGroup::CppOptionEntry::allocate_c_arg()
528 {
529   // Create an instance of the appropriate C type.
530   // This will be destroyed in the OptionGroup destructor.
531   //
532   // We must also call set_c_arg_default() to give these C types the specified
533   // defaults based on the C++-typed arguments.
534   switch (carg_type_)
535   {
536   case G_OPTION_ARG_STRING: // The char* will be for UTF8 a string.
537   case G_OPTION_ARG_FILENAME: // The char* will be for a string in the current locale's encoding.
538   {
539     char** typed_arg = new char*;
540     // The C code will allocate a char* and put it here, for us to g_free() later.
541     *typed_arg = nullptr;
542     carg_ = typed_arg;
543 
544     break;
545   }
546   case G_OPTION_ARG_INT:
547   {
548     int* typed_arg = new int;
549     *typed_arg = 0;
550     carg_ = typed_arg;
551 
552     break;
553   }
554   case G_OPTION_ARG_DOUBLE:
555   {
556     double* typed_arg = new double;
557     *typed_arg = 0.0;
558     carg_ = typed_arg;
559 
560     break;
561   }
562   case G_OPTION_ARG_STRING_ARRAY:
563   case G_OPTION_ARG_FILENAME_ARRAY:
564   {
565     char*** typed_arg = new char**;
566     // The C code will allocate a char** and put it here, for us to g_strfreev() later.
567     *typed_arg = nullptr;
568     carg_ = typed_arg;
569 
570     break;
571   }
572   case G_OPTION_ARG_NONE: // Actually a boolean.
573   {
574     gboolean* typed_arg = new gboolean;
575     *typed_arg = false;
576     carg_ = typed_arg;
577 
578     break;
579   }
580   case G_OPTION_ARG_CALLBACK:
581   {
582     // The C arg pointer is a function pointer, cast to void*.
583     //
584     //   carg_ = reinterpret_cast<void*>(&OptionGroup::option_arg_callback);
585     // or
586     //   union {
587     //     void* dp;
588     //     GOptionArgFunc fp;
589     //   } u;
590     //   u.fp = &OptionGroup::option_arg_callback;
591     //   carg_ = u.dp;
592     // ? See
593     // https://bugzilla.gnome.org/show_bug.cgi?id=589197
594     // https://github.com/libsigcplusplus/libsigcplusplus/issues/1
595     // https://github.com/libsigcplusplus/libsigcplusplus/issues/8
596     carg_ = reinterpret_cast<void*>(&OptionGroup::option_arg_callback);
597 
598     break;
599   }
600   default:
601   {
602     break;
603   }
604   }
605 }
606 
607 void
set_c_arg_default(void * cpp_arg)608 OptionGroup::CppOptionEntry::set_c_arg_default(void* cpp_arg)
609 {
610   switch (carg_type_)
611   {
612   case G_OPTION_ARG_INT:
613   {
614     *static_cast<int*>(carg_) = *static_cast<int*>(cpp_arg);
615     break;
616   }
617   case G_OPTION_ARG_DOUBLE:
618   {
619     *static_cast<double*>(carg_) = *static_cast<double*>(cpp_arg);
620     break;
621   }
622   case G_OPTION_ARG_NONE:
623   {
624     *static_cast<gboolean*>(carg_) = *static_cast<bool*>(cpp_arg);
625     break;
626   }
627   case G_OPTION_ARG_STRING:
628   case G_OPTION_ARG_FILENAME:
629   case G_OPTION_ARG_STRING_ARRAY:
630   case G_OPTION_ARG_FILENAME_ARRAY:
631   {
632     // No need to set default values for string-valued options.
633     // If *carg_ is still 0, when convert_c_to_cpp() is called, just don't
634     // touch *cpparg_. Besides, setting default values in *carg_ can result
635     // in memory leaks, because glib would not free the strings before
636     // the char*'s are overwritten with pointers to newly allocated copies
637     // of the command option arguments.
638     break;
639   }
640   case G_OPTION_ARG_CALLBACK:
641   {
642     // No value to set here. The arg pointer is a function pointer.
643 
644     // Set or clear FLAG_FILENAME in *entry_.
645     const OptionArgCallback* const option_arg = static_cast<const OptionArgCallback*>(cpp_arg);
646     if (option_arg->is_filename_option())
647     {
648       entry_->set_flags(entry_->get_flags() | OptionEntry::FLAG_FILENAME);
649     }
650     else
651     {
652       entry_->set_flags(entry_->get_flags() & ~OptionEntry::FLAG_FILENAME);
653     }
654     break;
655   }
656   default:
657   {
658     break;
659   }
660   }
661 }
662 
663 void
release_c_arg()664 OptionGroup::CppOptionEntry::release_c_arg()
665 {
666   // Delete the instances that we created in allocate_c_arg().
667   // Notice that we delete the type that we created, but not the value to which it points.
668   if (carg_)
669   {
670     switch (carg_type_)
671     {
672     case G_OPTION_ARG_STRING:
673     case G_OPTION_ARG_FILENAME:
674     {
675       char** typed_arg = static_cast<char**>(carg_);
676       g_free(*typed_arg); // Free the char* string at typed_arg, if allocated by the C code.
677       delete typed_arg; // Delete the char** that we allocated in allocate_c_arg().
678 
679       break;
680     }
681     case G_OPTION_ARG_INT:
682     {
683       int* typed_arg = static_cast<int*>(carg_);
684       delete typed_arg;
685 
686       break;
687     }
688     case G_OPTION_ARG_DOUBLE:
689     {
690       double* typed_arg = static_cast<double*>(carg_);
691       delete typed_arg;
692 
693       break;
694     }
695     case G_OPTION_ARG_STRING_ARRAY:
696     case G_OPTION_ARG_FILENAME_ARRAY:
697     {
698       char*** typed_arg = static_cast<char***>(carg_);
699       g_strfreev(*typed_arg); // Free the array of strings and the array at typed_arg, if allocated
700                               // by the C code.
701       delete typed_arg; // Delete the char*** that we allocated in allocate_c_arg().
702 
703       break;
704     }
705     case G_OPTION_ARG_NONE: // Actually a boolean.
706     {
707       gboolean* typed_arg = static_cast<gboolean*>(carg_);
708       delete typed_arg;
709 
710       break;
711     }
712     case G_OPTION_ARG_CALLBACK:
713     {
714       // Delete the OptionArgCallback instance that was allocated by add_entry()
715       // or add_entry_filename().
716       auto option_arg = static_cast<OptionArgCallback*>(cpparg_);
717       delete option_arg;
718       cpparg_ = nullptr;
719 
720       break;
721     }
722     default:
723     {
724       break;
725     }
726     }
727 
728     carg_ = nullptr;
729   }
730 
731   if (entry_)
732     delete entry_;
733 }
734 
735 void
convert_c_to_cpp()736 OptionGroup::CppOptionEntry::convert_c_to_cpp()
737 {
738   if (!carg_)
739     return;
740 
741   switch (carg_type_)
742   {
743   case G_OPTION_ARG_STRING:
744   {
745     char** typed_arg = static_cast<char**>(carg_);
746     auto typed_cpp_arg = static_cast<Glib::ustring*>(cpparg_);
747     if (typed_arg && *typed_arg && typed_cpp_arg)
748     {
749       *typed_cpp_arg = *typed_arg;
750     }
751     break;
752   }
753   case G_OPTION_ARG_FILENAME:
754   {
755     char** typed_arg = static_cast<char**>(carg_);
756     auto typed_cpp_arg = static_cast<std::string*>(cpparg_);
757     if (typed_arg && *typed_arg && typed_cpp_arg)
758     {
759       *typed_cpp_arg = *typed_arg;
760     }
761     break;
762   }
763   case G_OPTION_ARG_INT:
764   {
765     *((int*)cpparg_) = *(static_cast<int*>(carg_));
766     break;
767   }
768   case G_OPTION_ARG_DOUBLE:
769   {
770     *((double*)cpparg_) = *(static_cast<double*>(carg_));
771     break;
772   }
773   case G_OPTION_ARG_STRING_ARRAY:
774   {
775     char*** typed_arg = static_cast<char***>(carg_);
776     auto typed_cpp_arg = static_cast<vecustrings*>(cpparg_);
777     if (typed_arg && *typed_arg && typed_cpp_arg)
778     {
779       typed_cpp_arg->clear();
780 
781       // The C array is null-terminated.
782       // Glib::StringArrayHandle array_handle(*typed_arg,  Glib::OWNERSHIP_NONE);
783 
784       // The SUN Forte compiler complains about this:
785       // "optiongroup.cc", line 354: Error: Cannot assign Glib::ArrayHandle<Glib::ustring,
786       // Glib::Container_Helpers::TypeTraits<Glib::ustring>> to std::vector<Glib::ustring> without
787       // "std::vector<Glib::ustring>::operator=(const std::vector<Glib::ustring>&)";.
788       //
789       //(*typed_cpp_arg) = array_handle;
790       //
791       // And the Tru64 compiler does not even like us to instantiate the StringArrayHandle:
792       //
793       // cxx: Error: ../../glib/glibmm/containerhandle_shared.h, line 149: the operand
794       //     of a pointer dynamic_cast must be a pointer to a complete class type
795       //   return dynamic_cast<CppType>(Glib::wrap_auto(cobj, false /* take_copy */));
796 
797       // for(Glib::StringArrayHandle::iterator iter = array_handle.begin(); iter !=
798       // array_handle.end(); ++iter)
799       //{
800       //  typed_cpp_arg->emplace_back(*iter);
801       //}
802 
803       // So we do this:
804 
805       char** char_array_next = *typed_arg;
806       while (*char_array_next)
807       {
808         typed_cpp_arg->emplace_back(*char_array_next);
809         ++char_array_next;
810       }
811     }
812     break;
813   }
814   case G_OPTION_ARG_FILENAME_ARRAY:
815   {
816     char*** typed_arg = static_cast<char***>(carg_);
817     auto typed_cpp_arg = static_cast<vecstrings*>(cpparg_);
818     if (typed_arg && *typed_arg && typed_cpp_arg)
819     {
820       typed_cpp_arg->clear();
821 
822       // See comments above about the SUN Forte and Tru64 compilers.
823 
824       char** char_array_next = *typed_arg;
825       while (*char_array_next)
826       {
827         typed_cpp_arg->emplace_back(*char_array_next);
828         ++char_array_next;
829       }
830     }
831     break;
832   }
833   case G_OPTION_ARG_NONE: // Actually a boolean.
834   {
835     *(static_cast<bool*>(cpparg_)) = *(static_cast<gboolean*>(carg_));
836     break;
837   }
838   case G_OPTION_ARG_CALLBACK:
839   {
840     // Nothing to convert here. That's a task for the callback function
841     //(the SlotOptionArgString or SlotOptionArgFilename).
842     break;
843   }
844   default:
845   {
846     break;
847   }
848   }
849 }
850 
851 GOptionGroup*
gobj_give_ownership()852 OptionGroup::gobj_give_ownership()
853 {
854   has_ownership_ = false;
855   return gobj();
856 }
857 
858 } // namespace Glib
859 
860 namespace
861 {
862 } // anonymous namespace
863 
864 
865 namespace Glib
866 {
867 
868 
set_translation_domain(const Glib::ustring & domain)869 void OptionGroup::set_translation_domain(const Glib::ustring& domain)
870 {
871   g_option_group_set_translation_domain(gobj(), domain.c_str());
872 }
873 
874 
875 } // namespace Glib
876 
877 
878