home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / rc / part04 / footobar.c < prev    next >
C/C++ Source or Header  |  1992-05-30  |  9KB  |  369 lines

  1. /*
  2.    footobar.c: a collection of functions to convert internal representations of
  3.    variables and functions to external representations, and vice versa
  4. */
  5.  
  6. #include "rc.h"
  7.  
  8. #define FSCHAR '\1'
  9. #define FSSTRING "\1"
  10.  
  11. static char *getenvw(char *, bool);
  12.  
  13. #ifdef PROTECT_ENV
  14. static bool Fconv(Format *f, int ignore) {    /* protect an exported name from brain-dead shells */
  15.     int c;
  16.     unsigned const char *s = va_arg(f->args, unsigned const char *);
  17.  
  18.     while ((c = *s++) != '\0')
  19.         if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
  20.             fmtprint(f, "__%02x", c);
  21.         else
  22.             fmtputc(f, c);
  23.     return FALSE;
  24. }
  25. #endif
  26.  
  27. /* used to turn a function in Node * form into something we can export to the environment */
  28.  
  29. extern char *fun2str(char *name, Node *n) {
  30.     return mprint("fn_%F={%T}", name, n);
  31. }
  32.  
  33. /* convert a redirection to a printable form */
  34.  
  35. static bool Dconv(Format *f, int ignore) {
  36.     const char *name = "?";
  37.     int n = va_arg(f->args, int);
  38.     switch (n) {
  39.     case rCreate:        name = ">";    break;
  40.     case rAppend:        name = ">>";    break;
  41.     case rFrom:        name = "<";    break;
  42.     case rHeredoc:        name = "<<";    break;
  43.     case rHerestring:    name = "<<<";    break;
  44.     }
  45.     fmtcat(f, name);
  46.     return FALSE;
  47. }
  48.  
  49. /* defaultfd -- return the default fd for a given redirection operation */
  50.  
  51. extern int defaultfd(int op) {
  52.     return (op == rCreate || op == rAppend) ? 1 : 0;
  53. }
  54.  
  55. /* convert a function in Node * form into something rc can parse (and humans can read?) */
  56.  
  57. static bool Tconv(Format *f, int ignore) {
  58.     Node *n = va_arg(f->args, Node *);
  59.     if (n == NULL) {
  60.         fmtprint(f, "()");
  61.         return FALSE;
  62.     }
  63.     switch (n->type) {
  64.     case nWord:    fmtprint(f, "%S", n->u[0].s);                break;
  65.     case nQword:    fmtprint(f, "%#S", n->u[0].s);                break;
  66.     case nBang:    fmtprint(f, "! %T", n->u[0].p);                break;
  67.     case nCase:    fmtprint(f, "case %T", n->u[0].p);            break;
  68.     case nNowait:    fmtprint(f, "%T&", n->u[0].p);                break;
  69.     case nCount:    fmtprint(f, "$#%T", n->u[0].p);                break;
  70.     case nFlat:    fmtprint(f, "$^%T", n->u[0].p);                break;
  71.     case nRmfn:    fmtprint(f, "fn %T", n->u[0].p);            break;
  72.     case nSubshell:    fmtprint(f, "@ %T", n->u[0].p);                break;
  73.     case nVar:    fmtprint(f, "$%T", n->u[0].p);                break;
  74.     case nAndalso:    fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p);        break;
  75.     case nAssign:    fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p);        break;
  76.     case nConcat:    fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p);        break;
  77.     case nElse:    fmtprint(f, "{%T}else %T", n->u[0].p, n->u[1].p);    break;
  78.     case nNewfn:    fmtprint(f, "fn %T {%T}", n->u[0].p, n->u[1].p);    break;
  79.     case nIf:    fmtprint(f, "if(%T)%T", n->u[0].p, n->u[1].p);        break;
  80.     case nOrelse:    fmtprint(f, "%T||%T", n->u[0].p, n->u[1].p);        break;
  81.     case nArgs:    fmtprint(f, "%T %T", n->u[0].p, n->u[1].p);        break;
  82.     case nSwitch:    fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p);    break;
  83.     case nMatch:    fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p);        break;
  84.     case nVarsub:    fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p);        break;
  85.     case nWhile:    fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p);    break;
  86.     case nLappend:    fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p);        break;
  87.     case nForin:    fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
  88.     case nDup:
  89.         if (n->u[2].i != -1)
  90.             fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
  91.         else
  92.             fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i);
  93.         break;
  94.     case nBackq: {
  95.         Node *n0 = n->u[0].p, *n00;
  96.         if (n0 != NULL && n0->type == nVar
  97.             && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs"))
  98.             fmtprint(f, "`");
  99.         else
  100.             fmtprint(f, "``%T", n0);
  101.         fmtprint(f, "{%T}", n->u[1].p);
  102.         break;
  103.     }
  104.     case nCbody:
  105.     case nBody: {
  106.         Node *n0 = n->u[0].p;
  107.         if (n0 != NULL)
  108.             fmtprint(f, "%T", n->u[0].p);
  109.         if (n->u[1].p != NULL) {
  110.             if (n0 != NULL && n0->type != nNowait)
  111.                 fmtprint(f, ";");
  112.             fmtprint(f, "%T", n->u[1].p);
  113.         }
  114.         break;
  115.     }
  116.     case nBrace:
  117.         fmtprint(f, "{%T}", n->u[0].p);
  118.         if (n->u[1].p != NULL)
  119.             fmtprint(f, "%T", n->u[1].p);
  120.         break;
  121.     case nEpilog:
  122.     case nPre:
  123.         fmtprint(f, "%T", n->u[0].p);
  124.         if (n->u[1].p != NULL)
  125.             fmtprint(f, " %T", n->u[1].p);
  126.         break;
  127.     case nPipe: {
  128.         int ofd = n->u[0].i, ifd = n->u[1].i;
  129.         fmtprint(f, "%T|", n->u[2].p);
  130.         if (ifd != 0)
  131.             fmtprint(f, "[%d=%d]", ofd, ifd);
  132.         else if (ofd != 1)
  133.             fmtprint(f, "[%d]", ofd);
  134.         fmtprint(f, "%T", n->u[3].p);
  135.         break;
  136.     }
  137.     case nRedir: {
  138.         int op = n->u[0].i;
  139.         fmtprint(f, "%D", op);
  140.         if (n->u[1].i != defaultfd(op))
  141.             fmtprint(f, "[%d]", n->u[1].i);
  142.         fmtprint(f, "%T", n->u[2].p);
  143.         break;
  144.     }
  145.     case nNmpipe: {
  146.         int op = n->u[0].i;
  147.         fmtprint(f, "%D", op);
  148.         if (n->u[1].i != defaultfd(op))
  149.             fmtprint(f, "[%d]", n->u[1].i);
  150.         fmtprint(f, "{%T}", n->u[2].p);
  151.         break;
  152.     }
  153.      }
  154.     return FALSE;
  155. }
  156.  
  157. /* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
  158.  
  159. extern char *list2str(char *name, List *s) {
  160.     SIZE_T size, step;
  161.     List *t;
  162.     char *w, *x;
  163.     name = nprint("%F", name);
  164.     size = strlen(name) + listlen(s);
  165.     w = ealloc(size + 2);
  166.     t = s;
  167.     x = w;
  168.     strcpy(x, name);
  169.     strcpy(x += strlen(name), "=");
  170.     strcpy(x += conststrlen("="), t->w);
  171.     for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) {
  172.         memcpy(x, FSSTRING, step = conststrlen(FSSTRING));
  173.         x += step;
  174.         memcpy(x, s->w, step = strlen(s->w));
  175.         x += step;
  176.     }
  177.     *x = '\0';
  178.     return w;
  179. }
  180.  
  181. /* convert a List to an array, for execve() */
  182.  
  183. extern char **list2array(List *s, bool print) {
  184.     char **av;
  185.     int i;
  186.  
  187.     /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */
  188.     av = nalloc((listnel(s) + 4) * sizeof (char *));
  189.     av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */
  190.     if (print)
  191.         fprint(2, "%L\n", s, " ");
  192.     for (i = 0; s != NULL; i++) {
  193.         av[i] = s->w;
  194.         s = s->n;
  195.     }
  196.     av[i] = NULL;
  197.     return av;
  198. }
  199.  
  200. /* figure out the name of a variable given an environment string. copy this into malloc space */
  201.  
  202. extern char *get_name(char *s) {
  203.     int c;
  204.     SIZE_T i;
  205.     char *r, *namebuf;
  206.     for (i = 0; s[i] != '\0' && s[i] != '='; i++)
  207.         ;
  208.     if (s[i] == '\0')
  209.         return NULL;
  210.     r = namebuf = ealloc(i + 1);
  211.     while (1)
  212.         switch (c = *s++) {
  213.         case '=':
  214.             *r++ = '\0';
  215.             return namebuf;
  216. #ifdef PROTECT_ENV
  217.         case '_':
  218.             if (*s == '_') {
  219.                 static const char hexchar[] = "0123456789abcdef";
  220.                 char *h1 = strchr(hexchar, s[1]);
  221.                 char *h2 = strchr(hexchar, s[2]);
  222.                 if (h1 != NULL && h2 != NULL) {
  223.                     *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar);
  224.                     s += 3;
  225.                     break;
  226.                 }
  227.             }
  228.             /* FALLTHROUGH */
  229. #endif
  230.         default:
  231.             *r++ = c;
  232.             break;
  233.         }
  234. }
  235.  
  236. /* get the next word from a variable's value as represented in the environment. */
  237.  
  238. static char *getenvw(char *s, bool saw_alpha) {
  239.     SIZE_T i;
  240.     char *r;
  241.     for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
  242.         ;
  243.     if (i == 0) {
  244.         if (s[i] == '\0' && !saw_alpha)
  245.             return NULL;
  246.         else
  247.             return clear(enew(char), (SIZE_T) 1);
  248.     }
  249.     r = strncpy(ealloc(i + 1), s, i);
  250.     r[i] = '\0';
  251.     return r;
  252. }
  253.  
  254. /* take an environment entry for a variable (elements ^A separated) and turn it into a List */
  255.  
  256. extern List *parse_var(char *name, char *extdef) {
  257.     List *r, *top;
  258.     char *f;
  259.     bool saw_alpha;
  260.     top = r = enew(List);
  261.     extdef = strchr(extdef, '=') + 1;
  262.     if ((f = getenvw(extdef, FALSE)) == NULL) {
  263.         r->w = "";
  264.         r->m = NULL;
  265.         r->n = NULL;
  266.     } else {
  267.         while (1) {
  268.             r->w = f;
  269.             r->m = NULL;
  270.             extdef += strlen(f);
  271.             if (*extdef == FSCHAR) {
  272.                 extdef++;
  273.                 saw_alpha = TRUE;
  274.             } else {
  275.                 saw_alpha = FALSE;
  276.             }
  277.             if ((f = getenvw(extdef, saw_alpha)) == NULL) {
  278.                 r->n = NULL;
  279.                 break;
  280.             }
  281.             r = r->n = enew(List);
  282.         }
  283.     }
  284.     return top;
  285. }
  286.  
  287. /* get an environment entry for a function and have rc parse it. */
  288.  
  289. #define PREFIX "fn x"
  290. #define PRELEN conststrlen(PREFIX)
  291. extern Node *parse_fn(char *name, char *extdef) {
  292.     Node *def;
  293.     char *s, old[PRELEN];
  294.     if ((s = strchr(extdef, '=')) == NULL)
  295.         return NULL;
  296.     memcpy(old, s -= (PRELEN-1), PRELEN);
  297.     memcpy(s, PREFIX, PRELEN);
  298.     def = parseline(s);
  299.     memcpy(s, old, PRELEN);
  300.     return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p;
  301. }
  302.  
  303. static bool Aconv(Format *f, int c) {
  304.     char **a = va_arg(f->args, char **);
  305.     if (*a != NULL) {
  306.         fmtcat(f, *a);
  307.         while (*++a != NULL)
  308.             fmtprint(f, " %s", *a);
  309.     }
  310.     return FALSE;
  311. }
  312.  
  313. static bool Lconv(Format *f, int c) {
  314.     List *l = va_arg(f->args, List *);
  315.     char *sep = va_arg(f->args, char *);
  316.     char *fmt = (f->flags & FMT_leftside) ? "%s%s" : "%-S%s";
  317.     if (l == NULL && (f->flags & FMT_leftside) == 0)
  318.         fmtprint(f, "()");
  319.     else {
  320.         List *s;
  321.         for (s = l; s != NULL; s = s->n)
  322.             fmtprint(f, fmt, s->w, s->n == NULL ? "" : sep);
  323.     }
  324.     return FALSE;
  325. }
  326.  
  327. #define    ISMETA(c)    (c == '*' || c == '?' || c == '[')
  328.  
  329. static bool Sconv(Format *f, int ignore) {
  330.     int c;
  331.     unsigned char *s = va_arg(f->args, unsigned char *), *t = s;
  332.     bool quoted    = (f->flags & FMT_altform)  != 0;    /* '#' */
  333.     bool metaquote = (f->flags & FMT_leftside) != 0;    /* '-' */
  334.     if (*s == '\0') {
  335.         fmtprint(f, "''");
  336.         return FALSE;
  337.     }
  338.     if (!quoted) {
  339.         while ((c = *t++) != '\0')
  340.             if (nw[c] == 1 || (metaquote && ISMETA(c)))
  341.                 goto quoteit;
  342.         fmtprint(f, "%s", s);
  343.         return FALSE;
  344.     }
  345. quoteit:
  346.     fmtputc(f, '\'');
  347.     while ((c = *s++) != '\0') {
  348.         fmtputc(f, c);
  349.         if (c == '\'')
  350.             fmtputc(f, '\'');
  351.  
  352.     }
  353.     fmtputc(f, '\'');
  354.     return FALSE;
  355. }
  356.  
  357. void initprint(void) {
  358.     fmtinstall('A', Aconv);
  359.     fmtinstall('L', Lconv);
  360.     fmtinstall('S', Sconv);
  361.     fmtinstall('T', Tconv);
  362.     fmtinstall('D', Dconv);
  363. #ifdef PROTECT_ENV
  364.     fmtinstall('F', Fconv);
  365. #else
  366.     fmtinstall('F', fmtinstall('s', NULL));
  367. #endif
  368. }
  369.