commit c389a0aa54ec09d3daa125a2c4fbe923bf9422f1
parent d1a9045202019f60cab9530a5732b1281749033b
Auteur: ldp <ldp@asteride.xyz>
Date: Sun, 20 Apr 2025 00:13:38 -0400
généralisation
Diffstat:
M | Makefile | | | 2 | +- |
M | sous.c | | | 108 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
2 files changed, 69 insertions(+), 41 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,4 +1,4 @@
-COPT = -Wall -O2 -Wextra -Wpedantic --std=c89
+COPT = -Wall -O2 -Wextra -Wpedantic --std=c89 #-DNDEBUG
CC = cc
PREFIX = "/usr/local/bin"
diff --git a/sous.c b/sous.c
@@ -3,6 +3,7 @@
* Ce programme est distribué sous la licence GPLv3
*/
+#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
@@ -10,18 +11,26 @@
#include <string.h>
#include <unistd.h>
-#define DOS_DEF "/sous/" /* dossier relatif à $XDG_DATA_HOME */
-#define CH_DEF "/.local/share/sous/" /* dossier relatif à $HOME */
+#define DOS_DEF "/sous" /* dossier relatif à $XDG_DATA_HOME */
+#define CH_DEF "/.local/share/sous" /* dossier relatif à $HOME */
+#define CH_TLL 256 /* taille initiale du tampon du chemin */
+struct tampon {
+ char *tp; /* pointeur vers le tampon */
+ size_t tll; /* taille du tampon */
+ size_t noc; /* nombre d’octets occupés, sans le caractère terminal */
+};
+
+static struct tampon *tcreer(size_t tll);
+static void tajouter(struct tampon *t, char *cc);
static void fatal(char *msg);
int
main(int argc, char **argv)
{
- char *ch; /* chemin vers l’exécutable */
+ struct tampon *ch; /* chemin vers l’exécutable */
char *base; /* base de ch */
char *suff; /* chemin relatif à base */
- int tll; /* taille de ch */
DIR *dos;
/* Trouver le dossier de base dans les variables d’environnement et
@@ -35,52 +44,71 @@ main(int argc, char **argv)
else
fatal("$HOME est introuvable");
- /* argv[0], est nécessaire pour identifier le dossier;
- * argv[1], est nécessaire pour lancer le programme ou trouver un
- * sous-dossier */
- if (argc < 2)
- fatal("trop peu d’arguments");
-
- /* ch est formé au moins de la base, du suffixe et des deux premiers
- * arguments du programme. Le tampon vers lequel il pointe doit donc
- * être assez grand pour stocker ces quatre fragments. 2 est ajouté à
- * la somme pour laisser de la place au séparateur « / » et au
- * caractère terminal NUL. */
- tll = strlen(base) + strlen(suff) + strlen(argv[0]) + \
- strlen(argv[1]) + 2;
- if ((ch = malloc(tll)) == NULL)
- fatal(strerror(errno));
+ ch = tcreer(CH_TLL);
+ tajouter(ch, base);
+ tajouter(ch, suff);
- /* Copier les quatre fragments dans ch. */
- strcpy(ch, base);
- strcat(ch, suff);
- strcat(ch, argv[0]);
- strcat(ch, "/");
- strcat(ch, argv[1]);
-
- /* Tant que ch pointe vers un dossier, l’ouvrir et y ajouter le
- * prochain argument donné au programme. Il faut à chaque fois agrandir
- * ch. argc contient l’indice de cet argument. */
- argc = 1;
- while ((dos = opendir(ch)) != NULL) {
+ for (argc = 0; (dos = opendir(ch->tp)) != NULL; argc++) {
closedir(dos);
- if (argv[++argc] == NULL)
+ if (argv[argc] == NULL)
fatal("trop peu d’arguments");
- tll += strlen(argv[argc]) + 1; /* +1 pour « / » */
- if ((ch = realloc(ch, tll)) == NULL)
- fatal(strerror(errno));
- strcat(ch, "/");
- strcat(ch, argv[argc]);
+ tajouter(ch, "/");
+ tajouter(ch, argv[argc]);
}
/* Si tout va bien, errno == ENOTDIR. */
if (errno != ENOTDIR)
- fatal(strerror(errno));
+ goto err;
/* Exécuter le programme. */
- if (execv(ch, argv+argc) < 0)
- fatal(strerror(errno));
+ if (execv(ch->tp, argv+argc-1) < 0)
+ goto err;
return 0;
+
+err:
+ fatal(strerror(errno));
+ return 1;
+}
+
+/* Créer un tampon de taille tll. En cas d’erreur, le programme quitte et en
+ * affiche la cause. */
+static struct tampon *
+tcreer(size_t tll)
+{
+ struct tampon *t;
+
+ assert(tll >= 1);
+
+ if ((t = malloc(sizeof(struct tampon))) == NULL ||
+ (t->tp = malloc(t->tll = tll)) == NULL)
+ fatal(strerror(errno));
+ *t->tp = '\0';
+ t->noc = 0;
+
+ return t;
+}
+
+/* Ajouter la chaîne de caractères cc au tampon t. Si le tampon est trop petit
+ * pour accueillir cc, il est doublé jusqu’à être assez grand. En cas d’erreur,
+ * le programme quitte et en affiche la cause. */
+static void
+tajouter(struct tampon *t, char *cc)
+{
+ size_t lgr; /* longeur minimale de la chaîne de caratères */
+
+ lgr = t->noc + strlen(cc);
+ if (lgr >= t->tll) {
+ int puissance = 1;
+ int lgr2 = lgr + 1;
+ while (lgr2 >>= 1)
+ puissance++;
+ t->tll = 1 << puissance;
+ assert(t->tll > lgr + 1);
+ if ((t->tp = realloc(t->tp, t->tll)) == NULL)
+ fatal(strerror(errno));
+ }
+ strcpy(t->tp + t->noc, cc);
+ t->noc = lgr;
}
/* Afficher un message d’erreur et quitter. */