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