diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-18 20:03:23 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-18 20:03:23 +0000 |
commit | f316a2ed52195135a35e32d7096e876357c48c69 (patch) | |
tree | 5f4486b9a5a213a69e66ef574d6bc643a207981c /src/libexecline | |
download | execline-f316a2ed52195135a35e32d7096e876357c48c69.tar.xz |
initial commit: rc for execline-2.0.0.0
Diffstat (limited to 'src/libexecline')
-rwxr-xr-x | src/libexecline/deps-lib/execline | 21 | ||||
-rw-r--r-- | src/libexecline/el_execsequence.c | 41 | ||||
-rw-r--r-- | src/libexecline/el_getstrict.c | 18 | ||||
-rw-r--r-- | src/libexecline/el_obsolescent.c | 10 | ||||
-rw-r--r-- | src/libexecline/el_popenv.c | 44 | ||||
-rw-r--r-- | src/libexecline/el_pushenv.c | 49 | ||||
-rw-r--r-- | src/libexecline/el_semicolon.c | 35 | ||||
-rw-r--r-- | src/libexecline/el_spawn0.c | 15 | ||||
-rw-r--r-- | src/libexecline/el_spawn1.c | 15 | ||||
-rw-r--r-- | src/libexecline/el_substandrun.c | 13 | ||||
-rw-r--r-- | src/libexecline/el_substandrun_str.c | 25 | ||||
-rw-r--r-- | src/libexecline/el_substitute.c | 179 | ||||
-rw-r--r-- | src/libexecline/el_transform.c | 84 | ||||
-rw-r--r-- | src/libexecline/el_vardupl.c | 12 | ||||
-rw-r--r-- | src/libexecline/exlp.c | 78 | ||||
-rw-r--r-- | src/libexecline/exlsn_define.c | 50 | ||||
-rw-r--r-- | src/libexecline/exlsn_elglob.c | 78 | ||||
-rw-r--r-- | src/libexecline/exlsn_exlp.c | 27 | ||||
-rw-r--r-- | src/libexecline/exlsn_free.c | 12 | ||||
-rw-r--r-- | src/libexecline/exlsn_import.c | 76 | ||||
-rw-r--r-- | src/libexecline/exlsn_main.c | 19 | ||||
-rw-r--r-- | src/libexecline/exlsn_multidefine.c | 79 |
22 files changed, 980 insertions, 0 deletions
diff --git a/src/libexecline/deps-lib/execline b/src/libexecline/deps-lib/execline new file mode 100755 index 0000000..69d483d --- /dev/null +++ b/src/libexecline/deps-lib/execline @@ -0,0 +1,21 @@ +el_execsequence.o +el_getstrict.o +el_obsolescent.o +el_popenv.o +el_pushenv.o +el_semicolon.o +el_spawn0.o +el_spawn1.o +el_substandrun.o +el_substandrun_str.o +el_substitute.o +el_transform.o +el_vardupl.o +exlsn_define.o +exlsn_elglob.o +exlsn_import.o +exlsn_multidefine.o +exlsn_exlp.o +exlsn_main.o +exlsn_free.o +exlp.o diff --git a/src/libexecline/el_execsequence.c b/src/libexecline/el_execsequence.c new file mode 100644 index 0000000..6b825af --- /dev/null +++ b/src/libexecline/el_execsequence.c @@ -0,0 +1,41 @@ +/* ISC license. */ + +#include <sys/types.h> +#ifdef EXECLINE_OLD_VARNAMES +#include <skalibs/bytestr.h> +#endif +#include <skalibs/djbunix.h> +#include <skalibs/env.h> +#include <skalibs/strerr2.h> +#include <skalibs/uint.h> +#include <execline/execline.h> + +void el_execsequence (char const *const *argv1, char const *const *argv2, char const *const *envp) +{ + if (!argv2[0]) + { + pathexec0_run(argv1, envp) ; + strerr_dieexec(111, argv1[0]) ; + } + else + { + int wstat ; + unsigned int j = 2 ; +#ifdef EXECLINE_OLD_VARNAMES + char fmt[UINT_FMT * 2 + 15] = "?=" ; +#else + char fmt[UINT_FMT + 1] = "?=" ; +#endif + pid_t pid = el_spawn0(argv1[0], argv1, envp) ; + if (!pid) strerr_warnwu2sys("spawn ", argv1[0]) ; + if (wait_pid(pid, &wstat) < 0) + strerr_diefu2sys(111, "wait for ", argv1[0]) ; + j += uint_fmt(fmt + j, wait_status(wstat)) ; fmt[j++] = 0 ; +#ifdef EXECLINE_OLD_VARNAMES + byte_copy(fmt + j, 13, "LASTEXITCODE=") ; j += 13 ; + j += uint_fmt(fmt + j, wait_status(wstat)) ; fmt[j++] = 0 ; +#endif + pathexec_r(argv2, envp, env_len(envp), fmt, j) ; + } + strerr_dieexec(111, argv2[0]) ; +} diff --git a/src/libexecline/el_getstrict.c b/src/libexecline/el_getstrict.c new file mode 100644 index 0000000..091845c --- /dev/null +++ b/src/libexecline/el_getstrict.c @@ -0,0 +1,18 @@ +/* ISC license. */ + +#include <skalibs/env.h> +#include <skalibs/uint.h> +#include <execline/execline.h> + +unsigned int el_getstrict (void) +{ + static unsigned int strict = 0 ; + static int first = 1 ; + if (first) + { + char const *x = env_get("EXECLINE_STRICT") ; + first = 0 ; + if (x) uint0_scan(x, &strict) ; + } + return strict ; +} diff --git a/src/libexecline/el_obsolescent.c b/src/libexecline/el_obsolescent.c new file mode 100644 index 0000000..42b8a11 --- /dev/null +++ b/src/libexecline/el_obsolescent.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <skalibs/strerr2.h> +#include <execline/execline.h> + +void el_obsolescent (void) +{ + if (el_getstrict()) + strerr_warnw3x("this command is marked as obsolescent. Please update your script to use the ", PROG, "x command instead.") ; +} diff --git a/src/libexecline/el_popenv.c b/src/libexecline/el_popenv.c new file mode 100644 index 0000000..3726506 --- /dev/null +++ b/src/libexecline/el_popenv.c @@ -0,0 +1,44 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/uint.h> +#include <execline/execline.h> + +int el_popenv (stralloc *sa, char const *const *envp, unsigned int envlen, char const *const *list, unsigned int listlen) +{ + unsigned int i = 0, salen = sa->len, count = 0 ; + for (; i < envlen ; i++) + { + unsigned int equal, colon, n ; + unsigned int j = 0 ; + for (; j < listlen ; j++) if (str_start(envp[i], list[j])) break ; + if (j == listlen) goto copyit ; + j = str_len(list[j]) ; + colon = j + str_chr(envp[i] + j, ':') ; + equal = j + str_chr(envp[i] + j, '=') ; + if (!envp[i][equal]) goto badenv ; + if (colon >= equal) { count++ ; continue ; } + if (colon + 1 + uint_scan(envp[i] + colon + 1, &n) != equal) goto copyit ; + if (!n) goto copyit ; + if (!stralloc_catb(sa, envp[i], colon)) goto err ; + if (n > 1) + { + char fmt[UINT_FMT+1] = ":" ; + n = 1 + uint_fmt(fmt+1, n-1) ; + if (!stralloc_catb(sa, fmt, n)) goto err ; + } + if (!stralloc_catb(sa, envp[i] + equal, str_len(envp[i] + equal) + 1)) goto err ; + continue ; +copyit: + if (!stralloc_catb(sa, envp[i], str_len(envp[i]) + 1)) goto err ; + } + return (int)count ; + +badenv : + errno = EINVAL ; +err: + sa->len = salen ; + return -1 ; +} diff --git a/src/libexecline/el_pushenv.c b/src/libexecline/el_pushenv.c new file mode 100644 index 0000000..9b9608d --- /dev/null +++ b/src/libexecline/el_pushenv.c @@ -0,0 +1,49 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/uint.h> +#include <execline/execline.h> + +int el_pushenv (stralloc *sa, char const *const *envp, unsigned int envlen, char const *const *list, unsigned int listlen) +{ + unsigned int i = 0, salen = sa->len, count = 0 ; + for (; i < envlen ; i++) + { + unsigned int equal, colon ; + unsigned int j = 0 ; + for (; j < listlen ; j++) if (str_start(envp[i], list[j])) break ; + if (j == listlen) goto copyit ; + count++ ; + j = str_len(list[j]) ; + colon = j + str_chr(envp[i] + j, ':') ; + equal = j + str_chr(envp[i] + j, '=') ; + if (!envp[i][equal]) goto badenv ; + if (colon >= equal) + { + if (!stralloc_catb(sa, envp[i], equal) + || !stralloc_catb(sa, ":1", 2)) goto err ; + } + else + { + char fmt[UINT_FMT+1] = ":" ; + unsigned int n ; + if (colon + 1 + uint_scan(envp[i] + colon + 1, &n) != equal) goto copyit ; + n = 1 + uint_fmt(fmt+1, n+1) ; + if (!stralloc_catb(sa, envp[i], colon)) goto err ; + if (!stralloc_catb(sa, fmt, n)) goto err ; + } + if (!stralloc_catb(sa, envp[i] + equal, str_len(envp[i] + equal) + 1)) goto err ; + continue ; +copyit: + if (!stralloc_catb(sa, envp[i], str_len(envp[i]) + 1)) goto err ; + } + return (int)count ; + +badenv : + errno = EINVAL ; +err: + sa->len = salen ; + return -1 ; +} diff --git a/src/libexecline/el_semicolon.c b/src/libexecline/el_semicolon.c new file mode 100644 index 0000000..dc99daf --- /dev/null +++ b/src/libexecline/el_semicolon.c @@ -0,0 +1,35 @@ +/* ISC license. */ + +#include <skalibs/env.h> +#include <skalibs/strerr2.h> +#include <skalibs/uint.h> +#include <execline/execline.h> + +int el_semicolon (char const **argv) +{ + static unsigned int nblock = 0 ; + register int argc1 = 0 ; + nblock++ ; + for (;; argc1++, argv++) + { + register char const *arg = *argv ; + if (!arg) return argc1 + 1 ; + if ((arg[0] == EXECLINE_BLOCK_END_CHAR) && (!EXECLINE_BLOCK_END_CHAR || !arg[1])) return argc1 ; + else if (arg[0] == EXECLINE_BLOCK_QUOTE_CHAR) ++*argv ; + else + { + unsigned int strict = el_getstrict() ; + if (strict) + { + char fmt1[UINT_FMT] ; + char fmt2[UINT_FMT] ; + fmt1[uint_fmt(fmt1, nblock)] = 0 ; + fmt2[uint_fmt(fmt2, (unsigned int)argc1)] = 0 ; + if (strict >= 2) + strerr_dief6x(100, "unquoted argument ", arg, " at block ", fmt1, " position ", fmt2) ; + else + strerr_warnw6x("unquoted argument ", arg, " at block ", fmt1, " position ", fmt2) ; + } + } + } +} diff --git a/src/libexecline/el_spawn0.c b/src/libexecline/el_spawn0.c new file mode 100644 index 0000000..4b7f50f --- /dev/null +++ b/src/libexecline/el_spawn0.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <skalibs/djbunix.h> +#include <execline/execline.h> + +pid_t el_spawn0 (char const *prog, char const *const *argv, char const *const *envp) +{ + if (!argv[0]) + { + static char const *const newargv[2] = { "/bin/true", 0 } ; + return child_spawn0(newargv[0], newargv, 0) ; + } + else return child_spawn0(prog, argv, envp) ; +} diff --git a/src/libexecline/el_spawn1.c b/src/libexecline/el_spawn1.c new file mode 100644 index 0000000..4785b92 --- /dev/null +++ b/src/libexecline/el_spawn1.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <skalibs/djbunix.h> +#include <execline/execline.h> + +pid_t el_spawn1 (char const *prog, char const *const *argv, char const *const *envp, int *fd, int w) +{ + if (!argv[0]) + { + static char const *const newargv[2] = { "/bin/true", 0 } ; + return child_spawn1(newargv[0], newargv, 0, fd, w) ; + } + else return child_spawn1(prog, argv, envp, fd, w) ; +} diff --git a/src/libexecline/el_substandrun.c b/src/libexecline/el_substandrun.c new file mode 100644 index 0000000..7dddbca --- /dev/null +++ b/src/libexecline/el_substandrun.c @@ -0,0 +1,13 @@ +/* ISC license. */ + +#include <skalibs/env.h> +#include <skalibs/strerr2.h> +#include <skalibs/skamisc.h> +#include "exlsn.h" + +void el_substandrun (int argc, char const *const *argv, char const *const *envp, exlsn_t *info) +{ + satmp.len = 0 ; + if (!env_string(&satmp, argv, (unsigned int)argc)) strerr_diefu1sys(111, "env_string") ; + el_substandrun_str(&satmp, 0, envp, info) ; +} diff --git a/src/libexecline/el_substandrun_str.c b/src/libexecline/el_substandrun_str.c new file mode 100644 index 0000000..351ec9d --- /dev/null +++ b/src/libexecline/el_substandrun_str.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include <skalibs/djbunix.h> +#include <skalibs/env.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <execline/execline.h> +#include "exlsn.h" + +void el_substandrun_str (stralloc *src, unsigned int srcbase, char const *const *envp, exlsn_t *info) +{ + stralloc dst = STRALLOC_ZERO ; + register int r = el_substitute(&dst, src->s + srcbase, src->len, info->vars.s, info->values.s, genalloc_s(elsubst_t, &info->data), genalloc_len(elsubst_t, &info->data)) ; + if (r < 0) strerr_diefu1sys(111, "el_substitute") ; + exlsn_free(info) ; + stralloc_free(src) ; + { + char const *v[r + 1] ; + if (!env_make(v, r, dst.s, dst.len)) strerr_diefu1sys(111, "env_make") ; + v[r] = 0 ; + pathexec0_run(v, envp) ; + } + strerr_dieexec(111, dst.s) ; +} diff --git a/src/libexecline/el_substitute.c b/src/libexecline/el_substitute.c new file mode 100644 index 0000000..a94c16d --- /dev/null +++ b/src/libexecline/el_substitute.c @@ -0,0 +1,179 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <execline/execline.h> + +typedef struct elsubsu_s elsubsu_t, *elsubsu_t_ref ; +struct elsubsu_s +{ + elsubst_t const *subst ; + unsigned int pos ; +} ; + +typedef struct subsuinfo_s subsuinfo_t, *subsuinfo_t_ref ; +struct subsuinfo_s +{ + stralloc dst ; + stralloc sa ; + genalloc list ; /* array of elsubsu_t */ + char const *values ; +} ; + +#define SUBSUINFO_ZERO { .dst = STRALLOC_ZERO, .sa = STRALLOC_ZERO, .list = GENALLOC_ZERO, .values = 0 } + +#define TEST 0x80 +#define MARK 0x40 +#define KEEPESC 0x20 +#define INCRESC 0x10 + +#define STATE 0x07 +#define INWORD 0x00 +#define INDOLL 0x01 +#define INDBR 0x02 +#define INVAR 0x03 +#define INVARBR 0x04 +#define ACCEPT 0x05 + +static int parseword (stralloc *sa, genalloc *list, char const *s, char const *vars, elsubst_t const *substs, unsigned int nsubst) +{ + static char const class[5] = "\0\\${}" ; + static unsigned char const table[6][5] = + { + { ACCEPT, ACCEPT, ACCEPT, ACCEPT | TEST, ACCEPT }, + { INWORD | KEEPESC | INCRESC, INWORD | INCRESC, INWORD | INCRESC, INWORD | TEST | INCRESC, INWORD | INCRESC }, + { INDOLL | KEEPESC, INDOLL, INDOLL, INDOLL | TEST, INDOLL }, + { INWORD, INDBR | KEEPESC, INWORD, INWORD | TEST, INWORD }, + { INWORD, INWORD, INWORD, INWORD | TEST, INWORD | TEST }, + { INWORD, INVAR | MARK | KEEPESC, INVARBR | MARK | KEEPESC, INVAR | KEEPESC, INVARBR | KEEPESC } + } ; + + unsigned int mark = 0, pos = 0, offset = 0, esc = 0, salen = sa->len, listlen = genalloc_len(elsubsu_t, list) ; + unsigned char state = INWORD ; + + while (state != ACCEPT) + { + int nopush = 0 ; + unsigned char c = table[byte_chr(class, 5, s[pos])][state] ; + + if (c & TEST) + { + unsigned int supp = (state == INVARBR) ; + unsigned int i = 0 ; + for (; i < nsubst ; i++) + { + if (!str_diffn(vars + substs[i].var, s + mark, pos - mark) && !vars[substs[i].var + pos - mark]) + { + sa->len -= esc >> 1 ; offset += esc >> 1 ; + if (esc & 1) + { + byte_copy(sa->s + mark - offset - 2 - supp, pos - mark + 1 + supp, sa->s + mark - offset + (esc>>1) - 1 - supp) ; + sa->len-- ; offset++ ; + } + else + { + elsubsu_t cur ; + cur.subst = substs + i ; + cur.pos = mark - offset - 1 - supp ; + if (!genalloc_append(elsubsu_t, list, &cur)) goto err ; + offset += sa->len - cur.pos ; + sa->len = cur.pos ; + if (supp) nopush = 1 ; + } + break ; + } + } + } + if (nopush) offset++ ; + else if (!stralloc_catb(sa, s+pos, 1)) goto err ; + if (c & MARK) mark = pos ; + if (!(c & KEEPESC)) esc = 0 ; + if (c & INCRESC) esc++ ; + state = c & STATE ; pos++ ; + } + sa->len-- ; + return (int)pos ; + +err: + sa->len = salen ; + list->len = listlen ; + return -1 ; +} + +static int substword (subsuinfo_t *info, unsigned int wordstart, unsigned int wordlen, unsigned int n, unsigned int offset) +{ + if (n < genalloc_len(elsubsu_t, &info->list)) + { + elsubsu_t *list = genalloc_s(elsubsu_t, &info->list) ; + char const *p = info->values + list[n].subst->value ; + unsigned int l = list[n].pos + offset ; + unsigned int dstbase = info->dst.len ; + unsigned int sabase = info->sa.len ; + unsigned int i = 0 ; + int nc = 0 ; + if (!stralloc_readyplus(&info->sa, l)) return -1 ; + stralloc_catb(&info->sa, info->sa.s + wordstart, l) ; + for ( ; i < list[n].subst->n ; i++) + { + int r ; + unsigned int plen = str_len(p) ; + info->sa.len = sabase + l ; + if (!stralloc_readyplus(&info->sa, plen + wordlen - l)) goto err ; + stralloc_catb(&info->sa, p, plen) ; + stralloc_catb(&info->sa, info->sa.s + wordstart + l, wordlen - l) ; + r = substword(info, sabase, info->sa.len - sabase, n+1, offset + plen) ; + if (r < 0) goto err ; + nc += r ; + p += plen+1 ; + } + return nc ; + err: + info->sa.len = sabase ; + info->dst.len = dstbase ; + return -1 ; + } + else + { + if (!stralloc_readyplus(&info->dst, wordlen+1)) return -1 ; + stralloc_catb(&info->dst, info->sa.s + wordstart, wordlen) ; + stralloc_0(&info->dst) ; + return 1 ; + } +} + +int el_substitute (stralloc *dst, char const *src, unsigned int len, char const *vars, char const *values, elsubst_t const *substs, unsigned int nsubst) +{ + subsuinfo_t info = SUBSUINFO_ZERO ; + unsigned int nc = 0 ; + unsigned int i = 0 ; + unsigned int dstbase = dst->len ; + int wasnull = !dst->s ; + info.dst = *dst ; + info.values = values ; + + while (i < len) + { + int r ; + genalloc_setlen(elsubsu_t, &info.list, 0) ; + info.sa.len = 0 ; + r = parseword(&info.sa, &info.list, src + i, vars, substs, nsubst) ; + if (r < 0) goto err ; + i += r ; + r = substword(&info, 0, info.sa.len, 0, 0) ; + if (r < 0) goto err ; + nc += r ; + } + genalloc_free(elsubsu_t, &info.list) ; + stralloc_free(&info.sa) ; + if (!wasnull) stralloc_free(dst) ; + *dst = info.dst ; + return (int)nc ; + +err : + genalloc_free(elsubsu_t, &info.list) ; + stralloc_free(&info.sa) ; + if (wasnull) stralloc_free(&info.dst) ; else info.dst.len = dstbase ; + *dst = info.dst ; + return -1 ; +} diff --git a/src/libexecline/el_transform.c b/src/libexecline/el_transform.c new file mode 100644 index 0000000..ac84d1d --- /dev/null +++ b/src/libexecline/el_transform.c @@ -0,0 +1,84 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/netstring.h> +#include <skalibs/skamisc.h> +#include <skalibs/stralloc.h> +#include <execline/execline.h> + +static void el_crunch (stralloc *sa, unsigned int base, char const *delim) +{ + register unsigned int i = base, j = base ; + register int crunching = 0 ; + for (; i < sa->len ; i++) + { + if (!crunching) sa->s[j++] = sa->s[i] ; + if (delim[str_chr(delim, sa->s[i])]) crunching = 1 ; + else if (crunching) + { + i-- ; + crunching = 0 ; + } + } + sa->len = j ; +} + +static int el_split (stralloc *sa, unsigned int base, eltransforminfo_t const *si, int chomped) +{ + unsigned int n = 0 ; + register unsigned int i = base ; + for (; i < sa->len ; i++) + if (si->delim[str_chr(si->delim, sa->s[i])]) + { + sa->s[i] = 0 ; + n++ ; + base = i+1 ; + } + + if (sa->len && sa->s[sa->len - 1]) + { + if (si->chomp && !chomped) sa->len = base ; + else if (!stralloc_0(sa)) return -1 ; + else n++ ; + } + return n ; +} + +static int el_splitnetstring (stralloc *sa, unsigned int base) +{ + unsigned int tmpbase = satmp.len ; + unsigned int n = 0, i = base ; + while (i < sa->len) + { + register int r = netstring_decode(&satmp, sa->s + i, sa->len - i) ; + if (r < 0) goto err ; + if (!stralloc_0(&satmp)) goto err ; + i += r ; n++ ; + } + sa->len = base ; + if (!stralloc_catb(sa, satmp.s + tmpbase, satmp.len - tmpbase)) + { + sa->len = i ; + goto err ; + } + satmp.len = tmpbase ; + return n ; + +err: + satmp.len = tmpbase ; + return -1 ; +} + +int el_transform (stralloc *sa, unsigned int i, eltransforminfo_t const *si) +{ + int chomped = 0 ; + if (si->crunch && *si->delim) el_crunch(sa, i, si->delim) ; + if (si->chomp && (sa->len > i) + && si->delim[str_chr(si->delim, sa->s[sa->len-1])]) + { + sa->len-- ; + chomped = 1 ; + } + return si->split ? *si->delim ? el_split(sa, i, si, chomped) : el_splitnetstring(sa, i) : + stralloc_0(sa) ? 1 : -1 ; +} diff --git a/src/libexecline/el_vardupl.c b/src/libexecline/el_vardupl.c new file mode 100644 index 0000000..7583669 --- /dev/null +++ b/src/libexecline/el_vardupl.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <execline/execline.h> + +int el_vardupl (char const *key, char const *s, unsigned int len) +{ + register unsigned int i = 0 ; + for (; i < len ; i += str_len(s + i) + 1) + if (!str_diff(key, s + i)) return 1 ; + return 0 ; +} diff --git a/src/libexecline/exlp.c b/src/libexecline/exlp.c new file mode 100644 index 0000000..060eb68 --- /dev/null +++ b/src/libexecline/exlp.c @@ -0,0 +1,78 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/env.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/uint.h> +#include <execline/execline.h> +#include "exlsn.h" + +int exlp (unsigned int nmin, char const *const *envp, exlsn_t *info) +{ + unsigned int varbase = info->vars.len ; + unsigned int valbase = info->values.len ; + unsigned int datbase = genalloc_len(elsubst_t, &info->data) ; + unsigned int i = 0 ; + char const *x = env_get2(envp, "#") ; + elsubst_t blah ; + unsigned int n, ntot, poszero ; + if (!x) return -2 ; + if (!uint0_scan(x, &n)) return -2 ; + if (el_vardupl("#", info->vars.s, info->vars.len)) return -2 ; + if (el_vardupl("@", info->vars.s, info->vars.len)) return -2 ; + { + register unsigned int strict = el_getstrict() ; + if (strict && (n < nmin)) + { + char fmta[UINT_FMT] ; + char fmtn[UINT_FMT] ; + fmta[uint_fmt(fmta, n)] = 0 ; + fmtn[uint_fmt(fmtn, nmin)] = 0 ; + if (strict > 1) + strerr_dief4x(100, "too few arguments: expected at least ", fmtn, " but got ", fmta) ; + else + strerr_warnw4x("too few arguments: expected at least ", fmtn, " but got ", fmta) ; + } + } + blah.var = varbase ; + blah.value = info->values.len ; + blah.n = 1 ; + if (!stralloc_catb(&info->vars, "#\0@", 4) + || !stralloc_catb(&info->values, x, str_len(x) + 1) + || !genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + ntot = n > nmin ? n : nmin ; + poszero = info->values.len ; + for (; i <= ntot ; i++) + { + char fmt[UINT_FMT] ; + unsigned int l = uint_fmt(fmt, i) ; + fmt[l] = 0 ; + if (el_vardupl(fmt, info->vars.s, info->vars.len)) goto err2 ; + x = (i <= n) ? env_get2(envp, fmt) : "" ; + if (!x) goto err2 ; + blah.var = info->vars.len ; + blah.value = info->values.len ; + blah.n = 1 ; + if (!stralloc_catb(&info->vars, fmt, l+1) + || !stralloc_catb(&info->values, x, str_len(x) + 1) + || !genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + } + blah.var = varbase + 2 ; + blah.value = poszero + str_len(info->values.s + poszero) + 1 ; + blah.n = n ; + if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + return n ; + + err: + info->vars.len = varbase ; + info->values.len = valbase ; + genalloc_setlen(elsubst_t, &info->data, datbase) ; + return -1 ; + err2: + info->vars.len = varbase ; + info->values.len = valbase ; + genalloc_setlen(elsubst_t, &info->data, datbase) ; + return -2 ; +} diff --git a/src/libexecline/exlsn_define.c b/src/libexecline/exlsn_define.c new file mode 100644 index 0000000..3abe516 --- /dev/null +++ b/src/libexecline/exlsn_define.c @@ -0,0 +1,50 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <execline/execline.h> +#include "exlsn.h" + +int exlsn_define (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; + subgetopt_t localopt = SUBGETOPT_ZERO ; + elsubst_t blah ; + blah.var = info->vars.len ; + blah.value = info->values.len ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nsCcd:", &localopt) ; + if (opt < 0) break ; + switch (opt) + { + case 'n' : si.chomp = 1 ; break ; + case 's' : si.split = 1 ; break ; + case 'C' : si.crunch = 1 ; break ; + case 'c' : si.crunch = 0 ; break ; + case 'd' : si.delim = localopt.arg ; break ; + default : return -3 ; + } + } + argc -= localopt.ind ; argv += localopt.ind ; + + if (argc < 2) return -3 ; + if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; + if (!stralloc_catb(&info->vars, argv[0], str_len(argv[0]) + 1)) return -1 ; + if (!stralloc_cats(&info->values, argv[1])) goto err ; + { + register int r = el_transform(&info->values, blah.value, &si) ; + if (r < 0) goto err ; + blah.n = r ; + } + if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + (void)envp ; + return localopt.ind + 2 ; + + err: + info->vars.len = blah.var ; + info->values.len = blah.value ; + return -1 ; +} diff --git a/src/libexecline/exlsn_elglob.c b/src/libexecline/exlsn_elglob.c new file mode 100644 index 0000000..67e939b --- /dev/null +++ b/src/libexecline/exlsn_elglob.c @@ -0,0 +1,78 @@ +/* ISC license. */ + +#include <errno.h> +#include <glob.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <execline/execline.h> +#include "exlsn.h" + +static int elgloberrfunc (char const *s, int e) +{ + errno = e ; + strerr_warnw2sys("while globbing, error reading ", s) ; + return 0 ; +} + +int exlsn_elglob (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + glob_t pglob ; + subgetopt_t localopt = SUBGETOPT_ZERO ; + elsubst_t blah ; + int flags = GLOB_NOSORT | GLOB_NOCHECK ; + unsigned int i = 0 ; + int verbose = 0 ; + blah.var = info->vars.len ; + blah.value = info->values.len ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "vwsme0", &localopt) ; + if (opt < 0) break ; + switch (opt) + { + case 'v' : verbose = 1 ; break ; + case 'w' : flags |= GLOB_ERR ; break ; + case 's' : flags &= ~GLOB_NOSORT ; break ; + case 'm' : flags |= GLOB_MARK ; break ; + case 'e' : flags |= GLOB_NOESCAPE ; break ; + case '0' : flags &= ~GLOB_NOCHECK ; break ; + default : return -3 ; + } + } + argc -= localopt.ind ; argv += localopt.ind ; + + if (argc < 2) return -3 ; + if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; + if (!stralloc_catb(&info->vars, argv[0], str_len(argv[0]) + 1)) return -1 ; + + pglob.gl_offs = 0 ; + switch (glob(argv[1], flags, verbose ? &elgloberrfunc : 0, &pglob)) + { + case 0 : break ; + case GLOB_NOMATCH: + { + pglob.gl_pathc = 0 ; + pglob.gl_pathv = 0 ; + break ; + } + default: goto err ; + } + for ( ; i < (unsigned int)pglob.gl_pathc ; i++) + if (!stralloc_catb(&info->values, pglob.gl_pathv[i], str_len(pglob.gl_pathv[i]) + 1)) + goto globerr ; + blah.n = pglob.gl_pathc ; + globfree(&pglob) ; + if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + (void)envp ; + return localopt.ind + 2 ; + + globerr: + globfree(&pglob) ; + err: + info->vars.len = blah.var ; + info->values.len = blah.value ; + return -1 ; +} diff --git a/src/libexecline/exlsn_exlp.c b/src/libexecline/exlsn_exlp.c new file mode 100644 index 0000000..4ca513e --- /dev/null +++ b/src/libexecline/exlsn_exlp.c @@ -0,0 +1,27 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include "exlsn.h" + +int exlsn_exlp (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + subgetopt_t localopt = SUBGETOPT_ZERO ; + unsigned int nmin = 0 ; + int n ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "P:", &localopt) ; + if (opt < 0) break ; + switch (opt) + { + case 'P' : if (uint0_scan(localopt.arg, &nmin)) break ; + default : return -3 ; + } + } + argc -= localopt.ind ; argv += localopt.ind ; + if (!argc) return -3 ; + n = exlp(nmin, envp, info) ; + if (n < 0) return n ; + return localopt.ind ; +} diff --git a/src/libexecline/exlsn_free.c b/src/libexecline/exlsn_free.c new file mode 100644 index 0000000..4d9dde3 --- /dev/null +++ b/src/libexecline/exlsn_free.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include "exlsn.h" + +void exlsn_free (exlsn_t *info) +{ + stralloc_free(&info->vars) ; + stralloc_free(&info->values) ; + stralloc_free(&info->data) ; +} + diff --git a/src/libexecline/exlsn_import.c b/src/libexecline/exlsn_import.c new file mode 100644 index 0000000..1574027 --- /dev/null +++ b/src/libexecline/exlsn_import.c @@ -0,0 +1,76 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/env.h> +#include <execline/execline.h> +#include "exlsn.h" + +static int exlsn_import_as (int argc, char const **argv, char const *const *envp, exlsn_t *info, unsigned int as) +{ + eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; + subgetopt_t localopt = SUBGETOPT_ZERO ; + elsubst_t blah ; + char const *defaultval = 0 ; + char const *x ; + int insist = 0 ; + blah.var = info->vars.len ; + blah.value = info->values.len ; + + for (;;) + { + register int opt = subgetopt_r(argc, argv, "iD:nsCcd:", &localopt) ; + if (opt < 0) break ; + switch (opt) + { + case 'i' : insist = 1 ; break ; + case 'D' : defaultval = localopt.arg ; break ; + case 'n' : si.chomp = 1 ; break ; + case 's' : si.split = 1 ; break ; + case 'C' : si.crunch = 1 ; break ; + case 'c' : si.crunch = 0 ; break ; + case 'd' : si.delim = localopt.arg ; break ; + default : return -3 ; + } + } + argc -= localopt.ind ; argv += localopt.ind ; + + if ((unsigned int)argc < 1+as) return -3 ; + if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; + if (!stralloc_catb(&info->vars, argv[0], str_len(argv[0]) + 1)) return -1 ; + x = env_get2(envp, argv[as]) ; + if (!x) + { + if (insist) strerr_dienotset(100, argv[as]) ; + x = defaultval ; + } + if (!x) blah.n = 0 ; + else + { + register int r ; + if (!stralloc_cats(&info->values, x)) goto err ; + r = el_transform(&info->values, blah.value, &si) ; + if (r < 0) goto err ; + blah.n = r ; + } + if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + return localopt.ind + 1 + as ; + + err: + info->vars.len = blah.var ; + info->values.len = blah.value ; + return -1 ; +} + +int exlsn_import (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + return exlsn_import_as(argc, argv, envp, info, 0) ; +} + +int exlsn_importas (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + return exlsn_import_as(argc, argv, envp, info, 1) ; +} diff --git a/src/libexecline/exlsn_main.c b/src/libexecline/exlsn_main.c new file mode 100644 index 0000000..e50fc2d --- /dev/null +++ b/src/libexecline/exlsn_main.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <skalibs/strerr2.h> +#include <execline/execline.h> +#include "exlsn.h" + +void exlsn_main (int argc, char const **argv, char const *const *envp, exlsnfunc_t *func, char const *usage) +{ + exlsn_t info = EXLSN_ZERO ; + int r = (*func)(argc, argv, envp, &info) ; + if (r < 0) switch (r) + { + case -3 : strerr_dieusage(100, usage) ; + case -2 : strerr_dief1x(111, "bad substitution key") ; + case -1 : strerr_diefu1sys(111, "complete exlsn function") ; + default : strerr_diefu2x(111, "complete exlsn function", ": unknown error") ; + } + el_substandrun(argc-r, argv+r, envp, &info) ; +} diff --git a/src/libexecline/exlsn_multidefine.c b/src/libexecline/exlsn_multidefine.c new file mode 100644 index 0000000..e64cbfd --- /dev/null +++ b/src/libexecline/exlsn_multidefine.c @@ -0,0 +1,79 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <execline/execline.h> +#include "exlsn.h" + +int exlsn_multidefine (int argc, char const **argv, char const *const *envp, exlsn_t *info) +{ + eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; + subgetopt_t localopt = SUBGETOPT_ZERO ; + unsigned int varbase = info->vars.len ; + unsigned int valbase = info->values.len ; + unsigned int pos = valbase ; + unsigned int i = 0 ; + unsigned int max ; + char const *x ; + int argc1 ; + int zeroword = 0, likeread = 0 ; + si.split = 1 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "0rnCcd:", &localopt) ; + if (opt < 0) break ; + switch (opt) + { + case '0' : zeroword = 1 ; break ; + case 'r' : likeread = 1 ; break ; + case 'n' : si.chomp = 1 ; break ; + case 'C' : si.crunch = 1 ; break ; + case 'c' : si.crunch = 0 ; break ; + case 'd' : si.delim = localopt.arg ; break ; + default : return -3 ; + } + } + argc -= localopt.ind ; argv += localopt.ind ; + + if (argc < 2) return -3 ; + x = argv[0] ; + argv++ ; argc-- ; + argc1 = el_semicolon(argv) ; + if (argc1 >= argc) return -3 ; + if (!stralloc_cats(&info->values, x)) return -1 ; + { + register int r = el_transform(&info->values, valbase, &si) ; + if (r < 0) goto err ; + max = r ; + } + if (!stralloc_0(&info->values)) goto err ; + for (; i < (unsigned int)argc1 ; i++) + { + if (*argv[i]) + { + elsubst_t blah ; + blah.var = info->vars.len ; + if (el_vardupl(argv[i], info->vars.s, info->vars.len)) goto err2 ; + if (!stralloc_catb(&info->vars, argv[i], str_len(argv[i]) + 1)) goto err ; + blah.value = i < max ? pos : info->values.len - 1 ; + blah.n = (i < max) || !zeroword ; + if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; + } + if (i < max) pos += str_len(info->values.s + pos) + 1 ; + } + if ((i < max) && likeread) genalloc_s(elsubst_t, &info->data)[i-1].n = max - i + 1 ; + + (void)envp ; + return localopt.ind + argc1 + 2 ; + + err: + info->vars.len = varbase ; + info->values.len = valbase ; + return -1 ; + err2: + info->vars.len = varbase ; + info->values.len = valbase ; + return -2 ; +} |