aplat

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

commit 7db5eaa4a1f7b6bd0868ce8ac92c9a307a149814
parent 464d1087e7f428601c4a3d4cb7fb2278537d232e
Auteur: Selve <selve@asteride.xyz>
Date:   Sat, 23 Sep 2023 21:25:28 -0400

ajout du programme exclure

Diffstat:
MMakefile | 19+++++++++++++++----
Maplat.c | 76++--------------------------------------------------------------------------
Aeval.h | 4++++
Aexclure.c | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ameta.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ameta.h | 19+++++++++++++++++++
Atampon.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atampon.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