2011-09-20 12 views
13

OK, ho cercato e trovato il seguente due StackOverflow argomenti che mi ha iniziato nella giusta direzione:getopt_long() - modo corretto per usarlo?

Argument-parsing helpers for C/UNIX

Pass arguments into C program from command line

NOTA: Tutto il codice è pseudo-codice. VERRÀ IL CODICE COMPILABILE QUANDO FUNZIONA.

Tuttavia, sono ancora completamente confuso su come utilizzare getopt_long() in C. Il programma che sto scrivendo è definito come avente i seguenti possibili tag (ma può includere tutti quelli di cui hai assolutamente bisogno, riempiendo il resto con valori vuoti):

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

Ora, da quanto ho letto, ho bisogno di utilizzare una struttura per le lunghe opzioni, giusto? Se è così, ho scritto qualcosa sulla falsariga di questo:

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} 
} 

Ora, da quello che ho raccolto, sarei definendolo tramite questo:

int option_index = 0; 

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

Da qui, potrei utilizzare esclusivamente il campo strutturare e fare ciò di cui ho bisogno all'interno del mio programma? Tuttavia, se questo è il caso, qualcuno può spiegare l'intera struttura long_options? Ho letto le pagine man e così, e sono solo completamente confuso. Rileggendo le pagine man, posso vedere che posso impostare le variabili su null, e dovrei impostare tutti i miei requisiti per le opzioni su "required_argument"? E quindi impostare le strutture tramite un ciclo while()? Tuttavia, vedo l'optarg in uso. Questo è impostato da getopt_long()? Oppure manca nell'esempio?

E un ultimo numero, avrò sempre un'opzione richiesta senza nome: nomefile, dovrei semplicemente usare argv [0] per ottenere l'accesso a questo? (Dato che posso presumere che sarà il primo).

Su una nota a margine, questo è correlato a un problema di compiti a casa, ma non ha nulla a che fare con il suo fissaggio, è più fondamentale, deve capire l'argomento passando e analizzando in C tramite riga di comando prima.

+0

La definizione struct mostrati non verrà compilato. Si prega di fornire il codice compilabile. –

+0

'char * [] title;' non è una dichiarazione valida. prova 'char * title [];' Nota che '& field.title' restituirà un' char *** 'che probabilmente non è quello che vuoi. –

+1

Vedere le pagine man per getopt (3) e getopt_long (3), entrambi hanno esempi. –

risposta

22

Prima di tutto, probabilmente non si vuole 0 per il campo has_arg - deve essere uno dei no_argument, required_arguemnt o optional_argument. Nel tuo caso, tutti saranno required_argument. Oltre a ciò, non stai usando il campo flag correttamente - deve essere un puntatore intero. Se il flag corrispondente è impostato, getopt_long() lo inserirà con il numero intero inserito nel campo val. Non penso che tu abbia bisogno di questa funzionalità. Ecco una migliore (abbreviato) ad esempio per il vostro caso:

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

Poi, più tardi, si può usare in modo appropriato (direttamente dalla pagina di manuale, ho aggiunto alcuni commenti):

// 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; 
    } 
} 

È possibile estendere per la vostra altri campi se necessario (e aggiungere un po 'di gestione degli errori, per favore!). Nota: se si desidera utilizzare -title e -artist come nel proprio esempio, sarà necessario utilizzare getopt_long_only(), che non dispone di opzioni brevi.

Per quanto riguarda l'opzione filename, questa verrà visualizzata come '?' dalla chiamata getopt_long(), quindi è possibile gestirla in quel momento.Le altre opzioni richiedono che sia la prima o l'ultima opzione e gestirla separatamente.

+0

L'esempio dato all'uso usa -title, quindi suppongo getopt_long_only() sarà la mia migliore scommessa. Solo per essere sicuro: farò un ciclo while e li cambierò, e farò tutto il mio setting lì. Questo ha molto senso. Come gestirò la variabile senza nome in questo esempio? Impostarlo usando argv [0] prima di iniziare a elaborarli? –

+0

@Jeremy, si, se sai che sarà sempre il primo a star bene. Assicurati di passare 'argv + 1' e' argc-1' alla chiamata 'getopt()' allora, però. Puoi anche gestirlo in un "caso"? "All'interno dell'istruzione switch. –

+0

Dovrebbe essere "struct option" e non "struct options" – Nikko

5

Se si utilizza la libreria popt, si sarà in grado di creare qualcosa di intelligente come avete fatto nel vostro pseudo-codice:

#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) 

essere intelligenti di getopt;)

Problemi correlati