commit 7b89929da8e5b0899c841889b4357bb3f0ce64eb
parent 6b5107d01f93dba4f34d6e0ccb3e9a558686eec2
Auteur: Selve <selve@asteride.xyz>
Date: Fri, 17 Nov 2023 22:49:26 -0500
réécriture de aplat
Diffstat:
M | Makefile | | | 4 | ++-- |
M | aplat.c | | | 212 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
A | etq.c | | | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
A | etq.h | | | 12 | ++++++++++++ |
M | tampon.c | | | 79 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
M | tampon.h | | | 23 | ++++++++--------------- |
A | txt.c | | | 21 | +++++++++++++++++++++ |
A | txt.h | | | 8 | ++++++++ |
8 files changed, 260 insertions(+), 148 deletions(-)
diff --git a/Makefile b/Makefile
@@ -8,8 +8,8 @@ PREFIX = "/usr/local/bin"
all: aplat
-aplat: aplat.o tampon.o
- ${CC} ${COPT} -o "$@" aplat.o tampon.o
+aplat: aplat.o tampon.o etq.o txt.o
+ ${CC} ${COPT} -o "$@" aplat.o tampon.o etq.o txt.o
install: aplat
install -m 755 aplat ${PREFIX}/aplat
diff --git a/aplat.c b/aplat.c
@@ -1,26 +1,40 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include "tampon.h"
+#include "etq.h"
+#include "txt.h"
-#define TAILLE_ETQ 4096 /* taille initiale du tampon à étiquettes */
-#define TAILLE_TXT 4096 /* taille initiale du tampon à texte */
+#define TLL_ETQ 4096 /* taille initiale du tampon à étiquettes */
+#define TLL_TXT 4096 /* taille initiale du tampon à texte */
-struct tampon etq; /* tampon à étiquettes */
-struct tampon txt; /* tampon à texte */
+#define PENTE_DESC 0
+#define PENTE_EMRG 1
-int rec_etq(void);
-int manger_espaces(FILE *f);
-int transformer(FILE *f);;
-int guillemets(FILE *f, struct tampon *);
+void utilisation(void);
+int transformer(FILE *);
+int manger_espaces(FILE *);
+int guillemets(FILE *, struct tampon *);
+
+char *nom_prog; /* nom du programme */
+
+struct tampon etq; /* tampon à étiquettes */
+struct tampon txt; /* tampon à texte */
int
-main(void)
+main(int argc, char **argv)
{
+ if ((nom_prog = argv[0]) == NULL || nom_prog[0] == '\0')
+ nom_prog = "aplat";
+
+ if (argc > 1) {
+ utilisation();
+ return 1;
+ }
+
/* initialiser les tampons */
- if (t_init(&txt, TAILLE_TXT) < 0 || t_init(&etq, TAILLE_ETQ) < 0)
+ if (tp_init(&etq, TLL_ETQ) < 0 || tp_init(&txt, TLL_TXT) < 0)
return 1;
if (transformer(stdin) < 0)
@@ -29,103 +43,90 @@ main(void)
return 0;
}
-/* effacer le domaine cadet */
-int
-rec_etq(void)
+void
+utilisation(void)
{
- assert(etq.pcar > etq.t);
- /* prend aussi pour acquis que le format des domaines est respecté */
- while (--etq.pcar > etq.t)
- if (*etq.pcar == ':' && *--etq.pcar == '\\') {
- if (etq.pcar != etq.t && *(etq.pcar-1) == '\\')
- continue;
- break;
- }
- etq.ncar = etq.pcar - etq.t;
- assert(etq.pcar >= etq.t);
- return 0;
+ printf("UTILISATION: %s <[fichier]\n", nom_prog);
}
int
transformer(FILE *f)
{
int c;
- int prfd = 0; /* profondeur */
- int aff = 0; /* si étiquettes ont été affichées */
- int pente;
+ int prfd; /* profondeur */
+
+ assert(f != NULL);
+
+ prfd = 0;
if ((c = manger_espaces(f)) == EOF)
return 0;
if (c != '(') {
- fprintf(stderr, "aplat: le premier caractère doit être \"(\"\n");
+ fprintf(stderr,
+ "%s: le premier caractère affichable doit être « ( »\n",
+ nom_prog);
return -1;
}
-
+
ouv:
prfd++;
- pente = 1;
- if (aff) {
- putc('\t', stdout);
- t_aff(&txt);
- t_eff(&txt);
- putc('\n', stdout);
- aff = 0;
- }
- t_ecr('\\', &etq);
- t_ecr(':', &etq);
+ tp_ecr(':', &etq);
if ((c = manger_espaces(f)) == EOF)
goto deseq;
do {
switch (c) {
- case ' ': case '\n': case '\t':
+ case ' ': case '\t': case '\n':
+ tp_etq_aff(&etq);
+ fputs("\t(", stdout);
goto val;
case '(':
+ tp_etq_aff(&etq);
+ fputs("\t(\t\n", stdout);
goto ouv;
case ')':
- t_aff(&etq);
- printf(":\t()\n");
+ tp_etq_aff(&etq);
+ fputs("\t()\t\n", stdout);
goto ferm;
case '"':
if (guillemets(f, &etq) == EOF)
goto deseq;
- break;
+ continue;
case '\\':
if ((c = getc(f)) == EOF)
goto deseq;
if (c == '\\')
- t_ecr(c, &etq);
- /* passe à default */
+ tp_ecr('\\', &etq);
+ tp_ecr(c, &etq);
+ continue;
+ case ':':
+ tp_etq_aff(&etq);
+ fputs("\t(\t\n", stdout);
+ prfd++;
+ tp_ecr('\\', &etq);
default:
- t_ecr(c, &etq);
+ tp_ecr(c, &etq);
}
} while ((c = getc(f)) != EOF);
- goto deseq;
val:
- if ((c = manger_espaces(f)) == EOF)
- goto deseq;
-
- if (c != '(' || pente > 0) {
- t_aff(&etq);
- putc(':', stdout);
- aff = 1;
- putc('\t', stdout);
- if (pente > 0) {
- putc('(', stdout);
- pente = 0; /* ??? */
- }
- }
-
do {
switch (c) {
- case ' ': case '\n': case '\t': /* ignorer les espaces */
+ case ' ': case '\t': case '\n':
continue;
case '(':
+ putc('\t', stdout);
+ tp_txt_aff(&txt);
+ tp_eff(&txt);
+ putc('\n', stdout);
goto ouv;
case ')':
+ fputs(")\t", stdout);
+ tp_txt_aff(&txt);
+ tp_eff(&txt);
+ putc('\n', stdout);
goto ferm;
case '"':
if (guillemets(f, &txt) == EOF)
@@ -135,37 +136,58 @@ val:
if ((c = getc(f)) == EOF)
goto deseq;
if (c == '\\')
- t_ecr('\\', &txt);
- /* passe à default */
+ tp_ecr('\\', &txt);
+ /* CASCADE */
default:
- t_ecr(c, &txt);
+ tp_ecr(c, &txt);
}
} while ((c = getc(f)) != EOF);
goto deseq;
ferm:
- if (aff) {
- putc(')', stdout);
+ if (--prfd == 0)
+ goto fin;
+ assert(prfd > 0);
+
+ while (tp_etq_rec(&etq) != ETQ_SEP_REEL) {
+ tp_etq_aff(&etq);
+ fputs("\t)\t\n", stdout);
+ if (--prfd == 0)
+ goto fin;
+ }
+
+ if ((c = manger_espaces(f)) == EOF)
+ goto deseq;
+ switch (c) {
+ case '(':
+ goto ouv;
+ case ')':
+ tp_etq_aff(&etq);
+ fputs("\t)\t\n", stdout);
+ goto ferm;
+ default:
+ tp_etq_aff(&etq);
putc('\t', stdout);
- t_aff(&txt);
- t_eff(&txt);
- putc('\n', stdout);
- aff = 0;
+ goto val;
}
- rec_etq();
- pente = -1;
- if (--prfd == 0)
- goto verif;
+
goto val;
-verif:
- if (manger_espaces(f) != EOF) {
- fprintf(stderr, "aplat: le dernier caractère doit être \")\"\n");
+fin:
+ switch (manger_espaces(f)) {
+ case EOF:
+ return 0;
+ case '(': case ')':
+ goto deseq;
+ default:
+ fprintf(stderr,
+ "%s: le dernier caractère affichable doit être « ) »\n",
+ nom_prog);
return -1;
}
- return 0;
+
deseq:
- fprintf(stderr, "aplat: parenthèses déséquilibrées (%d)\n", prfd);
+ fprintf(stderr, "%s: parenthèses déséquilibrées\n", nom_prog);
return -1;
}
@@ -173,37 +195,41 @@ int
manger_espaces(FILE *f)
{
int c;
+
assert(f != NULL);
- while ((c = getc(f)) == ' '|| c == '\n' || c == '\t')
- if (c == EOF) break;
+
+ while ((c = getc(f)) == ' ' || c == '\n' || c == '\t')
+ if (c == EOF)
+ break;
return c;
}
int
-guillemets(FILE *f, struct tampon *t)
+guillemets(FILE *f, struct tampon *tp)
{
int c;
+
assert(f != NULL);
- assert(t != NULL);
+ assert(tp != NULL);
+
while ((c = getc(f)) != '"' && c != EOF) {
switch (c) {
case '\n':
- t_ecr('\\', t);
- t_ecr('n', t);
+ tp_ecr('\\', tp);
+ tp_ecr('n', tp);
continue;
case '\t':
- t_ecr('\\', t);
- t_ecr('t', t);
+ tp_ecr('\\', tp);
+ tp_ecr('t', tp);
continue;
case '\\':
if ((c = getc(f)) == EOF)
return EOF;
if (c == '\\')
- t_ecr('\\', t);
- /* passe à default */
+ tp_ecr('\\', tp);
+ /* CASCADE */
default:
- t_ecr(c, t);
- continue;
+ tp_ecr(c, tp);
}
}
return c;
diff --git a/etq.c b/etq.c
@@ -0,0 +1,49 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "etq.h"
+#include "tampon.h"
+
+/* afficher le contenu d'un tampon etq en sortie standard */
+int
+tp_etq_aff(struct tampon *tp)
+{
+ char *c;
+
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
+ assert(tp->pc - tp->tp > 0);
+ assert(*tp->tp == ':');
+
+ for (c = tp->tp; c < tp->pc; c++) {
+ if (*c == '\\')
+ /* les autres /\\./ doivent être préservés */
+ if (*++c != ':')
+ putc('\\', stdout);
+ if (putc(*c, stdout) < 0)
+ return -1;
+ }
+ putc(':', stdout);
+ return 0;
+}
+
+/* supprimer le domaine cadet */
+int
+tp_etq_rec(struct tampon *tp)
+{
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
+ assert(tp->pc - tp->tp > 1);
+ assert(*tp->tp == ':');
+
+ --tp->pc;
+ while (*--tp->pc != ':')
+ ;
+ if (tp->pc - tp->tp != 0 && *(tp->pc-1) == '\\') {
+ --tp->pc;
+ return ETQ_SEP_FICT;
+ }
+ return ETQ_SEP_REEL;
+}
diff --git a/etq.h b/etq.h
@@ -0,0 +1,12 @@
+#ifndef ETQ_H
+#define ETQ_H
+
+#include "tampon.h"
+
+#define ETQ_SEP_REEL 0 /* séparateur réel */
+#define ETQ_SEP_FICT 1 /* séparateur fictif (échappé) */
+
+int tp_etq_aff(struct tampon *);
+int tp_etq_rec(struct tampon *);
+
+#endif
diff --git a/tampon.c b/tampon.c
@@ -1,61 +1,64 @@
-#include <stdio.h>
+#include <assert.h>
#include <stdlib.h>
#include "tampon.h"
-#undef t_ecr
-/* initialiser un tampon t de taille taille */
+/* initialiser le tampon tp de taille tll */
int
-t_init(struct tampon *t, size_t taille)
+tp_init(struct tampon *tp, size_t tll)
{
- if ((t->t = malloc(taille)) == NULL)
+ assert(tll >= 1);
+ assert(tp != NULL);
+
+ if ((tp->tp = tp->pc = malloc(tll)) == NULL)
return -1;
- t->taille = taille;
- t->pcar = t->t;
- t->ncar = 0;
+ tp->tll = tll;
return 0;
}
-/* ajouter un caractère au tampon t */
+/* ajouter le caractère c au tampon tp */
int
-t_ecr(char c, struct tampon *t)
+tp_ecr(char c, struct tampon *tp)
{
- return ((++t->ncar > t->taille) ? t_plein(c, t) :
- (*t->pcar++ = c, (unsigned char) c));
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
+ assert(tp->pc - tp->tp >= 0);
+ assert((size_t) (tp->pc - tp->tp) <= tp->tll);
+
+ if ((size_t) (tp->pc - tp->tp) == tp->tll) /* le tampon est-il plein? */
+ return tp_plein(c, tp);
+ return (unsigned char) (*tp->pc++ = c);
}
-/* agrandir le tampon t par T_FACT_AGR */
+/* agrandir le tampon tp et y ajouter le caractère c */
int
-t_plein(char c, struct tampon *t)
+tp_plein(char c, struct tampon *tp)
{
- if ((t->t = realloc(t->t, t->taille * T_FACT_AGR)) == NULL)
+ size_t diff;
+
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
+ assert(tp->pc - tp->tp >= 0);
+ assert(tp->tll >= 1);
+ assert(tp->tll * TP_FACT_AGR > tp->tll); /* doit grandir */
+
+ diff = tp->pc - tp->tp;
+ if ((tp->tp = realloc(tp->tp, tp->tll * TP_FACT_AGR)) == NULL)
return -1;
- t->taille *= T_FACT_AGR;
- t->pcar = t->t + t->ncar - 1;
- *t->pcar++ = c;
- return (unsigned char) c;
+ tp->tll *= TP_FACT_AGR;
+ tp->pc = tp->tp + diff; /* tp->tp pourrait avoir changé */
+ return (unsigned char) (*tp->pc++ = c);
}
-/* afficher le contenu du tampon t */
+/* effacer le contenu du tampon tp */
void
-t_aff(struct tampon *t)
+tp_eff(struct tampon *tp)
{
- char *pcar = t->t;
- int ncar = t->ncar;
- while (ncar-- > 0) {
- if (*pcar == '\\') {
- ncar--;
- if (*++pcar != ':')
- putc('\\', stdout);
- }
- putc(*pcar++, stdout);
- }
-}
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
-/* effacer le contenu du tampon t */
-void
-t_eff(struct tampon *t)
-{
- t->pcar = t->t;
- t->ncar = 0;
+ tp->pc = tp->tp;
}
diff --git a/tampon.h b/tampon.h
@@ -1,24 +1,17 @@
#ifndef TAMPON_H
#define TAMPON_H
-#define T_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */
+#define TP_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */
struct tampon {
- char *t; /* le tampon lui-même */
- char *pcar; /* ptr vers le prochain caractère */
- size_t taille; /* taille du tampon */
- size_t ncar; /* nombre de caractères écrits */
+ char *tp; /* le tampon lui-même */
+ char *pc; /* ptr vers la prochaine cellule libre */
+ size_t tll; /* taille du tampon */
};
-int t_init(struct tampon *, size_t taille);
-int t_ecr(char c, struct tampon *);
-void t_aff(struct tampon *);
-void t_eff(struct tampon *);
-int t_plein(char c, struct tampon *);
-
-#define t_ecr(c, t) \
- ((++(t)->ncar > (t)->taille) ? \
- t_plein((c), (t)) : \
- (*(t)->pcar++ = (c), (unsigned char) (c)))
+int tp_init(struct tampon *, size_t taille);
+int tp_ecr(char c, struct tampon *);
+int tp_plein(char c,struct tampon *);
+void tp_eff(struct tampon *);
#endif
diff --git a/txt.c b/txt.c
@@ -0,0 +1,21 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "tampon.h"
+#include "txt.h"
+
+/* afficher le contenu d'un tampon txt en sortie standard */
+int
+tp_txt_aff(struct tampon *tp)
+{
+ char *c;
+
+ assert(tp != NULL);
+ assert(tp->tp != NULL);
+ assert(tp->pc != NULL);
+
+ for (c = tp->tp; c < tp->pc; c++)
+ if (putc(*c, stdout) < 0)
+ return -1;
+ return 0;
+}
diff --git a/txt.h b/txt.h
@@ -0,0 +1,8 @@
+#ifndef TXT_H
+#define TXT_H
+
+#include "tampon.h"
+
+int tp_txt_aff(struct tampon *);
+
+#endif