abattre.c (8298B)
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 #include "tampon.h" 7 #include "meta.h" 8 9 #define MAX_VARS 32 /* nombre maximal de variables */ 10 #define TLL_VAR 32 /* taille initiale du tampon à variable */ 11 #define TLL_META 64 /* taille initiale du tampon à métadonnées */ 12 #define TLL_PLS 16 /* taille des piles */ 13 14 /* drapeaux */ 15 #define DRAP_DEB 01 16 #define DRAP_FIN 02 17 18 /* types d'étiquette*/ 19 #define ETQ_RIEN 0 20 #define ETQ_SI 1 21 #define ETQ_A 2 22 #define ETQ_COND 3 23 24 /* opérateurs */ 25 /* en ordre de priorité */ 26 #define OP_OU 0 27 #define OP_ET 1 28 #define OP_NON 2 29 #define OP_PAR 3 30 31 struct pl { 32 int ctn[TLL_PLS]; 33 int tete; 34 }; 35 36 struct vars { 37 char *vars[MAX_VARS]; 38 int prch; 39 }; 40 41 static int valider_var(char *); 42 static int noter_var(char *); 43 static int filtrer(FILE *); 44 static int valider_etqs(struct meta *); 45 static int trv_type_cadet(struct meta *); 46 static int ana_draps(struct meta *); 47 static void aff_etq(struct meta *); 48 static int evaluer(char *); 49 static int val_var(char **); 50 static int appliquer(int); 51 static int ign_bloc(FILE *); 52 static void utilisation(FILE *); 53 54 struct tampon tamp_var; 55 struct meta tamp_meta; 56 57 struct vars pl_vars = { {0}, 0 }; 58 struct pl pl_vals = { {0}, -1 }; 59 struct pl pl_ops = { {0}, -1 }; 60 61 char *nom_prog; 62 63 int 64 main(int argc, char **argv) 65 { 66 int c; 67 68 if ((nom_prog = argv[0]) == NULL || nom_prog[0] == '\0') 69 nom_prog = "abattre"; 70 71 if (m_init(&tamp_meta, TLL_META) < 0 || tp_init(&tamp_var, TLL_VAR) < 0) 72 return 1; 73 74 while ((c = getopt(argc, argv, "v:h")) != -1) { 75 switch (c) { 76 case 'v': 77 if (valider_var(optarg) < 0) 78 return 1; 79 if (noter_var(optarg) < 0) 80 return 1; 81 break; 82 case 'h': 83 utilisation(stdout); 84 return 0; 85 default: 86 utilisation(stderr); 87 return 1; 88 } 89 } 90 91 if (filtrer(stdin) < 0) 92 return 1; 93 exit(0); 94 } 95 96 static int 97 noter_var(char *arg) 98 { 99 int i, j; 100 101 for (i = 0; i < pl_vars.prch; i++) 102 for (j = 0; pl_vars.vars[i][j] == arg[j]; j++) 103 if (arg[j] == '=' || arg[j+1] == '\0') { 104 pl_vars.vars[i] = arg; 105 return 0; 106 } 107 if (pl_vars.prch < MAX_VARS) { 108 pl_vars.vars[pl_vars.prch++] = arg; 109 return 0; 110 } 111 112 fprintf(stderr, "%s: trop de variables (maximum: %d)\n", 113 nom_prog, MAX_VARS); 114 return -1; 115 } 116 117 static int 118 valider_var(char *arg) 119 { 120 char *c; 121 122 if (*arg == '=') { 123 fprintf(stderr, "%s: une variable ne peut commencer par « = »\n", 124 nom_prog); 125 return -1; 126 } 127 for (c = arg; *c != '\0'; c++) { 128 switch (*c) { 129 case '!': case '&': case '|': case ':': case '(': case ')': 130 fprintf(stderr, "%s: « %c » est un caractère réservé\n", 131 nom_prog, *c); 132 return -1; 133 } 134 } 135 136 return 0; 137 } 138 139 static int 140 filtrer(FILE *f) 141 { 142 int c; 143 int draps; 144 int trouve; 145 char *pc; 146 147 trouve = 0; 148 while (m_lire(f, &tamp_meta) > 0) { 149 if (valider_etqs(&tamp_meta) < 0) 150 return -1; 151 switch (trv_type_cadet(&tamp_meta)) { 152 case ETQ_RIEN: 153 aff_etq(&tamp_meta); 154 goto afficher; 155 case ETQ_SI: 156 draps = ana_draps(&tamp_meta); 157 if (draps & DRAP_DEB) 158 trouve = 0; 159 aff_etq(&tamp_meta); 160 if (trouve == 0) { 161 if (draps & DRAP_FIN) 162 trouve = 1; 163 goto afficher; 164 } 165 putc('\n', stdout); 166 break; 167 case ETQ_A: 168 break; 169 case ETQ_COND: 170 draps = ana_draps(&tamp_meta); 171 if (trouve == 1 && draps & DRAP_DEB) { 172 ign_bloc(f); 173 break; 174 } 175 pc = tp_deb(&tamp_meta.tp) + tamp_meta.draps - 2; 176 while (*--pc != '#') 177 ; 178 if (evaluer(pc+1)) { 179 trouve = 1; 180 aff_etq(&tamp_meta); 181 goto afficher; 182 } else { 183 ign_bloc(f); 184 } 185 break; 186 } 187 while ((c = getc(f)) != '\n') 188 if (c == EOF) 189 return 0; 190 continue; 191 afficher: 192 while ((c = putc(getc(f), stdout)) != '\n') 193 if (c == EOF) 194 return 0; 195 } 196 return 0; 197 } 198 199 static int 200 valider_etqs(struct meta *m) 201 { 202 if (*tp_deb(&m->tp) != ':') { 203 fprintf(stderr, "%s: fichier corrompu: le premier champ ne " 204 "commence pas par « : »\n", nom_prog); 205 return -1; 206 } 207 if (*(tp_deb(&m->tp) + m->draps - 2) != ':') { 208 fprintf(stderr, "%s: fichier corrompu: le dernier champ ne se " 209 "termine pas par « : »\n", nom_prog); 210 } 211 return 0; 212 } 213 214 /* trouver le type de l'étiquette du domaine cadet */ 215 /* l'étiquette ne peut contenir « : » */ 216 static int 217 trv_type_cadet(struct meta *m) 218 { 219 char *c = tp_deb(&m->tp) + m->draps - 2; 220 int n = 0; 221 if (c == tp_deb(&m->tp)) 222 return 0; 223 while (*--c != ':') 224 ; 225 c++; 226 if (*c == '#') { 227 c -= 2; 228 n++; 229 } 230 if (c - tp_deb(&m->tp) < 4) 231 return 0; 232 if (*c == '@') { 233 c -= 3; 234 n++; 235 } 236 else if (n == 1) 237 return 0; 238 if (*(c-1) == ':' && *c == 's' && *(c+1) == 'i' && *(c+2) == ':') 239 return n + 1; 240 return 0; 241 } 242 243 static int 244 ana_draps(struct meta *m) 245 { 246 char *c; 247 int draps; 248 for (draps = 0, c = tp_deb(&m->tp) + m->draps; *c != '\0'; c++) { 249 switch (*c) { 250 case '(': 251 draps |= DRAP_DEB; 252 break; 253 case ')': 254 draps |= DRAP_FIN; 255 break; 256 } 257 } 258 return draps; 259 } 260 261 static void 262 aff_etq(struct meta *m) 263 { 264 char *c; 265 int fini; /* si on fini avec « :si », « :@ » ou « :#* » */ 266 267 fini = 0; 268 for (c = tp_deb(&m->tp); *c != '\0'; c++) { 269 fini = 0; 270 if (*c == ':') { 271 if (strncmp(c+1, "si:", 3) == 0) { 272 fini = 1; 273 c += 3; 274 if (strncmp(c+1, "@:", 2) == 0) { 275 c += 2; 276 if (*(c+1) == '#') { 277 for (c += 2; *c != ':'; c++) 278 ; 279 if (*(c+1) != '\0') { 280 c--; 281 continue; 282 } 283 } 284 } 285 } 286 } 287 putc(*c, stdout); 288 } 289 if (fini) 290 putc('\t', stdout); 291 else 292 printf("\t%s", tp_deb(&m->tp) + m->draps); 293 } 294 295 /* ps doit pointer vers un '#' */ 296 static int 297 evaluer(char *ps) 298 { 299 int op; 300 char *s = ps; 301 for (;;s++) { 302 switch (*s) { 303 case '!': 304 op = OP_NON; 305 break; 306 case '&': 307 op = OP_ET; 308 break; 309 case '|': 310 op = OP_OU; 311 break; 312 case '(': 313 op = OP_PAR; 314 break; 315 case ')': 316 while (pl_ops.tete >= 0) { 317 if (pl_ops.ctn[pl_ops.tete] == OP_PAR) { 318 pl_ops.tete--; 319 goto sortie; 320 } 321 if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0) 322 return -1; 323 } 324 return -1; 325 sortie: 326 continue; 327 case ':': 328 while (pl_ops.tete >= 0) 329 if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0) 330 return -1; 331 if (pl_vals.tete != 0) 332 return -1; 333 return pl_vals.ctn[pl_vals.tete--]; 334 default: 335 if (++pl_vals.tete >= TLL_PLS) { 336 fprintf(stderr, "%s: expression trop " 337 "complexe\n", nom_prog); 338 return -1; 339 } 340 if ((pl_vals.ctn[pl_vals.tete] = val_var(&s)) < 0) 341 return -1; 342 continue; 343 } 344 while (pl_ops.tete >= 0 && pl_ops.ctn[pl_ops.tete] != OP_PAR && 345 pl_ops.ctn[pl_ops.tete] != OP_NON && 346 pl_ops.ctn[pl_ops.tete] >= op) { 347 if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0) 348 return -1; 349 } 350 if (++pl_ops.tete >= TLL_PLS) 351 return -1; 352 pl_ops.ctn[pl_ops.tete] = op; 353 } 354 return -1; 355 } 356 357 static int 358 val_var(char **ps) 359 { 360 int i, j; 361 char *s = *ps; 362 tp_eff(&tamp_var); 363 for (i = 0; *s != '\0'; i++, s++) { 364 switch (*s) { 365 case '!': case '&': case '|': case ':': case '(': case ')': 366 goto trouver; 367 } 368 tp_ecr(*s, &tamp_var); 369 } 370 fprintf(stderr, "%s: le premier champ ne se termine pas par « : »\n", 371 nom_prog); 372 return -1; 373 trouver: 374 tp_ecr('\0', &tamp_var); 375 376 *ps = --s; 377 for (i = 0; i < pl_vars.prch; i++) { 378 for (j = 0; pl_vars.vars[i][j] == tamp_var.tp[j]; j++) 379 if (tamp_var.tp[j] == '\0') 380 return 1; 381 } 382 return 0; 383 } 384 385 static int 386 appliquer(int op) 387 { 388 switch (op) { 389 case OP_NON: 390 if (pl_vals.tete >= 0) { 391 pl_vals.ctn[pl_vals.tete] = !pl_vals.ctn[pl_vals.tete]; 392 return 0; 393 } 394 break; 395 case OP_ET: 396 if (pl_vals.tete >=1) { 397 pl_vals.ctn[pl_vals.tete-1] = 398 pl_vals.ctn[pl_vals.tete-1] && 399 pl_vals.ctn[pl_vals.tete]; 400 pl_vals.tete--; 401 return 0; 402 } 403 break; 404 case OP_OU: 405 if (pl_vals.tete >= 1) { 406 pl_vals.ctn[pl_vals.tete-1] = 407 pl_vals.ctn[pl_vals.tete-1] || 408 pl_vals.ctn[pl_vals.tete]; 409 pl_vals.tete--; 410 return 0; 411 } 412 break; 413 } 414 fprintf(stderr, "%s: trop d'opérateurs\n", nom_prog); 415 return -1; 416 } 417 418 static int 419 ign_bloc(FILE *f) 420 { 421 int draps; 422 int c; 423 int niveau = 0; 424 do { 425 draps = ana_draps(&tamp_meta); 426 if (draps & DRAP_DEB) 427 niveau++; 428 if (draps & DRAP_FIN) 429 niveau--; 430 if (niveau == 0) 431 break; 432 while ((c = getc(f)) != '\n') 433 if (c == EOF) 434 return 0; 435 } while (m_lire(f, &tamp_meta) > 0); 436 return 0; 437 } 438 439 static void 440 utilisation(FILE *f) 441 { 442 fprintf(f, "UTILISATION: %s -v[variable][=valeur] [...] <[fichier]\n", 443 nom_prog); 444 }