aroplat

Utilitaire pour manipuler le format aroplat (métaformat de plat)
git clone git://git.asteride.xyz/~ldp/aroplat.git
Journaux | Fichiers | Références | LICENCE

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 }