encore

Répétitions espacées dans le terminal
git clone git://git.asteride.xyz/~ldp/encore.git
Journaux | Fichiers | Références

commit 8c14f40db70e59d9bea3e873fd57e334dbf0a969
Auteur: Selve <selve@asteride.xyz>
Date:   Wed, 28 Feb 2024 15:34:54 -0500

naissance d'encore

Diffstat:
A.gitignore | 3+++
AMakefile | 19+++++++++++++++++++
Acve.c | 15+++++++++++++++
Acve.h | 6++++++
Aencore.c | 504+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apaquet.c | 545+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apaquet.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asm2.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asm2.h | 6++++++
9 files changed, 1213 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.core +encore diff --git a/Makefile b/Makefile @@ -0,0 +1,19 @@ +COPT_SPCL = -O2 -DNDEBUG +COPT = -Wall -Werror -Wextra -Wpedantic --std=c99 ${COPT_SPCL} +CC = cc +PREFIX = "/usr/local/bin" + +.SUFFIXES: .c .o +.c.o: + ${CC} ${COPT} -c "$<" + +all: encore + +encore: encore.o paquet.o sm2.o cve.o + ${CC} ${COPT} -o "$@" encore.o paquet.o sm2.o cve.o + +install: encore + install -m 755 encore ${PREFIX}/encore + +clean: + rm -rf *.o *.core encore diff --git a/cve.c b/cve.c @@ -0,0 +1,15 @@ +#include "cve.h" + +int +cve(char *s, unsigned int *n) +{ + int tmp; + + for (tmp = 0; *s != '\0'; s++) { + if (*s < '0' || *s > '9') + return -1; + tmp = tmp * 10 + *s - '0'; + } + *n = tmp; + return 0; +} diff --git a/cve.h b/cve.h @@ -0,0 +1,6 @@ +#ifndef CVE_H +#define CVE_H + +int cve(char *, unsigned int *); + +#endif diff --git a/encore.c b/encore.c @@ -0,0 +1,504 @@ +#include <assert.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "paquet.h" +#include "cve.h" + +#define CMD '\0' /* commande racine */ +#define CMD_Q 'q' /* questionner */ +#define CMD_R 'r' /* répondre */ +#define CMD_S 's' /* statistiquer */ +#define CMD_A 'a' /* ajouter */ +#define CMD_E 'e' /* enlever */ +#define CMD_I 'i' /* initiliser */ +#define CMD_M 'm' /* modifier */ +#define CMD_C 'c' /* commencer */ + +static int cmd_q(int, char **); +static int cmd_r(int, char **); +static int cmd_s(int, char **); +static int cmd_a(int, char **); +static int cmd_e(int, char **); +static int cmd_i(int, char **); +static int cmd_m(int, char **); +static int cmd_c(int, char **); + +static void utilisation(FILE *, int); + +char *nom_prog; + +int +main(int argc, char **argv) +{ + char opt; + int (*cmd)(int, char **); + + if ((nom_prog = argv[0]) == NULL || nom_prog[0] == '\0') + nom_prog = "encore"; + + opterr = 0; + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + utilisation(stdout, CMD); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + optind = 1; + optreset = 1; + + if (argc == 0) + goto err_util; + + if (argv[0][1] != '\0') + goto err_util; + + switch (argv[0][0]) { + case CMD_Q: cmd = &cmd_q; break; + case CMD_R: cmd = &cmd_r; break; + case CMD_S: cmd = &cmd_s; break; + case CMD_A: cmd = &cmd_a; break; + case CMD_E: cmd = &cmd_e; break; + case CMD_I: cmd = &cmd_i; break; + case CMD_M: cmd = &cmd_m; break; + case CMD_C: cmd = &cmd_c; break; + default: goto err_util; + } + + return (*cmd)(argc, argv); + +err_util: + utilisation(stderr, CMD); + return 1; +} + +static int +cmd_q(int argc, char **argv) +{ + struct paquet pq; + int opts_prch; + char opt; + int id; + + assert(argc >= 1); + assert(argv != NULL); + + opts_prch = 0; + + while ((opt = getopt(argc, argv, "NVh")) != -1) { + switch (opt) { + case 'N': + opts_prch |= PQ_OPT_PRCH_NOUV; + continue; + case 'V': + opts_prch |= PQ_OPT_PRCH_VIEU; + continue; + case 'h': + utilisation(stdout, CMD_Q); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + goto err_util; + + if (pq_ouvrir(argv[0], &pq) < 0) + return 1; + + if ((id = pq_prochain(&pq, opts_prch)) < 0) + return 1; + + printf("%u\n", id); + + return 0; + +err_util: + utilisation(stderr, CMD_Q); + return 1; +} + +static int +cmd_r(int argc, char **argv) +{ + struct paquet pq; + char opt; + unsigned int qual; + + assert(argc >= 1); + assert(argv != NULL); + + qual = 4; + + while ((opt = getopt(argc, argv, "q:h")) != -1) { + switch (opt) { + case 'q': + if (cve(optarg, &qual) < 0) + goto err_val; + if (qual < 0 || qual > 5) + goto err_val; + continue; + case 'h': + utilisation(stdout, CMD_R); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + goto err_util; + + if (pq_ouvrir(argv[0], &pq) < 0) + return 1; + + if (pq_reponse(&pq, qual) < 0) + return 1; + + return 0; + +err_util: + utilisation(stderr, CMD_R); + return 1; +err_val: + utilisation(stderr, CMD_R); + fprintf(stderr, "%s n'est pas un entier entre 0 et 5\n", optarg); + return 1; +} + +static int +cmd_s(int argc, char **argv) +{ + struct paquet pq; + char opt; + + assert(argc >= 1); + assert(argv != NULL); + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + utilisation(stdout, CMD_S); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + goto err_util; + + if (pq_ouvrir(argv[0], &pq) < 0) + return 1; + + printf("version: %d\n" + "drapeaux: %d\n" + "début du cimetière: %u\n" + "début de l'incubateur: %u\n" + "nombre d'entrées: %u\n" + "pins: %d\n" + "pipi: %u\n" + "pnpi: %u\n" + "fi: %u\n" + "date: %llu\n" + "nfs: %u\n" + "nfsn: %u\n", + pq.entete.version, + pq.entete.draps, + pq.entete.deb_s, + pq.entete.deb_n, + pq.entete.nb, + pq.entete.pins, + pq.entete.pipi, + pq.entete.pnpi, + pq.entete.fi, + pq.entete.date << 8, + pq.entete.nfs, + pq.entete.nfsn); + + if (pq_fiches_afficher(&pq) < 0) + return 1; + + return 0; + +err_util: + utilisation(stderr, CMD_S); + return 1; +} + +static int +cmd_a(int argc, char **argv) +{ + struct paquet pq; + unsigned int n; + char opt; + + assert(argc >= 1); + assert(argv != NULL); + + n = 1; + + while ((opt = getopt(argc, argv, "n:h")) != -1) { + switch (opt) { + case 'n': + if (cve(optarg, &n) < 0) { + utilisation(stderr, CMD_A); + fprintf(stderr, + "%s doit être un entier positif\n", + optarg); + return 0; + } + continue; + case 'h': + utilisation(stdout, CMD_A); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + goto err_util; + + if (pq_ouvrir(argv[0], &pq) < 0) + return 1; + + if (pq_ajouter(&pq, n) < 0) + return 1; + + return 0; + +err_util: + utilisation(stderr, CMD_A); + return 1; +} + +static int +cmd_e(int argc, char **argv) +{ + assert(argc >= 1); + assert(argv != NULL); + assert(argv[0] != NULL); + + (void)argc; + (void)argv; + + utilisation(stdout, CMD_E); + + return 0; +} + +static int +cmd_i(int argc, char **argv) +{ + int opt; + + assert(argc >= 1); + assert(argv != NULL); + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + utilisation(stdout, CMD_I); + return 0; + default: + goto err_util; + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + goto err_util; + + if (pq_init(argv[0]) < 0) + return 1; + + return 0; + +err_util: + utilisation(stderr, CMD_I); + return 1; +} + +static int +cmd_m(int argc, char **argv) +{ + struct paquet pq; + unsigned int n; + char opt; + char *opts = "s:i:n:f:q:c:h"; + + assert(argc >= 0); + assert(argv != NULL); + + while (getopt(argc, argv, opts) != -1) + ; + + if (argc - optind == 0) + goto err_util; + + if (pq_ouvrir(argv[optind], &pq) < 0) + return 1; + + optind = 1; + optreset = 1; + + while ((opt = getopt(argc, argv, opts)) != -1) { + switch (opt) { + case 's': + if (cve(optarg, &n) < 0 || n > (uint8_t) ~0) + goto invalide; + pq.entete.pins = n; + continue; + case 'i': + if (cve(optarg, &n) < 0 || n > (uint16_t) ~0) + goto invalide; + pq.entete.pipi = n; + continue; + case 'n': + if (cve(optarg, &n) < 0 || n > (uint16_t) ~0) + goto invalide; + pq.entete.pnpi = n; + continue; + case 'f': + if (cve(optarg, &n) < 0 || n > (uint8_t) ~0) + goto invalide; + pq.entete.fi = n; + continue; + case 'q': + if (cve(optarg, &n) < 0 || n > (uint8_t) ~0) + goto invalide; + pq.entete.nfsn = n; + continue; + case 'c': + if (optarg[1] != '\0') + goto err_util; + if (optarg[0] == '0') + pq.entete.draps &= ~PQ_DRAP_NOUV; + else if (optarg[0] == '1') + pq.entete.draps |= PQ_DRAP_NOUV; + continue; + case 'h': + utilisation(stdout, CMD_M); + return 0; + default: + goto err_util; + } + } + + if (pq_entete_maj(&pq) < 0) + return 1; + + return 0; + +invalide: + utilisation(stderr, CMD_M); + fprintf(stderr, "%s n'est pas un nombre valide\n", optarg); + return 1; +err_util: + utilisation(stderr, CMD_M); + return 1; +} + +static int +cmd_c(int argc, char **argv) +{ + struct paquet pq; + char opt; + char *opts = "sh"; + + assert(argc >= 0); + assert(argv != NULL); + + while (getopt(argc, argv, opts) != -1) + ; + + if (argc - optind == 0) + goto err_util; + + if (pq_ouvrir(argv[optind], &pq) < 0) + return 1; + + optind = 1; + optreset = 1; + while ((opt = getopt(argc, argv, opts)) != -1) { + switch (opt) { + case 's': + pq.entete.nfs = pq.entete.nfsn; + continue; + case 'h': + utilisation(stdout, CMD_C); + return 0; + default: + goto err_util; + } + } + + if (pq_entete_maj(&pq) < 0) + return 1; + + return 0; + +err_util: + utilisation(stderr, CMD_C); + return 1; +} + +static void +utilisation(FILE *f, int cmd) +{ + char *util; + unsigned int i; + char *msgs[] = { + "[-h]", + "q [-hNV] paquet", + "r [-h] [-q qualité] paquet", + "s [-h] paquet", + "a [-h] [-n nb] paquet", + "e ??? paquet", + "i [-h] paquet", + ("m [-h] [-s pins] [-i pipi] [-n pnpi] [-f fi] [-q nfsn] " + "[-c dn] paquet"), + "c [-h] ??? paquet" }; + + assert(f != NULL); + + util = "Utilisation:"; + fprintf(f, "%s", util); + + switch (cmd) { + case CMD: + fputc('\n', f); + for (i = 0; i < sizeof(msgs) / sizeof(char *); i++) + fprintf(f, " %s %s\n", nom_prog, msgs[i]); + return; + case CMD_Q: i = 1; break; + case CMD_R: i = 2; break; + case CMD_S: i = 3; break; + case CMD_A: i = 4; break; + case CMD_E: i = 5; break; + case CMD_I: i = 6; break; + case CMD_M: i = 7; break; + case CMD_C: i = 8; break; + default: assert(0); + } + + fprintf(f, " %s %s\n", nom_prog, msgs[i]); +} diff --git a/paquet.c b/paquet.c @@ -0,0 +1,545 @@ +#include <assert.h> +#include <fcntl.h> +#include <stdint.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "paquet.h" +#include "sm2.h" + +#define PQ_VERSION 0 + +#define PQ_ENTETE_LG 28 +#define PQ_FICHE_LG 12 + +#define DEC_ENTETE_VERSION 0 +#define DEC_ENTETE_DRAPS 1 +#define DEC_ENTETE_DEB_S 2 +#define DEC_ENTETE_DEB_N 5 +#define DEC_ENTETE_NB 8 +#define DEC_ENTETE_PINS 11 +#define DEC_ENTETE_PIPI 12 +#define DEC_ENTETE_PNPI 14 +#define DEC_ENTETE_FI 16 +#define DEC_ENTETE_DATE 17 +#define DEC_ENTETE_NFS 24 +#define DEC_ENTETE_NFSN 26 + +#define DEC_FICHE_PRCH 0 +#define DEC_FICHE_DERN 3 +#define DEC_FICHE_ID 6 +#define DEC_FICHE_FAC 9 +#define DEC_FICHE_NSUCC 10 + +#define PQ_PINS_DEF 3 +#define PQ_PIPI_DEF 1 +#define PQ_PNPI_DEF 377 +#define PQ_FI_DEF 180 +#define PQ_NFSN_DEF 20 + +#define TAMPON_TLL (4096 - (4096 % PQ_FICHE_LG)) +#define TAMPON_FICHES (TAMPON_TLL / PQ_FICHE_LG) + +#define LIRE_1(tp) \ + (((uint8_t) *(tp))) +#define LIRE_2(tp) \ + (((uint16_t) *(tp) << 8) \ + + ((uint16_t) *((tp) + 1))) +#define LIRE_3(tp) \ + (((uint32_t) *(tp) << 16) \ + + ((uint32_t) *((tp) + 1) << 8) \ + + ((uint32_t) *((tp) + 2))) +#define LIRE_7(tp) \ + (((uint64_t) *(tp) << 48) \ + + ((uint64_t) *((tp) + 1) << 40) \ + + ((uint64_t) *((tp) + 2) << 32) \ + + ((uint64_t) *((tp) + 3) << 24) \ + + ((uint64_t) *((tp) + 4) << 16) \ + + ((uint64_t) *((tp) + 5) << 8) \ + + ((uint64_t) *((tp) + 6))) + +#define PARENT(pos) ((pos) / 2) +#define ENFANT1(pos) ((pos) * 2 + 1) +#define ENFANT2(pos) ((pos) * 2 + 2) + +static int pq_fiche_copier(struct paquet *, uint32_t, uint8_t *); +static int pq_fiche_coller(struct paquet *, uint32_t, uint8_t *); +static int pq_fiche_monter(struct paquet *, uint32_t, uint8_t *); +static int pq_fiche_descendre(struct paquet *, uint32_t, uint8_t *); + +extern char *nom_prog; + +/* Créer la base de données au chemin et écrire les valeurs par défaut. + * Ne créer la base de données que s'il n'y a pas de paquet à chemin */ +int +pq_init(char *chemin) +{ + struct paquet pq; + + assert(chemin != NULL); + assert(PQ_ENTETE_LG + 1 < (1 << 8)); + + if ((pq.fd = open(chemin, O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR)) < 0) { + perror(chemin); + return -1; + } + + pq.nom = chemin; + pq.entete.version = 0; + pq.entete.draps = 0; + pq.entete.deb_s = 0; + pq.entete.deb_n = 0; + pq.entete.nb = 0; + pq.entete.pins = PQ_PINS_DEF; + pq.entete.pipi = PQ_PIPI_DEF; + pq.entete.pnpi = PQ_PNPI_DEF; + pq.entete.fi = PQ_FI_DEF; + pq.entete.date = (uint64_t) time(NULL) >> 8; + pq.entete.nfs = 0; + pq.entete.nfsn = PQ_NFSN_DEF - 20; + + if (pq_entete_maj(&pq) < 0) + return -1; + + if (close(pq.fd) < 0) { + perror(chemin); + return -1; + } + + return 0; +} + +/* ouvrir le paquet pointé par chemin, en lire l'entête et remplir un struct + * paquet */ +int +pq_ouvrir(char *chemin, struct paquet *pq) +{ + uint8_t tp[PQ_ENTETE_LG]; + + assert(chemin != NULL); + assert(pq != NULL); + + if ((pq->fd = open(chemin, O_RDWR)) < 0) { + perror(chemin); + return -1; + } + + if (read(pq->fd, tp, PQ_ENTETE_LG) != PQ_ENTETE_LG) { + fprintf(stderr, "%s: paquet corrompu\n", chemin); + return -1; + } + + pq->nom = chemin; + + if ((pq->entete.version = LIRE_1(tp + DEC_ENTETE_VERSION)) != 0) { + fprintf(stderr, "%d: version incompatible\n", + pq->entete.version); + return -1; + } + + pq->entete.draps = LIRE_1(tp + DEC_ENTETE_DRAPS); + pq->entete.deb_s = LIRE_3(tp + DEC_ENTETE_DEB_S); + pq->entete.deb_n = LIRE_3(tp + DEC_ENTETE_DEB_N); + pq->entete.nb = LIRE_3(tp + DEC_ENTETE_NB); + pq->entete.pins = LIRE_1(tp + DEC_ENTETE_PINS); + pq->entete.pipi = LIRE_2(tp + DEC_ENTETE_PIPI); + pq->entete.pnpi = LIRE_2(tp + DEC_ENTETE_PNPI); + pq->entete.fi = LIRE_1(tp + DEC_ENTETE_FI); + pq->entete.date = LIRE_7(tp + DEC_ENTETE_DATE); + pq->entete.nfs = LIRE_2(tp + DEC_ENTETE_NFS); + pq->entete.nfsn = LIRE_2(tp + DEC_ENTETE_NFSN); + + return 0; +} + +/* ajouter n entrées à la base de données + * les entrées sont ajoutées dans la section « nouveaux » */ +int +pq_ajouter(struct paquet *pq, unsigned int n) +{ + uint32_t id; + uint8_t tp[TAMPON_TLL] = { 0 }; + uint8_t *ptr; + int min; + int reste; + + assert(pq != NULL); + + id = pq->entete.nb ; + + if (lseek(pq->fd, PQ_ENTETE_LG + id * PQ_FICHE_LG, SEEK_SET) < 0) { + perror(pq->nom); + return -1; + } + + while (n != 0) { + assert(n > 0); + reste = min = n < TAMPON_FICHES ? n : TAMPON_FICHES; + for (ptr = tp; reste > 0; reste--, ptr += PQ_FICHE_LG) { + ptr[6] = (uint8_t) (id >> 16); + ptr[7] = (uint8_t) (id >> 8); + ptr[8] = (uint8_t) (id); + ptr[9] = (uint8_t) (pq->entete.fi); + id++; + } + reste = min * PQ_FICHE_LG; + if (write(pq->fd, tp, reste) != reste) { + perror(pq->nom); + return -1; + } + pq->entete.nb += min; + n -= min; + } + + if (pq_entete_maj(pq) < 0) + return -1; + + return 0; +} + +/* retourner l'identifiant de la prochaine fiche à réviser */ +int +pq_prochain(struct paquet *pq, int opts) +{ + uint8_t fiche[PQ_FICHE_LG]; + uint32_t indice; + + assert(pq != NULL); + + if (pq->entete.draps & PQ_DRAP_QST) { + if (pq->entete.draps & PQ_DRAP_MNC) + indice = 0; + else + indice = pq->entete.deb_n; + } else { + pq->entete.draps |= PQ_DRAP_QST; + + if (pq->entete.nb - pq->entete.deb_n > 0 + && (pq->entete.nfs > 0 + || !(pq->entete.draps & PQ_DRAP_NOUV) + || opts & PQ_OPT_PRCH_NOUV) + && !(opts & PQ_OPT_PRCH_VIEU)) { + pq->entete.draps &= ~PQ_DRAP_MNC; + indice = pq->entete.deb_n; + } else if (pq->entete.deb_s > 0) { + pq->entete.draps |= PQ_DRAP_MNC; + indice = 0; + } else { + fprintf(stderr, + "%s: le paquet %s ne contient aucune fiche\n", + nom_prog, pq->nom); + return -1; + } + + if (pq_entete_maj(pq) < 0) + return -1; + } + + if (pq_fiche_copier(pq, indice, fiche) < 0) + return -1; + + if (((uint64_t) time(NULL) >> 8) + < (LIRE_3(fiche + DEC_FICHE_PRCH) + pq->entete.date)) { + fprintf(stderr, "%s: aucune fiche à réviser\n", nom_prog); + return -1; + } + + return LIRE_3(fiche + DEC_FICHE_ID); +} + +int +pq_reponse(struct paquet *pq, int rep) +{ + struct fiche f; + int pos; + uint8_t fiche[PQ_FICHE_LG]; + + assert(rep >= 0 && rep <= 5); + + if (!(pq->entete.draps & PQ_DRAP_QST)) { + fprintf(stderr, "%s: veuillez d'abord exécuter la commande q\n", + nom_prog); + return -1; + } + + if (pq->entete.draps & PQ_DRAP_MNC) + pos = 0; + else + pos = pq->entete.deb_n; + + pq->entete.draps &= ~PQ_DRAP_QST; + + if (pq_fiche_copier(pq, pos, fiche) < 0) + return -1; + + f.prch = LIRE_3(fiche + DEC_FICHE_PRCH); + f.dern = LIRE_3(fiche + DEC_FICHE_DERN); + f.id = LIRE_3(fiche + DEC_FICHE_ID); + f.fac = LIRE_1(fiche + DEC_FICHE_FAC); + f.nsucc = LIRE_2(fiche + DEC_FICHE_NSUCC); + + sm2(&f, rep, pq->entete.pins, pq->entete.pipi, pq->entete.pnpi, pq->entete.date); + + fiche[0] = (uint8_t) (f.prch >> 16); + fiche[1] = (uint8_t) (f.prch >> 8); + fiche[2] = (uint8_t) (f.prch); + fiche[3] = (uint8_t) (f.dern >> 16); + fiche[4] = (uint8_t) (f.dern >> 8); + fiche[5] = (uint8_t) (f.dern); + fiche[6] = (uint8_t) (f.id >> 16); + fiche[7] = (uint8_t) (f.id >> 8); + fiche[8] = (uint8_t) (f.id); + fiche[9] = (uint8_t) (f.fac); + fiche[10] = (uint8_t) (f.nsucc >> 8); + fiche[11] = (uint8_t) (f.nsucc); + + if (pos == 0 && pq->entete.deb_s > 0) { + if (pq_fiche_coller(pq, 0, fiche) < 0) + return -1; + if (pq_fiche_descendre(pq, 0, fiche) < 0) + return -1; + } else { + if (pq->entete.deb_n != pq->entete.deb_s) { + uint8_t fiche2[PQ_FICHE_LG]; + if (pq_fiche_copier(pq, pq->entete.deb_s, fiche2) < 0) + return -1; + if (pq_fiche_coller(pq, pq->entete.deb_n, fiche2) < 0) + return -1; + } + if (pq_fiche_coller(pq, pq->entete.deb_s, fiche) < 0) + return -1; + pq->entete.deb_s++; + pq->entete.deb_n++; + if (pq->entete.draps & PQ_DRAP_NOUV) + pq->entete.nfs--; + assert(pq->entete.nfs >= 0); + if (pq_fiche_monter(pq, pos, fiche) < 0) + return -1; + } + + if (pq_entete_maj(pq) < 0) + return -1; + + return 0; +} + +int +pq_entete_maj(struct paquet *pq) +{ + uint8_t texte[] = { + pq->entete.version, + pq->entete.draps, + (uint8_t) (pq->entete.deb_s >> 16), + (uint8_t) (pq->entete.deb_s >> 8), + (uint8_t) (pq->entete.deb_s), + (uint8_t) (pq->entete.deb_n >> 16), + (uint8_t) (pq->entete.deb_n >> 8), + (uint8_t) (pq->entete.deb_n), + (uint8_t) (pq->entete.nb >> 16), + (uint8_t) (pq->entete.nb >> 8), + (uint8_t) (pq->entete.nb), + pq->entete.pins, + (uint8_t) (pq->entete.pipi >> 8), + (uint8_t) (pq->entete.pipi), + (uint8_t) (pq->entete.pnpi >> 8), + (uint8_t) (pq->entete.pnpi), + pq->entete.fi, + (uint8_t) (pq->entete.date >> 48), + (uint8_t) (pq->entete.date >> 40), + (uint8_t) (pq->entete.date >> 32), + (uint8_t) (pq->entete.date >> 24), + (uint8_t) (pq->entete.date >> 16), + (uint8_t) (pq->entete.date >> 8), + (uint8_t) (pq->entete.date), + (uint8_t) (pq->entete.nfs >> 8), + (uint8_t) (pq->entete.nfs), + (uint8_t) (pq->entete.nfsn >> 8), + (uint8_t) (pq->entete.nfsn) }; + + assert(pq != NULL); + assert(sizeof(texte) == PQ_ENTETE_LG); + + if (lseek(pq->fd, 0, SEEK_SET) < 0) { + perror(pq->nom); + return -1; + } + + if (write(pq->fd, texte, PQ_ENTETE_LG) != PQ_ENTETE_LG) { + perror(pq->nom); + return -1; + } + + return 0; +} + +static int +pq_fiche_copier(struct paquet *pq, uint32_t pos, uint8_t *tp) +{ + if (lseek(pq->fd, PQ_ENTETE_LG + pos * PQ_FICHE_LG, SEEK_SET) < 0) { + perror(pq->nom); + return -1; + } + + if (read(pq->fd, tp, PQ_FICHE_LG) != PQ_FICHE_LG) { + perror(pq->nom); + return -1; + } + + return 0; +} + +static int +pq_fiche_coller(struct paquet *pq, uint32_t pos, uint8_t *tp) +{ + if (lseek(pq->fd, PQ_ENTETE_LG + pos * PQ_FICHE_LG, SEEK_SET) < 0) { + perror(pq->nom); + } + + if (write(pq->fd, tp, PQ_FICHE_LG) != PQ_FICHE_LG) { + perror(pq->nom); + return -1; + } + + return 0; +} + +/* faire monter une fiche dans le monceau */ +static int +pq_fiche_monter(struct paquet *pq, uint32_t pos, uint8_t *tp) +{ + uint8_t tp_parent[PQ_FICHE_LG]; + uint32_t date; + uint32_t pos_orig; + + assert(pq != NULL); + assert(tp != NULL); + assert(pq->entete.deb_s > pos); /* l'entrée doit être dans le monceau */ + + date = LIRE_3(tp + DEC_FICHE_PRCH); + for (pos_orig = pos; pos != 0; pos = PARENT(pos)) { + /* copier le parent */ + if (pq_fiche_copier(pq, PARENT(pos), tp_parent) < 0) + return -1; + + if (date >= LIRE_3(tp_parent + DEC_FICHE_PRCH)) + break; + + /* descendre le parent */ + if (pq_fiche_coller(pq, pos, tp_parent) < 0) + return -1; + } + + /* ne coller l'entrée que si l'enfant doit être déplacé */ + if (pos != pos_orig) + if (pq_fiche_coller(pq, pos, tp) < 0) + return -1; + + return 0; +} + +/* faire descendre une entrée dans le monceau */ +static int +pq_fiche_descendre(struct paquet *pq, uint32_t pos, uint8_t *tp) +{ + uint8_t tp_enfants[PQ_FICHE_LG * 2]; + uint32_t date_parent; + uint32_t date_enfants[2]; + int inf; /* sert à sélectionner l'enfant inférieur */ + uint32_t pos_orig; + + assert(pq != NULL); + assert(pq->entete.deb_s > pos); /* l'entrée doit être dans le monceau */ + + date_parent = LIRE_3(tp + DEC_FICHE_PRCH); + for (pos_orig = pos; ENFANT1(pos) < pq->entete.deb_s; pos = ENFANT1(pos) + inf) { + if (pq_fiche_copier(pq, ENFANT1(pos), tp_enfants) < 0) + return -1; + + date_enfants[0] = LIRE_3(tp_enfants + DEC_FICHE_PRCH); + inf = 0; + + if (ENFANT2(pos) < pq->entete.deb_s) { + if (pq_fiche_copier(pq, ENFANT2(pos), + tp_enfants + PQ_FICHE_LG) < 0) + return -1; + date_enfants[1] = LIRE_3(tp_enfants + + PQ_FICHE_LG + + DEC_FICHE_PRCH); + if (date_enfants[1] < date_enfants[0]) { + date_enfants[0] = date_enfants[1]; + inf = 1; + } + } + + /* monter l'enfant */ + if (date_enfants[inf] <= date_parent) { + if (pq_fiche_coller(pq, pos, tp_enfants + + PQ_FICHE_LG * inf) < 0) + return -1; + } else { + break; + } + } + + + /* ne coller l'entrée que si le parent doit être déplacé */ + if (pos != pos_orig) + if (pq_fiche_coller(pq, pos, tp) < 0) + return -1; + + return 0; +} + +int +pq_fiches_afficher(struct paquet *pq) +{ + uint8_t *tp; + int n; + int ncar; + + ncar = pq->entete.nb * PQ_FICHE_LG; + + if ((tp = malloc(ncar)) == NULL) { + perror(NULL); + return -1; + } + + if (read(pq->fd, tp, ncar) != ncar) { + perror(pq->nom); + return -1; + } + + printf("# MONCEAU\n"); + for (n = pq->entete.deb_s; n > 0; n--, tp += PQ_FICHE_LG) + printf("%u\t%u\t%u\t%u\t%u\n", + LIRE_3(tp + DEC_FICHE_PRCH), + LIRE_3(tp + DEC_FICHE_DERN), + LIRE_3(tp + DEC_FICHE_ID), + LIRE_1(tp + DEC_FICHE_FAC), + LIRE_2(tp + DEC_FICHE_NSUCC)); + + printf("# CIMETIÈRE\n"); + for (n = pq->entete.deb_n - pq->entete.deb_s; n > 0; n--, tp += PQ_FICHE_LG) + printf("%u\t%u\t%u\t%u\t%u\n", + LIRE_3(tp + DEC_FICHE_PRCH), + LIRE_3(tp + DEC_FICHE_DERN), + LIRE_3(tp + DEC_FICHE_ID), + LIRE_1(tp + DEC_FICHE_FAC), + LIRE_2(tp + DEC_FICHE_NSUCC)); + + printf("# NOUVEAUX\n"); + for (n = pq->entete.nb - pq->entete.deb_n; n > 0; n--, tp += PQ_FICHE_LG) + printf("%u\t%u\t%u\t%u\t%u\n", + LIRE_3(tp + DEC_FICHE_PRCH), + LIRE_3(tp + DEC_FICHE_DERN), + LIRE_3(tp + DEC_FICHE_ID), + LIRE_1(tp + DEC_FICHE_FAC), + LIRE_2(tp + DEC_FICHE_NSUCC)); + + return 0; +} diff --git a/paquet.h b/paquet.h @@ -0,0 +1,53 @@ +#ifndef PAQUET_H +#define PAQUET_H + +#include <stdint.h> + +#define PQ_OPT_PRCH_VIEU 01 /* doit être un vieux, a préséance */ +#define PQ_OPT_PRCH_NOUV 02 /* peut être un nouveau */ + +#define PQ_DRAP_NOUV 01 /* prendre en compte nfs */ +#define PQ_DRAP_QST 02 /* si on a posé une question */ +#define PQ_DRAP_MNC 04 /* si la nouvelle question se trouve dans le monceau */ + +#define PQ_PHASE_N (1 << 15) + +struct entete { + uint8_t version; + uint8_t draps; + uint32_t deb_s; + uint32_t deb_n; + uint32_t nb; + uint8_t pins; + uint16_t pipi; + uint16_t pnpi; + uint8_t fi; + uint64_t date; + uint16_t nfs; + uint16_t nfsn; +}; + +struct paquet { + int fd; + char *nom; + struct entete entete; +}; + +struct fiche { + uint32_t prch; + uint32_t dern; + uint32_t id; + uint8_t fac; + uint16_t nsucc; +}; + +int pq_init(char *); +int pq_ouvrir(char *, struct paquet *); +int pq_ajouter(struct paquet *, unsigned int); +int pq_prochain(struct paquet *, int); +int pq_reponse(struct paquet *, int); +int pq_entete_maj(struct paquet *); + +int pq_fiches_afficher(struct paquet *); + +#endif diff --git a/sm2.c b/sm2.c @@ -0,0 +1,62 @@ +#include <stdint.h> +#include <time.h> + +#include <stdio.h> + +#include "paquet.h" +#include "sm2.h" + +#define FMIN 1.3 + +static uint8_t sm2_fac(int, int); + +void +sm2(struct fiche *f, unsigned int qual, unsigned int pins, unsigned int pipi, unsigned int pnpi, uint64_t date) { + int phase; + unsigned int nsucc; + uint32_t intrv; + uint64_t mtn; + + nsucc = f->nsucc & ~PQ_PHASE_N; + phase = (f->nsucc & PQ_PHASE_N) > 0; + + f->fac = sm2_fac(f->fac, qual); + + if (qual >= 4 && nsucc < PQ_PHASE_N - 1) + nsucc++; + else + nsucc = 0; + + if (nsucc <= 1) { + if (phase == 0) + intrv = pipi; + else + intrv = pnpi; + } else if (phase == 0 && nsucc == pins + 1) { + phase = 1; + intrv = pnpi; + } else { + f->fac = sm2_fac(f->fac, qual); + intrv = (f->prch - f->dern) * (f->fac / 100.0 + FMIN) + 1; + } + + mtn = (uint64_t) time(NULL) >> 8; + + f->dern = mtn - date; + f->prch = f->dern + intrv; + + f->nsucc = nsucc | (phase * PQ_PHASE_N); +} + +static uint8_t +sm2_fac(int fac, int qual) +{ + fac = fac - 80 + 28 * qual - 2 * qual * qual; + + if (fac > 255) + fac = 255; + if (fac < 0) + fac = 0; + + return fac; +} diff --git a/sm2.h b/sm2.h @@ -0,0 +1,6 @@ +#ifndef SM2_H +#define SM2_H + +void sm2(struct fiche *f, unsigned int qual, unsigned int pins, unsigned int pipi, unsigned int pnpi, uint64_t date); + +#endif