aplat

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

commit c8b59f1564489e8a877a1058e11ea74fd3819123
parent ce229984182cf0c50e4e57bbe6c6a743567665c1
Auteur: Selve <selve@asteride.xyz>
Date:   Fri, 22 Mar 2024 15:25:18 -0400

changements importants

Diffstat:
Maplat.c | 350++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mchangements.txt | 10++++++++++
Mtampon.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mtampon.h | 19+++++++++++--------
4 files changed, 240 insertions(+), 217 deletions(-)

diff --git a/aplat.c b/aplat.c @@ -1,75 +1,77 @@ #include <assert.h> #include <stdio.h> -#include <stdlib.h> -#include <unistd.h> + +#ifdef __OpenBSD__ + #include <unistd.h> +#endif #include <libintl.h> #include <locale.h> #include "tampon.h" -#define TLL_ETQ 4096 /* taille initiale du tampon à étiquettes */ -#define TLL_CTN 4096 /* taille initiale du tampon à texte */ - #define DRAP_OUV 01 /* parenthèse ouvrante */ #define DRAP_FRM 02 /* parenthèse fermante */ -#define NGUI_BLOC 3 /* nombre de guillemets pour ouvrir ou fermer un bloc */ - -#define TP_TYPE_ETQ 0 /* tampon contenant des étiquettes */ -#define TP_TYPE_CTN 1 /* tampon contenant du « contenu » */ +#define CTN_TLL 4096 /* taille initiale du tampon contenu */ +#define ETQ_TLL 256 /* taille initiale du tampon de l'étiquette */ +#define PILE_TLL 128 /* profondeur initiale de la pile */ #define JT_OUV 0 /* parenthèse ouvrante */ #define JT_FRM 1 /* parenthèse fermante */ -#define JT_FCT 2 /* séparateur fictif */ -#define JT_ATM 3 /* atome */ +#define JT_ATM 2 /* atome */ -#define _(c) gettext(c) +#define _(c) gettext(c) static void utilisation(void); -static int transformer(FILE *); -static int prch_jeton(FILE *, struct tampon *, int); -static int afficher_ligne(struct tampon *, struct tampon *, int *); -static int guillemets(FILE *, struct tampon *); -static int bloc(FILE *, struct tampon *); +static int aplatir(FILE *); +static int obt_jeton(FILE *, struct tampon *); +static int mang_blancs(FILE *); +static void aff_ligne(int *, struct tampon *, struct tampon *); +static int echapp(FILE *, struct tampon *); +static int echapp_guillemets(FILE *, struct tampon *); +static int echapp_bloc(FILE *, struct tampon *); -char *nom_prog; /* nom du programme */ +char *prog_nom; /* nom du programme */ -struct tampon etq; /* tampon à étiquettes */ -struct tampon ctn; /* tampon à texte */ +struct tampon ctn; /* tampon du contenu */ +struct tampon etq; /* tampon de l'étiquette du domaine cadet */ +struct tampon pile; /* pile */ int main(int argc, char **argv) { - if ((nom_prog = argv[0]) == NULL || nom_prog[0] == '\0') - nom_prog = "aplat"; + if ((prog_nom = argv[0]) == NULL || prog_nom[0] == '\0') + prog_nom = "aplat"; + + setlocale(LC_ALL, ""); + bindtextdomain(I18N_DOMAINE, I18N_DOS); + textdomain(I18N_DOMAINE); #ifdef __OpenBSD__ if (unveil(I18N_DOS, "r") < 0 || unveil("/usr/share/locale/UTF-8/LC_CTYPE", "r") < 0) { - fprintf(stderr, _("%s: erreur avec unveil()\n"), nom_prog); + fprintf(stderr, _("%s: erreur avec unveil()\n"), prog_nom); return 1; } if (pledge("stdio rpath", NULL) < 0) { - fprintf(stderr, _("%s: erreur avec pledge()\n"), nom_prog); + fprintf(stderr, _("%s: erreur avec pledge()\n"), prog_nom); return 1; } #endif - setlocale(LC_ALL, ""); - bindtextdomain(I18N_DOMAINE, I18N_DOS); - textdomain(I18N_DOMAINE); - if (argc > 1) { utilisation(); return 1; } /* initialiser les tampons */ - if (tp_init(&etq, TLL_ETQ) < 0 || tp_init(&ctn, TLL_CTN) < 0) + if (tp_init(&etq, ETQ_TLL) < 0 + || tp_init(&ctn, CTN_TLL) < 0 + || tp_init(&pile, PILE_TLL)) return 1; - if (transformer(stdin) < 0) + if (aplatir(stdin) < 0) return 1; return 0; @@ -78,55 +80,56 @@ main(int argc, char **argv) static void utilisation(void) { - printf(_("Utilisation: %s <[fichier]\n"), nom_prog); + printf(_("Utilisation: %s <[fichier]\n"), prog_nom); } static int -transformer(FILE *f) +aplatir(FILE *f) { - int prfd; /* profondeur */ - int draps; /* drapeaux */ - int c; + int prfd; /* profondeur */ + int draps; /* drapeaux */ + size_t nc; /* nombre de caractères */ + size_t tp_nc; /* nombre de caractères dans un tampon */ + char *tp_c; /* pointeur vers un caractère du tampon */ assert(f != NULL); prfd = 0; draps = 0; - switch (prch_jeton(f, &etq, TP_TYPE_ETQ)) { - case JT_OUV: + switch (mang_blancs(f)) { + case '(': break; case EOF: return 0; default: - fprintf(stderr, - _("%s: le premier caractère non blanc " - "doit être « ( »\n"), - nom_prog); + fprintf(stderr, _("%s: le premier caractère non blanc doit " + "être « ( »\n"), prog_nom); return -1; } ouv: prfd++; + tp_ecr(0, &pile); + draps |= DRAP_OUV; - tp_ecr(':', &etq); - - switch (prch_jeton(f, &etq, TP_TYPE_ETQ)) { + switch (obt_jeton(f, &etq)) { case JT_OUV: - draps |= DRAP_OUV; - afficher_ligne(&etq, &ctn, &draps); + aff_ligne(&draps, &etq, &ctn); goto ouv; case JT_FRM: - draps |= DRAP_OUV | DRAP_FRM; - afficher_ligne(&etq, &ctn, &draps); - goto ferm; - case JT_FCT: - draps |= DRAP_OUV; - afficher_ligne(&etq, &ctn, &draps); - tp_ecr('\\', &etq); - goto ouv; + goto frm; case JT_ATM: - draps |= DRAP_OUV; + tp_c = tp_tp(&etq); + tp_nc = tp_ncar(&etq); + for (nc = 1; tp_nc > 0; tp_nc--, tp_c++, nc++) + if (*tp_c == ':') { + tp_ecr(1, &pile); + *tp_c = '\0'; + printf("(\t%s\t\n", tp_tp(&etq)); + prfd++; + tp_deb(&etq, nc); + } goto ctn; case EOF: goto deseq; @@ -134,14 +137,12 @@ ouv: assert(0); ctn: - switch (prch_jeton(f, &ctn, TP_TYPE_CTN)) { + switch (obt_jeton(f, &ctn)) { case JT_OUV: - afficher_ligne(&etq, &ctn, &draps); + aff_ligne(&draps, &etq, &ctn); goto ouv; case JT_FRM: - draps |= DRAP_FRM; - afficher_ligne(&etq, &ctn, &draps); - goto ferm; + goto frm; case JT_ATM: goto ctn; case EOF: @@ -149,25 +150,21 @@ ctn: } assert(0); -ferm: - if (--prfd == 0) - goto fin; - assert(prfd > 0); - - while (tp_etq_rec(&etq) != ETQ_SEP_REL) { +frm: + do { draps |= DRAP_FRM; - afficher_ligne(&etq, &ctn, &draps); - if (--prfd == 0) - goto fin; - } + aff_ligne(&draps, &etq, &ctn); + prfd--; + } while (tp_rec(&pile) != 0); + + if (prfd == 0) + goto fin; - switch (prch_jeton(f, &ctn, TP_TYPE_CTN)) { + switch (obt_jeton(f, &ctn)) { case JT_OUV: goto ouv; case JT_FRM: - draps |= DRAP_FRM; - afficher_ligne(&etq, &ctn, &draps); - goto ferm; + goto frm; case JT_ATM: goto ctn; case EOF: @@ -176,33 +173,27 @@ ferm: assert(0); fin: - while ((c = getc(f)) == ' ' || c == '\n' || c == '\t') - ; - if (c == EOF) + if (mang_blancs(f) == EOF) return 0; fprintf(stderr, _("%s: aucun caractère non blanc ne peut suivre " - "le dernier « ) »\n"), - nom_prog); + "le dernier « ) »\n"), prog_nom); return -1; deseq: - fprintf(stderr, _("%s: parenthèses déséquilibrées\n"), nom_prog); + fprintf(stderr, _("%s: parenthèses déséquilibrées\n"), prog_nom); return -1; } static int -prch_jeton(FILE *f, struct tampon *tp, int tp_type) +obt_jeton(FILE *f, struct tampon *tp) { int c; - int ngui; /* nombre de guillemets */ - assert(f != NULL); - assert(tp != NULL); - assert(tp_type == TP_TYPE_ETQ || tp_type == TP_TYPE_CTN); + assert(f != NULL); + assert(tp != NULL); - while ((c = getc(f)) == ' ' || c == '\n' || c == '\t') - if (c == EOF) - return EOF; + if ((c = mang_blancs(f)) == EOF) + return EOF; switch (c) { case '(': @@ -219,105 +210,101 @@ prch_jeton(FILE *f, struct tampon *tp, int tp_type) case ' ': case '\t': case '\n': return JT_ATM; case '"': - /* compter le nombre de guillemets */ - for (ngui = 1; (c = getc(f)) == '"'; ngui++) - if (c == EOF) - return EOF; - if (ngui == NGUI_BLOC) { - /* ignorer le reste de la ligne */ - while (c != '\n') - if ((c = getc(f)) == EOF) + if ((c = getc(f)) == '"') { + if ((c = getc(f)) == '"') { + if (echapp_bloc(f, tp) == EOF) return EOF; - if (bloc(f, tp) == EOF) - return EOF; - continue; - } - ungetc(c, f); - if (ngui % 2 == 1) { /* nombre impaire de guillemets */ - if (guillemets(f, tp) == EOF) + } else { + ungetc(c, f); + } + } else { + ungetc(c, f); + if (echapp_guillemets(f, tp) == EOF) return EOF; } continue; - case ':': - if (tp_type == TP_TYPE_ETQ) - return JT_FCT; - tp_ecr(':', tp); case '\\': - switch (c = getc(f)) { - case '\\': - tp_ecr('\\', tp); - break; - case '\t': - tp_ecr('\\', tp); - tp_ecr('t', tp); - continue; - case '\n': - continue; - case EOF: + if (echapp(f, tp) == EOF) return EOF; - } - /* CASCADE */ + continue; default: tp_ecr(c, tp); } } while ((c = getc(f)) != EOF); + return EOF; } static int -afficher_ligne(struct tampon *etq, struct tampon *ctn, int *draps) +mang_blancs(FILE *f) { - char *c; - - assert(etq != NULL); - assert(ctn != NULL); - assert(draps != NULL); - assert(etq->tp != NULL); - assert(ctn->tp != NULL); - assert(etq->pc != NULL); - assert(ctn->pc != NULL); - - /* étiquettes */ - for (c = etq->tp; c < etq->pc; c++) { - if (*c == '\\') - /* les autres /\\./ doivent être préservés */ - if (*++c != ':') - putc('\\', stdout); - if (putc(*c, stdout) < 0) - return -1; - } - putc(':', stdout); /* ajouter le point final */ - putc('\t', stdout); + int c; + while ((c = getc(f)) == ' ' || c == '\n' || c == '\t') + ; + return c; +} + +static void +aff_ligne(int *draps, struct tampon *etq, struct tampon *ctn) +{ + assert(draps != NULL); + assert(etq != NULL); + assert(ctn != NULL); - /* drapeaux */ if (*draps & DRAP_OUV) putc('(', stdout); if (*draps & DRAP_FRM) putc(')', stdout); - *draps = 0; - putc('\t', stdout); + tp_ecr('\0', etq); + tp_ecr('\0', ctn); - /* contenu */ - for (c = ctn->tp; c < ctn->pc; c++) - if (putc(*c, stdout) < 0) - return -1; + printf("\t%s\t%s\n", tp_tp(etq), tp_tp(ctn)); + *draps = 0; + tp_eff(etq); tp_eff(ctn); - putc('\n', stdout); +} + +static int +echapp(FILE *f, struct tampon *tp) +{ + int c; + + assert(f != NULL); + assert(tp != NULL); + + switch (c = getc(f)) { + case '\n': + break; + case '\t': + tp_ecr('\\', tp); + tp_ecr('t', tp); + break; + case EOF: + return EOF; + case '\\': + tp_ecr('\\', tp); + /* CASCADE */ + default: + tp_ecr(c, tp); + } + return 0; } static int -guillemets(FILE *f, struct tampon *tp) +echapp_guillemets(FILE *f, struct tampon *tp) { int c; - assert(f != NULL); + assert(f != NULL); assert(tp != NULL); - while ((c = getc(f)) != '"' && c != EOF) { - switch (c) { + for (;;) { + switch ((c = getc(f))) { + case '"': + return 0; case '\n': tp_ecr('\\', tp); tp_ecr('n', tp); @@ -327,41 +314,36 @@ guillemets(FILE *f, struct tampon *tp) tp_ecr('t', tp); continue; case '\\': - switch (c = getc(f)) { - case '\\': - tp_ecr('\\', tp); - break; - case '\n': - continue; - case '\t': - tp_ecr('\\', tp); - tp_ecr('t', tp); + if (echapp(f, tp) != EOF) continue; - case EOF: - return EOF; - } /* CASCADE */ + case EOF: + return EOF; default: tp_ecr(c, tp); } } - return c; } static int -bloc(FILE *f, struct tampon *tp) +echapp_bloc(FILE *f, struct tampon *tp) { int c; int ngui; size_t ncar; - assert(f != NULL); + assert(f != NULL); assert(tp != NULL); + /* ignorer le reste de la ligne */ + while ((c = getc(f)) != '\n') + if (c == EOF) + return EOF; + ncar = tp_ncar(tp); - while ((c = getc(f)) != EOF) { - switch (c) { + for (;;) { + switch (c = getc(f)) { case '\n': tp_ecr('\\', tp); tp_ecr('n', tp); @@ -371,23 +353,26 @@ bloc(FILE *f, struct tampon *tp) tp_ecr('t', tp); continue; case '"': - /* compter le nombre de guillemets */ - for (ngui = 1; (c = getc(f)) == '"' && ngui < NGUI_BLOC; - ngui++) - ; - if (c != '!' || ngui < NGUI_BLOC) - ungetc(c, f); - if (ngui == NGUI_BLOC) { - if (c != '!') { - /* si le bloc n'est pas vide */ + ngui = 1; + while ((c = getc(f)) == '"') { + if (++ngui == 3) { + if ((c = getc(f)) == '!') + goto afficher; + ungetc(c, f); if (ncar != tp_ncar(tp)) - tp_bloc_rec(tp); - return c; + tp_eff_ligne(tp); + return 0; } } + /* retourner au flux le caractère lu en trop */ + ungetc(c, f); + /* écrire au tampon les guillemets lus */ +afficher: while (ngui-- > 0) tp_ecr('"', tp); continue; + case EOF: + return EOF; case '\\': tp_ecr('\\', tp); /* CASCADE */ @@ -395,5 +380,4 @@ bloc(FILE *f, struct tampon *tp) tp_ecr(c, tp); } } - return EOF; } diff --git a/changements.txt b/changements.txt @@ -1,6 +1,16 @@ Changements =========== +Version ?.? +----------- + +* plat(5): Permutation du champ des drapeaux et de celui des étiquettes. Le + champ des drapeaux est maintenant premier et celui des étiquettes second. +* plat(5): Seule l'étiquette du domaine cadet est maintenant affichée dans le + champ des étiquettes, plutôt que la hiérarchie complète. +* aplat(1): Correction d'un problème où le deux-points d'une étiquette n'était + pas interprété comme il faut lorsque placé entre guillemets ou dans un bloc. + Version 1.0 ----------- diff --git a/tampon.c b/tampon.c @@ -11,7 +11,9 @@ assert((t)->tll >= 1), \ assert((t)->pc - (t)->tp >= 0), \ assert((size_t) ((t)->pc - (t)->tp) <= (t)->tll), \ - assert((t)->tll * TP_FACT_AGR > (t)->tll)) + assert((t)->tll * TP_FACT_AGR > (t)->tll), \ + assert((t)->deb < (t)->tll), \ + assert((size_t) ((t)->pc - (t)->tp) >= (t)->deb)) static int tp_plein(char, struct tampon *); @@ -20,11 +22,12 @@ int tp_init(struct tampon *tp, size_t tll) { assert(tll >= 1); - assert(tp != NULL); + assert(tp != NULL); if ((tp->pc = tp->tp = malloc(tll)) == NULL) return -1; tp->tll = tll; + tp->deb = 0; INVARIANTS_TP(tp); @@ -73,49 +76,72 @@ tp_eff(struct tampon *tp) INVARIANTS_TP(tp); tp->pc = tp->tp; + tp->deb = 0; INVARIANTS_TP(tp); } +/* obtenir le nombre de caractères dans un tampon */ +size_t +tp_ncar(struct tampon *tp) +{ + INVARIANTS_TP(tp); + + return tp->pc - (tp->tp + tp->deb); +} + +/* obtenir un pointeur vers le début du tampon */ +char * +tp_tp(struct tampon *tp) +{ + INVARIANTS_TP(tp); + + return tp->tp + tp->deb; +} + /* effacer les caractères du tampon tp jusqu'à la dernière nouvelle ligne, * inclusivement */ void -tp_bloc_rec(struct tampon *tp) +tp_eff_ligne(struct tampon *tp) { + int echapp; + INVARIANTS_TP(tp); - while (tp->pc > tp->tp) { - if (*--tp->pc == 'n' && *--tp->pc == '\\') - break; - } + /* problème dans le cas de \\n */ + while (tp->pc > tp->tp) + if (*--tp->pc == 'n') { + echapp = 0; + while (*(tp->pc - 1) == '\\') { + echapp = !echapp; + tp->pc--; + } + if (echapp == 1) + break; + } INVARIANTS_TP(tp); } -/* supprimer le domaine cadet */ -int -tp_etq_rec(struct tampon *tp) +/* supprimer le dernier caractère d'un tampon */ +char +tp_rec(struct tampon *tp) { INVARIANTS_TP(tp); - assert(tp->pc - tp->tp > 1); - assert(*tp->tp == ':'); - - while (*--tp->pc != ':') - ; - if (tp->pc - tp->tp != 0 && *(tp->pc-1) == '\\') { - --tp->pc; - assert(tp->pc - tp->tp > 0); - return ETQ_SEP_FCT; - } - assert(tp->pc - tp->tp > 0); - return ETQ_SEP_REL; + + --tp->pc; + + INVARIANTS_TP(tp); + + return *tp->pc; } -/* obtenir le nombre de caractères dans un tampon */ -size_t -tp_ncar(struct tampon *tp) +void +tp_deb(struct tampon *tp, size_t deb) { INVARIANTS_TP(tp); - return tp->pc - tp->tp; + tp->deb = deb; + + INVARIANTS_TP(tp); } diff --git a/tampon.h b/tampon.h @@ -1,22 +1,25 @@ #ifndef TAMPON_H #define TAMPON_H -#define TP_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */ +#include <stddef.h> -#define ETQ_SEP_REL 0 /* séparateur réel */ -#define ETQ_SEP_FCT 1 /* séparateur fictif (échappé) */ +#define TP_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */ struct tampon { - char *tp; /* le tampon lui-même */ - char *pc; /* ptr vers la prochaine cellule libre */ - size_t tll; /* taille du tampon */ + char *tp; /* le tampon lui-même */ + char *pc; /* ptr vers la prochaine cellule libre */ + size_t tll; /* taille du tampon */ + size_t deb; /* début logique du tampon */ }; int tp_init(struct tampon *, size_t); int tp_ecr(char, struct tampon *); +char tp_rec(struct tampon *); void tp_eff(struct tampon *); -void tp_bloc_rec(struct tampon *); -int tp_etq_rec(struct tampon *); +void tp_eff_ligne(struct tampon *); size_t tp_ncar(struct tampon *); +char *tp_tp(struct tampon *); +void tp_deb(struct tampon *tp, size_t deb); + #endif