Blob Blame History Raw
// Generated by gmmproc 2.54.1 -- DO NOT MODIFY!


#include <glibmm.h>

#include <glibmm/optiongroup.h>
#include <glibmm/private/optiongroup_p.h>


/* Copyright (C) 2002 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <glibmm/optionentry.h>
#include <glibmm/optioncontext.h>
#include <glibmm/utility.h>
#include <glibmm/exceptionhandler.h>
//#include <glibmm/containers.h>
#include <glib.h> // g_malloc
#include <cstring> // std::memset()

namespace Glib
{

namespace // anonymous
{

// A pointer to an OptionArgCallback instance is stored in CppOptionEntry::cpparg_
// when a callback function shall parse the command option's value.
class OptionArgCallback
{
public:
  explicit OptionArgCallback(const OptionGroup::SlotOptionArgString& slot)
  : slot_string_(new OptionGroup::SlotOptionArgString(slot)), slot_filename_(nullptr)
  {
  }

  explicit OptionArgCallback(const OptionGroup::SlotOptionArgFilename& slot)
  : slot_string_(nullptr), slot_filename_(new OptionGroup::SlotOptionArgFilename(slot))
  {
  }

  bool is_filename_option() const { return slot_filename_ != nullptr; }

  const OptionGroup::SlotOptionArgString* get_slot_string() const { return slot_string_; }

  const OptionGroup::SlotOptionArgFilename* get_slot_filename() const { return slot_filename_; }

  ~OptionArgCallback()
  {
    delete slot_string_;
    delete slot_filename_;
  }

private:
  // One of these slot pointers is 0 and the other one points to a slot.
  OptionGroup::SlotOptionArgString* slot_string_;
  OptionGroup::SlotOptionArgFilename* slot_filename_;

  // Not copyable
  OptionArgCallback(const OptionArgCallback&);
  OptionArgCallback& operator=(const OptionArgCallback&);
};

extern "C" {

static gboolean
g_callback_pre_parse(
  GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** error)
{
  OptionContext cppContext(context, false /* take_ownership */);

  auto option_group = static_cast<OptionGroup*>(data);
  if (!option_group)
  {
    OptionError(OptionError::FAILED, "Glib::OptionGroup: g_callback_pre_parse(): "
                                     "No OptionGroup pointer available")
      .propagate(error);
    return false;
  }

  try
  {
    return option_group->on_pre_parse(cppContext, *option_group);
  }
  catch (Glib::Error& err)
  {
    err.propagate(error);
  }
  catch (...)
  {
    Glib::exception_handlers_invoke();
  }
  return false;
}

static void
g_callback_error(
  GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** /* TODO error */)
{
  // TODO GError** error is input data containing information on an error that
  // has occurred before this function is called. When API can be broken,
  // the function prototype of on_error ought to be changed to
  // void on_error(OptionContext& context, Error& error).

  OptionContext cppContext(context, false /* take_ownership */);

  auto option_group = static_cast<OptionGroup*>(data);
  if (option_group)
    return option_group->on_error(cppContext, *option_group);
}

const gchar*
OptionGroup_Translate_glibmm_callback(const gchar* string, gpointer data)
{
  Glib::OptionGroup::SlotTranslate* the_slot = static_cast<Glib::OptionGroup::SlotTranslate*>(data);

  try
  {
    // The C docs says that the char* belongs to Glib.
    return g_strdup((*the_slot)(Glib::ustring(string)).c_str());
  }
  catch (...)
  {
    Glib::exception_handlers_invoke();
  }

  return nullptr;
}

static void
OptionGroup_Translate_glibmm_callback_destroy(void* data)
{
  delete static_cast<Glib::OptionGroup::SlotTranslate*>(data);
}

} /* extern "C" */

} // anonymous namespace

