From 26bb34cf036027dfa22dfae8d8fc2f6bfd6acb75 Mon Sep 17 00:00:00 2001 From: Byron Rakitzis Date: Wed, 27 May 1992 00:00:01 +0100 Subject: release: rc-1.4 --- footobar.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 footobar.c (limited to 'footobar.c') diff --git a/footobar.c b/footobar.c new file mode 100644 index 0000000..f50db3c --- /dev/null +++ b/footobar.c @@ -0,0 +1,368 @@ +/* + footobar.c: a collection of functions to convert internal representations of + variables and functions to external representations, and vice versa +*/ + +#include "rc.h" + +#define FSCHAR '\1' +#define FSSTRING "\1" + +static char *getenvw(char *, bool); + +#ifdef PROTECT_ENV +static bool Fconv(Format *f, int ignore) { /* protect an exported name from brain-dead shells */ + int c; + unsigned const char *s = va_arg(f->args, unsigned const char *); + + while ((c = *s++) != '\0') + if (dnw[c] || c == '*' || (c == '_' && *s == '_')) + fmtprint(f, "__%02x", c); + else + fmtputc(f, c); + return FALSE; +} +#endif + +/* used to turn a function in Node * form into something we can export to the environment */ + +extern char *fun2str(char *name, Node *n) { + return mprint("fn_%F={%T}", name, n); +} + +/* convert a redirection to a printable form */ + +static bool Dconv(Format *f, int ignore) { + const char *name = "?"; + int n = va_arg(f->args, int); + switch (n) { + case rCreate: name = ">"; break; + case rAppend: name = ">>"; break; + case rFrom: name = "<"; break; + case rHeredoc: name = "<<"; break; + case rHerestring: name = "<<<"; break; + } + fmtcat(f, name); + return FALSE; +} + +/* defaultfd -- return the default fd for a given redirection operation */ + +extern int defaultfd(int op) { + return (op == rCreate || op == rAppend) ? 1 : 0; +} + +/* convert a function in Node * form into something rc can parse (and humans can read?) */ + +static bool Tconv(Format *f, int ignore) { + Node *n = va_arg(f->args, Node *); + if (n == NULL) { + fmtprint(f, "()"); + return FALSE; + } + switch (n->type) { + case nWord: fmtprint(f, "%S", n->u[0].s); break; + case nQword: fmtprint(f, "%#S", n->u[0].s); break; + case nBang: fmtprint(f, "! %T", n->u[0].p); break; + case nCase: fmtprint(f, "case %T", n->u[0].p); break; + case nNowait: fmtprint(f, "%T&", n->u[0].p); break; + case nCount: fmtprint(f, "$#%T", n->u[0].p); break; + case nFlat: fmtprint(f, "$^%T", n->u[0].p); break; + case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break; + case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break; + case nVar: fmtprint(f, "$%T", n->u[0].p); break; + case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break; + case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break; + case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break; + case nElse: fmtprint(f, "{%T}else %T", n->u[0].p, n->u[1].p); break; + case nNewfn: fmtprint(f, "fn %T {%T}", n->u[0].p, n->u[1].p); break; + case nIf: fmtprint(f, "if(%T)%T", n->u[0].p, n->u[1].p); break; + case nOrelse: fmtprint(f, "%T||%T", n->u[0].p, n->u[1].p); break; + case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break; + case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break; + case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break; + case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; + case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break; + case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break; + case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; + case nDup: + if (n->u[2].i != -1) + fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i); + else + fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i); + break; + case nBackq: { + Node *n0 = n->u[0].p, *n00; + if (n0 != NULL && n0->type == nVar + && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs")) + fmtprint(f, "`"); + else + fmtprint(f, "``%T", n0); + fmtprint(f, "{%T}", n->u[1].p); + break; + } + case nCbody: + case nBody: { + Node *n0 = n->u[0].p; + if (n0 != NULL) + fmtprint(f, "%T", n->u[0].p); + if (n->u[1].p != NULL) { + if (n0 != NULL && n0->type != nNowait) + fmtprint(f, ";"); + fmtprint(f, "%T", n->u[1].p); + } + break; + } + case nBrace: + fmtprint(f, "{%T}", n->u[0].p); + if (n->u[1].p != NULL) + fmtprint(f, "%T", n->u[1].p); + break; + case nEpilog: + case nPre: + fmtprint(f, "%T", n->u[0].p); + if (n->u[1].p != NULL) + fmtprint(f, " %T", n->u[1].p); + break; + case nPipe: { + int ofd = n->u[0].i, ifd = n->u[1].i; + fmtprint(f, "%T|", n->u[2].p); + if (ifd != 0) + fmtprint(f, "[%d=%d]", ofd, ifd); + else if (ofd != 1) + fmtprint(f, "[%d]", ofd); + fmtprint(f, "%T", n->u[3].p); + break; + } + case nRedir: { + int op = n->u[0].i; + fmtprint(f, "%D", op); + if (n->u[1].i != defaultfd(op)) + fmtprint(f, "[%d]", n->u[1].i); + fmtprint(f, "%T", n->u[2].p); + break; + } + case nNmpipe: { + int op = n->u[0].i; + fmtprint(f, "%D", op); + if (n->u[1].i != defaultfd(op)) + fmtprint(f, "[%d]", n->u[1].i); + fmtprint(f, "{%T}", n->u[2].p); + break; + } + } + return FALSE; +} + +/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */ + +extern char *list2str(char *name, List *s) { + SIZE_T size, step; + List *t; + char *w, *x; + name = nprint("%F", name); + size = strlen(name) + listlen(s); + w = ealloc(size + 2); + t = s; + x = w; + strcpy(x, name); + strcpy(x += strlen(name), "="); + strcpy(x += conststrlen("="), t->w); + for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) { + memcpy(x, FSSTRING, step = conststrlen(FSSTRING)); + x += step; + memcpy(x, s->w, step = strlen(s->w)); + x += step; + } + *x = '\0'; + return w; +} + +/* convert a List to an array, for execve() */ + +extern char **list2array(List *s, bool print) { + char **av; + int i; + + /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */ + av = nalloc((listnel(s) + 4) * sizeof (char *)); + av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */ + if (print) + fprint(2, "%L\n", s, " "); + for (i = 0; s != NULL; i++) { + av[i] = s->w; + s = s->n; + } + av[i] = NULL; + return av; +} + +/* figure out the name of a variable given an environment string. copy this into malloc space */ + +extern char *get_name(char *s) { + int c; + SIZE_T i; + char *r, *namebuf; + for (i = 0; s[i] != '\0' && s[i] != '='; i++) + ; + if (s[i] == '\0') + return NULL; + r = namebuf = ealloc(i + 1); + while (1) + switch (c = *s++) { + case '=': + *r++ = '\0'; + return namebuf; +#ifdef PROTECT_ENV + case '_': + if (*s == '_') { + static const char hexchar[] = "0123456789abcdef"; + char *h1 = strchr(hexchar, s[1]); + char *h2 = strchr(hexchar, s[2]); + if (h1 != NULL && h2 != NULL) { + *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar); + s += 3; + break; + } + } + /* FALLTHROUGH */ +#endif + default: + *r++ = c; + break; + } +} + +/* get the next word from a variable's value as represented in the environment. */ + +static char *getenvw(char *s, bool saw_alpha) { + SIZE_T i; + char *r; + for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++) + ; + if (i == 0) { + if (s[i] == '\0' && !saw_alpha) + return NULL; + else + return clear(enew(char), (SIZE_T) 1); + } + r = strncpy(ealloc(i + 1), s, i); + r[i] = '\0'; + return r; +} + +/* take an environment entry for a variable (elements ^A separated) and turn it into a List */ + +extern List *parse_var(char *name, char *extdef) { + List *r, *top; + char *f; + bool saw_alpha; + top = r = enew(List); + extdef = strchr(extdef, '=') + 1; + if ((f = getenvw(extdef, FALSE)) == NULL) { + r->w = ""; + r->m = NULL; + r->n = NULL; + } else { + while (1) { + r->w = f; + r->m = NULL; + extdef += strlen(f); + if (*extdef == FSCHAR) { + extdef++; + saw_alpha = TRUE; + } else { + saw_alpha = FALSE; + } + if ((f = getenvw(extdef, saw_alpha)) == NULL) { + r->n = NULL; + break; + } + r = r->n = enew(List); + } + } + return top; +} + +/* get an environment entry for a function and have rc parse it. */ + +#define PREFIX "fn x" +#define PRELEN conststrlen(PREFIX) +extern Node *parse_fn(char *name, char *extdef) { + Node *def; + char *s, old[PRELEN]; + if ((s = strchr(extdef, '=')) == NULL) + return NULL; + memcpy(old, s -= (PRELEN-1), PRELEN); + memcpy(s, PREFIX, PRELEN); + def = parseline(s); + memcpy(s, old, PRELEN); + return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p; +} + +static bool Aconv(Format *f, int c) { + char **a = va_arg(f->args, char **); + if (*a != NULL) { + fmtcat(f, *a); + while (*++a != NULL) + fmtprint(f, " %s", *a); + } + return FALSE; +} + +static bool Lconv(Format *f, int c) { + List *l = va_arg(f->args, List *); + char *sep = va_arg(f->args, char *); + char *fmt = (f->flags & FMT_leftside) ? "%s%s" : "%-S%s"; + if (l == NULL && (f->flags & FMT_leftside) == 0) + fmtprint(f, "()"); + else { + List *s; + for (s = l; s != NULL; s = s->n) + fmtprint(f, fmt, s->w, s->n == NULL ? "" : sep); + } + return FALSE; +} + +#define ISMETA(c) (c == '*' || c == '?' || c == '[') + +static bool Sconv(Format *f, int ignore) { + int c; + unsigned char *s = va_arg(f->args, unsigned char *), *t = s; + bool quoted = (f->flags & FMT_altform) != 0; /* '#' */ + bool metaquote = (f->flags & FMT_leftside) != 0; /* '-' */ + if (*s == '\0') { + fmtprint(f, "''"); + return FALSE; + } + if (!quoted) { + while ((c = *t++) != '\0') + if (nw[c] == 1 || (metaquote && ISMETA(c))) + goto quoteit; + fmtprint(f, "%s", s); + return FALSE; + } +quoteit: + fmtputc(f, '\''); + while ((c = *s++) != '\0') { + fmtputc(f, c); + if (c == '\'') + fmtputc(f, '\''); + + } + fmtputc(f, '\''); + return FALSE; +} + +void initprint(void) { + fmtinstall('A', Aconv); + fmtinstall('L', Lconv); + fmtinstall('S', Sconv); + fmtinstall('T', Tconv); + fmtinstall('D', Dconv); +#ifdef PROTECT_ENV + fmtinstall('F', Fconv); +#else + fmtinstall('F', fmtinstall('s', NULL)); +#endif +} -- cgit v1.2.3