Commit 9c55cd60 authored by Daniel Elstner's avatar Daniel Elstner
Browse files

New class that implements the command-line option interface using the

* src/main.cc (RegexxerOptions): New class that implements the
command-line option interface using the option parsing facilities
of glibmm instead of libpopt.
(parse_command_line): Remove old function that used libpopt to
parse command line options.
(main): Use the new option parsing code.  Also, merge the gettext
initialization into a single call again.  The special trickery that
used to bind the codeset separately after option processing is no
longer necessary with the new parser.

* src/mainwindow.{cc,h} (Regexxer::InitState): Reorganize the data
structure so that default-constructed objects equal the default
values of the command-line options.  This is a work-around for
glibmm bug #393571.
(MainWindow::initialize): Adapt to Regexxer::InitState changes.

* src/translation.{cc,h} (Util::enable_utf8_gettext): Merge back
into Util::initialize_gettext(), as the separation is no longer
necessary.
(compose_impl): Optimize a bit by reserving the memory for the
result string in advance.  Also, replace a couple of `...' quotes
with "..." in a warning message.

* Makefile.am (src_regexxer_LDADD): Remove $(POPTLIBS).
* configure.ac (DK_LIB_POPT): Remove check for libpopt.
* m4/dk-popt.m4: Remove now obsolete file.

svn path=/trunk/; revision=603
parent 003f8dfe
2007-01-06 Daniel Elstner <daniel.kitta@gmail.com>
* src/main.cc (RegexxerOptions): New class that implements the
command-line option interface using the option parsing facilities
of glibmm instead of libpopt.
(parse_command_line): Remove old function that used libpopt to
parse command line options.
(main): Use the new option parsing code. Also, merge the gettext
initialization into a single call again. The special trickery that
used to bind the codeset separately after option processing is no
longer necessary with the new parser.
* src/mainwindow.{cc,h} (Regexxer::InitState): Reorganize the data
structure so that default-constructed objects equal the default
values of the command-line options. This is a work-around for
glibmm bug #393571.
(MainWindow::initialize): Adapt to Regexxer::InitState changes.
* src/translation.{cc,h} (Util::enable_utf8_gettext): Merge back
into Util::initialize_gettext(), as the separation is no longer
necessary.
(compose_impl): Optimize a bit by reserving the memory for the
result string in advance. Also, replace a couple of `...' quotes
with "..." in a warning message.
* Makefile.am (src_regexxer_LDADD): Remove $(POPTLIBS).
* configure.ac (DK_LIB_POPT): Remove check for libpopt.
* m4/dk-popt.m4: Remove now obsolete file.
2007-01-06 Daniel Elstner <daniel.kitta@gmail.com>
* configure.ac (AC_CONFIG_SRCDIR): Name a file that will be
......
......@@ -79,7 +79,7 @@ AM_CPPFLAGS = $(global_defs) -I$(top_builddir) $(REGEXXER_MODULES_CFLAGS) $(REGE
src_regexxer_DEPENDENCIES = src/exported-symbols
src_regexxer_LDFLAGS = $(REGEXXER_EXPORT_DYNAMIC) $(REGEXXER_VERSION_SCRIPT)
src_regexxer_LDADD = $(REGEXXER_MODULES_LIBS) $(POPT_LIBS) $(INTLLIBS)
src_regexxer_LDADD = $(REGEXXER_MODULES_LIBS) $(INTLLIBS)
dist_pkgdata_DATA = ui/mainwindow.glade ui/prefdialog.glade
......
......@@ -44,8 +44,6 @@ AM_GCONF_SOURCE_2()
AC_SUBST([REGEXXER_GCONF_DIRECTORY], ['/apps/regexxer'])
AC_LANG([C++])
DK_LIB_POPT()
DK_LINK_EXPORT_DYNAMIC([REGEXXER_EXPORT_DYNAMIC])
DK_LINK_VERSION_SCRIPT([REGEXXER_VERSION_SCRIPT], [src/exported-symbols])
......
## Copyright (c) 2004-2007 Daniel Elstner <daniel.kitta@gmail.com>
##
## This file is part of danielk's Autostuff.
##
## danielk's Autostuff is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as published
## by the Free Software Foundation; either version 2 of the License, or (at
## your option) any later version.
##
## danielk's Autostuff 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 General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with danielk's Autostuff; if not, write to the Free Software Foundation,
## Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#serial 20070105
## DK_LIB_POPT()
##
## Check whether the popt library and its header file popt.h are available.
## On success, set the output variable POPT_LIBS to "-lpopt".
##
AC_DEFUN([DK_LIB_POPT],
[dnl
AC_CACHE_CHECK([for libpopt], [dk_cv_have_lib_popt],
[
DK_SH_VAR_PUSH([LIBS], ["-lpopt $LIBS"])
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[
#include <popt.h>
]], [[
static struct poptOption option_table[] = { POPT_TABLEEND };
poptContext context;
context = poptGetContext(0, 0, 0, option_table, 0);
poptFreeContext(context);
]])],
[dk_cv_have_lib_popt=yes],
[dk_cv_have_lib_popt=no])
DK_SH_VAR_POP([LIBS])
])
AS_IF([test "x$dk_cv_have_lib_popt" != xyes], [AC_MSG_FAILURE([[
The popt library is required in order to compile $PACKAGE_NAME.
Please install your distribution's libpopt development package.
]])])
AC_SUBST([POPT_LIBS], ['-lpopt'])
])
......@@ -23,7 +23,6 @@
#include "miscutils.h"
#include "translation.h"
#include <popt.h>
#include <glib.h>
#include <gtk/gtkwindow.h> /* for gtk_window_set_default_icon_name() */
#include <glibmm.h>
......@@ -43,7 +42,6 @@
#include <config.h>
namespace
{
......@@ -52,7 +50,6 @@ namespace
*/
#include <ui/stockimages.h>
struct StockIconData
{
const guint8* data;
......@@ -68,6 +65,24 @@ struct StockItemData
const char* label;
};
class RegexxerOptions
{
private:
std::auto_ptr<Regexxer::InitState> init_state_;
Glib::OptionGroup group_;
Glib::OptionContext context_;
static Glib::OptionEntry entry(const char* long_name, char short_name,
const char* description, const char* arg_description = 0);
RegexxerOptions();
public:
static std::auto_ptr<RegexxerOptions> create();
~RegexxerOptions();
Glib::OptionContext& context() { return context_; }
std::auto_ptr<Regexxer::InitState> take_init_state() { return init_state_; }
};
const StockIconData stock_icon_save_all[] =
{
......@@ -82,76 +97,66 @@ const StockItemData regexxer_stock_items[] =
const char *const locale_directory = REGEXXER_DATADIR G_DIR_SEPARATOR_S "locale";
std::auto_ptr<Regexxer::InitState> parse_command_line(int argc, char** argv)
// static
Glib::OptionEntry RegexxerOptions::entry(const char* long_name, char short_name,
const char* description, const char* arg_description)
{
enum
{
NONE = POPT_ARG_NONE,
STRING = POPT_ARG_STRING
};
static const poptOption option_table[] =
{
{ "pattern", 'p', STRING, 0, 'p', N_("Find files matching PATTERN"), N_("PATTERN") },
{ "no-recursion", 'R', NONE, 0, 'R', N_("Do not recurse into subdirectories"), 0 },
{ "hidden", 'h', NONE, 0, 'h', N_("Also find hidden files"), 0 },
{ "regex", 'e', STRING, 0, 'e', N_("Find text matching REGEX"), N_("REGEX") },
{ "no-global", 'G', NONE, 0, 'G', N_("Find only the first match in a line"), 0 },
{ "ignore-case", 'i', NONE, 0, 'i', N_("Do case insensitive matching"), 0 },
{ "substitution", 's', STRING, 0, 's', N_("Replace matches with STRING"), N_("STRING") },
{ "line-number", 'n', NONE, 0, 'n', N_("Print match location to standard output"), 0 },
{ "no-autorun", 'A', NONE, 0, 'A', N_("Do not automatically start search"), 0 },
POPT_AUTOHELP
POPT_TABLEEND
};
std::auto_ptr<Regexxer::InitState> init (new Regexxer::InitState());
const poptContext context = poptGetContext(0, argc, const_cast<const char**>(argv),
option_table, 0);
poptSetOtherOptionHelp(context, _("[OPTION]... [FOLDER]"));
bool autorun = true;
int rc;
while ((rc = poptGetNextOpt(context)) >= 0)
switch (rc)
{
case 'p': init->pattern = Glib::locale_to_utf8(poptGetOptArg(context)); break;
case 'e': init->regex = Glib::locale_to_utf8(poptGetOptArg(context)); break;
case 's': init->substitution = Glib::locale_to_utf8(poptGetOptArg(context)); break;
case 'R': init->recursive = false; break;
case 'h': init->hidden = true; break;
case 'G': init->global = false; break;
case 'i': init->ignorecase = true; break;
case 'n': init->feedback = true; break;
case 'A': autorun = false; break;
}
Glib::OptionEntry option_entry;
if (rc < -1)
{
std::fprintf(stderr, "%s: %s\n%s\n",
poptBadOption(context, 0), poptStrerror(rc),
_("Try \"regexxer --help\" for more information."));
std::exit(1);
}
option_entry.set_long_name(long_name);
option_entry.set_short_name(short_name);
if (const char *const folder = poptGetArg(context))
{
init->folder = folder;
init->autorun = autorun;
if (description)
option_entry.set_description(description);
if (arg_description)
option_entry.set_arg_description(arg_description);
if (poptPeekArg(context)) // more leftover arguments?
{
poptPrintUsage(context, stderr, 0);
std::exit(1);
}
}
return option_entry;
}
poptFreeContext(context);
RegexxerOptions::RegexxerOptions()
:
init_state_ (new Regexxer::InitState()),
group_ (PACKAGE_TARNAME, Glib::ustring()),
context_ ()
{}
return init;
RegexxerOptions::~RegexxerOptions()
{}
// static
std::auto_ptr<RegexxerOptions> RegexxerOptions::create()
{
std::auto_ptr<RegexxerOptions> options (new RegexxerOptions());
Glib::OptionGroup& group = options->group_;
Regexxer::InitState& init = *options->init_state_;
group.add_entry(entry("pattern", 'p', N_("Find files matching PATTERN"), N_("PATTERN")),
init.pattern);
group.add_entry(entry("no-recursion", 'R', N_("Do not recurse into subdirectories")),
init.no_recursive);
group.add_entry(entry("hidden", 'h', N_("Also find hidden files")),
init.hidden);
group.add_entry(entry("regex", 'e', N_("Find text matching REGEX"), N_("REGEX")),
init.regex);
group.add_entry(entry("no-global", 'G', N_("Find only the first match in a line")),
init.no_global);
group.add_entry(entry("ignore-case", 'i', N_("Do case insensitive matching")),
init.ignorecase);
group.add_entry(entry("substitution", 's', N_("Replace matches with STRING"), N_("STRING")),
init.substitution);
group.add_entry(entry("line-number", 'n', N_("Print match location to standard output")),
init.feedback);
group.add_entry(entry("no-autorun", 'A', N_("Do not automatically start search")),
init.no_autorun);
group.add_entry_filename(entry(G_OPTION_REMAINING, '\0', 0, N_("[FOLDER]")),
init.folder);
group.set_translation_domain(PACKAGE_TARNAME);
options->context_.set_main_group(group);
return options;
}
void register_stock_items()
......@@ -226,32 +231,34 @@ void initialize_configuration()
} // anonymous namespace
int main(int argc, char** argv)
{
try
{
Util::initialize_gettext(PACKAGE_TARNAME, locale_directory);
Gnome::Conf::init();
Gtk::Main main_instance (&argc, &argv);
Glib::set_application_name(PACKAGE_NAME);
// Set the target encoding of the translation domain to UTF-8 only after
// parse_command_line() finished, so that the help message is displayed
// correctly on the console in locale encoding.
Util::initialize_gettext(PACKAGE_TARNAME, locale_directory);
std::auto_ptr<Regexxer::InitState> init_state = parse_command_line(argc, argv);
Util::enable_utf8_gettext(PACKAGE_TARNAME);
std::auto_ptr<RegexxerOptions> options = RegexxerOptions::create();
Gtk::Main main_instance (argc, argv, options->context());
Glib::set_application_name(PACKAGE_NAME);
register_stock_items();
gtk_window_set_default_icon_name("regexxer");
gtk_window_set_default_icon_name(PACKAGE_TARNAME);
Regexxer::MainWindow window;
initialize_configuration();
window.initialize(init_state);
window.initialize(options->take_init_state());
options.reset();
Gtk::Main::run(*window.get_window());
}
catch (const Glib::OptionError& error)
{
const Glib::ustring what = error.what();
g_printerr(PACKAGE_TARNAME ": %s\n", what.c_str());
return 1;
}
catch (const Glib::Error& error)
{
const Glib::ustring what = error.what();
......
......@@ -132,16 +132,16 @@ namespace Regexxer
InitState::InitState()
:
folder (Glib::get_current_dir()),
pattern ("*"),
folder (),
pattern (),
regex (),
substitution (),
recursive (true),
no_recursive (false),
hidden (false),
global (true),
no_global (false),
ignorecase (false),
feedback (false),
autorun (false)
no_autorun (false)
{}
InitState::~InitState()
......@@ -201,22 +201,23 @@ MainWindow::~MainWindow()
void MainWindow::initialize(std::auto_ptr<InitState> init)
{
entry_folder_->set_text(
Util::filename_to_utf8_fallback(Util::shorten_pathname(init->folder)));
const std::string folder =
(init->folder.empty()) ? Glib::get_current_dir() : init->folder.front();
entry_pattern_ ->set_text(init->pattern);
entry_folder_ ->set_text(Util::filename_to_utf8_fallback(Util::shorten_pathname(folder)));
entry_pattern_ ->set_text((init->pattern.empty()) ? Glib::ustring("*") : init->pattern);
entry_regex_ ->set_text(init->regex);
entry_substitution_->set_text(init->substitution);
button_recursive_->set_active(init->recursive);
button_recursive_->set_active(!init->no_recursive);
button_hidden_ ->set_active(init->hidden);
button_multiple_ ->set_active(init->global);
button_multiple_ ->set_active(!init->no_global);
button_caseless_ ->set_active(init->ignorecase);
if (init->feedback)
filetree_->signal_feedback.connect(&print_location);
if (init->autorun)
if (!init->no_autorun && !init->folder.empty())
Glib::signal_idle().connect(sigc::mem_fun(*this, &MainWindow::autorun_idle));
}
......
......@@ -30,6 +30,7 @@
#include <glibmm/ustring.h>
#include <list>
#include <memory>
#include <vector>
namespace Gtk
{
......@@ -55,16 +56,16 @@ struct FileInfo;
struct InitState
{
std::string folder;
Glib::ustring pattern;
Glib::ustring regex;
Glib::ustring substitution;
bool recursive;
bool hidden;
bool global;
bool ignorecase;
bool feedback;
bool autorun;
std::vector<std::string> folder;
Glib::ustring pattern;
Glib::ustring regex;
Glib::ustring substitution;
bool no_recursive;
bool hidden;
bool no_global;
bool ignorecase;
bool feedback;
bool no_autorun;
InitState();
~InitState();
......
......@@ -28,7 +28,6 @@
#include <glib.h>
#include <glibmm.h>
namespace
{
......@@ -38,6 +37,13 @@ Glib::ustring compose_impl(const Glib::ustring& format,
using Glib::ustring;
ustring result;
ustring::size_type result_size = format.raw().size();
// Guesstimate the final string size.
for (int i = 0; i < argc; ++i)
result_size += argv[i]->raw().size();
result.reserve(result_size);
ustring::const_iterator p = format.begin();
const ustring::const_iterator pend = format.end();
......@@ -62,7 +68,7 @@ Glib::ustring compose_impl(const Glib::ustring& format,
const ustring buf (1, uc);
g_warning("Util::compose(): invalid substitution `%%%s' in format string `%s'",
g_warning("Util::compose(): invalid substitution \"%%%s\" in format string \"%s\"",
buf.c_str(), format.c_str());
result += '%'; // print invalid substitutions literally
......@@ -82,6 +88,9 @@ Glib::ustring compose_impl(const Glib::ustring& format,
void Util::initialize_gettext(const char* domain, const char* localedir)
{
bindtextdomain(domain, localedir);
# if HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset(domain, "UTF-8");
# endif
textdomain(domain);
}
#else
......@@ -89,16 +98,6 @@ void Util::initialize_gettext(const char*, const char*)
{}
#endif /* !ENABLE_NLS */
#if ENABLE_NLS && HAVE_BIND_TEXTDOMAIN_CODESET
void Util::enable_utf8_gettext(const char* domain)
{
bind_textdomain_codeset(domain, "UTF-8");
}
#else
void Util::enable_utf8_gettext(const char*)
{}
#endif /* !(ENABLE_NLS && HAVE_BIND_TEXTDOMAIN_CODESET) */
const char* Util::translate(const char* msgid)
{
#if ENABLE_NLS
......
......@@ -35,7 +35,6 @@ namespace Util
{
void initialize_gettext(const char* domain, const char* localedir);
void enable_utf8_gettext(const char* domain);
const char* translate(const char* msgid) G_GNUC_PURE G_GNUC_FORMAT(1);
Glib::ustring compose(const Glib::ustring& format, const Glib::ustring& arg1);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment