From c602bfd08a47f4840bf2e8d96663f76e2fb22f1c Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Wed, 20 Nov 2019 22:15:56 +0100 Subject: initial commit --- atxec.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100755 atxec.c (limited to 'atxec.c') diff --git a/atxec.c b/atxec.c new file mode 100755 index 0000000..9432c56 --- /dev/null +++ b/atxec.c @@ -0,0 +1,144 @@ +/* + * atxec - run command expanding arguments from file or environment + * + * To the extent possible under law, Leah Neukirchen + * has waived all copyright and related or neighboring rights to this work. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// '''' => ' + +// # line comment (space or beginning of line before #) +// @file +// @$ENV +// @@argwithone@ +// fallbacks? + +#include + +#include +#include +#include +#include +#include + +#define MAXARGS 2048 +int narg; +char *args[MAXARGS]; + +static void +push_arg(char *s) +{ + if (narg >= MAXARGS) { + fprintf(stderr, "atxec: too many arguments\n"); + exit(111); + } + + args[narg++] = s; +} + +void +arg_splice(char *s) +{ + char *beg; + char *t; + + if (!s) + return; + + while (1) { + while (isspace(*s) || *s == '#') + if (*s == '#') /* skip line comment */ + while (*s != '\n') + s++; + else + s++; + + if (!*s) + break; + + if (*s == '\'') { /* rc-quoted string */ + s++; + beg = t = s; + + while (*s) + if (*s == '\'') { + *t++ = *s++; + if (*s == '\'') { + s++; + } else { + *--t = 0; + if (!*s) + beg--; + break; + } + } else { + *t++ = *s++; + } + } else { /* bareword, may contain # without whitespace */ + beg = s; + while (*s && !isspace(*s)) + s++; + } + + push_arg(beg); + + if (*s) { + *s = 0; + s++; + } + } +} + +void +file_splice(char *file) +{ + struct stat st; + char *s; + + FILE *f = fopen(file, "rb"); + if (!f) + return; /* ignore file does not exist */ + + fstat(fileno(f), &st); + + s = malloc(st.st_size + 1); + if (!s) { + fclose(f); + return; + } + fread(s, 1, st.st_size, f); + fclose(f); + + s[st.st_size] = 0; + + arg_splice(s); + + /* leak string, args points into it! */ +} + +int +main(int argc, char *argv[]) +{ + if (argc == 1) { + fprintf(stderr, "usage\n"); + return 1; + } + + for (int i = 1; i < argc; i++) + if (argv[i][0] == '@') { + if (argv[i][1] == '@') + push_arg(argv[i]+1); + if (argv[i][1] == '$') + arg_splice(getenv(argv[i]+2)); + else + file_splice(argv[i]+1); + } else { + push_arg(argv[i]); + } + + execvp(args[0], args); + + perror("argsplice: exec"); + return 111; +} -- cgit 1.4.1