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 }