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