// static
gboolean
OptionGroup::post_parse_callback(
  GOptionContext* context, GOptionGroup* /* group */, gpointer data, GError** error)
{
  OptionContext cppContext(context, false /* take_ownership */);

  OptionGroup* option_group = static_cast<OptionGroup*>(data);
  if (!option_group)
  {
    OptionError(OptionError::FAILED, "Glib::OptionGroup::post_parse_callback(): "
                                     "No OptionGroup pointer available")
      .propagate(error);
    return false;
  }

  // The C args have now been given values by g_option_context_parse().
  // Convert C values to C++ values:
  for (auto& the_pair : option_group->map_entries_)
  {
    auto& cpp_entry = the_pair.second;
    cpp_entry.convert_c_to_cpp();
  }

  try
  {
    return option_group->on_post_parse(cppContext, *option_group);
  }
  catch (Glib::Error& err)
  {
    err.propagate(error);
  }
  catch (...)
  {
    Glib::exception_handlers_invoke();
  }
  return false;
}

// static
gboolean
OptionGroup::option_arg_callback(
  const gchar* option_name, const gchar* value, gpointer data, GError** error)
{
  const Glib::ustring cpp_option_name(option_name);
  const OptionGroup* const option_group = static_cast<const OptionGroup*>(data);
  if (!option_group)
  {
    OptionError(OptionError::FAILED, "Glib::OptionGroup::option_arg_callback(): "
                                     "No OptionGroup pointer available for option " +
                                       cpp_option_name)
      .propagate(error);
    return false;
  }

  // option_name is either a single dash followed by a single letter (for a
  // short name) or two dashes followed by a long option name.
  OptionGroup::type_map_entries::const_iterator iterFind = option_group->map_entries_.end();
  if (option_name[1] == '-')
  {
    // Long option name.
    const auto long_option_name = Glib::ustring(option_name + 2);
    iterFind = option_group->map_entries_.find(long_option_name);
  }
  else
  {
    // Short option name.
    const auto short_option_name = option_name[1];
    for (iterFind = option_group->map_entries_.begin();
         iterFind != option_group->map_entries_.end(); ++iterFind)
    {
      const auto& cppOptionEntry = iterFind->second;
      if (cppOptionEntry.entry_ && cppOptionEntry.entry_->get_short_name() == short_option_name)
        break;
    }
  }

  if (iterFind == option_group->map_entries_.end())
  {
    OptionError(OptionError::UNKNOWN_OPTION, "Glib::OptionGroup::option_arg_callback(): "
                                             "Unknown option " +
                                               cpp_option_name)
      .propagate(error);
    return false;
  }

  const auto& cppOptionEntry = iterFind->second;
  if (cppOptionEntry.carg_type_ != G_OPTION_ARG_CALLBACK)
  {
    OptionError(OptionError::FAILED, "Glib::OptionGroup::option_arg_callback() "
                                     "called for non-callback option " +
                                       cpp_option_name)
      .propagate(error);
    return false;
  }

  const bool has_value = (value != nullptr);
  const OptionArgCallback* const option_arg =
    static_cast<const OptionArgCallback*>(cppOptionEntry.cpparg_);
  try
  {
    if (option_arg->is_filename_option())
    {
      const auto the_slot = option_arg->get_slot_filename();
      const std::string cpp_value(value ? value : "");
      return (*the_slot)(cpp_option_name, cpp_value, has_value);
    }
    else
    {
      const auto the_slot = option_arg->get_slot_string();
      const Glib::ustring cpp_value(value ? value : "");
      return (*the_slot)(cpp_option_name, cpp_value, has_value);
    }
  }
  catch (Glib::Error& err)
  {
    err.propagate(error);
  }
  catch (...)
  {
    Glib::exception_handlers_invoke();
  }
  return false;
}

OptionGroup::OptionGroup(const Glib::ustring& name, const Glib::ustring& description,
  const Glib::ustring& help_description)
: gobject_(g_option_group_new(name.c_str(), description.c_str(), help_description.c_str(),
    this /* user_data */, nullptr /* destroy_func */)),
  has_ownership_(true)
{
  // g_callback_pre_parse(), post_parse_callback(), g_callback_error(), and
  // option_arg_callback() depend on user_data being this. The first three
  // functions get a GOptionGroup*, but it would not be correct to use it for
  // creating a new OptionGroup. They must call their virtual functions in the
  // original OptionGroup instance.

  // Connect callbacks, so that derived classes can override the virtual methods:
  g_option_group_set_parse_hooks(gobj(), &g_callback_pre_parse, &post_parse_callback);
  g_option_group_set_error_hook(gobj(), &g_callback_error);
}

