Archive

Posts Tagged ‘argumentos’

Tratando argumentos passados a um programa em C


Recentemente, tive de escrever um programa em C na minha iniciação científica e o objetivo principal do programa era ler o arquivo de um outro e retirar dele, algumas informações. Assim, eu precisaria passar o nome do programa e mais algumas opções que se fizessem necessárias como argumentos para o meu programa, mas queria fazer isso de uma maneira mais organizada e então resolvi procurar alguma função que fosse capaz de tratar desses argumentos.  Tive sorte de encontrar a função getopt da biblioteca unistd.h. Essa função é muito similar ao comando getopts em shell script. De fato, é a cópia dela em linguagem C (ou seria a getopts a cópia da getopt em shell script? Bah! Deixa pra lá!)

A sintaxe dessa função é:

int getopt (int argc, char **argv, const char *options)
extern char *optarg;
extern int optind, opterr, optopt;

A função getopt retorna o próximo caractere passado como argumento ou -1 quando a lista de argumentos passados termina. Se o caractere é desconhecido ou não foi passado o argumento a uma opção que requer, será retornado  ‘?’.  O argumento options é uma string que irá dizer quais são as opções válidas para o seu programa.  Se uma opção requer um argumento, você precisa especificar isso colocando um ‘:’ na frente dessa opção.

As variáveis externas apresentadas acima carecem de uma explicação:

  • opterr – Se a função getopt encontra algum erro como um caractere de opção inválido ou a falta de algum argumento que não foi passado para uma opção, ela imprime uma mensagem de erro. Para desativar essas mensagens e você mesmo tratar elas, você pode definir a variável com um valor zero no seu programa.
  • optarg –  Você passa ao seu programa opções, mas algumas delas requerem algum argumento. Por exemplo, uma opção como -o poderia necessitar que você especificasse um arquivo de saída. A variável optarg é um ponteiro para a string que contém o argumento passado a opção retornada pela função getopt.
  • optind – Essa variável é utilizada como forma de saber qual o próximo elemento de argv deve ser processado. Ele é bastante útil para você tratar argumentos que não são opções e nem argumentos de opções. O programa abaixo irá mostrar um exemplo.
  • optopt – Se a função getopt encontrar um caractere de opção desconhecido ou o usuário não passou o argumento que deveria para uma determinada opção,  será retornado ‘?’ e  a função getopt irá armazenar caractere nessa variável.

Assim, vamos considerar um programa que aceite  as opções x, y e z, sendo que z necessita de um argumento a ser passado.  Esse programa poderia se chamar testagetopt e ser como abaixo:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>

int main ( int argc, char *argv[] )
{
	int opcao;		// Opção passada pelo usuário ao programa.
	int indice;		// Usado para pegar argumentos que não são opções
				    // Nem argumentos usados em opções.

	int xflag =  0;		// Opção -x desativada por default
	int yflag =  0;		// Opção -y desativada por default

	char *zarg = NULL;      // Irá apontar para o argumento de z
				            // se for passado.

	// Desativa as mensagens de erro da função getopt
	opterr = 0;

	// Faz um loop pegando as opções passados pelo usuário. Note
	// o ':' depois do 'z'. Isso quer dizer que deve haver um
	// argumento depois dessa opção.
	while ( ( opcao = getopt ( argc, argv, "xyz:" ) ) != -1 )
	{
		switch ( opcao )
		{
			// Usuário passou a opção -x, habilita:
			case 'x':
				xflag = 1;
				break;

			// Usuário passou a opção -y, habilita:
			case 'y':
				yflag = 1;
				break;

			// Usuário escolheu a opção -z, pegar o argumento
			case 'z':
				zarg = optarg;
				break;

			// Se houve algum problema, vamos diagnosticar e enviar
			// nossas próprias mensagens de erro.
			case '?':
				if ( optopt == 'z' )	// Esqueceu um argumento
					fprintf (stderr, "Opção '-%c' requer argumento.\n",
					optopt);
				else if ( isprint ( optopt ) )
				     	fprintf( stderr, "Opção '-%c' desconhecida.\n",
				        optopt );
			        else
			            fprintf( stderr, "Caractere '\\x%x' de opção desconhecido.\n",
				            optopt );
				exit ( 1 );
		}
	}

	printf ( "         xflag = %s\n", xflag ? "sim" : "não" );
	printf ( "         yflag = %s\n", yflag ? "sim" : "não" );
	printf ( "          zarg = %s\n", zarg  ?  zarg : "nenhum" );

	printf ( "Outros argumentos:\n" );

	for ( indice = optind; indice < argc; indice++ )
		printf ( "                 %s\n", argv[indice]);

	return 0;
}

Compile o programa:

$ gcc -o testagetopt testagetopt.c

Executando com algumas opções teríamos:

shell> ./testagetopt -xy -z topgear.txt testagetopt blabla
         xflag = sim
         yflag = sim
          zarg = topgear.txt
 Outros argumentos:
                 testagetopt
                 blabla

shell> ./testagetopt -x -z topgear.txt testagetopt blabla
         xflag = sim
         yflag = não
          zarg = topgear.txt
Outros argumentos:
                 testagetopt
                 blabla

shell> ./testagetopt -y -z topgear.txt testa?.txt
         xflag = não
         yflag = sim
          zarg = topgear.txt
Outros argumentos:
                 testa1.txt
                 testa2.txt
                 testa3.txt
                 testa4.txt
shell> ./testagetopt -z
Opção '-z' requer argumento.

$ ./testagetopt -c
Opção '-c' desconhecida.

shell> ./testagetopt -xy topgear.txt
         xflag = sim
         yflag = sim
          zarg = nenhum
Outros argumentos:
                 topgear.txt

Bem mais prático!

Referências:

Using getopt – Documentação oficial da função

Documentação relacionada:

Getopt Long Options –  Para o caso de você querer usar opções longas, não somente com uma letra.

Argp – Um função que permite tanto opções longas quanto curtas, além de criar uma saída para as opções --help e --version automaticamente.