examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

commit 86ed3d35616d58be660771325d65f2e1e3abb0ca
parent 7f468e9155e4ea68b86dc56e85be7f29e832633c
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Fri, 26 Aug 2022 23:42:53 +0100

enviro: Run program with environment variables set

Diffstat:
Asrc/enviro.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 134 insertions(+), 0 deletions(-)

diff --git a/src/enviro.c b/src/enviro.c @@ -0,0 +1,134 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <regex.h> +#include <fcntl.h> +#include <sys/stat.h> + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +__attribute__((noreturn)) +void die(char const* msg) +{ + fprintf(stderr, "enviro: %s\n", msg); + exit(1); +} + +__attribute__((noreturn)) +void errorno_die(char const* msg) +{ + perror(msg); + exit(1); +} + +__attribute__((noreturn)) +void regex_die(int e, regex_t const* r, char const* msg) +{ + size_t size = regerror(e, r, NULL, 0); + char* buf = malloc(size); + + regerror(e, r, buf, size); + fprintf(stderr, "%s: %s\n", msg, buf); + exit(1); +} + +int regexec_or_die(const regex_t *restrict preg, const char *restrict string, size_t nmatch, regmatch_t pmatch[restrict], int eflags) +{ + int e = regexec(preg, string, nmatch, pmatch, eflags); + switch (e) + { + case REG_NOMATCH: + case 0: + return e; + + default: + regex_die(e, preg, "regexec"); + } +} + +char const usage[] = + "USAGE:\n" + "\tenviro (file | -) command [args...]\n" + "\nSUMMARY:\n" + "\tRun command with the environment from a file or stdin\n"; + +char const* regexes[] = +{ + "^[[:blank:]]*(#.*)?\n$", + "^[[:blank:]]*([[:alnum:]_.,]+=.*)\n$", +}; + +regex_t r[ARRAY_SIZE(regexes)]; + +int main(int argc, char* argv[]) +{ + FILE* f = stdin; + + for (unsigned i = 0; i < ARRAY_SIZE(r); ++i) + { + int e = regcomp(r + i, regexes[i], REG_EXTENDED | REG_NEWLINE); + if (e) + regex_die(e, r + i, "regcomp"); + } + + if (argc < 3) + { + fputs(usage, stderr); + return 1; + } + + if (strcmp("-", argv[1])) + { + struct stat s; + int fd = open(argv[1], O_RDONLY); + + if (fd < 0) + errorno_die("open"); + + if (fstat(fd, &s)) + errorno_die("fstat"); + + if ((s.st_mode & S_IFMT) == S_IFDIR) + { + fprintf(stderr, "enviro: '%s' is a directory\n", argv[1]); + exit(1); + } + + f = fdopen(fd, "r"); + if (!f) + errorno_die("fdopen"); + } + + clearenv(); + + for (;;) + { + char* line = NULL; + size_t size = 0; + regmatch_t m[2]; + + if (getline(&line, &size, f) == -1) + break; + + if (!regexec_or_die(&r[0], line, 0, NULL, 0)) + continue; + + if (regexec_or_die(r+1, line, ARRAY_SIZE(m), m, 0)) + { + fprintf(stderr, "enviro: bad format: %s\n", line); + return 1; + } + + if (m[1].rm_so == -1) + die("bad match"); + + line[m[1].rm_eo] = '\0'; + + if (putenv(line + m[1].rm_so)) + errorno_die("putenv"); + } + + execvp(argv[2], argv + 2); + errorno_die("execvp"); +}