aplat

Documents structurés pour Unix
git clone git://git.asteride.xyz/~ldp/aplat.git
Journaux | Fichiers | Références | LISEZ-MOI | LICENCE

aplat.c (8842B)


      1 #include <assert.h>
      2 #include <stdio.h>
      3 
      4 #ifdef __OpenBSD__
      5 #include <unistd.h>
      6 #endif
      7 
      8 #include <libintl.h>
      9 #include <locale.h>
     10 
     11 #include "general.h"
     12 #include "tampon.h"
     13 
     14 #define _(c) gettext(c)
     15 
     16 #define JT_RIEN (-1)
     17 #define JT_OUV    0
     18 #define JT_FRM    1
     19 #define JT_ATM    2
     20 #define JT_FRG    3
     21 
     22 #define DRAP_FRM 1
     23 #define DRAP_OUV 2
     24 
     25 #define cr_variable     static int cr_etat=0;
     26 #define cr_tableau      switch (cr_etat)
     27 #define cr_definir(n)   case n: goto cr_e ## n;
     28 #define cr_entrer(n)    cr_e ## n:
     29 #define cr_sortir(e, v) do { cr_etat=(e); return (v); } while (0)
     30 
     31 static void utilisation(FILE *fichier);
     32 static void version(void);
     33 static int  aplatir(FILE *f);
     34 static int  obt_jeton(FILE *fichier, struct tampon *tp);
     35 static int  echapper(FILE *fichier, struct tampon *tp);
     36 static int  echapper_guillemets(FILE *fichier, struct tampon *tp);
     37 static int  echapper_bloc(FILE *fichier, struct tampon *tp);
     38 static int  afficher_ligne(int *draps, struct tampon *tp_etq,
     39 	struct tampon *tp_ctn);
     40 
     41 char *nom_prog;
     42 
     43 struct tampon tp_etq;
     44 struct tampon tp_ctn;
     45 
     46 int
     47 main(int argc, char **argv)
     48 {
     49 	int c;
     50 
     51 	/* trouver le nom du programme */
     52 	if ((nom_prog = *argv) == NULL || *nom_prog == '\0')
     53 		nom_prog = "aplat";
     54 
     55 	setlocale(LC_ALL, "");
     56 	bindtextdomain(I18N_DOMAINE, I18N_DOS);
     57 	textdomain(I18N_DOMAINE);
     58 
     59 #ifdef __OpenBSD__
     60 	if (unveil(I18N_DOS, "r") < 0 ||
     61 			unveil("/usr/share/locale/UTF-8/LC_CTYPE", "r") < 0) {
     62 		fprintf(stderr, _("%s: erreur avec unveil()\n"), nom_prog);
     63 	}
     64 	if (pledge("stdio rpath", NULL) < 0) {
     65 		fprintf(stderr, _("%s: erreur avec pledge()\n"), nom_prog);
     66 		return 1;
     67 	}
     68 #endif
     69 
     70 	while ((c = getopt(argc, argv, "Vh")) != -1) {
     71 		switch (c) {
     72 		case 'V':
     73 			version();
     74 			return 0;
     75 		case 'h':
     76 			utilisation(stdout);
     77 			return 0;
     78 		default:
     79 			goto erreur;
     80 		}
     81 	}
     82 
     83 	if (argc > 1)
     84 		goto erreur;
     85 
     86 	/* initialiser les tampons */
     87 	if (tp_init(&tp_etq, TLL_ETQ) < 0 ||
     88 			tp_init(&tp_ctn, TLL_CTN) < 0)
     89 		return 1;
     90 
     91 	if (aplatir(stdin) < 0)
     92 		return 1;
     93 
     94 	return 0;
     95 
     96 erreur:
     97 	utilisation(stderr);
     98 	return 1;
     99 }
    100 
    101 static void
    102 utilisation(FILE *f)
    103 {
    104 	fprintf(f, _("Utilisation: %s <[fichier]\n"
    105 		"             %s -V | -h\n"), nom_prog, nom_prog);
    106 }
    107 
    108 static void
    109 version(void)
    110 {
    111 	fprintf(stdout, "%s " VERSION "\n", nom_prog);
    112 }
    113 
    114 static int
    115 aplatir(FILE *f)
    116 {
    117 	int prfd;          /* profondeur */
    118 	int draps;         /* drapeaux */
    119 	struct tampon *tp; /* dans lequel écrire le jeton */
    120 	int jta; /* jeton actuel */
    121 	int jtp; /* jeton précédent */
    122 
    123 	assert(f);
    124 
    125 	jtp = JT_RIEN;
    126 	switch (jta = (obt_jeton(f, &tp_etq))) {
    127 	case JT_OUV:
    128 		prfd = 0;
    129 		draps = 0;
    130 		tp = &tp_etq;
    131 		break;
    132 	case EOF:
    133 		return 0;
    134 	default:
    135 		fprintf(stderr, _("%s: le premier caractère non blanc doit "
    136 			"être « ( »\n"), nom_prog);
    137 		return -1;
    138 	}
    139 
    140 	do {
    141 		switch (jta) {
    142 		case JT_OUV:
    143 			prfd++;
    144 			tp = &tp_etq;
    145 			if (jtp == JT_OUV || jtp == JT_ATM)
    146 				(void) afficher_ligne(&draps, &tp_etq, &tp_ctn);
    147 			draps |= DRAP_OUV;
    148 			break;
    149 		case JT_FRM:
    150 			draps |= DRAP_FRM;
    151 			(void) afficher_ligne(&draps, &tp_etq, &tp_ctn);
    152 			if (--prfd == 0)
    153 				goto fin;
    154 			break;
    155 		case JT_ATM:
    156 			tp = &tp_ctn;
    157 			break;
    158 		case JT_FRG:
    159 			if (jtp == JT_OUV) {
    160 				fprintf(stderr, _("%s: la longueur d'une "
    161 					"étiquette ne peut excéder les %d "
    162 					"octets\n"),
    163 					nom_prog, TLL_ETQ);
    164 				return -1;
    165 			}
    166 			(void) afficher_ligne(&draps, &tp_etq, &tp_ctn);
    167 		}
    168 		jtp = jta;
    169 	} while ((jta = obt_jeton(f, tp)) != EOF);
    170 
    171 	fprintf(stderr, _("%s: parenthèses déséquilibrées\n"), nom_prog);
    172 	return -1;
    173 
    174 fin:
    175 	if (obt_jeton(f, tp) == EOF)
    176 		return 0;
    177 	fprintf(stderr, _("%s: aucun caractère non blanc ne peut suivre "
    178 		"le dernier « ) »\n"), nom_prog);
    179 	return -1;
    180 }
    181 
    182 static int
    183 obt_jeton(FILE *f, struct tampon *tp)
    184 {
    185 	static int d;
    186 	static int c;
    187 	cr_variable;
    188 
    189 	assert(f);
    190 	assert(tp);
    191 
    192 	cr_tableau {
    193 		cr_definir(0);
    194 		cr_definir(1);
    195 		cr_definir(2);
    196 		cr_definir(3);
    197 		cr_definir(4);
    198 		cr_definir(5);
    199 	}
    200 	assert(0);
    201 
    202 	cr_entrer(0);
    203 	for (d = '\0'; ((c = getc(f)) == ' ' || c == '\n' || c == '\t'); d = c)
    204 		;
    205 
    206 	switch (c) {
    207 	case '(':
    208 		cr_sortir(0, JT_OUV);
    209 	case ')':
    210 		cr_sortir(0, JT_FRM);
    211 	case '=':
    212 		if (d == '\n') {
    213 			if ((c = getc(f)) == '!') {
    214 				c = '=';
    215 				break;
    216 			}
    217 			ungetc(c, f);
    218 			cr_entrer(3)
    219 			switch (echapper_bloc(f, tp)) {
    220 			case EOF:
    221 				cr_sortir(0, EOF);
    222 			case 0:
    223 				cr_sortir(0, JT_ATM);
    224 			case 1:
    225 				cr_sortir(3, JT_FRG);
    226 			}
    227 		}
    228 	}
    229 
    230 	for (;; c = getc(f)) {
    231 		switch (c) {
    232 		case '(': case ')': case '\n':
    233 			ungetc(c, f);
    234 			/* CASCADE */
    235 		case ' ': case '\t':
    236 			cr_sortir(0, JT_ATM);
    237 		case '\\':
    238 			cr_entrer(1);
    239 			switch (echapper(f, tp)) {
    240 			case EOF:
    241 				/* ignore tous les caractères du jeton */
    242 				cr_sortir(0, EOF);
    243 			case 0:
    244 				continue;
    245 			case 1:
    246 				cr_sortir(1, JT_FRG);
    247 			}
    248 			assert(0);
    249 		case '"':
    250            		cr_entrer(2);
    251 			switch (echapper_guillemets(f, tp)) {
    252 			case EOF:
    253 				/* ignore tous les caractères du jeton */
    254 				cr_sortir(0, EOF);
    255 			case 0:
    256 				continue;
    257 			case 1:
    258 				cr_sortir(2, JT_FRG);
    259 			}
    260 			assert(0);
    261 		case EOF:
    262 			cr_sortir(0, EOF);
    263 		case ':':
    264 			cr_entrer(4);
    265 			if (tp_ecr(tp, '\\') < 0)
    266 				cr_sortir(4, JT_FRG);
    267 			c = 'd';
    268 			/* CASCADE */
    269 		default:
    270 			cr_entrer(5);
    271 			if (tp_ecr(tp, c) < 0)
    272 				cr_sortir(5, JT_FRG);
    273 		}
    274 	}
    275 
    276 	assert(0);
    277 }
    278 
    279 static int
    280 echapper(FILE *f, struct tampon *tp)
    281 {
    282 	static int c;
    283 	cr_variable;
    284 
    285 	assert(f);
    286 	assert(tp);
    287 
    288 	cr_tableau {
    289 		cr_definir(0);
    290 		cr_definir(1);
    291 		cr_definir(2);
    292 		cr_definir(3);
    293 	}
    294 	assert(0);
    295 
    296 	cr_entrer(0);
    297 	switch (c = getc(f)) {
    298 	case '\n':
    299 		if ((c = getc(f)) == '=' ) {
    300 			if ((c = getc(f)) != '!') {
    301 				ungetc(c, f);
    302 				cr_entrer(1)
    303 				switch (echapper_bloc(f, tp)) {
    304 				case EOF:
    305 					cr_sortir(0, EOF);
    306 				case 0:
    307 					cr_sortir(0, 0);
    308 				case 1:
    309 					cr_sortir(1, 1);
    310 				}
    311 			}
    312 			c = '=';
    313 		}
    314 		ungetc(c, f);
    315 		cr_sortir(0, 0);
    316 	case '\t':
    317 		c = 't';
    318 		break;
    319 	case EOF:
    320 		cr_sortir(0, EOF);
    321 	case ':':
    322 		c = 'd';
    323 		break;
    324 	case '\\':
    325 		c = 'e';
    326 		break;
    327 	default:
    328 		goto cseulement;
    329 	}
    330 	cr_entrer(2);
    331 	if (tp_ecr(tp, '\\') < 0)
    332 		cr_sortir(2, 1);
    333 cseulement:
    334 	cr_entrer(3);
    335 	if (tp_ecr(tp, c) < 0)
    336 		cr_sortir(3, 1);
    337 
    338 	cr_sortir(0, 0);
    339 }
    340 
    341 static int
    342 echapper_guillemets(FILE *f, struct tampon *tp)
    343 {
    344 	static int c;
    345 	cr_variable;
    346 
    347 	assert(f);
    348 	assert(tp);
    349 
    350 	cr_tableau {
    351 		cr_definir(0);
    352 		cr_definir(1);
    353 		cr_definir(2);
    354 		cr_definir(3);
    355 	}
    356 	assert(0);
    357 
    358 	cr_entrer(0);
    359 	for (;;) {
    360 		switch ((c = getc(f))) {
    361 		case '"':
    362 			cr_sortir(0, 0);
    363 		case '\n':
    364 			if ((c = getc(f)) == '=') {
    365 				if ((c = getc(f)) != '!') {
    366 					ungetc(c, f);
    367 					cr_entrer(1)
    368 					switch (echapper_bloc(f, tp)) {
    369 					case EOF:
    370 						cr_sortir(0, EOF);
    371 					case 0:
    372 						continue;
    373 					case 1:
    374 						cr_sortir(1, 1);
    375 					}
    376 				}
    377 				c = '=';
    378 			}
    379 			ungetc(c, f);
    380 			c = 'n';
    381 			break;
    382 		case '\t':
    383 			c = 't';
    384 			break;
    385 		case '\\':
    386 			switch (echapper(f, tp)) {
    387 			case EOF:
    388 				cr_sortir(0, EOF);
    389 			case 0:
    390 				continue;
    391 			case 1:
    392 				cr_sortir(6, 1);
    393 			}
    394 			assert(0);
    395 		case EOF:
    396 			cr_sortir(0, EOF);
    397 		case ':':
    398 			c = 'd';
    399 			break;
    400 		default:
    401 			goto cseulement;
    402 		}
    403 		cr_entrer(2);
    404 		if (tp_ecr(tp, '\\') < 0)
    405 			cr_sortir(2, 1);
    406 cseulement:
    407 		cr_entrer(3);
    408 		if (tp_ecr(tp, c) < 0)
    409 			cr_sortir(3, 1);
    410 	}
    411 	assert(0);
    412 }
    413 
    414 static int
    415 echapper_bloc(FILE *f, struct tampon *tp)
    416 {
    417 	static int c;
    418 	static int pf;
    419 	cr_variable;
    420 
    421 	assert(f);
    422 	assert(tp);
    423 
    424 	cr_tableau {
    425 		cr_definir(0);
    426 		cr_definir(1);
    427 		cr_definir(2);
    428 	}
    429 	assert(0);
    430 
    431 	cr_entrer(0);
    432 	pf = 1;
    433 	/* ignorer le reste de la ligne */
    434 	while ((c = getc(f)) != '\n')
    435 		if (c == EOF)
    436 			cr_sortir(0, EOF);
    437 
    438 	do {
    439 		switch (c) {
    440 		case '\n':
    441 			if ((c = getc(f)) == '=') {
    442 				if ((c = getc(f)) != '!') {
    443 					/* ignorer le reste de la ligne */
    444 					while (c != '\n')
    445 						if ((c = getc(f)) == EOF)
    446 							break;
    447 					cr_sortir(0, 0);
    448 				}
    449 				c = '=';
    450 			}
    451 			ungetc(c, f);
    452 			if (pf) {
    453 				pf = 0;
    454 				continue;
    455 			}
    456 			c = 'n';
    457 			break;
    458 		case '\t':
    459 			c = 't';
    460 			break;
    461 		case ':':
    462 			c = 'd';
    463 			break;
    464 		case '\\':
    465 			c = 'e';
    466 			break;
    467 		default:
    468 			goto cseulement;
    469 		}
    470 		cr_entrer(1);
    471 		if (tp_ecr(tp, '\\') < 0)
    472 			cr_sortir(1, 1);
    473 cseulement:
    474 		cr_entrer(2);
    475 		if (tp_ecr(tp, c) < 0)
    476 			cr_sortir(2, 1);
    477 	} while ((c = getc(f)) != EOF);
    478 	cr_sortir(0, EOF);
    479 }
    480 
    481 static int
    482 afficher_ligne(int *draps, struct tampon *tp_etq, struct tampon *tp_ctn)
    483 {
    484 	size_t lngr;
    485 
    486 	assert(draps);
    487 	assert(tp_etq);
    488 	assert(tp_ctn);
    489 
    490 	if (*draps & DRAP_OUV)
    491 		putc('(', stdout);
    492 	if (*draps & DRAP_FRM)
    493 		putc(')', stdout);
    494 
    495 	if (tp_terminer(tp_etq) < 0 || tp_terminer(tp_ctn) < 0)
    496 		return -1;
    497 
    498 	putc('\t', stdout);
    499 	lngr = tp_longueur(tp_etq);
    500 	if (fwrite(tp_etq->tp, 1, lngr, stdout) < lngr)
    501 		return -1;
    502 	putc('\t', stdout);
    503 	lngr = tp_longueur(tp_ctn);
    504 	if (fwrite(tp_ctn->tp, 1, lngr, stdout) < lngr)
    505 		return -1;
    506 	putc('\n', stdout);
    507 
    508 	*draps = 0;
    509 	tp_reinit(tp_etq);
    510 	tp_reinit(tp_ctn);
    511 
    512 	return 0;
    513 }