OptionGroup::OptionGroup(GOptionGroup* castitem) : gobject_(castitem), has_ownership_(true)
{
  // Always takes ownership - never takes copy.
}

OptionGroup::OptionGroup(OptionGroup&& other) noexcept
  : map_entries_(std::move(other.map_entries_)),
    gobject_(std::move(other.gobject_)),
    has_ownership_(std::move(other.has_ownership_))
{
  other.gobject_ = nullptr;
  other.has_ownership_ = false;
}

OptionGroup&
OptionGroup::operator=(OptionGroup&& other) noexcept
{
  release_gobject();

  map_entries_ = std::move(other.map_entries_);
  gobject_ = std::move(other.gobject_);
  has_ownership_ = std::move(other.has_ownership_);

  other.gobject_ = nullptr;
  other.has_ownership_ = false;

  return *this;
}

void
OptionGroup::release_gobject() noexcept
{
  // Free any C types that were allocated during add_entry():
  for (auto& the_pair : map_entries_)
  {
    auto& cpp_entry = the_pair.second;
    cpp_entry.release_c_arg();
  }

  if (has_ownership_ && gobject_)
  {
    g_option_group_unref(gobj());
    gobject_ = nullptr;
  }
}

OptionGroup::~OptionGroup()
{
  release_gobject();
}

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.
  std::memset(&array[1], 0, sizeof(GOptionEntry));

  g_option_group_add_entries(gobj(), array);
}

void
OptionGroup::add_entry(const OptionEntry& entry, bool& arg)
{
  add_entry_with_wrapper(entry,
    G_OPTION_ARG_NONE /* Actually a boolean on/off, depending on whether the argument name was given, without argument parameters. */,
    &arg);
}

void
OptionGroup::add_entry(const OptionEntry& entry, int& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_INT, &arg);
}

void
OptionGroup::add_entry(const OptionEntry& entry, double& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_DOUBLE, &arg);
}

void
OptionGroup::add_entry(const OptionEntry& entry, Glib::ustring& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_STRING, &arg);
}

void
OptionGroup::add_entry(const OptionEntry& entry, vecustrings& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_STRING_ARRAY, &arg);
}

void
OptionGroup::add_entry_filename(const OptionEntry& entry, std::string& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_FILENAME, &arg);
}

void
OptionGroup::add_entry_filename(const OptionEntry& entry, vecstrings& arg)
{
  add_entry_with_wrapper(entry, G_OPTION_ARG_FILENAME_ARRAY, &arg);
}

// When the command argument value is to be parsed by a user-supplied function
// (indicated by G_OPTION_ARG_CALLBACK), the FLAG_FILENAME in 'entry' is ignored.
// set_c_arg_default() clears or sets it as required in a copy of 'entry'.
//
// The glib API is inconsistent here. The choice between UTF-8 and filename
// encoding is done with G_OPTION_ARG_STRING, G_OPTION_ARG_FILENAME,
// G_OPTION_ARG_STRING_ARRAY, and G_OPTION_ARG_FILENAME_ARRAY, which in glibmm
// are set by OptionGroup::add_entry[_filename]. But when a callback function
// is chosen, there is only G_OPTION_ARG_CALLBACK, and the encoding is chosen
// with G_OPTION_FLAG_FILENAME. We do this automatiically in set_c_arg_default().
// Other option flags are set by OptionEntry::set_flags().

void
OptionGroup::add_entry(const OptionEntry& entry, const SlotOptionArgString& slot)
{
  // The OptionArgCallback is deleted in release_c_arg().
  add_entry_with_wrapper(entry, G_OPTION_ARG_CALLBACK, new OptionArgCallback(slot));
}

void
OptionGroup::add_entry_filename(const OptionEntry& entry, const SlotOptionArgFilename& slot)
{
  // The OptionArgCallback is deleted in release_c_arg().
  add_entry_with_wrapper(entry, G_OPTION_ARG_CALLBACK, new OptionArgCallback(slot));
}

