2011-09-20 2 views
13

OK, je l'ai cherché et trouvé les deux sujets de suite qui m'a commencé dans la bonne direction:getopt_long() - bonne façon de l'utiliser?

Argument-parsing helpers for C/UNIX

Pass arguments into C program from command line

NOTE: TOUS CODE EST-CODE PSEUDO. POSTERA UN CODE COMPILABLE LORSQU'IL FONCTIONNERA.

Cependant, je suis encore complètement confus sur la façon d'utiliser getopt_long() en C. Le programme que j'écris est défini comme ayant les balises possibles suivantes (mais peut inclure autant que vous en avez absolument besoin, en remplissant le reste avec des valeurs vides):

id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1 

maintenant, d'après ce que je lis, je dois utiliser une struct pour les options longues, non? Si oui, je l'ai écrit quelque chose le long des lignes de ce:

struct fields field = 
{ 
    char *[] title; 
    char *[] artist; 
    char *[] album; 
    int year; 
    char *[] comment; 
    int track; 
} 


static struct options long_options[] = 
{ 
    {"title", 0, &field.title, 't'}, 
    {"artist", 0, &field.artist, 'a'}, 
    {"album", 0, &field.album, 'b'}, 
    {"year", 0, &field.year, 'y'}, 
    {"comment", 0, &field.comment, 'c'}, 
    {"track", 0, &field.track, 'u'}, 
    {0, 0, 0, 0} 
} 

Maintenant, ce que je compris, je serais l'appeler par ceci:

int option_index = 0; 

int values = getopt_long(argc, argv, "tabycu", long_options, &option_index); 

A partir de là, pourrais-je utiliser strictement le champ struct et faire ce dont j'ai besoin dans mon programme? Cependant, si tel est le cas, quelqu'un peut-il expliquer la structure entière de long_options? J'ai lu les pages de manuel et autres, et je suis complètement confus. En relisant les pages man, je peux voir que je peux définir des variables à null, et devrait mettre toutes mes exigences d'option à "required_argument"? Et puis définir les structures via une boucle while()? Cependant, je vois optarg utilisé. Est-ce que cela est défini par getopt_long()? Ou est-il manquant de l'exemple?

Et un dernier problème, j'aurai toujours une option obligatoire non nommée: nom de fichier, est-ce que j'utiliserais simplement argv [0] pour y avoir accès? (Puisque je peux supposer que ce sera le premier). Sur une note de côté, cela est lié à un problème de devoirs, mais il n'a rien à voir avec la fixation, c'est plus fondamental, avoir à comprendre l'argument passant et l'analyse en C via la ligne de commande d'abord.

+0

La définition struct montre ne compilera pas. S'il vous plaît fournir un code compilable. –

+0

'char * [] title;' n'est pas une déclaration valide. essayez 'char * title [];' Notez que '& field.title' renverra un' char *** 'qui n'est probablement pas ce que vous voulez. –

+1

Voir les pages de man pour getopt (3) et getopt_long (3), les deux ont des exemples. –

Répondre

22

Tout d'abord, vous ne voulez probablement pas 0 pour le champ has_arg - il doit être l'un des no_argument, required_arguemnt ou optional_argument. Dans votre cas, tous vont être required_argument. De plus, vous n'utilisez pas correctement le champ flag - il doit s'agir d'un pointeur entier. Si l'indicateur correspondant est défini, getopt_long() le remplira par l'entier que vous avez transmis via le champ val. Je ne pense pas que vous ayez besoin de cette fonctionnalité. Voici une meilleure (raccourci) par exemple pour votre cas:

static struct option long_options[] = 
{ 
    {"title", required_argument, NULL, 't'}, 
    {"artist", required_argument, NULL, 'a'}, 
    {NULL, 0, NULL, 0} 
}; 

Puis, plus tard, vous pouvez l'utiliser de façon appropriée (directement à partir de la page de manuel, j'ai ajouté quelques commentaires):

// loop over all of the options 
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1) 
{ 
    // check to see if a single character or long option came through 
    switch (ch) 
    { 
     // short option 't' 
     case 't': 
      field.title = optarg; // or copy it if you want to 
      break; 
     // short option 'a' 
     case 'a': 
      field.artist = optarg; // or copy it if you want to 
      break; 
    } 
} 

Vous pouvez étendre votre d'autres champs si nécessaire (et ajouter une manipulation d'erreur, s'il vous plaît!). Note - Si vous voulez utiliser -title et -artist comme dans votre exemple, vous devez utiliser getopt_long_only(), qui n'a pas d'options courtes. En ce qui concerne votre option filename, vous obtiendrez cette option en tant que '?' à partir de l'appel getopt_long(), afin que vous puissiez le gérer à ce moment-là.Vos autres options sont d'exiger que ce soit la première ou la dernière option et de le gérer séparément.

+0

L'exemple donné à utiliser utilise -title, donc je suppose que getopt_long_only() sera mon meilleur pari. Juste pour être sûr: je vais faire un tour en boucle et les changer, et faire tout mon réglage là. Cela a beaucoup de sens. Comment gérer la variable sans nom dans cet exemple? Définissez-le en utilisant argv [0] avant de commencer à les traiter? –

+0

@Jeremy, ouais si tu sais que ce sera toujours le premier qui ira bien. Assurez-vous de passer 'argv + 1' et' argc-1''a l'appel 'getopt()' alors, cependant. Vous pouvez aussi le gérer dans un 'cas '?'' Dans l'instruction switch. –

+0

Il devrait être "option struct" et non "struct options" – Nikko

5

Si vous utilisez la bibliothèque popt, vous serez en mesure de créer quelque chose d'intelligent que vous avez fait dans votre pseudo-code:

#include <stdio.h> 
#include "popt.h" 

struct _field { 
    char *title; 
    char *artist; 
    /* etc */ 
} field; 

field.title = NULL; 
field.artist = NULL; 

/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */ 
struct poptOption optionsTable[] = { 

    {"title", 't', POPT_ARG_STRING, &field.title, 't' 
    "set the 'title' of the album" }, 
    {"artist", 'a', POPT_ARG_STRING, &field.artist, 'a' 
    "set the 'artist' of the album" }, 
    POPT_AUTOHELP 
    POPT_TABLEEND 
}; 

poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); 
poptSetOtherOptionHelp(optCon, "[OPTIONS]"); 

char c; 
while ((c = poptGetNextOpt(optCon)) >= 0) { 
    switch (c) { 
     case 't': 
      /* do extra stuff only if you need */ 
      break; 
     case 'a': 
      /* do extra stuff only if you need */ 
      break; 
     default: 
      poptPrintUsage(optCon, stderr, 0); 
      exit(1); 
    } 
} 

if (field.title) printf("\nTitle is [%s]", field.title); 
if (field.artist) printf("\nArtist is [%s]", field.artist) 

Soyez intelligent que getopt;)