C : récupérer les arguments grâce à getopt_long
J’ai commencé à lire les premiers chapitres de l’excellent e-book Advanced Linux Programming, et je dois avouer apprendre pas mal de choses. Je vous propose ici de vous partager l’une d’entre elles, à savoir comment récupérer efficacement les arguments de la ligne de commande en C.
Nous allons dans ce billet développer une simple application de type Hello World!, mais qui prendra en compte différents arguments. Sinon, avouez que ce billet ne servirait pas à grand chose. Tout d’abord donc, rédigeons notre programme, sans argument. A priori, pas de difficultés particulières.
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Hello world!n");
return 0;
}
A présent, nous allons ajouter plusieurs options à notre programme : une option d’aide permettant d’afficher les différents arguments acceptés, ainsi qu’une fonction output permettant d’écrire Hello world! dans un fichier plutôt que dans la sortie standard.
On dispose donc de deux arguments facultatifs, dont l’un attend obligatoirement une option. Ceux-ci peuvent donc apparaître ou non, dans n’importe quel ordre. De plus, pour être le plus proche possible des bonnes pratiques Linux, nous allons autoriser l’écriture de ces arguments sous forme longue (par exemple, –help) ou sous forme courte (-h). Tout cela pourrait s’avérer particulièrement lourd à gérer si nous nous contentions d’utiliser le tableau d’arguments argv. Heureusement pour vous, il y a la fonction getopt_long. ;)
Pour l’utiliser, nous devons tout d’abord inclure le header associé.
#include <getopt.h>
Nous devons ensuite définir notre liste d’arguments. Pour ce faire, nous devons définir une chaîne de caractère et un tableau de structures de type option.
const char* const short_options = "ho:"
Cette chaîne de caractères comprend la liste de toutes nos options au format court. On ajoute deux points après la lettre correspondante afin d’indiquer que nous attendons une valeur pour cet argument. Dans ce cas, ce sera le nom du fichier de sortie (-o myfile.txt).
const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "output", 1, NULL, 'o' },
{ NULL, 0, NULL, 0 }
};
Chaque structure contient, dans l’ordre, le nom de l’argument, un entier selon si cet argument attend une valeur, un argument NULL (pour que la fonction nous retourne bien la valeur spécifiée), et enfin son équivalent raccourci.
Tout est donc prêt pour que nous parsions notre commande. Voyons donc comment faire.
int next_option = 0;
do {
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
switch(next_option)
{
case 'o': // Or --output
break;
case 'h': // Or --help
return 0;
case -1: // End of arguments list.
break;
default: // Unexpected behavior.
return -1;
}
} while(next_option != -1);
On utilise un compteur qui nous permettra de nous déplacer dans nos arguments. Celui-ci prendra alors les valeurs de nos caractères (qui ne sont au final que des entiers en C) tant qu’il rencontrera des arguments. Celui-ci prendra la valeur -1 si nous arrivons à la fin. Libre à vous d’implémenter les comportements qui vous intéressent.
A titre d’information, le reste du code étant du C standard, voici le code source de notre « Hello World! » amélioré.
#include <getopt.h>
#include <stdio.h>
void print_help()
{
printf("\n\nUsage:\n");
printf("\t-o (--output): display 'Hello world!' into the specified file.\n");
printf("\t-h (--help): display this help message.\n\n");
}
int main(int argc, char* argv[])
{
int next_option = 0;
const char* const short_options = "ho:";
const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "output", 1, NULL, 'o' },
{ NULL, 0, NULL, 0 }
};
const char* output_filename = NULL;
// Retrieving all our arguments
do {
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
switch(next_option)
{
case 'o': // Or --output
output_filename = optarg;
break;
case 'h': // Or --help
print_help();
return 0;
case -1: // End of arguments list.
break;
default: // Unexpected behavior.
print_help();
return -1;
}
} while(next_option != -1);
// Writing our Hello World!
if(output_filename != NULL)
{
FILE *file = NULL;
file = fopen(output_filename, "w");
fprintf(file, "Hello world!\n");
fclose(file);
}
else
{
printf("Hello world!\n");
}
return 0;
}
A noter qu’il existe un équivalent pour Windows de cette librairie : la librairie ArgTable.
Comments
Trackbacks
There are no trackbacks on this entry.
Merci pour ce code nettement mieux expliqué (et avec des noms de variable plus explicites) que ce que l’on peut trouver sur le manpage.
Personnellement, je n’avais pas compris l’interet du short_options, je pensais que ce paramètre ne servait a rien vu qu’on déclarait deja les short_options dans la structure option au niveau du parametre « val » …
Merci !