aplat

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

commit f0bf30fb99d595c5740601f6d8d34c614148109d
parent e81e34c35fde22a0a8c861c2e000c0e51658afba
Auteur: Loïc Daignault-Pichette <loic@asteride.xyz>
Date:   Fri,  7 Jun 2024 13:43:01 -0400

Réécriture complète d'aplat

* Des limites de 128 octets pour le champ des étiquettes et de 256 octets pour
  celui du contenu ont été imposées.
* Ajout de la séquence d'échappement « \d », qui signifie « : ». Les deux-points
  sont donc maintenant échappables.
* Le raccourcis syntaxique utilisant les deux-points n'existe plus.
* Les blocs sont délimités par le caractère « = », plutôt que par la séqunece
  « """ ». Ce caractère doit en outre se trouver en début de ligne.
* Les caractères se trouvant sur la même ligne que le caractère de limite d'un
  bloc sont ignorés.
* Suppression d'accumuler(1).

Diffstat:
MMakefile | 79++++++++++---------------------------------------------------------------------
Daccumuler.c | 116-------------------------------------------------------------------------------
Maplat.c | 697+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mchangements.txt | 20++++++++++++--------
Aconfig.mk | 19+++++++++++++++++++
Acoroutines.h | 10++++++++++
Mgeneral.c | 38++++++++++++--------------------------
Mgeneral.h | 4+---
Dtampon.c | 168-------------------------------------------------------------------------------
Dtampon.h | 25-------------------------
10 files changed, 532 insertions(+), 644 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,80 +1,21 @@ -PREFIX = /usr/local -BIN_DOS = ${PREFIX}/bin -MAN_DOS = ${PREFIX}/man -I18N_DOS = ${PREFIX}/share/locale -LIB_DOS = /usr/local/lib -INC_DOS = /usr/local/include -LIBS = -lintl +include config.mk -DOS_PO = po -DOS_MAN = man +#FCH_PO != find ${DOS_PO} -name '*.po' +#FCH_MO != find ${DOS_PO} -name '*.po' | sed 's/\.po$$/\.mo/' -CC = cc -#COPTS_SPCL = -O2 -DNDEBUG -COPTS = -Wall -Wextra -Werror -Wpedantic -Wno-implicit-fallthrough \ - --std=c89 ${COPTS_SPCL} -CPPOPTS = -I${INC_DOS} -DI18N_DOMAINE=\"aplat\" -DI18N_DOS=\"${I18N_DOS}\" -LDOPTS = -L${LIB_DOS} - -FCH_PO != find ${DOS_PO} -name '*.po' -FCH_MO != find ${DOS_PO} -name '*.po' | sed 's/\.po$$/\.mo/' - -LANG_MAN != ls "${DOS_MAN}" +#LANG_MAN != ls "${DOS_MAN}" .SUFFIXES: .c .o .po .mo .c.o: ${CC} ${COPTS} ${CPPOPTS} -c "$<" -.po.mo: - msgfmt -o "$@" "$<" - -all: aplat accumuler traductions - -aplat: aplat.o tampon.o general.o - ${CC} ${COPTS} ${LDOPTS} -o "$@" aplat.o tampon.o general.o ${LIBS} - -accumuler: accumuler.o tampon.o general.o - ${CC} ${COPTS} ${LDOPTS} -o "$@" accumuler.o tampon.o general.o ${LIBS} - -traductions: ${FCH_MO} - -maj_trad: - xgettext --from-code=UTF-8 -k_ -o - *.c | \ - msgmerge -qo "${DOS_PO}/modele.pot" "${DOS_PO}/modele.pot" - - for F in ${FCH_PO} ; \ - do \ - msgmerge -qo "$$F" "$$F" "${DOS_PO}/modele.pot" ; \ - done - -inst_aplat: - mkdir -p "${BIN_DOS}" - install -m 755 aplat "${BIN_DOS}"/aplat - -inst_trad: - for F in ${FCH_MO} ; \ - do \ - LANGUE="$$(echo "$$F" | sed 's|.*/\(.*\)\..*|\1|')" ; \ - mkdir -p "${I18N_DOS}/$$LANGUE/LC_MESSAGES" ; \ - cp $$F \ - "${I18N_DOS}/$$LANGUE/LC_MESSAGES/aplat.mo" ; \ - done - -inst_man: - for L in ${LANG_MAN} ; \ - do \ - mkdir -p ${MAN_DOS}/$$L/man1 ; \ - cp "${DOS_MAN}/$$L/aplat.1" "${MAN_DOS}/$$L/man1" ; \ - mkdir -p ${MAN_DOS}/$$L/man5 ; \ - cp "${DOS_MAN}/$$L/aplat.5" "${MAN_DOS}/$$L/man5" ; \ - cp "${DOS_MAN}/$$L/plat.5" "${MAN_DOS}/$$L/man5" ; \ - done +#.po.mo: +# msgfmt -o "$@" "$<" -install: all inst_aplat inst_trad inst_man +all: aplat -uninstall: - rm -f ${BIN_DOS}/aplat - find "${I18N_DOS}" -type f -name 'aplat.mo' | xargs rm -f - find "${MAN_DOS}" -type f -name 'a?plat.[123456789]' | xargs rm -f +aplat: aplat.o general.o + ${CC} ${COPTS} ${LDOPTS} -o "$@" aplat.o general.o ${BIBS} clean: - rm -f aplat accumuler *.o *.core po/*.mo + rm -rf *.o *.core diff --git a/accumuler.c b/accumuler.c @@ -1,116 +0,0 @@ -#include <stdio.h> - -#ifdef __OpenBSD__ -#include <unistd.h> -#endif - -#include <libintl.h> -#include <locale.h> - -#include "general.h" -#include "tampon.h" - -#define ETQ_TLL 1024 /* taile initiale du tampon à étiquettes */ - -#define DRAP_OUV 01 /* parenthèse ouvrante */ -#define DRAP_FRM 02 /* parenthèse fermante */ - -static void utilisation(void); -static int accumuler(FILE *); - -char *prog_nom; /* nom du programme */ - -struct tampon etq; - -int -main(int argc, char **argv) -{ - prog_nom = trouv_prog_nom(argv, "aplat"); - - if (i18n_init() < 0) - return 1; - - if (pledge_envlp("stdio rpath", NULL) < 0) - return 1; - - if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'V' - && argv[1][2] == '\0') { - printf("accumuler %s\n", VERSION); - return 0; - } else if (argc > 1) { - utilisation(); - return 1; - } - - /* initialiser le tampon */ - if (tp_init(&etq, ETQ_TLL) < 0) - return 1; - - if (accumuler(stdin) < 0) - return 1; - - return 0; -} - -static void -utilisation(void) -{ - printf(_("Utilisation: %s <[fichier]\n"), prog_nom); -} - -static int -accumuler(FILE *f) -{ - int c; - int draps; - - tp_ecr(':', &etq); - -deb_ligne: - if ((c = getc(f)) == EOF) - return 0; - draps = 0; - for (;;) { - putc(c, stdout); - switch (c) { - case '(': - draps |= DRAP_OUV; - break; - case ')': - draps |= DRAP_FRM; - break; - case '\t': - goto etq; - case EOF: - goto invalide; - } - c = getc(f); - } - -etq: - while ((c = getc(f)) != '\t') { - if (c == EOF) - goto invalide; - tp_ecr(c, &etq); - } - if (draps & DRAP_OUV) - tp_ecr(':', &etq); - tp_ecr('\0', &etq); - printf("%s\t", tp_tp(&etq)); - tp_rec(&etq); - if (draps & DRAP_FRM) { - tp_rec(&etq); - if (tp_eff_etq(&etq) < 0) - goto invalide; - } - - while ((c = getc(f)) != EOF) { - putc(c, stdout); - if (c == '\n') - goto deb_ligne; - } - -invalide: - fprintf(stderr, "%s: entrée invalide\n", prog_nom); - return -1; -} diff --git a/aplat.c b/aplat.c @@ -1,5 +1,7 @@ #include <assert.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #ifdef __OpenBSD__ #include <unistd.h> @@ -9,60 +11,73 @@ #include <locale.h> #include "general.h" -#include "tampon.h" - -#define DRAP_OUV 01 /* parenthèse ouvrante */ -#define DRAP_FRM 02 /* parenthèse fermante */ - -#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_ATM 2 /* atome */ - -static void utilisation(void); -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 *prog_nom; /* nom du programme */ - -struct tampon ctn; /* tampon du contenu */ -struct tampon etq; /* tampon de l'étiquette du domaine cadet */ -struct tampon pile; /* pile */ +#include "coroutines.h" + +#define TP_ETQ_TLL 128 +#define TP_CTN_TLL 256 + +#define JT_OUV 0 /* __00 */ +#define JT_FRM 1 /* __01 */ +#define JT_ATM 2 /* __10 */ +#define JT_FRG 3 /* __11 */ + +#define DRAP_FRM 1 +#define DRAP_OUV 2 + +struct tampon { + char *tp; /* début du tampon */ + char *po; /* prochain octet libre */ + int nt; /* nombre d'octets écrits en trop */ + size_t tll; /* taille du tampon */ + size_t nl; /* nombre d'octets libres */ +}; + +static void utilisation(FILE *fichier); +static int tp_init(struct tampon *tp, size_t taille); +static int tp_ecr(struct tampon *tp, char c); +static int tp_terminer(struct tampon *tp); +static void tp_reinit(struct tampon *tp); +static int utf8_incomplet(char *base, char *fin); +static int aplatir(FILE *f); +static int obt_jeton(FILE *fichier, struct tampon *tp); +static int echapper(FILE *fichier, struct tampon *tp); +static int echapper_guillemets(FILE *fichier, struct tampon *tp); +static int echapper_bloc(FILE *fichier, struct tampon *tp); +static void afficher_ligne(int *draps, struct tampon *tp_etq, + struct tampon *tp_ctn); + +char *nom_prog; + +struct tampon tp_etq; +struct tampon tp_ctn; int main(int argc, char **argv) { - prog_nom = trouv_prog_nom(argv, "aplat"); + nom_prog = nom_prog_trouver(argv, "aplat"); if (i18n_init() < 0) return 1; - if (pledge_envlp("stdio rpath", NULL) < 0) +#ifdef __OpenBSD__ + if (pledge("stdio rpath", NULL) < 0) return 1; +#endif if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'V' && argv[1][2] == '\0') { - printf("aplat %s\n", VERSION); + printf("aplat " VERSION "\n"); return 0; } else if (argc > 1) { - utilisation(); + utilisation(stderr); return 1; } /* initialiser les tampons */ - if (tp_init(&etq, ETQ_TLL) < 0 - || tp_init(&ctn, CTN_TLL) < 0 - || tp_init(&pile, PILE_TLL)) + if (tp_init(&tp_etq, TP_ETQ_TLL) < 0 || + tp_init(&tp_ctn, TP_CTN_TLL) < 0) return 1; - + if (aplatir(stdin) < 0) return 1; @@ -70,306 +85,530 @@ main(int argc, char **argv) } static void -utilisation(void) +utilisation(FILE *f) { - printf(_("Utilisation: %s <[fichier]\n"), prog_nom); + fprintf(f, _("Utilisation: %s <[fichier]\n"), nom_prog); } static int aplatir(FILE *f) { - 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 */ + int prfd; /* profondeur */ + int draps; /* drapeaux */ + struct tampon *tp; /* dans lequel écrire le jeton */ + int jta; /* jeton actuel */ + int jtp; /* jeton précédent */ - assert(f != NULL); + assert(f); - prfd = 0; - draps = 0; - - switch (mang_blancs(f)) { - case '(': + switch (jta = (obt_jeton(f, &tp_etq))) { + case JT_OUV: + prfd = 0; + draps = 0; + tp = &tp_etq; break; case EOF: return 0; default: - fprintf(stderr, _("%s: le premier caractère non blanc doit " - "être « ( »\n"), prog_nom); + fprintf(stderr, "ERREUR\n"); return -1; } -ouv: - prfd++; - tp_ecr(0, &pile); - draps |= DRAP_OUV; - - switch (obt_jeton(f, &etq)) { - case JT_OUV: - aff_ligne(&draps, &etq, &ctn); - goto ouv; - case JT_FRM: - goto frm; - case JT_ATM: - 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); + while ((jtp = jta) != EOF) { + if (jtp == JT_OUV) + tp = &tp_etq; + while ((jta = obt_jeton(f, tp)) == JT_FRG) { + if (jtp == JT_OUV) { + fprintf(stderr, "ERREUR\n"); + return -1; } - goto ctn; - case EOF: - goto deseq; - } - assert(0); - -ctn: - switch (obt_jeton(f, &ctn)) { - case JT_OUV: - aff_ligne(&draps, &etq, &ctn); - goto ouv; - case JT_FRM: - goto frm; - case JT_ATM: - goto ctn; - case EOF: - goto deseq; + afficher_ligne(&draps, &tp_etq, &tp_ctn); + } + switch (jtp) { + case JT_OUV: + prfd++; + draps |= DRAP_OUV; + switch (jta) { + case JT_OUV: + afficher_ligne(&draps, &tp_etq, &tp_ctn); + break; + case JT_ATM: + tp = &tp_ctn; + break; + } + break; + case JT_FRM: + draps |= DRAP_FRM; + afficher_ligne(&draps, &tp_etq, &tp_ctn); + if (--prfd == 0) + goto fin; + break; + case JT_ATM: + if (jta == JT_OUV) + afficher_ligne(&draps, &tp_etq, &tp_ctn); + break; + default: + assert(0); + } } - assert(0); - -frm: - do { - draps |= DRAP_FRM; - aff_ligne(&draps, &etq, &ctn); - prfd--; - } while (tp_rec(&pile) != 0); - if (prfd == 0) - goto fin; - - switch (obt_jeton(f, &ctn)) { - case JT_OUV: - goto ouv; - case JT_FRM: - goto frm; - case JT_ATM: - goto ctn; - case EOF: - goto deseq; - } - assert(0); + fprintf(stderr, "ERREUR: deseq\n"); + return -1; fin: - if (mang_blancs(f) == EOF) + if (obt_jeton(f, tp) == EOF) return 0; - fprintf(stderr, _("%s: aucun caractère non blanc ne peut suivre " - "le dernier « ) »\n"), prog_nom); - return -1; - -deseq: - fprintf(stderr, _("%s: parenthèses déséquilibrées\n"), prog_nom); + fprintf(stderr, "ERREUR\n"); return -1; } static int obt_jeton(FILE *f, struct tampon *tp) { - int c; - - assert(f != NULL); - assert(tp != NULL); + int d; + static int c; + cr_variable; + + assert(f); + assert(tp); + + cr_tableau { + cr_definir(0); + cr_definir(1); + cr_definir(2); + cr_definir(3); + cr_definir(4); + cr_definir(5); + } + assert(0); - if ((c = mang_blancs(f)) == EOF) - return EOF; + cr_entrer(0); + for (d = '\0'; ((c = getc(f)) == ' ' || c == '\n' || c == '\t'); d = c) + ; switch (c) { case '(': - return JT_OUV; + cr_sortir(0, JT_OUV); case ')': - return JT_FRM; + cr_sortir(0, JT_FRM); + case '=': + if (d == '\n') { + cr_entrer(3) + switch (echapper_bloc(f, tp)) { + case EOF: + cr_sortir(0, EOF); + case 0: + cr_sortir(0, JT_ATM); + case 1: + cr_sortir(3, JT_FRG); + } + } } - do { + for (;; c = getc(f)) { switch (c) { - case '(': case ')': + case '(': case ')': case '\n': ungetc(c, f); /* CASCADE */ - case ' ': case '\t': case '\n': - return JT_ATM; + case ' ': case '\t': + cr_sortir(0, JT_ATM); + case '\\': + cr_entrer(1); + switch (echapper(f, tp)) { + case EOF: + /* ignore tous les caractères du jeton */ + cr_sortir(0, EOF); + case 0: + continue; + case 1: + cr_sortir(1, JT_FRG); + } + assert(0); case '"': - if ((c = getc(f)) == '"') { - if ((c = getc(f)) == '"') { - if (echapp_bloc(f, tp) == EOF) - return EOF; - } else { - ungetc(c, f); - } - } else { - ungetc(c, f); - if (echapp_guillemets(f, tp) == EOF) - return EOF; + cr_entrer(2); + switch (echapper_guillemets(f, tp)) { + case EOF: + /* ignore tous les caractères du jeton */ + cr_sortir(0, EOF); + case 0: + continue; + case 1: + cr_sortir(2, JT_FRG); } - continue; - case '\\': - if (echapp(f, tp) == EOF) - return EOF; - continue; + assert(0); + case EOF: + cr_sortir(0, EOF); + case ':': + cr_entrer(4); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(4, JT_FRG); + c = 'd'; + /* CASCADE */ default: - tp_ecr(c, tp); + cr_entrer(5); + if (tp_ecr(tp, c) < 0) + cr_sortir(5, JT_FRG); } - } while ((c = getc(f)) != EOF); + } - return EOF; + /*cr_sortir(0, EOF);*/ } +#define tp_invariants(t) \ + (assert((t)), \ + assert((t)->tp), \ + assert((t)->po), \ + assert((t)->po >= (t)->tp), \ + assert((t)->tll >= (t)->nl)) + static int -mang_blancs(FILE *f) +tp_init(struct tampon *tp, size_t tll) { - int c; - while ((c = getc(f)) == ' ' || c == '\n' || c == '\t') - ; - return c; + assert(tp); + assert(tll >= 1); + + if ((tp->tp = malloc(tll+1)) == NULL) + return -1; + tp->po = tp->tp; + tp->tll = tp->nl = tll; + tp->nt = 0; + + tp_invariants(tp); + + return 0; +} + +static int +tp_ecr(struct tampon *tp, char c) +{ + tp_invariants(tp); + + if (tp->nl > 0) { + tp->nl--; + *tp->po++ = c; + tp_invariants(tp); + return (unsigned char) c; + } + + return -1; } static void -aff_ligne(int *draps, struct tampon *etq, struct tampon *ctn) +tp_reinit(struct tampon *tp) { - assert(draps != NULL); - assert(etq != NULL); - assert(ctn != NULL); + tp_invariants(tp); + + tp->nl = tp->tll; + tp->po = tp->tp; + if (tp->nt > 0) { + char *src, *dst; + tp->po += tp->nt; + tp->nl -= tp->nt; + *tp->tp = tp->tp[tp->tll]; + dst = tp->tp + 1; + src = tp->tp + tp->tll - (tp->nt - 1); + while (--tp->nt > 0) { + *dst = *src; + } + } - if (*draps & DRAP_OUV) - putc('(', stdout); - if (*draps & DRAP_FRM) - putc(')', stdout); + tp_invariants(tp); +} - tp_ecr('\0', etq); - tp_ecr('\0', ctn); +static int +tp_terminer(struct tampon *tp) +{ + tp_invariants(tp); + + if (tp->nl > 0) { + *tp->po = '\0'; + } else { + char *fin; + if ((tp->nt = utf8_incomplet(tp->tp, tp->po-1)) < 0) { + tp->nt = 0; + return -1; + } + fin = tp->po - tp->nt; + *tp->po = *fin; + *fin = '\0'; + } - printf("\t%s\t%s\n", tp_tp(etq), tp_tp(ctn)); + tp_invariants(tp); - *draps = 0; - tp_eff(etq); - tp_eff(ctn); + return 0; } +/* nombre d'octets en trop */ static int -echapp(FILE *f, struct tampon *tp) +utf8_incomplet(char *base, char *fin) { - int c; + int i, n; + unsigned char c; - assert(f != NULL); - assert(tp != NULL); + assert(base); + assert(fin); + assert(base <= fin); + if (((unsigned char) *base >> 6) == 0x2) + return -1; + + for (i = 1; ((unsigned char) *fin >> 6) == 0x2; fin--) + i++; + c = *fin; + if (c <= 0x7F) /* un octet */ + n = 1; + else if (c >= 0xF0) /* quatre octets */ + n = 4; + else if (c >= 0xE0) /* trois octets */ + n = 3; + else if (c >= 0xC2) /* deux octets */ + n = 2; + else /* séquence invalide */ + n = 0;; + + if (i < n) + return i; + else if (i == n) + return 0; + else + return n - i; +} + +static int +echapper(FILE *f, struct tampon *tp) +{ + static int c; + cr_variable; + + assert(f); + assert(tp); + + cr_tableau { + cr_definir(0); + cr_definir(1); + cr_definir(2); + cr_definir(3); + cr_definir(4); + cr_definir(5); + } + assert(0); + + cr_entrer(0); switch (c = getc(f)) { case '\n': + if ((c = getc(f)) == '=') { + cr_entrer(1) + switch (echapper_bloc(f, tp)) { + case EOF: + cr_sortir(0, EOF); + case 0: + break; + case 1: + cr_sortir(1, 1); + } + } + ungetc(c, f); break; case '\t': - tp_ecr('\\', tp); - tp_ecr('t', tp); + cr_entrer(2); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(2, 1); + cr_entrer(3); + if (tp_ecr(tp, 't') < 0) + cr_sortir(3, 1); break; case EOF: - return EOF; + cr_sortir(0, EOF); + case ':': + c = 'd'; + /* CASCADE */ case '\\': - tp_ecr('\\', tp); + cr_entrer(4); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(4, 1); /* CASCADE */ default: - tp_ecr(c, tp); + cr_entrer(5); + if (tp_ecr(tp, c) < 0) + cr_sortir(5, 1); } - return 0; + cr_sortir(0, 0); } static int -echapp_guillemets(FILE *f, struct tampon *tp) +echapper_guillemets(FILE *f, struct tampon *tp) { - int c; - - assert(f != NULL); - assert(tp != NULL); + static int c; + cr_variable; + + assert(f); + assert(tp); + + cr_tableau { + cr_definir(0); + cr_definir(1); + cr_definir(2); + cr_definir(3); + cr_definir(4); + cr_definir(5); + cr_definir(6); + cr_definir(7); + cr_definir(8); + } + assert(0); + cr_entrer(0); for (;;) { switch ((c = getc(f))) { case '"': - return 0; + cr_sortir(0, 0); case '\n': - tp_ecr('\\', tp); - tp_ecr('n', tp); + if ((c = getc(f)) == '=') { + cr_entrer(1); + switch (echapper_bloc(f, tp)) { + case EOF: + cr_sortir(0, EOF); + case 0: + continue; + case 1: + cr_sortir(1, 1); + } + } + ungetc(c, f); + cr_entrer(2); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(2, 1); + cr_entrer(3); + if (tp_ecr(tp, 'n') < 0) + cr_sortir(3, 1); continue; case '\t': - tp_ecr('\\', tp); - tp_ecr('t', tp); + cr_entrer(4); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(4, 1); + cr_entrer(5); + if (tp_ecr(tp, 't') < 0) + cr_sortir(5, 1); continue; case '\\': - if (echapp(f, tp) != EOF) + cr_entrer(6); + switch (echapper(f, tp)) { + case EOF: + cr_sortir(0, EOF); + case 0: continue; - /* CASCADE */ + case 1: + cr_sortir(6, 1); + } + assert(0); case EOF: - return EOF; + cr_sortir(0, EOF); + case ':': + cr_entrer(7); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(7, 1); + c = 'd'; + /* CASCADE */ default: - tp_ecr(c, tp); + cr_entrer(8); + if (tp_ecr(tp, c) < 0) + cr_sortir(8, 1); } } + assert(0); } static int -echapp_bloc(FILE *f, struct tampon *tp) +echapper_bloc(FILE *f, struct tampon *tp) { - int c; - int ngui; - size_t ncar; - - assert(f != NULL); - assert(tp != NULL); + static int c; + cr_variable; + + assert(f); + assert(tp); + + cr_tableau { + cr_definir(0); + cr_definir(1); + cr_definir(2); + cr_definir(3); + cr_definir(4); + cr_definir(5); + cr_definir(6); + } + assert(0); + cr_entrer(0); /* ignorer le reste de la ligne */ while ((c = getc(f)) != '\n') if (c == EOF) - return EOF; - - ncar = tp_ncar(tp); - - for (;;) { + cr_sortir(0, EOF); + + for (;;){ switch (c = getc(f)) { case '\n': - tp_ecr('\\', tp); - tp_ecr('n', tp); - continue; - case '\t': - tp_ecr('\\', tp); - tp_ecr('t', tp); - continue; - case '"': - ngui = 1; - while ((c = getc(f)) == '"') { - if (++ngui == 3) { - if ((c = getc(f)) == '!') - goto afficher; - ungetc(c, f); - if (ncar != tp_ncar(tp)) - tp_eff_ligne(tp); - return 0; - } + if ((c = getc(f)) == '=') { + /* ignorer le reste de la ligne */ + while (c != '\n') + if ((c = getc(f)) == EOF) + break; + ungetc(c, f); + cr_sortir(0, 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); + cr_entrer(1); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(1, 1); + cr_entrer(2); + if (tp_ecr(tp, 'n') < 0) + cr_sortir(2, 1); + continue; + case '\t': + cr_entrer(3); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(3, 1); + cr_entrer(4); + if (tp_ecr(tp, 't') < 0) + cr_sortir(4, 1); continue; case EOF: - return EOF; + cr_sortir(0, EOF); + case ':': + c = 'd'; + /* CASCADE */ case '\\': - tp_ecr('\\', tp); + cr_entrer(5); + if (tp_ecr(tp, '\\') < 0) + cr_sortir(5, 1); /* CASCADE */ default: - tp_ecr(c, tp); + cr_entrer(6); + if (tp_ecr(tp, c) < 0) + cr_sortir(6, 1); } } + assert(0); +} + +static void +afficher_ligne(int *draps, struct tampon *tp_etq, struct tampon *tp_ctn) +{ + assert(draps); + assert(tp_etq); + assert(tp_ctn); + + if (*draps & DRAP_OUV) + putc('(', stdout); + if (*draps & DRAP_FRM) + putc(')', stdout); + + tp_terminer(tp_etq); + tp_terminer(tp_ctn); + + printf("\t%s\t%s\n", tp_etq->tp, tp_ctn->tp); + + *draps = 0; + tp_reinit(tp_etq); + tp_reinit(tp_ctn); } diff --git a/changements.txt b/changements.txt @@ -7,17 +7,21 @@ Version 2.0 (???) * 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. Chaque étiquette - n'est même affichée qu'une seule fois. -* 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. + champ des étiquettes, plutôt que la hiérarchie complète, et chaque étiquette + n'est affichée qu'une seule fois. +* plat(5): Imposition de limites de 128 octets pour le champ des étiquettes et + de 256 octets pour celui du contenu. +* plat(5): Ajout de la séquence d'échappement « /d », qui signifie « : ». Les + deux-points sont donc maintenant échappables. * aplat(1): La nouvelle option -V affiche la version du programme. -* accumuler(1): Ajout d'un programme qui, à la manière de la sortie de la - version 1.0 d'aplat(1), accumule dans le champ des étiquettes toutes les - étiquettes parentes d'un domaine. +* aplat(1): Le raccourcis syntaxique utilisant les deux-points n'existe plus. +* aplat(1): Les blocs sont délimités par le caractère « = », plutôt que par la + séquence « """ ». Ce caractère doit en outre se trouver en début de ligne. +* aplat(1): Les caractères se trouvant sur la même ligne que le caractère de + limite d'un bloc sont ignorés. * traductions: catalan: aplat(1), aplat(5), plat(5) Version 1.0 (2024/01/25) ----------- -* Existence +* Existence. diff --git a/config.mk b/config.mk @@ -0,0 +1,19 @@ +VERSION = 2.0-ε/1 (2024/06/07) + +PREFIXE = /usr/local +BIN_DOS = ${PREFIXE}/bin +MAN_DOS = ${PREFIXE}/man +I18N_DOS = ${PREFIXE}/share/locale +INC_DOS = /usr/local/include +BIB_DOS = /usr/local/lib +BIBS = -lintl + +DOS_PO = po +DOS_MAN = man + +CC = cc +COPTS = -Wall -Wextra -Wpedantic -Werror --std=c89 #-O2 -DNDEBUG +CPPOPTS = -I${INC_DOS} -DI18N_DOMAINE='"aplat"' \ + -DI18N_DOS='"${I18N_DOS}"' \ + -DVERSION='"${VERSION}"' +LDOPTS = -L${BIB_DOS} diff --git a/coroutines.h b/coroutines.h @@ -0,0 +1,10 @@ +#ifndef COROUTINES_H +#define COROUTINES_H + +#define cr_variable static int cr_etat=0; +#define cr_tableau switch (cr_etat) +#define cr_definir(n) case n: goto cr_e ## n; +#define cr_entrer(n) cr_e ## n: +#define cr_sortir(e, v) do { cr_etat=(e); return (v); } while (0) + +#endif diff --git a/general.c b/general.c @@ -1,30 +1,30 @@ #include <assert.h> #include <stdio.h> -#include <stdlib.h> +/* L'appel système unveil(2) n'est présent que sur OpenBSD. */ #ifdef __OpenBSD__ #include <unistd.h> #endif +/* Bibliothèques pour l'internationalisation. */ #include <libintl.h> #include <locale.h> #include "general.h" -extern char *prog_nom; +extern char *nom_prog; char * -trouv_prog_nom(char **argv, char *nom) +nom_prog_trouver(char **argv, char *defaut) { - char *n; + char *nom; - assert(argv != NULL); - assert(nom != NULL); - - if ((n = argv[0]) == NULL || n[0] == '\0') - return nom; - return n; + assert(argv); + assert(defaut); + if ((nom = *argv) == NULL || *nom == '\0') + return defaut; + return nom; } int @@ -37,24 +37,10 @@ i18n_init(void) #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"), prog_nom); - return -1; - } -#endif - return 0; -} - -/* enveloppe pour pledge */ -int -pledge_envlp(char *prom, char *execprom) -{ - assert(prom != NULL); - -#ifdef __OpenBSD__ - if (pledge(prom, execprom) < 0) { - fprintf(stderr, _("%s: erreur avec pledge()\n"), prog_nom); + fprintf(stderr, _("%s: erreur avec unveil()\n"), nom_prog); return -1; } #endif + return 0; } diff --git a/general.h b/general.h @@ -1,11 +1,9 @@ #ifndef GENERAL_H #define GENERAL_H -#define VERSION "2.0 (?\?\?)" #define _(c) gettext(c) -char *trouv_prog_nom(char **, char *); +char *nom_prog_trouver(char **argv, char *defaut); int i18n_init(void); -int pledge_envlp(char *, char *); #endif diff --git a/tampon.c b/tampon.c @@ -1,168 +0,0 @@ -#include <assert.h> -#include <stdlib.h> - -#include "tampon.h" - -/* invariants de la structure tampon */ -#define INVARIANTS_TP(t) \ - (assert((t) != NULL), \ - assert((t)->tp != NULL), \ - assert((t)->pc != NULL), \ - 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)->deb < (t)->tll), \ - assert((size_t) ((t)->pc - (t)->tp) >= (t)->deb)) - -static int tp_plein(char, struct tampon *); - -/* initialiser le tampon tp de taille tll */ -int -tp_init(struct tampon *tp, size_t tll) -{ - assert(tll >= 1); - assert(tp != NULL); - - if ((tp->pc = tp->tp = malloc(tll)) == NULL) - return -1; - tp->tll = tll; - tp->deb = 0; - - INVARIANTS_TP(tp); - - return 0; -} - -/* ajouter le caractère c au tampon tp */ -int -tp_ecr(char c, struct tampon *tp) -{ - INVARIANTS_TP(tp); - - if ((size_t) (tp->pc - tp->tp) == tp->tll) /* le tampon est-il plein? */ - return tp_plein(c, tp); - *tp->pc++ = c; - - INVARIANTS_TP(tp); - - return (unsigned char) c; -} - -/* agrandir le tampon tp et y ajouter le caractère c */ -static int -tp_plein(char c, struct tampon *tp) -{ - size_t diff; - - INVARIANTS_TP(tp); - - diff = tp->pc - tp->tp; - if ((tp->tp = realloc(tp->tp, tp->tll * TP_FACT_AGR)) == NULL) - return -1; - tp->tll *= TP_FACT_AGR; - tp->pc = tp->tp + diff; /* tp->tp pourrait avoir changé */ - *tp->pc++ = c; - - INVARIANTS_TP(tp); - - return (unsigned char) c; -} - -/* effacer le contenu du tampon tp */ -void -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_eff_ligne(struct tampon *tp) -{ - int echapp; - - INVARIANTS_TP(tp); - - /* 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); -} - -/* effacer le dernier deux-points et les caractères qui le suivent */ -int -tp_eff_etq(struct tampon *tp) -{ - INVARIANTS_TP(tp); - - assert(*tp->tp == ':'); - assert(tp->pc - tp->tp > 0); - - if (tp->pc == tp->tp + 1) - return -1; - - while (*--tp->pc != ':') - ; - tp->pc++; - - INVARIANTS_TP(tp); - - return 0; -} - -/* supprimer le dernier caractère d'un tampon */ -char -tp_rec(struct tampon *tp) -{ - INVARIANTS_TP(tp); - - --tp->pc; - - INVARIANTS_TP(tp); - - return *tp->pc; -} - -void -tp_deb(struct tampon *tp, size_t deb) -{ - INVARIANTS_TP(tp); - - tp->deb = deb; - - INVARIANTS_TP(tp); -} diff --git a/tampon.h b/tampon.h @@ -1,25 +0,0 @@ -#ifndef TAMPON_H -#define TAMPON_H - -#include <stddef.h> - -#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 */ - 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 *); -int tp_eff_etq(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