[PATCH] Implement support for command line argument parsing using <argp.h>
Sergio Durigan Junior
sergiodj en sergiodj.net
Sab Mar 15 21:48:33 UTC 2014
On Saturday, March 15 2014, Thadeu Lima de Souza Cascardo wrote:
>> diff --git a/configure.ac b/configure.ac
>> index c7a85dc..e06ecdf 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -7,4 +7,5 @@ PKG_CHECK_MODULES(GNUTLS, gnutls >= 1.4.0, , AC_MSG_ERROR(Could not find gnutls)
>> AM_PATH_LIBGCRYPT(,,AC_MSG_ERROR(Could not find gcrypt))
>> LIBS="$LIBGCRYPT_LIBS $GNUTLS_LIBS $LIBS -lz"
>> CFLAGS="$LIBGCRYPT_CFLAGS $GNUTLS_CFLAGS $CFLAGS"
>> +AC_CONFIG_HEADERS([config.h])
>> AC_OUTPUT(Makefile)
>> diff --git a/rnetclient.c b/rnetclient.c
>> index d264c72..eb5a391 100644
>> --- a/rnetclient.c
>> +++ b/rnetclient.c
>> @@ -27,10 +27,81 @@
>> #include <netdb.h>
>> #include <gnutls/gnutls.h>
>> #include <zlib.h>
>> +#include <argp.h>
>> +#include "config.h"
>> #include "decfile.h"
>> #include "rnet_message.h"
>> #include "rnet_encode.h"
>>
>> +/* Program version and bug report address. */
>> +
>> +const char *argp_program_version = PACKAGE_VERSION;
>> +const char *argp_program_bug_address = PACKAGE_BUGREPORT;
>
> Esse bug report vai usar o meu endereço de email que está no configure.ac,
> correto? Melhor mudarmos para o endereço da lista.
Sim, correto. Endereço alterado.
>> +
>> +/* Documentation strings. */
>> +
>> +static const char rnetclient_doc[] =
>> + "Send the Brazilian Income Tax Declaration to the Brazilian "
>> + "Tax Authority";
>
> Eu prefiro Tax Report. Pra quem está procurando uma oportunidade de
> contribuir, já vamos precisar internacionalizar o rnetclient.
OK, coloquei Income Tax Report.
BTW, pra quem quiser internacionalizar, gettext na cabeça.
>> +static const char rnetclient_args_doc[] =
>> + "[-d|--declaration] FILE";
>> +
>
> Será que não tem um nome de opção mais neutro entre as duas línguas? Ia
> sugerir input e output. report e receipt não vai funcionar muito bem.
> Talvez a gente tenha que deixar esse "declaration" mesmo.
Eu prefiro/preferi deixar declaration. Acho que report e receipt não
ficam legais, mesmo.
>> +/* Description and definition of each option accepted by the program. */
>> +
>> +static const struct argp_option rnetclient_options_desc[] = {
>> + { "declaration", 'd', "FILE", OPTION_ARG_OPTIONAL,
>> + "The Income Tax Declaration file that will be sent.",
>> + 0 },
>> +
>> + { NULL },
>> +};
>> +
>> +struct rnetclient_args {
>> + /* File representing the declaration. */
>> + char *file;
>> +};
>
> Sugiro já usar algo como input_file, pois a sequência lógica a esse
> patch é permitir passar o caminho do arquivo do recibo como parâmetro.
Feito.
>> +
>> +/* Parser for command line arguments. */
>> +
>> +static error_t rnetclient_parse_opt(int key, char *arg, struct argp_state *state)
>> +{
>> + struct rnetclient_args *a = state->input;
>> + switch (key) {
>> + case 'd':
>> + /* The user has explicitly provided a filename through
>> + the '-d' switch. */
>> + a->file = arg;
>> + break;
>> +
>> + case ARGP_KEY_ARG:
>> + /* The user has possibly provided a filename without
>> + using any switches (e.g., by running './rnetclient
>> + file'). */
>> + a->file = arg;
>> + break;
>> +
>> + case ARGP_KEY_END:
>> + /* We have reached the end of the argument parsing.
>> + Let's check if the user has provided a filename. */
>> + if (arg == NULL && a->file == NULL)
>
> Quando arg não é NULL nesse caso? O que acontece?
Ops, falha minha, esse código era diferente mas eu esqueci de tirar essa
checagem. Só verifico por a->input_file == NULL agora.
>> @@ -329,17 +394,17 @@ int main(int argc, char **argv)
>> int r;
>> struct rnet_decfile *decfile;
>> struct rnet_message *message = NULL;
>> + struct rnetclient_args rnet_args;
>> gnutls_session_t session;
>> int finish = 0;
>> char *cpf;
>>
>> - if (argc < 2) {
>> - usage();
>> - }
>> + memset (&rnet_args, 0, sizeof (rnet_args));
>> + argp_parse (&rnetclient_argp, argc, argv, 0, NULL, &rnet_args);
>
> argp_parse pode falhar por outra razão que não chame exit, e retorne um
> código de erro?
De acordo com a documentação da função, presente em /usr/include/argp.h:
/* Parse the options strings in ARGC & ARGV according to the options in ARGP.
FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the
index in ARGV of the first unparsed option is returned in it. If an
unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser
routine returned a non-zero value, it is returned; otherwise 0 is
returned. This function may also call exit unless the ARGP_NO_HELP flag
is set. INPUT is a pointer to a value to be passed in to the parser. */
extern error_t argp_parse (const struct argp *__restrict __argp,
int __argc, char **__restrict __argv,
unsigned __flags, int *__restrict __arg_index,
void *__restrict __input);
É possível, em casos isolados, que a função retorne algum código
diferente de zero caso o parser interno (definido por nós) retorne esse
código. No entanto, do jeito que ele está feito hoje, esse cenário é
impossível. Portanto, eu coloquei um check pra verificar isso.
> Note também o estilo do código: memset () vs memset().
Ouch, eu juro que me esforcei pra seguir, mas justo nessa eu escorreguei
:-).
Bem, vou mandar o v2 em seguida, já que esse tal de git dificulta o
patch review absurdamente!
--
Sergio
Más información sobre la lista de distribución Softwares-impostos