void
OptionGroup::add_entry_with_wrapper(const OptionEntry& entry, GOptionArg arg_type, void* cpp_arg)
{
  const auto 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;
    // g_option_group_add_entry() does not take its own copy, so we must keep the instance alive.
    cppEntry.entry_ = new OptionEntry(entry);
    // cppEntry.entry_ is deleted in release_c_arg(), via the destructor.

    // Several options can refer to the same C++ variable,
    // typically a pair of --enable-x / --disable-x options.
    // Only one C variable shall be allocated for them.
    // See https://bugzilla.gnome.org/show_bug.cgi?id=744854.
    bool is_duplicate = false;
    void* carg = nullptr;
    if (arg_type != G_OPTION_ARG_CALLBACK)
    {
      for (type_map_entries::iterator iter = map_entries_.begin(); iter != map_entries_.end();
           ++iter)
      {
        const auto& cpp_entry = iter->second;
        if (cpp_entry.cpparg_ == cpp_arg && cpp_entry.carg_type_ == arg_type && cpp_entry.carg_)
        {
          is_duplicate = true;
          carg = cpp_entry.carg_;
          break;
        }
      }
    }

    cppEntry.carg_type_ = arg_type;
    if (!is_duplicate)
    {
      cppEntry.allocate_c_arg();
      cppEntry.set_c_arg_default(cpp_arg);
      carg = cppEntry.carg_;
    }
    cppEntry.cpparg_ = cpp_arg;

    // Give the information to the C API:
    cppEntry.entry_->gobj()->arg = arg_type;
    cppEntry.entry_->gobj()->arg_data = carg;

    // Remember the C++/C mapping so that we can use it later:
    map_entries_[name] = cppEntry;

    add_entry(*(cppEntry.entry_));
  }
  else if (arg_type == G_OPTION_ARG_CALLBACK)
  {
    // Delete the OptionArgCallback instance that was allocated by add_entry()
    // or add_entry_filename().
    auto option_arg = static_cast<OptionArgCallback*>(cpp_arg);
    delete option_arg;
  }
}

bool
OptionGroup::on_pre_parse(OptionContext& /* context */, OptionGroup& /* group */)
{
  return true;
}

bool
OptionGroup::on_post_parse(OptionContext& /* context */, OptionGroup& /* group */)
{
  return true;
}

void
OptionGroup::on_error(OptionContext& /* context */, OptionGroup& /* group */)
{
}

void
OptionGroup::set_translate_func(const SlotTranslate& slot)
{
  // Create a copy of the slot. A pointer to this will be passed through the
  // callback's data parameter.  It will be deleted when
  // OptionGroup_Translate_glibmm_callback_destroy() is called.
  auto slot_copy = new SlotTranslate(slot);
  g_option_group_set_translate_func(gobj(), &OptionGroup_Translate_glibmm_callback, slot_copy,
    &OptionGroup_Translate_glibmm_callback_destroy);
}

OptionGroup::CppOptionEntry::CppOptionEntry()
: carg_type_(G_OPTION_ARG_NONE), carg_(nullptr), cpparg_(nullptr), entry_(nullptr)
{
}

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 a string.
  case G_OPTION_ARG_FILENAME: // The char* will be for a string in the current locale's encoding.
  {
    char** typed_arg = new char*;
    // The C code will allocate a char* and put it here, for us to g_free() later.
    *typed_arg = nullptr;
    carg_ = typed_arg;

    break;
  }
  case G_OPTION_ARG_INT:
  {
    int* typed_arg = new int;
    *typed_arg = 0;
    carg_ = typed_arg;

    break;
  }
  case G_OPTION_ARG_DOUBLE:
  {
    double* typed_arg = new double;
    *typed_arg = 0.0;
    carg_ = typed_arg;

    break;
  }
  case G_OPTION_ARG_STRING_ARRAY:
  case G_OPTION_ARG_FILENAME_ARRAY:
  {
    char*** typed_arg = new char**;
    // The C code will allocate a char** and put it here, for us to g_strfreev() later.
    *typed_arg = nullptr;
    carg_ = typed_arg;

    break;
  }
  case G_OPTION_ARG_NONE: // Actually a boolean.
  {
    gboolean* typed_arg = new gboolean;
    *typed_arg = false;
    carg_ = typed_arg;

    break;
  }
  case G_OPTION_ARG_CALLBACK:
  {
    // The C arg pointer is a function pointer, cast to void*.
    union {
      void* dp;
      GOptionArgFunc fp;
    } u;
    u.fp = &OptionGroup::option_arg_callback;
    carg_ = u.dp;

    // With all compiler warnings turned on and a high optimization level
    // it's difficult to cast a function pointer to a void*. See bug 589197.
    // A few results with g++ 4.4.5 with the flags -pedantic -O2 -Werror:
    //
    // carg_ = reinterpret_cast<void*>(&OptionGroup::option_arg_callback);
    // error: ISO C++ forbids casting between pointer-to-function and pointer-to-object
    //
    // *reinterpret_cast<GOptionArgFunc*>(&carg_) = &OptionGroup::option_arg_callback;
    // *(OptionArgFunc*)&carg_ = &OptionGroup::option_arg_callback;
    // error: dereferencing type-punned pointer will break strict-aliasing rules
    //
    // If any compiler dislikes the union, the following code is worth testing:
    // carg_ = reinterpret_cast<void*>(
    //         reinterpret_cast<unsigned long>(&OptionGroup::option_arg_callback));

    break;
  }
  default:
  {
    break;
  }
  }
}

