Re: popt



On Mon, 8 May 2000, NotZed wrote:

> > 
> > Thoughts? Maybe we should fork off the codebase? That sort of sucks on
> > one hand, but on the other hand it's only 600 lines of code.
> 
> Rewrite your own version ...

i really have to side with notzed here, popt is a bunch of
inconvenient crufty code that doesn't scale or provide the
necessary flexibility we'd want in glib.

any program that does:

int
main (int   argc,
      char *argv[])
{
  int i;
  
  /* let submodules filter their options */
  gtk_init (&argc, &argv);
  foo_init (&argc, &argv);
  mymodule1_init (&argc, &argv);
  mymodule2_init (&argc, &argv);
  
  /* process left over options */
  for (i = 1; i < argc; i++)
    process_arg (argv[i]);


is totaly screwed if a library depends on popt arg parsing.
popt takes the immodest approach of "use me all the way or die"
which is simply unaccaptable for scalable code. while i've
seen lots of mails ala "popt handles - as a filename prefix"
and "popt auto-generates my program's help screen!", these
aren't issues that we couldn't facilitate with a good glib
arg parser on our own. i haven't looked at argp yet as federico
suggested, i probably should ;)

so the minimum requirements that have to be fullfilled here are:

- provide a simple but flexible way to describe a program's
  arguments
- support submodules in parsing/removing arguments
- allow the programmer to supply argument descriptions for
  submodules that don't bring their own
- generate --usage and --help style messages
- provide gettext facilities <shrug>; we either need to make
  the translating entity pluggable here, or introduce a
  gettext<-glib dependancy
- pass on unparsed options, e.g. for argv[i] iteration loops
  or further specialized parsing (nice +20)

ad hoc (!), i could imagine something like:

typedef enum
{
  G_OPTION_LAST,
  G_OPTION_PACKAGE,	/* description is i18n domain here */
  G_OPTION_NO_ARG,	/* no argument to this option */
  G_OPTION_REQ_LONG,	/* option requires number argument */
  G_OPTION_CAN_LONG,	/* option can have number argument */
  G_OPTION_REQ_STRING,	/* option requires string argument */
  G_OPTION_CAN_STRING,	/* option can have string argument */
} GOptionType;

struct _GOption
{
  GOptionType otype;
  gchar      *long_name;
  gchar       opt_char;
  glong      *value_p;		/* value location */
  glong       value;		/* *value_p = value; if option found */
  gchar      *description;	/* option description or intl domain */
  gchar	     *arg_name;		/* argument name */
  GOParserCb  option_callback;
  gpointer    callback_data;
};

static void
help_callback (GOParser *oparser, ..., gpointer callback_data)
{
  GString *gstring = g_string_new ("you've gotta use this kickass program:\n");
  
  g_oparser_put_help (oparser, gstring, 80 /* n_columns */);
  g_print ("%s\n", gstring->str);
  g_string_free (gstring, TRUE);
  exit (0);
}

/* options for our program "frobenizer"; translations are done within the
 * "Frobenizer" domain
 */
static glong   tweak = 0;
static glong   with_n_bugs = 1;
static GOption my_options[] = {
  { G_OPTION_PACKAGE,  "frobenizer", 0, NULL, 0, "Frobenizer", "[FILES...]", },
  { G_OPTION_NO_ARG,   "--tweak", 't', &tweak, TRUE, N_ ("enable tweaking"), },
  { G_OPTION_REQ_LONG, "--bugs", 'b', &with_n_bugs, 0,
                       N_ ("set number of bugs [default=1]"), N_ ("NUMBER"), },
  { G_OPTION_NO_ARG,   "--help", 'h', NULL, 0, N_ ("show help message"), NULL,
                       help_callback, NULL, },
  { G_OPTION_LAST, },
};
/* we just provide gtk args here, because gtk doesn't itself come with
 * a GOption array. these provide nothing more than the neccessary stuff
 * for help/usage generation
 */
static GOption gtk_options[] = {
  { G_OPTION_PACKAGE,    "Gtk+", 0, NULL, 0, "Gtk", NULL, },
  { G_OPTION_REQ_STRING, "gtk-debug", 0, NULL, 0,
                         N_ ("Gtk debug flags"), N_ ("FLAGS",) },
  { G_OPTION_NO_ARG,     "sync", 0, NULL, 0,
                         N_ ("Make X calls synchronous"), },
  { G_OPTION_LAST, },
};

int
main (int   argc,
      char *argv[])
{
  GOParser *oparser;
  int *argc_p;
  char **argv_p[];
  int i;
  
  /* initialize GOParser */
  oparser = g_oparser_init (&argc, &argv, 0 /* flags */,
                            my_options,
                            gtk_options,
                            foo_options,
                            mymodule1_options,
                            mymodule2_options,
                            NULL);

  /* get argc & argv that can be crippled by submodules,
   * this already strips options passed after a "--" option
   */
  g_oparser_get_module_options (oparser, &argc, &argv);

  gtk_init (&argc, &argv);
  foo_init (&argc, &argv);
  mymodule1_init (&argc, &argv);
  mymodule2_init (&argc, &argv);
  
  /* let GOParser know what submodules made out of that */
  g_oparser_set_module_options (oparser, &argc, &argv);
  
  /* parse our own options, callbacks are invoked from here */
  g_oparser_process_options (oparser, &argc, &argv);
  
  /* retrive left-over options/file names (merges with what
   * came after "--"
   */
  g_oparser_get_remaining_options (oparser, &argc, &argv);
  
  /* process left over options */
  for (i = 1; i < argc; i++)
    process_arg (argv[i]);
  
  


we may even skip the GOParser *oparser arguments alltogether, assuming
that a program only deals with one set of options. this is just
a sketchy exemplary outline of how a program _could_ be using glib
for option parsing. the g_oparser_* API needs to be somewhat richer,
e.g. to allow to retrive the initial comand line, compose usage
information into a GString, let g_oparser_process_options() support
an error callback for argumentless G_OPTION_REQ_* options,
have g_oparser_get_remaining_options() variants that don't join
left over args with what came after "--", etc...

> 
> Popt is pretty grotty, and well, its only argument parsing.

argument parsing has become quite an issue. it requires quite
thoughfull design if we want to come up with a decent solution.
but i agree that we should really do this thing from scratch ;)


---
ciaoTJ





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]