commit fc438badb464f4f81b12fda7f0f884a6ef47b41b
parent c389a0aa54ec09d3daa125a2c4fbe923bf9422f1
Auteur: ldp <ldp@asteride.xyz>
Date: Mon, 21 Apr 2025 17:59:20 -0400
refonte pour simplifier
Diffstat:
M | Makefile | | | 2 | +- |
M | sous.c | | | 130 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
2 files changed, 54 insertions(+), 78 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,4 +1,4 @@
-COPT = -Wall -O2 -Wextra -Wpedantic --std=c89 #-DNDEBUG
+COPT = -Wall -O2 -Wextra -Wpedantic --std=c89
CC = cc
PREFIX = "/usr/local/bin"
diff --git a/sous.c b/sous.c
@@ -3,118 +3,94 @@
* Ce programme est distribué sous la licence GPLv3
*/
-#include <assert.h>
-#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#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 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);
+static int fatal(char *msg);
int
main(int argc, char **argv)
{
- struct tampon *ch; /* chemin vers l’exécutable */
+ char *ch; /* chemin vers l’exécutable */
char *base; /* base de ch */
char *suff; /* chemin relatif à base */
- DIR *dos;
+ size_t tll; /* taille de ch */
+ int df1, df2; /* deux descripteurs de fichier */
/* Trouver le dossier de base dans les variables d’environnement et
* régler le suffixe en conséquence. */
if ((base = getenv("SOUS_CH")) != NULL)
suff = "";
else if ((base = getenv("XDG_DATA_HOME")) != NULL)
- suff = DOS_DEF;
+ suff = "/sous";
else if ((base = getenv("HOME")) != NULL)
- suff = CH_DEF;
+ suff = "/.local/share/sous";
else
- fatal("$HOME est introuvable");
+ return fatal("impossible de trouver $HOME");
+
+ /* Assembler le chemin menant au dossier. La taille de ce chemin est
+ * d’abord calculé. 1 est ajouté pour laisser de la place au caractère
+ * terminal NUL. De l’espace est alors alloué et base et suff y sont
+ * copiés. */
+ tll = strlen(base) + strlen(suff) + 1;
+ if ((ch = malloc(tll)) == NULL)
+ goto err;
+ strcpy(ch, base);
+ strcat(ch, suff);
- ch = tcreer(CH_TLL);
- tajouter(ch, base);
- tajouter(ch, suff);
+ /* Ouvrir le dossier. */
+ if ((df1 = open(ch, O_RDONLY | O_DIRECTORY)) < 0)
+ goto err;
- for (argc = 0; (dos = opendir(ch->tp)) != NULL; argc++) {
- closedir(dos);
+ /* Pour chaque argument dans argv, tenter de l’ouvrir comme un dossier.
+ * Cesser au premier échec. L’argument suivant devrait alors contenir
+ * le nom d’un exécutable situé quelque part dans l’arborescence de ch.
+ * Compter la taille de chaque argument vu et l’ajouter au total, plus1
+ * un pour laisser de la place au séparateur « / ». Enfin, pour éviter
+ * que des arguments ne soient interprétés comme des chemins absolus,
+ * les séparateurs « / » initiaux sont ignorés. */
+ for (argc = 0; df1 >= 0; df1 = df2, argc++) {
if (argv[argc] == NULL)
- fatal("trop peu d’arguments");
- tajouter(ch, "/");
- tajouter(ch, argv[argc]);
+ return fatal("trop peu d’arguments");
+ while (*argv[argc] == '/')
+ argv[argc]++;
+ tll += strlen(argv[argc]) + 1;
+ df2 = openat(df1, argv[argc], O_RDONLY | O_DIRECTORY);
+ if (close(df1) < 0)
+ goto err;
}
/* Si tout va bien, errno == ENOTDIR. */
if (errno != ENOTDIR)
goto err;
- /* Exécuter le programme. */
- if (execv(ch->tp, argv+argc-1) < 0)
+ /* Agrandir le tampon vers lequel pointe ch pour qu’il puisse contenir
+ * le chemin absolu complet vers l’exécutable. */
+ if ((ch = realloc(ch, tll)) == NULL)
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);
+ /* Assembler le chemin. */
+ while (argc--) {
+ strcat(ch, "/");
+ strcat(ch, *argv++);
+ }
- if ((t = malloc(sizeof(struct tampon))) == NULL ||
- (t->tp = malloc(t->tll = tll)) == NULL)
- fatal(strerror(errno));
- *t->tp = '\0';
- t->noc = 0;
+ /* Exécuter le programme */
+ execv(ch, argv-1);
- 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;
+ /* N’atteint cette partie que s’il y a une erreur. */
+err:
+ return fatal(strerror(errno));
}
-/* Afficher un message d’erreur et quitter. */
-static void
+/* Afficher un message d’erreur. Renvoie 1 pour pouvoir faire « return
+ * fatal(msg) » dans main() */
+static int
fatal(char *msg)
{
fprintf(stderr, "sous: %s\n", msg);
- exit(1);
+ return 1;
}