commit 7db5eaa4a1f7b6bd0868ce8ac92c9a307a149814
parent 464d1087e7f428601c4a3d4cb7fb2278537d232e
Auteur: Selve <selve@asteride.xyz>
Date: Sat, 23 Sep 2023 21:25:28 -0400
ajout du programme exclure
Diffstat:
M | Makefile | | | 19 | +++++++++++++++---- |
M | aplat.c | | | 76 | ++-------------------------------------------------------------------------- |
A | eval.h | | | 4 | ++++ |
A | exclure.c | | | 440 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | meta.c | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | meta.h | | | 19 | +++++++++++++++++++ |
A | tampon.c | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tampon.h | | | 24 | ++++++++++++++++++++++++ |
8 files changed, 653 insertions(+), 78 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,14 +2,25 @@ COPT = -Wall -Wextra -Werror --std=c89 -O2
CC = cc
PREFIX = "/usr/local/bin"
-aplat: aplat.c
- ${CC} ${COPT} -o aplat aplat.c
+.SUFFIXES: .c .o
+.c.o:
+ ${CC} ${COPT} -c "$<"
-install: aplat
+all: aplat exclure
+
+aplat: aplat.o tampon.o
+ ${CC} ${COPT} -o "$@" aplat.o tampon.o
+
+exclure: exclure.o meta.o tampon.o
+ ${CC} ${COPT} -o "$@" exclure.o meta.o tampon.o
+
+install: aplat exclure
install -m 755 aplat ${PREFIX}/aplat
+ install -m 755 exclure ${PREFIX}/exclure
uninstall:
rm -f ${PREFIX}/aplat
+ rm -f ${PREFIX}/exclure
clean:
- rm -f aplat
+ rm -f aplat exclure *.o
diff --git a/aplat.c b/aplat.c
@@ -2,27 +2,14 @@
#include <stdlib.h>
#include <unistd.h>
+#include "tampon.h"
+
#define TAILLE_ETQ 4096 /* taille du tampon à étiquettes */
#define TAILLE_TXT 4096 /* taille du tampon à texte */
-#define FACT_AGR 2 /* facteur d'agrandissement d'un tampon */
-
-struct tampon {
- char *t; /* le tampon lui-même */
- size_t taille; /* taille du tampon */
- size_t ncar; /* nombre de caractères écrits */
- char *pcar; /* ptr vers le prochain caractère */
-};
-/* déclaration des tampons */
struct tampon etq; /* tampon à étiquettes */
struct tampon txt; /* tampon à texte */
-/* fonctions locales */
-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, struct tampon *);
int rec_etq(void);
int manger_espaces(FILE *f);
int transformer(FILE *f);;
@@ -41,65 +28,6 @@ main(void)
return 0;
}
-/* initialiser un tampon t de taille taille */
-int
-t_init(struct tampon *t, size_t taille)
-{
- if ((t->t = realloc(t->t, taille)) == NULL)
- return -1;
- t->taille = taille;
- t->pcar = t->t;
- t->ncar = 0;
- return 0;
-}
-
-/* ajouter un caractère au tampon t */
-int
-t_ecr(char c, struct tampon *t)
-{
- return ((++t->ncar > t->taille) ? t_plein(c, t) : (*t->pcar++ = c));
-}
-
-#define t_ecr(c, t) \
- ((++(t)->ncar > (t)->taille) ? \
- t_plein((c), (t)) : \
- (*(t)->pcar++ = (c)))
-
-/* agrandir le tampon t par FACT_AGR */
-int
-t_plein(char c, struct tampon *t)
-{
- if ((t->t = realloc(t->t, t->taille * FACT_AGR)) == NULL)
- return EOF;
- t->taille *= FACT_AGR;
- t->pcar = t->t + t->ncar - 1;
- return *t->pcar++ = c;
-}
-
-/* afficher le contenu du tampon t */
-void
-t_aff(struct tampon *t)
-{
- char *pcar = t->t;
- int ncar = t->ncar;
- while (ncar-- > 0) {
- if (*pcar == '\\') {
- ncar--;
- if (*++pcar != ':')
- putc('\\', stdout);
- }
- putc(*pcar++, stdout);
- }
-}
-
-/* effacer le contenu du tampon t */
-void
-t_eff(struct tampon *t)
-{
- t->pcar = t->t;
- t->ncar = 0;
-}
-
int
rec_etq(void)
{
diff --git a/eval.h b/eval.h
@@ -0,0 +1,4 @@
+#ifndef EVAL_H
+#define EVAL_H
+
+#endif
diff --git a/exclure.c b/exclure.c
@@ -0,0 +1,440 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "meta.h"
+#include "tampon.h"
+
+#define MAX_VARS 32 /* nombre maximal de variables */
+#define TLL_VAR 32 /* taille initiale du tampon à variable */
+#define TLL_META 64 /* taille initiale du tampon à métadonnées */
+#define TLL_PLS 16 /* taille des piles */
+
+/* drapeaux */
+#define DRAP_DEB 01
+#define DRAP_FIN 02
+
+/* types d'étiquette*/
+#define TP_RIEN 0
+#define TP_COND 1
+#define TP_A 2
+#define TP_SI 3
+
+/* opérateurs */
+/* en ordre de priorité */
+#define OP_OU 0
+#define OP_ET 1
+#define OP_NON 2
+#define OP_PAR 3
+
+struct pl {
+ int ctn[TLL_PLS];
+ int tete;
+};
+
+struct vars {
+ char *vars[MAX_VARS];
+ int prch;
+};
+
+int valider_var(char *);
+int noter_var(char *);
+int filtrer(void);
+int valider_etqs(struct meta *);
+int trv_base(struct meta *);
+int ana_draps(struct meta *);
+void aff_etq_sans(struct meta *);
+int evaluer(char *);
+int val_var(char **);
+int appliquer(int);
+int ign_bloc(FILE *);
+void utilisation(FILE *);
+
+struct tampon tamp_var;
+struct meta tamp_meta;
+
+struct vars pl_vars = { {}, 0 };
+struct pl pl_vals = { {}, -1 };
+struct pl pl_ops = { {}, -1 };
+
+char *nom_prog;
+
+int
+main(int argc, char **argv)
+{
+ int c;
+
+ if (m_init(&tamp_meta, TLL_META) < 0 ||
+ t_init(&tamp_var, TLL_VAR) < 0)
+ return 1;
+
+ nom_prog = *argv;
+ while ((c = getopt(argc, argv, "v:h")) != -1) {
+ switch (c) {
+ case 'v':
+ if (valider_var(optarg) < 0)
+ return 1;
+ if (noter_var(optarg) < 0)
+ return 1;
+ break;
+ case 'h':
+ utilisation(stdout);
+ return 0;
+ break;
+ default:
+ utilisation(stderr);
+ return 1;
+ }
+ }
+
+ if (filtrer() < 0)
+ return -1;
+ exit(0);
+}
+
+int
+noter_var(char *arg)
+{
+ int i, j;
+ for (i = 0; i < pl_vars.prch; i++)
+ for (j = 0; pl_vars.vars[i][j] == arg[j]; j++)
+ if (arg[j] == '=' || arg[j+1] == '\0') {
+ pl_vars.vars[i] = arg;
+ return 0;
+ }
+ if (pl_vars.prch < MAX_VARS) {
+ pl_vars.vars[pl_vars.prch++] = arg;
+ return 0;
+ }
+ fprintf(stderr, "%s: trop de variables (maximum: %d)\n",
+ nom_prog, MAX_VARS);
+ return -1;
+}
+
+int
+valider_var(char *arg)
+{
+ char *c;
+ if (*arg == '=') {
+ fprintf(stderr, "%s: une variable ne peut commencer par «=»\n",
+ nom_prog);
+ return -1;
+ }
+ for (c = arg; *c != '\0'; c++) {
+ switch (*c) {
+ case '!': case '&': case '|': case ':': case '(': case ')':
+ fprintf(stderr, "%s: «%c» est un caractère réservé\n",
+ nom_prog, *c);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+filtrer(void)
+{
+ int c;
+ int draps;
+ int trouve = 0;
+ char *pc;
+ while (m_lire(stdin, &tamp_meta) > 0) {
+ if (valider_etqs(&tamp_meta) < 0)
+ return -1;
+ switch (trv_base(&tamp_meta)) {
+ case 0:
+ aff_etq_sans(&tamp_meta);
+ goto afficher;
+ case 1: /* si */
+ draps = ana_draps(&tamp_meta);
+ if (draps & DRAP_DEB)
+ trouve = 0;
+ aff_etq_sans(&tamp_meta);
+ if (trouve == 0) {
+ if (draps & DRAP_FIN)
+ trouve = 1;
+ goto afficher;
+ }
+ putc('\n', stdout);
+ break;
+ case 2: /* @ */
+ break;
+ case 3: /* # */
+ draps = ana_draps(&tamp_meta);
+ if (trouve == 1 && draps & DRAP_DEB) {
+ ign_bloc(stdin);
+ break;
+ }
+ pc = tamp_meta.draps-2;
+ while (*--pc != '#')
+ ;
+ if (evaluer(pc+1)) {
+ trouve = 1;
+ aff_etq_sans(&tamp_meta);
+ goto afficher;
+ } else {
+ ign_bloc(stdin);
+ }
+ break;
+ }
+ while ((c = getc(stdin)) != '\n')
+ if (c == EOF)
+ return 0;
+ continue;
+afficher:
+ while ((c = putc(getc(stdin), stdout)) != '\n')
+ if (c == EOF)
+ return 0;
+ }
+ return 0;
+}
+
+int
+valider_etqs(struct meta *m)
+{
+ if (*(m->etqs) != ':') {
+ fprintf(stderr, "%s: fichier corrompu; le premier champ ne "
+ "commence pas par «:»\n", nom_prog);
+ return -1;
+ }
+ if (*(m->draps-2) != ':') {
+ fprintf(stderr, "%s: fichier corrompu; le premier champ ne se "
+ "termine pas par «:»\n", nom_prog);
+ return -1;
+ }
+ return 0;
+}
+
+/* trouver la dernière occurence d'une étiquette */
+/* l'étiquette ne peut contenir «:» */
+int
+trv_base(struct meta *m)
+{
+ char *c = m->draps-2;
+ int n = 0;
+ if (c == m->etqs)
+ return 0;
+ while (*--c != ':')
+ ;
+ c++;
+ if (*c == '#') {
+ c -= 2;
+ n++;
+ }
+ if (c - m->etqs < 4)
+ return 0;
+ if (*c == '@') {
+ c -= 3;
+ n++;
+ }
+ else if (n == 1)
+ return 0;
+ if (*(c-1) == ':' && *c == 's' && *(c+1) == 'i' && *(c+2) == ':')
+ return n+1;
+ return 0;
+}
+
+int
+ana_draps(struct meta *m)
+{
+ char *c;
+ int draps;
+ for (draps = 0, c = m->draps; *c != '\0'; c++) {
+ switch (*c) {
+ case '(':
+ draps |= DRAP_DEB;
+ break;
+ case ')':
+ draps |= DRAP_FIN;
+ break;
+ }
+ }
+ return draps;
+}
+
+void
+aff_etq_sans(struct meta *m)
+{
+ char *c;
+ int fini = 0;
+ for (c = m->etqs; *c != '\0'; c++) {
+ fini = 0;
+ if (*c == ':') {
+ if (strncmp(c+1, "si:", 3) == 0) {
+ fini = 1;
+ c += 3;
+ if (strncmp(c+1, "@:", 2) == 0) {
+ c += 2;
+ if (*(c+1) == '#') {
+ for (c += 2; *c != ':'; c++)
+ ;
+ if (*(c+1) == '\0') {
+ break;
+ } else {
+ c--;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ putc(*c, stdout);
+ }
+ if (fini) {
+ putc('\t', stdout);
+ } else {
+ printf("\t%s", m->draps);
+ }
+}
+
+/* ps doit pointer vers un '#' */
+int
+evaluer(char *ps)
+{
+ int op;
+ char *s = ps;
+ for (;;s++) {
+ switch (*s) {
+ case '!':
+ op = OP_NON;
+ break;
+ case '&':
+ op = OP_ET;
+ break;
+ case '|':
+ op = OP_OU;
+ break;
+ case '(':
+ op = OP_PAR;
+ break;
+ case ')':
+ while (pl_ops.tete >= 0) {
+ if (pl_ops.ctn[pl_ops.tete] == OP_PAR) {
+ pl_ops.tete--;
+ goto sortie;
+ }
+ if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0)
+ return -1;
+ }
+ return -1;
+sortie:
+ continue;
+ case ':':
+ while (pl_ops.tete >= 0)
+ if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0)
+ return -1;
+ if (pl_vals.tete != 0)
+ return -1;
+ return pl_vals.ctn[pl_vals.tete--];
+ default:
+ if (++pl_vals.tete >= TLL_PLS) {
+ fprintf(stderr, "%s: expression trop "
+ "complexe\n", nom_prog);
+ return -1;
+ }
+ if ((pl_vals.ctn[pl_vals.tete] = val_var(&s)) < 0)
+ return -1;
+ continue;
+ }
+ while (pl_ops.tete >= 0 && pl_ops.ctn[pl_ops.tete] != OP_PAR &&
+ pl_ops.ctn[pl_ops.tete] != OP_NON &&
+ pl_ops.ctn[pl_ops.tete] >= op) {
+ if (appliquer(pl_ops.ctn[pl_ops.tete--]) < 0)
+ return -1;
+ }
+ if (++pl_ops.tete >= TLL_PLS)
+ return -1;
+ pl_ops.ctn[pl_ops.tete] = op;
+ }
+ return -1;
+}
+
+int
+val_var(char **ps)
+{
+ int i, j;
+ char *s = *ps;
+ t_eff(&tamp_var);
+ for (i = 0; *s != '\0'; i++, s++) {
+ switch (*s) {
+ case '!': case '&': case '|': case ':': case '(': case ')':
+ goto trouver;
+ }
+ t_ecr(*s, &tamp_var);
+ }
+ fprintf(stdin, "%s: le premier champ ne se termine pas par «:»\n",
+ nom_prog);
+ return -1;
+trouver:
+ t_ecr('\0', &tamp_var);
+
+ *ps = --s;
+ for (i = 0; i < pl_vars.prch; i++) {
+ for (j = 0; pl_vars.vars[i][j] == tamp_var.t[j]; j++)
+ if (tamp_var.t[j] == '\0')
+ return 1;
+ }
+ return 0;
+}
+
+int
+appliquer(int op)
+{
+ switch (op) {
+ case OP_NON:
+ if (pl_vals.tete >= 0) {
+ pl_vals.ctn[pl_vals.tete] = !pl_vals.ctn[pl_vals.tete];
+ return 0;
+ }
+ break;
+ case OP_ET:
+ if (pl_vals.tete >=1) {
+ pl_vals.ctn[pl_vals.tete-1] =
+ pl_vals.ctn[pl_vals.tete-1] &&
+ pl_vals.ctn[pl_vals.tete];
+ pl_vals.tete--;
+ return 0;
+ }
+ break;
+ case OP_OU:
+ if (pl_vals.tete >= 1) {
+ pl_vals.ctn[pl_vals.tete-1] =
+ pl_vals.ctn[pl_vals.tete-1] ||
+ pl_vals.ctn[pl_vals.tete];
+ pl_vals.tete--;
+ return 0;
+ }
+ break;
+ }
+ fprintf(stderr, "%s: trop d'opérateurs\n", nom_prog);
+ return -1;
+}
+
+int
+ign_bloc(FILE *f)
+{
+ int draps;
+ int c;
+ int niveau = 0;
+ do {
+ draps = ana_draps(&tamp_meta);
+ if (draps & DRAP_DEB)
+ niveau++;
+ if (draps & DRAP_FIN)
+ niveau--;
+ if (niveau == 0)
+ break;
+ while ((c = getc(f)) != '\n')
+ if (c == EOF)
+ return 0;
+ } while (m_lire(f, &tamp_meta) > 0);
+ return 0;
+}
+
+void
+utilisation(FILE *f)
+{
+ fprintf(f, "UTILISATION: %s -v[variable][=valeur] [...] <[fichier]\n",
+ nom_prog);
+}
diff --git a/meta.c b/meta.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "meta.h"
+
+static int m_ecr(char, struct meta *);
+static int m_plein(char, struct meta *);
+static void m_reinit(struct meta *);
+
+/* initialiser un tampon m de taille tll */
+int
+m_init(struct meta *m, size_t tll)
+{
+ if ((m->etqs = malloc(tll)) == NULL)
+ return -1;
+ m->draps = m->etqs;
+ m->pcar = m->etqs;
+ m->ncar = 0;
+ m->tll = tll;
+ return 0;
+}
+
+/* renvoyer le dernier caractère lu
+ * une valeur positive indique le succès
+ * négative indique une erreur
+ * nulle indique EOF */
+int
+m_lire(FILE *f, struct meta *m)
+{
+ char c;
+ m_reinit(m);
+
+ /* lire les étiquettes */
+ while ((c = getc(f)) != '\t' && c != '\n') {
+ if (c == EOF)
+ return 0;
+ if (m_ecr(c, m) < 0)
+ return -1;
+ }
+ m_ecr('\0', m);
+
+ /* lire les drapeaux */
+ m->draps = m->pcar;
+ if (c != '\n') {
+ while ((c = getc(f)) != '\t' && c != '\n') {
+ if (c == EOF)
+ return 0;
+ if (m_ecr(c, m) < 0)
+ return -1;
+ }
+ }
+ m_ecr('\0', m);
+ ungetc(c, stdin);
+ return 1;
+}
+
+/* écrire un caractère dans le tampon */
+static int
+m_ecr(char c, struct meta *m)
+{
+ return ((++m->ncar > m->tll) ? m_plein(c, m) :
+ (*m->pcar++ = c, (unsigned char) c));
+}
+
+/* agrandir le tampon et écrire un caractère */
+int
+m_plein(char c, struct meta *m)
+{
+ char *tmp;
+ if ((tmp = realloc(m->etqs, m->tll * M_FACT_AGR)) == NULL)
+ return -1;
+ m->tll *= M_FACT_AGR;
+ if (tmp != m->etqs) {
+ m->draps = tmp + (m->draps - m->etqs);
+ m->pcar = tmp + m->ncar - 1;
+ m->etqs = tmp;
+ }
+ *m->pcar++ = c;
+ return (unsigned char) c;
+}
+
+/* réinitaliser un tampon méta */
+void
+m_reinit(struct meta *m)
+{
+ m->pcar = m->etqs;
+ m->ncar = 0;
+}
diff --git a/meta.h b/meta.h
@@ -0,0 +1,19 @@
+#ifndef META_H
+#define META_H
+
+#include <stdio.h>
+
+#define M_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */
+
+struct meta {
+ char *etqs;
+ char *draps;
+ char *pcar;
+ size_t ncar;
+ size_t tll;
+};
+
+int m_init(struct meta *, size_t);
+int m_lire(FILE *, struct meta *);
+
+#endif
diff --git a/tampon.c b/tampon.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tampon.h"
+#undef t_ecr
+
+/* initialiser un tampon t de taille taille */
+int
+t_init(struct tampon *t, size_t taille)
+{
+ if ((t->t = realloc(t->t, taille)) == NULL)
+ return -1;
+ t->taille = taille;
+ t->pcar = t->t;
+ t->ncar = 0;
+ return 0;
+}
+
+/* ajouter un caractère au tampon t */
+int
+t_ecr(char c, struct tampon *t)
+{
+ return ((++t->ncar > t->taille) ? t_plein(c, t) :
+ (*t->pcar++ = c, (unsigned char) c));
+}
+
+/* agrandir le tampon t par T_FACT_AGR */
+int
+t_plein(char c, struct tampon *t)
+{
+ if ((t->t = realloc(t->t, t->taille * T_FACT_AGR)) == NULL)
+ return -1;
+ t->taille *= T_FACT_AGR;
+ t->pcar = t->t + t->ncar - 1;
+ *t->pcar++ = c;
+ return (unsigned char) c;
+}
+
+/* afficher le contenu du tampon t */
+void
+t_aff(struct tampon *t)
+{
+ char *pcar = t->t;
+ int ncar = t->ncar;
+ while (ncar-- > 0) {
+ if (*pcar == '\\') {
+ ncar--;
+ if (*++pcar != ':')
+ putc('\\', stdout);
+ }
+ putc(*pcar++, stdout);
+ }
+}
+
+/* effacer le contenu du tampon t */
+void
+t_eff(struct tampon *t)
+{
+ t->pcar = t->t;
+ t->ncar = 0;
+}
diff --git a/tampon.h b/tampon.h
@@ -0,0 +1,24 @@
+#ifndef TAMPON_H
+#define TAMPON_H
+
+#define T_FACT_AGR 2 /* facteur d'agrandissement d'un tampon */
+
+struct tampon {
+ char *t; /* le tampon lui-même */
+ size_t taille; /* taille du tampon */
+ size_t ncar; /* nombre de caractères écrits */
+ char *pcar; /* ptr vers le prochain caractère */
+};
+
+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)))
+
+#endif