Exercice langage C : Analyser les Paramètres

Écrire un programme qui analyse les paramètres qui lui sont passés. Ce programme devra être appelé de la manière suivante :

exo11 -a chaine1|-b chaine2|-c chaine3 [-d -e -f] fichier

  1. une seule des options -a-b ou -c doit être spécifiée, suivie d'une chaîne,
  2. les options -d-e-f sont facultatives. Si aucune d'entre elles n'est indiquée, le programme doit les considérer comme toutes présentes,
  3. un nom de fichier doit être spécifié.

On essaiera de rendre l'appel le plus souple possible :

  1. exo11 -a chaîne -e fichier
  2. exo11 -b chaîne fichier -d -f
  3. exo11 -c chaîne fichier -df 
    (regroupement des options -d et -f).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include 
#include 
#include 

void traitement_option( const unsigned char option );
void usage( char *s );

const unsigned char  option_a = 1;
const unsigned char  option_b = 2;
const unsigned char  option_c = 4;
const unsigned char  option_d = 8;
const unsigned char  option_e = 16;
const unsigned char  option_f = 32;
unsigned char        mask_options = 0;
char                *valeur_option = NULL, *fichier = NULL;
char                *module;

void bilan_options( void );

§MEVBCBfint main( int argc, char **argv )
{
  /* Sauvegarde du nom de l'exécutable. */
  module = strdup( *argv );
  /* Boucle sur les arguments. */
  while( *++argv != NULL )
  {
    /*
     * Est-ce que l'argument commence
     * par le caractère '-' ?
     */

    if( (*argv)[0] == '-' )
    {
      /* On analyse les caractères qui suivent. */
      for( (*argv)++; **argv; (*argv)++ )
      {
        switch( **argv )
        {
          case 'a':
            traitement_option( option_a );
            break;
          case 'b':
            traitement_option( option_b );
            break;
          case 'c':
            traitement_option( option_c );
            break;
          case 'd':
            traitement_option( option_d );
            break;

           case 'e':
            traitement_option( option_e );
            break;
          case 'f':
            traitement_option( option_f );
            break;
          default : usage( module );
        }
        if ( **argv == 'a' || **argv == 'b' || **argv == 'c' )
        {
          /*
           * La valeur de l'option 'a', 'b' ou 'c' peut
           * suivre immédiatement, ou bien être séparée
           * de l'option par des blancs.
           */
          if( *++*argv != '\0' )
            valeur_option = strdup( *argv );
          /* Cas où aucune valeur ne suit. */
          else if( (*++argv)[0] == '-' )
            usage( module );
          else
            valeur_option = strdup( *argv );
          break;
        }
      }
    }

     /*
     * L'argument ne commence pas
     * par le caractère '-'.
     */
    else if( fichier != NULL )
      usage( module );
    else
      fichier = strdup( *argv );
  }
  bilan_options();

  printf( "\n\nFin EXO11.\n" );

  return 0;
}

§MEVBCBfvoid bilan_options( void )
{
  /*
   * L'option 'a', 'b', ou 'c' suivie d'une
   * chaîne, ainsi qu'un nom de fichier
   * doivent être spécifiés.
   */

  if( valeur_option == NULL || fichier == NULL )
    usage( module );

   /*
   * Si aucune des options 'd', 'e', 'f'
   * n'a été spécifiée, on les considère toutes.
   */

  if( ! (mask_options & option_d) &&
      ! (mask_options & option_e) &&
      ! (mask_options & option_f) )
    mask_options |= option_d + option_e + option_f;
  if( mask_options & option_a )
    printf( "Option \"a\" fournie avec comme valeur : "
            "%s\n", valeur_option );
  if( mask_options & option_b )
    printf( "Option \"b\" fournie avec comme valeur : "
            "%s\n", valeur_option );
  if( mask_options & option_c )
    printf( "Option \"c\" fournie avec comme valeur : "
            "%s\n", valeur_option );
  printf( "Option \"d\" %s.\n",
           mask_options & option_d ? "active" : "inactive" );
  printf( "Option \"e\" %s.\n",
           mask_options & option_e ? "active" : "inactive" );
  printf( "Option \"f\" %s.\n",
           mask_options & option_f ? "active" : "inactive" );

  printf( "fichier indiqué : %s\n", fichier );

  return;
}

 §MEVBCBfvoid traitement_option( const unsigned char option )
{
  /*
   * Une seule des options "-a", "-b", "-c"
   * doit avoir été spécifiée.
   */

  if ( option == option_a ||
       option == option_b ||
       option == option_c )
    if ( valeur_option != NULL )
      usage( module );

  /*
   * On interdit qu'une option
   * soit indiquée 2 fois.
   */

  if ( mask_options & option )
    usage( module );
  else
    mask_options |= option;

  return;
}

§MEVBCBfvoid usage( char *s )
{
  printf( "usage : %s -a chaine | -b chaine"
          " | -c chaine [-d -e -f] fichier\n", s );
  exit(1);
}