sous

Exécuter de sous-commandes
git clone git://git.asteride.xyz/~ldp/sous.git
Journaux | Fichiers | Références | LICENCE

commit c389a0aa54ec09d3daa125a2c4fbe923bf9422f1
parent d1a9045202019f60cab9530a5732b1281749033b
Auteur: ldp <ldp@asteride.xyz>
Date:   Sun, 20 Apr 2025 00:13:38 -0400

généralisation

Diffstat:
MMakefile | 2+-
Msous.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. */