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