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