void
OptionGroup::CppOptionEntry::set_c_arg_default(void* cpp_arg)
{
  switch (carg_type_)
  {
  case G_OPTION_ARG_INT:
  {
    *static_cast<int*>(carg_) = *static_cast<int*>(cpp_arg);
    break;
  }
  case G_OPTION_ARG_DOUBLE:
  {
    *static_cast<double*>(carg_) = *static_cast<double*>(cpp_arg);
    break;
  }
  case G_OPTION_ARG_NONE:
  {
    *static_cast<gboolean*>(carg_) = *static_cast<bool*>(cpp_arg);
    break;
  }
  case G_OPTION_ARG_STRING:
  case G_OPTION_ARG_FILENAME:
  case G_OPTION_ARG_STRING_ARRAY:
  case G_OPTION_ARG_FILENAME_ARRAY:
  {
    // No need to set default values for string-valued options.
    // If *carg_ is still 0, when convert_c_to_cpp() is called, just don't
    // touch *cpparg_. Besides, setting default values in *carg_ can result
    // in memory leaks, because glib would not free the strings before
    // the char*'s are overwritten with pointers to newly allocated copies
    // of the command option arguments.
    break;
  }
  case G_OPTION_ARG_CALLBACK:
  {
    // No value to set here. The arg pointer is a function pointer.

    // Set or clear FLAG_FILENAME in *entry_.
    const OptionArgCallback* const option_arg = static_cast<const OptionArgCallback*>(cpp_arg);
    if (option_arg->is_filename_option())
    {
      entry_->set_flags(entry_->get_flags() | OptionEntry::FLAG_FILENAME);
    }
    else
    {
      entry_->set_flags(entry_->get_flags() & ~OptionEntry::FLAG_FILENAME);
    }
    break;
  }
  default:
  {
    break;
  }
  }
}

void
OptionGroup::CppOptionEntry::release_c_arg()
{
  // Delete the instances that we created in allocate_c_arg().
  // Notice that we delete the type that we created, but not the value to which it points.
  if (carg_)
  {
    switch (carg_type_)
    {
    case G_OPTION_ARG_STRING:
    case G_OPTION_ARG_FILENAME:
    {
      char** typed_arg = static_cast<char**>(carg_);
      g_free(*typed_arg); // Free the char* string at typed_arg, if 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 = static_cast<int*>(carg_);
      delete typed_arg;

      break;
    }
    case G_OPTION_ARG_DOUBLE:
    {
      double* typed_arg = static_cast<double*>(carg_);
      delete typed_arg;

      break;
    }
    case G_OPTION_ARG_STRING_ARRAY:
    case G_OPTION_ARG_FILENAME_ARRAY:
    {
      char*** typed_arg = static_cast<char***>(carg_);
      g_strfreev(*typed_arg); // Free the array of strings and the array at typed_arg, if allocated
                              // by the C code.
      delete typed_arg; // Delete the char*** that we allocated in allocate_c_arg().

      break;
    }
    case G_OPTION_ARG_NONE: // Actually a boolean.
    {
      gboolean* typed_arg = static_cast<gboolean*>(carg_);
      delete typed_arg;

      break;
    }
    case G_OPTION_ARG_CALLBACK:
    {
      // Delete the OptionArgCallback instance that was allocated by add_entry()
      // or add_entry_filename().
      auto option_arg = static_cast<OptionArgCallback*>(cpparg_);
      delete option_arg;
      cpparg_ = nullptr;

      break;
    }
    default:
    {
      break;
    }
    }

    carg_ = nullptr;
  }

  if (entry_)
    delete entry_;
}

