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:
M | Makefile | | | 79 | ++++++++++--------------------------------------------------------------------- |
D | accumuler.c | | | 116 | ------------------------------------------------------------------------------- |
M | aplat.c | | | 697 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | changements.txt | | | 20 | ++++++++++++-------- |
A | config.mk | | | 19 | +++++++++++++++++++ |
A | coroutines.h | | | 10 | ++++++++++ |
M | general.c | | | 38 | ++++++++++++-------------------------- |
M | general.h | | | 4 | +--- |
D | tampon.c | | | 168 | ------------------------------------------------------------------------------- |
D | tampon.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