/*--------------------------------------------------------------- getopt_long Si parte del presupposto che si conosca la teoria retrostante la gestione dei parametri "opzionali". Un limite di questi e' la cripticita', dato che sono lunghi 1 solo carattere. Per ovviare a questo inconveniente sono state approntate le opzioni lunghe, costituite da una stringa di lunghezza arbitraria. Ed e' possi- bile scrivere un programma che si basi solo su queste. Oppure, terza possibilita', si fanno convivere opzioni corte e lunghe. In quest'ultimo caso la funzione da usare e' la getopt_long cui ven- gono passati 5 parametri: 1) numero parametri (desunto dal richiamo del main) 2) array di puntatori ai parametri (desunto dal richiamo del main) 3) stringa con le opzioni corte, seguite o meno da : (1 : per i valori obbligatori; 2 : per quelli opzionali). Nessun : se non sono previsti parametri 4) indirizzo dell'array che mette in corrispondenza opzioni lunghe e corte 5) indice a questo array (in realta' un puntatore) L'array di corrispondenza e' costituito da un array distrutture,i con l'obbligo che l'ultima abbia tutti i campi nulli/azzerati. Ciascuna struttura e' composta da 4 membri: 1) nome lungo 2) indicatore presenza di un argomento supplementare secondo lo schema: 0 oppure no_argument 1 oppure required_argument 2 oppure optional_argument Porre attenzione a non creare incongruenze tra il secondo membro (presenza/non presenza di un argomento supplementare) e carattere ":" nel terzo parametro di chiamata a getopt_long. 3) indicatore "diabolico" se e' 0, allora getopt_long restituisce il valore del 4.to membro della struttura. Viene cosi' realizzato il collega- mento tra opzione lunga e corta. Se ha un valore diverso da 0, allora deve essere il puntatore di una variabile intera in cui verra' memorizzato il valore del 4.to membro della struttura. Ovviamente in questo caso funziona solo l'opzione lunga non esistendo la corrispondente versione corta. L'unico valore sensato per il secondo membro e' no_argument perche' in caso contrario non c'e' modo di recuperalo 4) nome corto dell'opzione (1 carattere) Date le premesse sottostanti: int main (int argc, char **argv) int indopt, ind_zeta; struct option stropt [] = {{"alfa", no_argument, 0, 'a'}, {"beta", required_argument, 0, 'b'}, {"gamma", optional_argument, 0, 'g'}, {"zeta", no_argument, &ind_zeta, 7}, ... getopt_long (argc, argv, "ab:g::", stropt, &indopt); il programma, che supponiamo essere a.out, puo' essere chiamato in maniere diverse. a.out -a a.out --alfa le 2 chiamate sono "quasi" equivalenti. Per distinguere un'opzione breve da una lunga, questa e' preceduta 2 volte dalla lineetta. Se viene usata l'opzione lunga getopt_long restituisce 'a' ed indopt e' posto a 0. Se viene usata l'opzione corta getopt_long restituisce 'a' lasciando intatto il contenuto di in- dopt a.out -bxx a.out -b xx a.out --beta xx a.out --beta=xx le 4 chiamate sono "quasi" equivalenti. Poiche' l'opzione breve e' costituita da un solo carattere l'argomento opzionale puo' es- sere anche separato dall'opzione. Se questa e' nel formato lungo, di cui non e' nota la lunghezza, il separatore e' o il carattere spazio oppure si usa il carattere = (uguale) senza spazi. getopt_ long restituisce 'b' e pone indopt ad 1 solo se viene usata l'opzione lunga a.out --zeta memorizza il valore 7 (che e' arbitrario) nella variabile ind_ze- ta. getopt_long restituisce 0 ed indopt e' posto a 3 a.out -gyy a.out --gamma=yy le 2 chiamate sono "quasi" equivalenti. Poiche' l'argomento opzionale puo' esserci ma anche mancare, l'unica sintassi ammessa e' quella indicata. getopt_restituisce 'g' ed indopt e' posto a 2 (ma solo se viene usata l'opzione lunga) getopt_long ha un comportamento piuttosto bizzarro per quanto ri- guarda il riconoscimento delle opzioni lunghe. Se ad esempio e' prevista l'opzione lunga --delta, --del viene comunque accettata, non pero' --deltam. Da qui la necessita' di un controllo piu' ac- curato delle stringhe passate. ---------------------------------------------------------------*/ #include <getopt.h> #include <regex.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define longopt main int longopt (int argc, char **argv) { extern char *optarg; int carat, indopt, ind_zeta; extern int opterr, optind; struct option stropt [] = { {"alfa", no_argument, 0, 'a'}, {"beta", required_argument, 0, 'b'}, {"gamma", optional_argument, 0, 'g'}, {"zeta", no_argument, 0, 7}, {NULL, 0, 0, 0} }; extern void checkopt (int, char **, int, struct option *); ind_zeta = 0; optarg = NULL; opterr = 0; stropt [3].flag = (int *) (&ind_zeta); while ((indopt = -1, carat = getopt_long (argc, argv, "ab:g::", stropt, &indopt)) != EOF) switch (carat) { case 'a': case 'b': case 'g': if (indopt >= 0) { checkopt (argc, argv, indopt, stropt); printf ("presente opzione %c", carat); printf ("; usata l'opzione lunga (indopt %d)", indopt); } else printf ("presente opzione %c", carat); if (optarg) printf ("; parametro: %s", optarg); printf ("\n"); break; case 0: checkopt (argc, argv, indopt, stropt); printf ("indopt %d; ind_zeta %d\n", indopt, ind_zeta); break; default: fprintf (stderr, "getopt_long error\n"); exit (EXIT_FAILURE); } fprintf (stderr, "numero parametri: %d\n", optind); exit (EXIT_SUCCESS); } void checkopt (int argc, char **argv, int indopt, struct option *stropt) { char *param; int ind, len; extern int match (char *, char *, regmatch_t *); regmatch_t pmatch; for (ind = 1; ind < argc; ind++) { if (strncmp (argv[ind], "--", 2)) continue; (void) match (argv[ind]+2, "[a-zA-Z]+", &pmatch); len = pmatch.rm_eo - pmatch.rm_so; param = (char *) calloc (1, len + 1); strncpy (param, argv[ind]+2+pmatch.rm_so, len); if (!strcmp (param, stropt[indopt].name)) { free ((void *) param); return; } } free ((void *) param); fprintf (stderr, "opzione errata\n"); exit (EXIT_FAILURE); }