/*----------------------------------------------------------------
                             shortopt

 Il programma usa i parametri opzionali, cioe' quelli che iniziano
 con il - (meno). Sono previsti 2 parametri:  un  file  e  l'indi-
 cazione se compremerlo o decomprimerlo. In pratica:
      programma -fxxxx -c  // per comprimere
      programma -fxxxx -d  // per decomprimere
 In  caso  di compressione, si puo' aggiungere un numero, compreso
 tra 1 e 9, che indica la massima velocita' (1) oppure la migliore
 compressione (9). In mancanza, viene usato il 6.


      Messaggistica

 ci sono xxxx parametri extra
      ci sono xxxx parametri non opzionali
 exec error
 getopt error
 parametri incompleti|errati
 parametro xxxx duplicato/incompatibile
      autoesplicativi

                             ---(O)---

 Un  programma  puo'  essere  congegnato  in  modo da poter essere
 chiamato con dei parametri del tipo:
      -x[valore]
 ovvero il carattere - (meno) seguito da  1  carattere.  Opzional-
 mente  il  carattere puo' essere seguito, senza separatori, da un
 valore.  Un esempio e' la compilazione  di  un  programma  C  che
 richieda  la  libreria  matematica e lo strip dell'eseguibile. Il
 comando e':
      cc ... -lm -s
 Questi parametri, detti "opzionali", vengono gestiti  tramite  la
 chiamata alla funzione getopt (inserire lo header getopt.h).

 Se  un programma e' congegnato in modo da essere chiamato con dei
 parametri  opzionali, ad  esempio «x» e «y», allora  la defizione
 del main e della getopt devono  essere correlate come segue:

      int main (int argc, char **argv)
      getopt (argc, argv, "x:y")

 ove argc e' il numero dei parametri con cui l'eseguibile e' stato
 chiamato  ed  argv  e'  un  array di puntatori  alle stringhe co-
 stituenti i parametri. Come 3^ parametro  della getopt  c'e'  una
 stringa   contenente   i   caratteri   che  contraddistinguono  i
 parametri. Ciascun carattere puo' essere seguito da nessun, 1 op-
 pure  2  :  (doppio  punto).  Il  singolo  : indica che l'opzione
 richiede un valore, mentre il doppio : indica che un valore  puo'
 seguire  il  parametro.   L'assenza di : indica che non sono pre-
 visti valori.

 La getopt restituisce il carattere del parametro, se esso e'  ri-
 conosciuto.   Oppure  un  errore.  Alla  fine della scansione dei
 parametri viene restituito EOF.  Nel caso di errore, si puo' con-
 trollare  la  diagnostica  ponendo  a  zero  la  variabile intera
 opterr, da definire come extern int. E' possibile  sapere  se  ci
 sono  dei  parametri extra (non opzionali). Alla fine della scan-
 sione dei parametri la variabile optind -da definire come  extern
 int-  conterra'  il  numero dei parametri opzionali, validi o no,
 aumentato di 1. argc, come al solito, contiene il  numero  totale
 dei  parametri.  Se  le  due quantita' non coincidono allora sono
 presenti dei parametri non opzionali.  Se  infine  sono  previsti
 dei  valori,  allora bisogna predisporre delle apposite variabili
 per ospitarli. Ma la getopt restituisce un puntatore  al  valore,
 considerato  sempre come una stringa. Il puntatore viene messo in
 optarg, da definire come «extern char *».
----------------------------------------------------------------*/

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define True  1
#define False !True

int main (int argc, char **argv)
{
  char          *d = NULL, degr [3], *f = NULL;
  unsigned char mask = 0;
  extern char   *optarg;
  int           c, op = 0, err = False;
  extern int    opterr, optind;
  void          checkey (int, unsigned char *, int, int *);

  memset (degr, (int) NULL, sizeof degr);
  opterr = 0;
  while ((c = getopt (argc, argv, "c::df:")) != EOF)
    switch (c)
      {
        case 'c':
          checkey (1, &mask, c, &err);
          d = optarg;
          op = c;
          break;
        case 'd':
          checkey (1, &mask, c, &err);
          op = c;
          break;
        case 'f':
          f = optarg;
          break;
        default:
          fprintf (stderr, "getopt error\n");
          err = True;
          break;
      }
  if (optind != argc)
    fprintf (stderr, "ci sono %d parametri extra\n", argc - optind);
  if (op == 0 || f == NULL || err)
    {
      fprintf (stderr, "parametri incompleti|errati\n");
      exit (EXIT_FAILURE);
    }
  else
    if (op == 'c')
      {
        if (d == NULL)
          strcpy (degr, "-6");
        else
          strcpy (degr, "-"), strcat (degr, d);
        execl ("/bin/gzip", "gzip", degr, f, NULL);
      }
    else
      execl ("/bin/gunzip", "gunzip", f, NULL);
  fprintf (stderr, "exec error\n");
  exit (EXIT_SUCCESS);
}

void checkey (int i, unsigned char *m, int op, int *e)
{
  unsigned char tmp = 0;

  tmp = (1 << i);
  if (! ((tmp & *m) ^ tmp))
    {
      fprintf (stderr, "parametro (%c) duplicato/incompatibile\n", op);
      *e = True;
    }
  else
    *m |= tmp;
}