1 0 stevel /* 2 356 muffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 0 stevel * Use is subject to license terms. 4 0 stevel */ 5 0 stevel 6 0 stevel /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 0 stevel /* All Rights Reserved */ 8 0 stevel 9 0 stevel /* 10 0 stevel * Copyright (c) 1980 Regents of the University of California. 11 0 stevel * All rights reserved. The Berkeley Software License Agreement 12 0 stevel * specifies the terms and conditions for redistribution. 13 0 stevel */ 14 0 stevel 15 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 16 0 stevel 17 0 stevel #include <unistd.h> /* for lseek prototype */ 18 0 stevel #include "sh.h" 19 0 stevel #include "sh.tconst.h" 20 0 stevel 21 0 stevel /* 22 0 stevel * C shell 23 0 stevel */ 24 0 stevel 25 0 stevel /* 26 0 stevel * These routines perform variable substitution and quoting via ' and ". 27 0 stevel * To this point these constructs have been preserved in the divided 28 0 stevel * input words. Here we expand variables and turn quoting via ' and " into 29 0 stevel * QUOTE bits on characters (which prevent further interpretation). 30 0 stevel * If the `:q' modifier was applied during history expansion, then 31 0 stevel * some QUOTEing may have occurred already, so we dont "trim()" here. 32 0 stevel */ 33 0 stevel 34 0 stevel int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */ 35 0 stevel tchar *Dcp, **Dvp; /* Input vector for Dreadc */ 36 0 stevel 37 0 stevel #define DEOF -1 38 0 stevel 39 0 stevel #define unDgetC(c) Dpeekc = c 40 0 stevel 41 559 nakanon #define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */ 42 0 stevel 43 0 stevel /* 44 0 stevel * The following variables give the information about the current 45 0 stevel * $ expansion, recording the current word position, the remaining 46 0 stevel * words within this expansion, the count of remaining words, and the 47 0 stevel * information about any : modifier which is being applied. 48 0 stevel */ 49 0 stevel tchar *dolp; /* Remaining chars from this word */ 50 0 stevel tchar **dolnxt; /* Further words */ 51 0 stevel int dolcnt; /* Count of further words */ 52 0 stevel tchar dolmod; /* : modifier character */ 53 0 stevel int dolmcnt; /* :gx -> 10000, else 1 */ 54 0 stevel 55 356 muffin void Dfix2(tchar **); 56 356 muffin void Dgetdol(void); 57 356 muffin void setDolp(tchar *); 58 356 muffin void unDredc(int); 59 356 muffin 60 0 stevel /* 61 0 stevel * Fix up the $ expansions and quotations in the 62 0 stevel * argument list to command t. 63 0 stevel */ 64 356 muffin void 65 356 muffin Dfix(struct command *t) 66 0 stevel { 67 356 muffin tchar **pp; 68 356 muffin tchar *p; 69 0 stevel 70 0 stevel #ifdef TRACE 71 0 stevel tprintf("TRACE- Dfix()\n"); 72 0 stevel #endif 73 0 stevel if (noexec) 74 0 stevel return; 75 0 stevel /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */ 76 559 nakanon for (pp = t->t_dcom; p = *pp++; ) 77 0 stevel while (*p) 78 0 stevel if (cmap(*p++, _DOL|QUOTES)) { /* $, \, ', ", ` */ 79 0 stevel Dfix2(t->t_dcom); /* found one */ 80 0 stevel blkfree(t->t_dcom); 81 0 stevel t->t_dcom = gargv; 82 0 stevel gargv = 0; 83 0 stevel return; 84 0 stevel } 85 0 stevel } 86 0 stevel 87 0 stevel /* 88 0 stevel * $ substitute one word, for i/o redirection 89 0 stevel */ 90 0 stevel tchar * 91 356 muffin Dfix1(tchar *cp) 92 0 stevel { 93 0 stevel tchar *Dv[2]; 94 0 stevel 95 0 stevel #ifdef TRACE 96 0 stevel tprintf("TRACE- Dfix1()\n"); 97 0 stevel #endif 98 0 stevel if (noexec) 99 0 stevel return (0); 100 0 stevel Dv[0] = cp; Dv[1] = NOSTR; 101 0 stevel Dfix2(Dv); 102 0 stevel if (gargc != 1) { 103 0 stevel setname(cp); 104 0 stevel bferr("Ambiguous"); 105 0 stevel } 106 0 stevel cp = savestr(gargv[0]); 107 0 stevel blkfree(gargv), gargv = 0; 108 0 stevel return (cp); 109 0 stevel } 110 0 stevel 111 0 stevel /* 112 0 stevel * Subroutine to do actual fixing after state initialization. 113 0 stevel */ 114 356 muffin void 115 356 muffin Dfix2(tchar **v) 116 0 stevel { 117 0 stevel tchar *agargv[GAVSIZ]; 118 0 stevel 119 0 stevel #ifdef TRACE 120 0 stevel tprintf("TRACE- Dfix2()\n"); 121 0 stevel #endif 122 0 stevel ginit(agargv); /* Initialize glob's area pointers */ 123 559 nakanon Dvp = v; Dcp = S_ /* "" */; /* Setup input vector for Dreadc */ 124 0 stevel unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ 125 0 stevel dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ 126 0 stevel while (Dword()) 127 0 stevel continue; 128 0 stevel gargv = copyblk(gargv); 129 0 stevel } 130 0 stevel 131 0 stevel /* 132 0 stevel * Get a word. This routine is analogous to the routine 133 0 stevel * word() in sh.lex.c for the main lexical input. One difference 134 0 stevel * here is that we don't get a newline to terminate our expansion. 135 0 stevel * Rather, DgetC will return a DEOF when we hit the end-of-input. 136 0 stevel */ 137 356 muffin int 138 356 muffin Dword(void) 139 0 stevel { 140 356 muffin int c, c1; 141 0 stevel static tchar *wbuf = NULL; 142 0 stevel static int wbufsiz = BUFSIZ; 143 356 muffin int wp = 0; 144 356 muffin bool dolflg; 145 0 stevel bool sofar = 0; 146 0 stevel #define DYNAMICBUFFER() \ 147 0 stevel do { \ 148 0 stevel if (wp >= wbufsiz) { \ 149 0 stevel wbufsiz += BUFSIZ; \ 150 0 stevel wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \ 151 0 stevel } \ 152 0 stevel } while (0) 153 0 stevel 154 0 stevel #ifdef TRACE 155 0 stevel tprintf("TRACE- Dword()\n"); 156 0 stevel #endif 157 0 stevel if (wbuf == NULL) 158 0 stevel wbuf = xalloc((wbufsiz+1) * sizeof (tchar)); 159 0 stevel loop: 160 0 stevel c = DgetC(DODOL); 161 0 stevel switch (c) { 162 0 stevel 163 0 stevel case DEOF: 164 0 stevel deof: 165 0 stevel if (sofar == 0) 166 0 stevel return (0); 167 0 stevel /* finish this word and catch the code above the next time */ 168 0 stevel unDredc(c); 169 0 stevel /* fall into ... */ 170 0 stevel 171 0 stevel case '\n': 172 0 stevel wbuf[wp] = 0; 173 0 stevel goto ret; 174 0 stevel 175 0 stevel case ' ': 176 0 stevel case '\t': 177 0 stevel goto loop; 178 0 stevel 179 0 stevel case '`': 180 0 stevel /* We preserve ` quotations which are done yet later */ 181 0 stevel wbuf[wp++] = c; 182 0 stevel case '\'': 183 0 stevel case '"': 184 0 stevel /* 185 0 stevel * Note that DgetC never returns a QUOTES character 186 0 stevel * from an expansion, so only true input quotes will 187 0 stevel * get us here or out. 188 0 stevel */ 189 0 stevel c1 = c; 190 0 stevel dolflg = c1 == '"' ? DODOL : 0; 191 0 stevel for (;;) { 192 0 stevel c = DgetC(dolflg); 193 0 stevel if (c == c1) 194 0 stevel break; 195 0 stevel if (c == '\n' || c == DEOF) 196 0 stevel error("Unmatched %c", (tchar) c1); 197 0 stevel if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE)) 198 0 stevel --wp; 199 0 stevel DYNAMICBUFFER(); 200 0 stevel switch (c1) { 201 0 stevel 202 0 stevel case '"': 203 0 stevel /* 204 0 stevel * Leave any `s alone for later. 205 0 stevel * Other chars are all quoted, thus `...` 206 0 stevel * can tell it was within "...". 207 0 stevel */ 208 0 stevel wbuf[wp++] = c == '`' ? '`' : c | QUOTE; 209 0 stevel break; 210 0 stevel 211 0 stevel case '\'': 212 0 stevel /* Prevent all further interpretation */ 213 0 stevel wbuf[wp++] = c | QUOTE; 214 0 stevel break; 215 0 stevel 216 0 stevel case '`': 217 0 stevel /* Leave all text alone for later */ 218 0 stevel wbuf[wp++] = c; 219 0 stevel break; 220 0 stevel } 221 0 stevel } 222 0 stevel if (c1 == '`') { 223 0 stevel DYNAMICBUFFER(); 224 0 stevel wbuf[wp++] = '`'; 225 0 stevel } 226 0 stevel goto pack; /* continue the word */ 227 0 stevel 228 0 stevel case '\\': 229 0 stevel c = DgetC(0); /* No $ subst! */ 230 0 stevel if (c == '\n' || c == DEOF) 231 0 stevel goto loop; 232 0 stevel c |= QUOTE; 233 0 stevel break; 234 0 stevel #ifdef MBCHAR /* Could be a space char from aux. codeset. */ 235 0 stevel default: 236 0 stevel if (isauxsp(c)) goto loop; 237 0 stevel #endif /* MBCHAR */ 238 0 stevel } 239 0 stevel unDgetC(c); 240 0 stevel pack: 241 0 stevel sofar = 1; 242 0 stevel /* pack up more characters in this word */ 243 0 stevel for (;;) { 244 0 stevel c = DgetC(DODOL); 245 0 stevel if (c == '\\') { 246 0 stevel c = DgetC(0); 247 0 stevel if (c == DEOF) 248 0 stevel goto deof; 249 0 stevel if (c == '\n') 250 0 stevel c = ' '; 251 0 stevel else 252 0 stevel c |= QUOTE; 253 0 stevel } 254 0 stevel if (c == DEOF) 255 0 stevel goto deof; 256 0 stevel if (cmap(c, _SP|_NL|_Q|_Q1) || 257 0 stevel isauxsp(c)) { /* sp \t\n'"` or aux. sp */ 258 0 stevel unDgetC(c); 259 0 stevel if (cmap(c, QUOTES)) 260 0 stevel goto loop; 261 0 stevel DYNAMICBUFFER(); 262 0 stevel wbuf[wp++] = 0; 263 0 stevel goto ret; 264 0 stevel } 265 0 stevel DYNAMICBUFFER(); 266 0 stevel wbuf[wp++] = c; 267 0 stevel } 268 0 stevel ret: 269 0 stevel Gcat(S_ /* "" */, wbuf); 270 0 stevel return (1); 271 0 stevel } 272 0 stevel 273 0 stevel /* 274 0 stevel * Get a character, performing $ substitution unless flag is 0. 275 0 stevel * Any QUOTES character which is returned from a $ expansion is 276 0 stevel * QUOTEd so that it will not be recognized above. 277 0 stevel */ 278 356 muffin int 279 356 muffin DgetC(int flag) 280 0 stevel { 281 356 muffin int c; 282 0 stevel 283 0 stevel top: 284 0 stevel if (c = Dpeekc) { 285 0 stevel Dpeekc = 0; 286 0 stevel return (c); 287 0 stevel } 288 0 stevel if (lap) { 289 0 stevel c = *lap++ & (QUOTE|TRIM); 290 0 stevel if (c == 0) { 291 0 stevel lap = 0; 292 0 stevel goto top; 293 0 stevel } 294 0 stevel quotspec: 295 0 stevel /* 296 0 stevel * don't quote things if there was an error (err!=0) 297 0 stevel * the input is original, not from a substitution and 298 0 stevel * therefore should not be quoted 299 0 stevel */ 300 0 stevel if (!err && cmap(c, QUOTES)) 301 0 stevel return (c | QUOTE); 302 0 stevel return (c); 303 0 stevel } 304 0 stevel if (dolp) { 305 0 stevel if (c = *dolp++ & (QUOTE|TRIM)) 306 0 stevel goto quotspec; 307 0 stevel if (dolcnt > 0) { 308 0 stevel setDolp(*dolnxt++); 309 0 stevel --dolcnt; 310 0 stevel return (' '); 311 0 stevel } 312 0 stevel dolp = 0; 313 0 stevel } 314 0 stevel if (dolcnt > 0) { 315 0 stevel setDolp(*dolnxt++); 316 0 stevel --dolcnt; 317 0 stevel goto top; 318 0 stevel } 319 0 stevel c = Dredc(); 320 0 stevel if (c == '$' && flag) { 321 0 stevel Dgetdol(); 322 0 stevel goto top; 323 0 stevel } 324 0 stevel return (c); 325 0 stevel } 326 0 stevel 327 0 stevel tchar *nulvec[] = { 0 }; 328 0 stevel struct varent nulargv = { nulvec, S_argv, 0 }; 329 0 stevel 330 0 stevel /* 331 0 stevel * Handle the multitudinous $ expansion forms. 332 0 stevel * Ugh. 333 0 stevel */ 334 356 muffin void 335 356 muffin Dgetdol(void) 336 0 stevel { 337 356 muffin tchar *np; 338 356 muffin struct varent *vp; 339 0 stevel tchar name[MAX_VREF_LEN]; 340 0 stevel int c, sc; 341 0 stevel int subscr = 0, lwb = 1, upb = 0; 342 0 stevel bool dimen = 0, bitset = 0; 343 559 nakanon tchar wbuf[BUFSIZ + MB_LEN_MAX]; /* read_ may return extra bytes */ 344 0 stevel 345 0 stevel #ifdef TRACE 346 0 stevel tprintf("TRACE- Dgetdol()\n"); 347 0 stevel #endif 348 0 stevel dolmod = dolmcnt = 0; 349 0 stevel c = sc = DgetC(0); 350 0 stevel if (c == '{') 351 0 stevel c = DgetC(0); /* sc is { to take } later */ 352 0 stevel if ((c & TRIM) == '#') 353 0 stevel dimen++, c = DgetC(0); /* $# takes dimension */ 354 0 stevel else if (c == '?') 355 0 stevel bitset++, c = DgetC(0); /* $? tests existence */ 356 0 stevel switch (c) { 357 559 nakanon 358 0 stevel case '$': 359 0 stevel if (dimen || bitset) 360 0 stevel syntax: 361 0 stevel error("Variable syntax"); /* No $?$, $#$ */ 362 0 stevel setDolp(doldol); 363 0 stevel goto eatbrac; 364 0 stevel 365 0 stevel case '<'|QUOTE: 366 0 stevel if (dimen || bitset) 367 0 stevel goto syntax; /* No $?<, $#< */ 368 0 stevel for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) { 369 0 stevel if (np >= &wbuf[BUFSIZ-1]) 370 0 stevel error("$< line too long"); 371 0 stevel if (*np <= 0 || *np == '\n') 372 0 stevel break; 373 0 stevel } 374 0 stevel *np = 0; 375 0 stevel /* 376 0 stevel * KLUDGE: dolmod is set here because it will 377 0 stevel * cause setDolp to call domod and thus to copy wbuf. 378 0 stevel * Otherwise setDolp would use it directly. If we saved 379 0 stevel * it ourselves, no one would know when to free it. 380 0 stevel * The actual function of the 'q' causes filename 381 0 stevel * expansion not to be done on the interpolated value. 382 0 stevel */ 383 0 stevel dolmod = 'q'; 384 0 stevel dolmcnt = 10000; 385 0 stevel setDolp(wbuf); 386 0 stevel goto eatbrac; 387 0 stevel 388 0 stevel case DEOF: 389 0 stevel case '\n': 390 0 stevel goto syntax; 391 0 stevel 392 0 stevel case '*': 393 0 stevel (void) strcpy_(name, S_argv); 394 0 stevel vp = adrof(S_argv); 395 0 stevel subscr = -1; /* Prevent eating [...] */ 396 0 stevel break; 397 0 stevel 398 0 stevel default: 399 0 stevel np = name; 400 0 stevel if (digit(c)) { 401 0 stevel if (dimen) 402 0 stevel goto syntax; /* No $#1, e.g. */ 403 0 stevel subscr = 0; 404 0 stevel do { 405 0 stevel subscr = subscr * 10 + c - '0'; 406 0 stevel c = DgetC(0); 407 0 stevel } while (digit(c)); 408 0 stevel unDredc(c); 409 0 stevel if (subscr < 0) 410 0 stevel error("Subscript out of range"); 411 0 stevel if (subscr == 0) { 412 0 stevel if (bitset) { 413 559 nakanon dolp = file ? S_1 /* "1" */ : S_0 /* "0" */; 414 0 stevel goto eatbrac; 415 0 stevel } 416 0 stevel if (file == 0) 417 0 stevel error("No file for $0"); 418 0 stevel setDolp(file); 419 0 stevel goto eatbrac; 420 0 stevel } 421 0 stevel if (bitset) 422 0 stevel goto syntax; 423 0 stevel vp = adrof(S_argv); 424 0 stevel if (vp == 0) { 425 0 stevel vp = &nulargv; 426 0 stevel goto eatmod; 427 0 stevel } 428 0 stevel break; 429 0 stevel } 430 0 stevel if (!alnum(c)) 431 0 stevel goto syntax; 432 0 stevel for (;;) { 433 0 stevel *np++ = c; 434 0 stevel c = DgetC(0); 435 0 stevel if (!alnum(c)) 436 0 stevel break; 437 0 stevel /* if variable name is > 20, complain */ 438 0 stevel if (np >= &name[MAX_VAR_LEN]) 439 0 stevel error("Variable name too long"); 440 0 stevel 441 0 stevel } 442 0 stevel *np++ = 0; 443 0 stevel unDredc(c); 444 0 stevel vp = adrof(name); 445 0 stevel } 446 0 stevel if (bitset) { 447 559 nakanon /* 448 559 nakanon * getenv() to getenv_(), because 'name''s type is now tchar * 449 559 nakanon * no need to xalloc 450 559 nakanon */ 451 559 nakanon dolp = (vp || getenv_(name)) ? S_1 /* "1" */ : S_0 /* "0" */; 452 0 stevel goto eatbrac; 453 0 stevel } 454 0 stevel if (vp == 0) { 455 559 nakanon /* 456 559 nakanon * getenv() to getenv_(), because 'name''s type is now tchar * 457 559 nakanon * no need to xalloc 458 559 nakanon */ 459 0 stevel np = getenv_(name); 460 0 stevel if (np) { 461 0 stevel addla(np); 462 0 stevel goto eatbrac; 463 0 stevel } 464 0 stevel udvar(name); 465 0 stevel /*NOTREACHED*/ 466 0 stevel } 467 0 stevel c = DgetC(0); 468 0 stevel upb = blklen(vp->vec); 469 0 stevel if (dimen == 0 && subscr == 0 && c == '[') { 470 0 stevel np = name; 471 0 stevel for (;;) { 472 0 stevel c = DgetC(DODOL); /* Allow $ expand within [ ] */ 473 0 stevel if (c == ']') 474 0 stevel break; 475 0 stevel if (c == '\n' || c == DEOF) 476 0 stevel goto syntax; 477 0 stevel if (np >= &name[MAX_VREF_LEN]) 478 0 stevel error("Variable reference too long"); 479 0 stevel *np++ = c; 480 0 stevel } 481 0 stevel *np = 0, np = name; 482 0 stevel if (dolp || dolcnt) /* $ exp must end before ] */ 483 0 stevel goto syntax; 484 0 stevel if (!*np) 485 0 stevel goto syntax; 486 0 stevel if (digit(*np)) { 487 356 muffin int i = 0; 488 0 stevel 489 0 stevel while (digit(*np)) 490 0 stevel i = i * 10 + *np++ - '0'; 491 559 nakanon /* if ((i < 0 || i > upb) && !any(*np, "-*")) { */ 492 559 nakanon if ((i < 0 || i > upb) && (*np != '-') && (*np != '*')) { 493 0 stevel oob: 494 0 stevel setname(vp->v_name); 495 0 stevel error("Subscript out of range"); 496 0 stevel } 497 0 stevel lwb = i; 498 0 stevel if (!*np) 499 559 nakanon upb = lwb, np = S_AST /* "*" */; 500 0 stevel } 501 0 stevel if (*np == '*') 502 0 stevel np++; 503 0 stevel else if (*np != '-') 504 0 stevel goto syntax; 505 0 stevel else { 506 356 muffin int i = upb; 507 0 stevel 508 0 stevel np++; 509 0 stevel if (digit(*np)) { 510 0 stevel i = 0; 511 0 stevel while (digit(*np)) 512 0 stevel i = i * 10 + *np++ - '0'; 513 0 stevel if (i < 0 || i > upb) 514 0 stevel goto oob; 515 0 stevel } 516 0 stevel if (i < lwb) 517 0 stevel upb = lwb - 1; 518 0 stevel else 519 0 stevel upb = i; 520 0 stevel } 521 0 stevel if (lwb == 0) { 522 0 stevel if (upb != 0) 523 0 stevel goto oob; 524 0 stevel upb = -1; 525 0 stevel } 526 0 stevel if (*np) 527 0 stevel goto syntax; 528 0 stevel } else { 529 0 stevel if (subscr > 0) 530 0 stevel if (subscr > upb) 531 0 stevel lwb = 1, upb = 0; 532 0 stevel else 533 0 stevel lwb = upb = subscr; 534 0 stevel unDredc(c); 535 0 stevel } 536 0 stevel if (dimen) { 537 0 stevel tchar *cp = putn(upb - lwb + 1); 538 0 stevel 539 0 stevel addla(cp); 540 0 stevel xfree(cp); 541 0 stevel } else { 542 0 stevel eatmod: 543 0 stevel c = DgetC(0); 544 0 stevel if (c == ':') { 545 0 stevel c = DgetC(0), dolmcnt = 1; 546 0 stevel if (c == 'g') 547 0 stevel c = DgetC(0), dolmcnt = 10000; 548 0 stevel if (!any(c, S_htrqxe)) 549 0 stevel error("Bad : mod in $"); 550 0 stevel dolmod = c; 551 0 stevel if (c == 'q') 552 0 stevel dolmcnt = 10000; 553 0 stevel } else 554 0 stevel unDredc(c); 555 0 stevel dolnxt = &vp->vec[lwb - 1]; 556 0 stevel dolcnt = upb - lwb + 1; 557 0 stevel } 558 0 stevel eatbrac: 559 0 stevel if (sc == '{') { 560 0 stevel c = Dredc(); 561 0 stevel if (c != '}') 562 0 stevel goto syntax; 563 0 stevel } 564 0 stevel } 565 0 stevel 566 356 muffin void 567 356 muffin setDolp(tchar *cp) 568 0 stevel { 569 356 muffin tchar *dp; 570 0 stevel 571 0 stevel #ifdef TRACE 572 0 stevel tprintf("TRACE- setDolp()\n"); 573 0 stevel #endif 574 0 stevel if (dolmod == 0 || dolmcnt == 0) { 575 0 stevel dolp = cp; 576 0 stevel return; 577 0 stevel } 578 0 stevel dp = domod(cp, dolmod); 579 0 stevel if (dp) { 580 0 stevel dolmcnt--; 581 0 stevel addla(dp); 582 0 stevel xfree(dp); 583 0 stevel } else 584 0 stevel addla(cp); 585 559 nakanon dolp = S_ /* "" */; 586 0 stevel } 587 0 stevel 588 356 muffin void 589 356 muffin unDredc(int c) 590 0 stevel { 591 0 stevel 592 0 stevel Dpeekrd = c; 593 0 stevel } 594 0 stevel 595 356 muffin int 596 0 stevel Dredc() 597 0 stevel { 598 356 muffin int c; 599 0 stevel 600 0 stevel if (c = Dpeekrd) { 601 0 stevel Dpeekrd = 0; 602 0 stevel return (c); 603 0 stevel } 604 0 stevel if (Dcp && (c = *Dcp++)) 605 0 stevel return (c&(QUOTE|TRIM)); 606 0 stevel if (*Dvp == 0) { 607 0 stevel Dcp = 0; 608 0 stevel return (DEOF); 609 0 stevel } 610 0 stevel Dcp = *Dvp++; 611 0 stevel return (' '); 612 0 stevel } 613 0 stevel 614 356 muffin void 615 356 muffin Dtestq(int c) 616 0 stevel { 617 0 stevel 618 0 stevel if (cmap(c, QUOTES)) 619 0 stevel gflag = 1; 620 0 stevel } 621 0 stevel 622 0 stevel /* 623 0 stevel * Form a shell temporary file (in unit 0) from the words 624 0 stevel * of the shell input up to a line the same as "term". 625 0 stevel * Unit 0 should have been closed before this call. 626 0 stevel */ 627 356 muffin void 628 356 muffin heredoc(tchar *term) 629 0 stevel { 630 356 muffin int c; 631 0 stevel tchar *Dv[2]; 632 0 stevel tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; 633 0 stevel int ocnt, lcnt, mcnt; 634 356 muffin tchar *lbp, *obp, *mbp; 635 0 stevel tchar **vp; 636 0 stevel bool quoted; 637 0 stevel tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X', 638 0 stevel 'X', 'X', 'X', 0}; 639 0 stevel int fd1; 640 0 stevel 641 0 stevel #ifdef TRACE 642 0 stevel tprintf("TRACE- heredoc()\n"); 643 0 stevel #endif 644 0 stevel if ((fd1 = mkstemp_(shtemp)) < 0) 645 0 stevel Perror(shtemp); 646 0 stevel (void) unlink_(shtemp); /* 0 0 inode! */ 647 0 stevel unsetfd(fd1); 648 0 stevel Dv[0] = term; Dv[1] = NOSTR; gflag = 0; 649 0 stevel trim(Dv); rscan(Dv, Dtestq); quoted = gflag; 650 0 stevel ocnt = BUFSIZ; obp = obuf; 651 0 stevel for (;;) { 652 0 stevel /* 653 0 stevel * Read up a line 654 0 stevel */ 655 0 stevel lbp = lbuf; lcnt = BUFSIZ - 4; 656 0 stevel for (;;) { 657 0 stevel c = readc(1); /* 1 -> Want EOF returns */ 658 0 stevel if (c < 0) { 659 0 stevel setname(term); 660 0 stevel bferr("<< terminator not found"); 661 0 stevel } 662 0 stevel if (c == '\n') 663 0 stevel break; 664 0 stevel if (c &= TRIM) { 665 0 stevel *lbp++ = c; 666 0 stevel if (--lcnt < 0) { 667 559 nakanon setname(S_LESLES /* "<<" */); 668 0 stevel error("Line overflow"); 669 559 nakanon } 670 0 stevel } 671 0 stevel } 672 0 stevel *lbp = 0; 673 0 stevel 674 0 stevel /* 675 0 stevel * Compare to terminator -- before expansion 676 0 stevel */ 677 0 stevel if (eq(lbuf, term)) { 678 0 stevel (void) write_(0, obuf, BUFSIZ - ocnt); 679 0 stevel (void) lseek(0, (off_t)0, 0); 680 0 stevel return; 681 0 stevel } 682 0 stevel 683 0 stevel /* 684 0 stevel * If term was quoted or -n just pass it on 685 0 stevel */ 686 0 stevel if (quoted || noexec) { 687 0 stevel *lbp++ = '\n'; *lbp = 0; 688 559 nakanon for (lbp = lbuf; c = *lbp++; ) { 689 0 stevel *obp++ = c; 690 0 stevel if (--ocnt == 0) { 691 0 stevel (void) write_(0, obuf, BUFSIZ); 692 0 stevel obp = obuf; ocnt = BUFSIZ; 693 0 stevel } 694 0 stevel } 695 0 stevel continue; 696 0 stevel } 697 0 stevel 698 0 stevel /* 699 0 stevel * Term wasn't quoted so variable and then command 700 0 stevel * expand the input line 701 0 stevel */ 702 0 stevel Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; 703 0 stevel for (;;) { 704 0 stevel c = DgetC(DODOL); 705 0 stevel if (c == DEOF) 706 0 stevel break; 707 0 stevel if ((c &= TRIM) == 0) 708 0 stevel continue; 709 0 stevel /* \ quotes \ $ ` here */ 710 559 nakanon if (c == '\\') { 711 0 stevel c = DgetC(0); 712 559 nakanon /* if (!any(c, "$\\`")) */ 713 559 nakanon if ((c != '$') && (c != '\\') && (c != '`')) 714 0 stevel unDgetC(c | QUOTE), c = '\\'; 715 0 stevel else 716 0 stevel c |= QUOTE; 717 0 stevel } 718 0 stevel *mbp++ = c; 719 0 stevel if (--mcnt == 0) { 720 559 nakanon setname(S_LESLES /* "<<" */); 721 0 stevel bferr("Line overflow"); 722 0 stevel } 723 0 stevel } 724 0 stevel *mbp++ = 0; 725 0 stevel 726 0 stevel /* 727 0 stevel * If any ` in line do command substitution 728 0 stevel */ 729 0 stevel mbp = mbuf; 730 0 stevel if (any('`', mbp)) { 731 0 stevel /* 732 0 stevel * 1 arg to dobackp causes substitution to be literal. 733 0 stevel * Words are broken only at newlines so that all blanks 734 0 stevel * and tabs are preserved. Blank lines (null words) 735 0 stevel * are not discarded. 736 0 stevel */ 737 0 stevel vp = dobackp(mbuf, 1); 738 0 stevel } else 739 0 stevel /* Setup trivial vector similar to return of dobackp */ 740 0 stevel Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv; 741 0 stevel 742 0 stevel /* 743 0 stevel * Resurrect the words from the command substitution 744 0 stevel * each separated by a newline. Note that the last 745 0 stevel * newline of a command substitution will have been 746 0 stevel * discarded, but we put a newline after the last word 747 0 stevel * because this represents the newline after the last 748 0 stevel * input line! 749 0 stevel */ 750 0 stevel for (; *vp; vp++) { 751 0 stevel for (mbp = *vp; *mbp; mbp++) { 752 0 stevel *obp++ = *mbp & TRIM; 753 0 stevel if (--ocnt == 0) { 754 0 stevel (void) write_(0, obuf, BUFSIZ); 755 0 stevel obp = obuf; ocnt = BUFSIZ; 756 0 stevel } 757 0 stevel } 758 0 stevel *obp++ = '\n'; 759 0 stevel if (--ocnt == 0) { 760 0 stevel (void) write_(0, obuf, BUFSIZ); 761 0 stevel obp = obuf; ocnt = BUFSIZ; 762 0 stevel } 763 0 stevel } 764 0 stevel if (pargv) 765 0 stevel blkfree(pargv), pargv = 0; 766 0 stevel } 767 0 stevel } 768