Hello,

First of all, thanks for the initial review of my proposal!

I have made some changes in response to the comments as well as last
mail on the mailing list by Darshit Shah. Kindly consider reviewing it.
For reference here is the link.
https://docs.google.com/document/d/1SBM-jNG5dJL85C7iK9aid2eDlByrxOsYUNDrk4049vQ/edit?usp=sharing

The proposal is still not final, in the sense that I am analysing the
code for further ideas of what can be customized using plugins.

I was asked to elaborate on rewriting of command line option processing
code. So here are my thoughts on it.

The current code in src/options.c has following drawbacks:
  -  Built around order-insensitive and idempotent model (Supplying
     an option modifies a variable). This might be adequete for wget,
     but might not be the case for plugins. Repeated options or
     order of options can matter for plugins.
  -  The need for keeping the list of options sorted. I don't think
     we can expect plugin writers to do the same.
  -  And most importantly, options cannot be added at runtime.

So far I think rewriting the option processing code would be easier
than trying to patch existing code to support custom options.
Some parts of the original code could be reused but structure
would undergo a drastic change anyway.

The idea I have is to expose an interface for plugins to describe
command line options they want to receive. I have attached a
prototype header. From this interface, wget will have a list of
command line options to support, along with plugin function to
be called for handling plugin specific options. In addition to
using this to parse command line, wget can Use the descriptions
and category information provided to generate --help output.

Regarding the need to support plugin side addition of command line
options at the first place, here are my thoughts.
Plugins might need additional data from the user. I can think
of 3 ways in which it can be done:
  1. Environment variables.
  2. Files with well-known names.
  3. Command line.
Environment variables have a disadvantage that they are automatically
passed to the subprocesses, creating a chance for interference.
Also, name clashes cannot be discovered.

Using files with well-known names has a chance of interference
with parallel running instances of wget.

None of these disadvantages are shared with using command line
options.

Opinions are welcome.

Regards,
Akash Rawal.



/* This is a prototype. Final product can be different. */

/**
 * \addtogroup argp
 * \{
 *
 * This section documents functions for extending command line 
 * option processing. 
 *
 * The procedure is to first create a new option list using 
 * _wget_argp_optlist_init_. Options and categories are then added by
 * _wget_argp_optlist_add_option_ and _wget_argp_optlist_add_category_. 
 * Finally, options are added for consideration by _wget_argp_add_optlist_.
 * After this, option list should be free'd using _wget_argp_optlist_free_.
 */


///Data structure for command line options
typedef struct _wget_argp_optlist_t wget_argp_optlist_t;

/**Creates a new option list
 * \return A newly constructed option list. Free with _wget_argp_optlist_free_
 */
wget_argp_optlist_t *wget_argp_optlist_init();

/**Frees all memory associated with _optlist_.
 * \param optlist An option list created with _wget_argp_optlist_init_
 */
void wget_argp_optlist_free(wget_argp_optlist_t *optlist);

/**Adds a new category to command line options.
 * \param optlist An option list
 * \param catid Category identifier. This must be unique.
 * \param desc Description which will appear in the _--help_ output.
 */
void wget_argp_optlist_add_category
	(wget_argp_optlist_t *optlist, const char *catid, const char *desc);

///Type of command line options supported
typedef enum
{
	///Option accepts no arguments
	WGET_ARGP_ARG_NONE,
	//Option requires argument.
	WGET_ARGP_ARG_REQUIRED,
	//Option accepts argument, but it is optional.
	WGET_ARGP_ARG_OPTIONAL
} wget_argp_option_arg_type;

/**Adds a command line option to option list.
 * \param catid Category identifier to specify which category to 
 *              add option to in _--help_ output. 
 * \param optlist An option list
 * \param id A numeric ID to associate with the option.
 * \param short_option Single letter short option, or 0 for no short option.
 * \param option Long option. 
 * \param arg_desc A short description of the argument it takes.
 * \param argtype Argument accepting policy. See _wget_argp_option_arg_type_
 * \param negatable Nonzero if _option_ can be supplied as --no-option.
 * \param desc Description which will appear in _--help_ output.
 */
void wget_argp_optlist_add_option
	(wget_argp_optlist_t *optlist, 
	 const char *catid, int id, 
	 char short_option, const char *option, const char *arg_desc, 
	 wget_argp_option_arg_type argtype, int negatable,
	 const char *desc);

/**Type of function to be registered as a callback
 * \param id Identifier of the option matched
 * \param value Option value, which can be NULL if value if optional 
 *              or is negated. 
 * \param negated Option supplied as --no-option. 
 *                _value_ is NULL in this case.
 * \param user_data User data passed to wget_argp_add_optlist
 * \return 0 should be returned if the option was parsed correctly, or -1 
 *         in case of failure.
 */
typedef int (*wget_argp_callback_fn)
	(int id, const char *value, int negated, void *user_data);

/**Adds a list of command line options to a category.
 * \param optlist Option list
 * \param callback Callback function to call for a matching option.
 * \param user_data Data to pass to callback function. 
 * \return 0 if the operation was successful, or -1 in case of name clashes.
 */
/* Implementation note: This is the only function that will be implemented 
 * outside libwget.
 */
int wget_argp_add_optlist(wget_argp_optlist_t *optlist,
		wget_argp_callback_fn callback, void *user_data);

/* ***********/
//Utility functions

/**Reads argument as integer and stores into _out_. 
 * On failure _out_ is not modified.
 * \param arg Argument to parse
 * \param out Pointer to store resultant value.
 * \return 0 if operation was successful, -1 if _arg_ is not a valid integer.
 */
int wget_argp_parse_int(const char *arg, int *out);

/**Reads argument as a human readable size and stores into _out_. 
 * On failure _out_ is not modified.
 * \param arg Argument to parse
 * \param out Pointer to store resultant value.
 * \return 0 if operation was successful, -1 if _arg_ is not a valid input.
 */
int wget_argp_parse_numbytes(const char *arg, long long *out);

/**Perform shell-style expansion of argument as a filename.
 * \param arg Argument to parse
 * \return expanded filename
 */
char *wget_argp_parse_filename(const char *arg);

/**Reads argument as a list of strings and stores into _out_
 * \param arg Argument to parse
 * \out Destination to store the list
 */
void wget_argp_parse_stringset(const char *arg, wget_stringmap_t **out);

///\}

Reply via email to