void
OptionGroup::CppOptionEntry::convert_c_to_cpp()
{
  if (!carg_)
    return;

  switch (carg_type_)
  {
  case G_OPTION_ARG_STRING:
  {
    char** typed_arg = static_cast<char**>(carg_);
    auto typed_cpp_arg = static_cast<Glib::ustring*>(cpparg_);
    if (typed_arg && *typed_arg && typed_cpp_arg)
    {
      *typed_cpp_arg = *typed_arg;
    }
    break;
  }
  case G_OPTION_ARG_FILENAME:
  {
    char** typed_arg = static_cast<char**>(carg_);
    auto typed_cpp_arg = static_cast<std::string*>(cpparg_);
    if (typed_arg && *typed_arg && typed_cpp_arg)
    {
      *typed_cpp_arg = *typed_arg;
    }
    break;
  }
  case G_OPTION_ARG_INT:
  {
    *((int*)cpparg_) = *(static_cast<int*>(carg_));
    break;
  }
  case G_OPTION_ARG_DOUBLE:
  {
    *((double*)cpparg_) = *(static_cast<double*>(carg_));
    break;
  }
  case G_OPTION_ARG_STRING_ARRAY:
  {
    char*** typed_arg = static_cast<char***>(carg_);
    auto typed_cpp_arg = static_cast<vecustrings*>(cpparg_);
    if (typed_arg && *typed_arg && typed_cpp_arg)
    {
      typed_cpp_arg->clear();

      // The C array is 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<Glib::ustring,
      // Glib::Container_Helpers::TypeTraits<Glib::ustring>> to std::vector<Glib::ustring> without
      // "std::vector<Glib::ustring>::operator=(const std::vector<Glib::ustring>&)";.
      //
      //(*typed_cpp_arg) = array_handle;
      //
      // And the Tru64 compiler does not even like us to instantiate the StringArrayHandle:
      //
      // 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<CppType>(Glib::wrap_auto(cobj, false /* take_copy */));

      // for(Glib::StringArrayHandle::iterator iter = array_handle.begin(); iter !=
      // array_handle.end(); ++iter)
      //{
      //  typed_cpp_arg->emplace_back(*iter);
      //}

      // So we do this:

      char** char_array_next = *typed_arg;
      while (*char_array_next)
      {
        typed_cpp_arg->emplace_back(*char_array_next);
        ++char_array_next;
      }
    }
    break;
  }
  case G_OPTION_ARG_FILENAME_ARRAY:
  {
    char*** typed_arg = static_cast<char***>(carg_);
    auto typed_cpp_arg = static_cast<vecstrings*>(cpparg_);
    if (typed_arg && *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)
      {
        typed_cpp_arg->emplace_back(*char_array_next);
        ++char_array_next;
      }
    }
    break;
  }
  case G_OPTION_ARG_NONE: // Actually a boolean.
  {
    *(static_cast<bool*>(cpparg_)) = *(static_cast<gboolean*>(carg_));
    break;
  }
  case G_OPTION_ARG_CALLBACK:
  {
    // Nothing to convert here. That's a task for the callback function
    //(the SlotOptionArgString or SlotOptionArgFilename).
    break;
  }
  default:
  {
    break;
  }
  }
}

GOptionGroup*
OptionGroup::gobj_give_ownership()
{
  has_ownership_ = false;
  return gobj();
}

} // namespace Glib

namespace
{
} // anonymous namespace


namespace Glib
{


void OptionGroup::set_translation_domain(const Glib::ustring& domain)
{
  g_option_group_set_translation_domain(gobj(), domain.c_str());
}


} // namespace Glib