Parser la ligne de commande avec getopt_long()

Durant un projet C/C++, j’ai eu besoin de parser efficacement les arguments du programme. Le nombre d’options étant devenu important, j’ai décidé d’utiliser getopt_long, disponible avec GNU C. Une fois l’outil pris en main, j’ai eu un peu de mal à trouver comment se déroulait le parsing des arguments n’étant pas des options (nom de fichier par exemple). C’est finalement en tombant sur de la documentation oracle/sun que j’ai trouvé la solution.

Voici tout d’abord les déclarations de base de pour utiliser getopt_long:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <getopt.h> //requis pour l'utilisation de getopt_long
struct globalArgs_t {
unsigned int help; /* -h option*/
unsigned int algorithm; /* -t option */
bool toStdout ; /*-stdout option*/
bool fromStdin ; /*-stdin option*/
string* infile;
int verbosity; /* -v option */
} globalArgs;

static const char *optString = "t:h?;";//"Il:o:vh?"; //pour plus de détails, cf doc GNU

static const struct option longOpts[] = {
{ "help", no_argument, NULL, 'h' },
{ "algorithm", required_argument, NULL, 't' },
{ "stdin", no_argument, NULL, 0 },
{ "stdout", no_argument, NULL, 0 },
{ "verbose", no_argument, NULL, 'v' },
{NULL, 0, NULL, 0}
};

La première structure globalArgs permet de stocker les valeurs pour les options de nos programmes (et les utiliser plus tard).

La chaîne optString permet de définir la structure des arguments. Les deux points signifient par exemple d’un paramètre est attendu pour l’option -t. Pour plus de détails, je vous conseille la doc GNU.

Enfin, le tableau d’option longOpts[] permet de définir les options longues (spécifiées par –option) ainsi que les options courtes comme -h ou -t.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int parseCmd(int argc, char** argv)

{

int longIndex;
int opt = getopt_long( argc, argv, optString, longOpts, &amp;longIndex );
globalArgs.algorithm = 0;
while ( opt != -1 ) {
switch ( opt ) {
case 't':
if ( strcmp( "alg1", optarg ) == 0 ) {
globalArgs.algorithm = ALG1;
}
//...
if(globalArgs.algorithm == 0){
fprintf(stderr,"Invalid algorithm option, defaulting to alg5\n");
globalArgs.algorithm = ALG5;
}
break;

case 'v':
globalArgs.verbosity++; //-vv will set verbosity to 2 for example
break;

case 'h':   /* fall-through is intentional */
case '?':
displayHelp();
break;
case 0:     /* long option without a short arg */
fprintf(stderr,"case 0");
filtered = false;
if ( strcmp( "stdin", longOpts[longIndex].name ) == 0 ) {
globalArgs.fromStdin = true;
filtered = true;
}

if ( strcmp( "stdout", longOpts[longIndex].name ) == 0 ) {
globalArgs.toStdout = true;
filtered = true;
}
break;

default:
/* You won't actually get here. */
fprintf(stderr,"Error parsing arguments...");
return -1;
break;
}

opt = getopt_long( argc, argv, optString, longOpts, &amp;longIndex );
}
for ( ; optind &lt; argc; optind++) {
if (access(argv[optind], R_OK)) {
// c'est ici que l'on pourra récupérer, par exemple, un non de fichier en entrée et tenter de l'ouvrir
fprintf(stderr,"Non-option argument: %s\n",argv[optind]);
}
}
return 0;
}

L’appel à getopt_long() ne permet pas de récupérer un non de fichier (par exemple) autrement qu’avec -i fichier. Pour utiliser les arguments n’étant pas des options, il faut procéder comme ci-dessus en utilisant optind.

About Ludovic

Ingénieur en informatique dipl. EPFL
Cette entrée a été postée dans la catégorie Uncategorized et taggée , , , . Ajouter le permalink aux favoris.

Comments are closed.