/* * Subroutine to do actual fixing after state initialization. */ void Dfix2(tchar **v) { tchar *agargv[GAVSIZ]; #ifdef TRACE tprintf("TRACE- Dfix2()\n"); #endif ginit(agargv); /* Initialize glob's area pointers */ Dvp = v; Dcp = S_ /* "" */; /* Setup input vector for Dreadc */ unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ while (Dword()) continue; gargv = copyblk(gargv); }
/* * Pack up more characters in this word */ static Char * Dpack(Char *wbuf, Char *wp) { int c; int i = MAXWLEN - (wp - wbuf); for (;;) { c = DgetC(DODOL); if (c == '\\') { c = DgetC(0); if (c == DEOF) { unDredc(c); *wp = 0; Gcat(STRNULL, wbuf); return (NULL); } if (c == '\n') c = ' '; else c |= QUOTE; } if (c == DEOF) { unDredc(c); *wp = 0; Gcat(STRNULL, wbuf); return (NULL); } if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */ unDgetC(c); if (cmap(c, QUOTES)) return (wp); *wp++ = 0; Gcat(STRNULL, wbuf); return (NULL); } if (--i <= 0) stderror(ERR_WTOOLONG); *wp++ = c; } }
/* * Form a shell temporary file (in unit 0) from the words * of the shell input up to EOF or a line the same as "term". * Unit 0 should have been closed before this call. */ void /*ARGSUSED*/ heredoc(Char *term) { int c; Char *Dv[2]; Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; int ocnt, lcnt, mcnt; Char *lbp, *obp, *mbp; Char **vp; bool quoted; char tmp[] = "/tmp/sh.XXXXXXXX"; if (mkstemp(tmp) < 0) stderror(ERR_SYSTEM, tmp, strerror(errno)); (void) unlink(tmp); /* 0 0 inode! */ Dv[0] = term; Dv[1] = NULL; gflag = 0; trim(Dv); rscan(Dv, Dtestq); quoted = gflag; ocnt = BUFSIZ; obp = obuf; for (;;) { /* * Read up a line */ lbp = lbuf; lcnt = BUFSIZ - 4; for (;;) { c = readc(1); /* 1 -> Want EOF returns */ if (c < 0 || c == '\n') break; if ((c &= TRIM) != '\0') { *lbp++ = c; if (--lcnt < 0) { setname("<<"); stderror(ERR_NAME | ERR_OVERFLOW); } } } *lbp = 0; /* * Check for EOF or compare to terminator -- before expansion */ if (c < 0 || eq(lbuf, term)) { (void) write(STDIN_FILENO, short2str(obuf), (size_t) (BUFSIZ - ocnt)); (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET); return; } /* * If term was quoted or -n just pass it on */ if (quoted || noexec) { *lbp++ = '\n'; *lbp = 0; for (lbp = lbuf; (c = *lbp++) != '\0';) { *obp++ = c; if (--ocnt == 0) { (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } continue; } /* * Term wasn't quoted so variable and then command expand the input * line */ Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; for (;;) { c = DgetC(DODOL); if (c == DEOF) break; if ((c &= TRIM) == 0) continue; /* \ quotes \ $ ` here */ if (c == '\\') { c = DgetC(0); if (!any("$\\`", c)) unDgetC(c | QUOTE), c = '\\'; else c |= QUOTE; } *mbp++ = c; if (--mcnt == 0) { setname("<<"); stderror(ERR_NAME | ERR_OVERFLOW); } } *mbp++ = 0; /* * If any ` in line do command substitution */ mbp = mbuf; if (any(short2str(mbp), '`')) { /* * 1 arg to dobackp causes substitution to be literal. Words are * broken only at newlines so that all blanks and tabs are * preserved. Blank lines (null words) are not discarded. */ vp = dobackp(mbuf, 1); } else /* Setup trivial vector similar to return of dobackp */ Dv[0] = mbp, Dv[1] = NULL, vp = Dv; /* * Resurrect the words from the command substitution each separated by * a newline. Note that the last newline of a command substitution * will have been discarded, but we put a newline after the last word * because this represents the newline after the last input line! */ for (; *vp; vp++) { for (mbp = *vp; *mbp; mbp++) { *obp++ = *mbp & TRIM; if (--ocnt == 0) { (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } *obp++ = '\n'; if (--ocnt == 0) { (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } if (pargv) blkfree(pargv), pargv = 0; } }
/* * Get a word. This routine is analogous to the routine * word() in sh.lex.c for the main lexical input. One difference * here is that we don't get a newline to terminate our expansion. * Rather, DgetC will return a DEOF when we hit the end-of-input. */ static int Dword(void) { int c, c1; Char wbuf[BUFSIZ]; Char *wp = wbuf; int i = MAXWLEN; bool dolflg; bool sofar = 0, done = 0; while (!done) { done = 1; c = DgetC(DODOL); switch (c) { case DEOF: if (sofar == 0) return (0); /* finish this word and catch the code above the next time */ unDredc(c); /* fall into ... */ case '\n': *wp = 0; Gcat(STRNULL, wbuf); return (1); case ' ': case '\t': done = 0; break; case '`': /* We preserve ` quotations which are done yet later */ *wp++ = c, --i; case '\'': case '"': /* * Note that DgetC never returns a QUOTES character from an * expansion, so only true input quotes will get us here or out. */ c1 = c; dolflg = c1 == '"' ? DODOL : 0; for (;;) { c = DgetC(dolflg); if (c == c1) break; if (c == '\n' || c == DEOF) stderror(ERR_UNMATCHED, c1); if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) --wp, ++i; if (--i <= 0) stderror(ERR_WTOOLONG); switch (c1) { case '"': /* * Leave any `s alone for later. Other chars are all * quoted, thus `...` can tell it was within "...". */ *wp++ = c == '`' ? '`' : c | QUOTE; break; case '\'': /* Prevent all further interpretation */ *wp++ = c | QUOTE; break; case '`': /* Leave all text alone for later */ *wp++ = c; break; default: break; } } if (c1 == '`') *wp++ = '`' /* i--; eliminated */; sofar = 1; if ((wp = Dpack(wbuf, wp)) == NULL) return (1); else { i = MAXWLEN - (wp - wbuf); done = 0; } break; case '\\': c = DgetC(0); /* No $ subst! */ if (c == '\n' || c == DEOF) { done = 0; break; } c |= QUOTE; break; default: break; } if (done) { unDgetC(c); sofar = 1; if ((wp = Dpack(wbuf, wp)) == NULL) return (1); else { i = MAXWLEN - (wp - wbuf); done = 0; } } } /* Really NOTREACHED */ return (0); }
/* * Form a shell temporary file (in unit 0) from the words * of the shell input up to EOF or a line the same as "term". * Unit 0 should have been closed before this call. */ void heredoc(Char *term) { eChar c; Char *Dv[2]; struct Strbuf lbuf = Strbuf_INIT, mbuf = Strbuf_INIT; Char obuf[BUFSIZE + 1]; #define OBUF_END (obuf + sizeof(obuf) / sizeof (*obuf) - 1) Char *lbp, *obp, *mbp; Char **vp; int quoted; #ifdef HAVE_MKSTEMP char *tmp = short2str(shtemp); char *dot = strrchr(tmp, '.'); if (!dot) stderror(ERR_NAME | ERR_NOMATCH); strcpy(dot, TMP_TEMPLATE); xclose(0); if (mkstemp(tmp) == -1) stderror(ERR_SYSTEM, tmp, strerror(errno)); #else /* !HAVE_MKSTEMP */ char *tmp; # ifndef WINNT_NATIVE again: # endif /* WINNT_NATIVE */ tmp = short2str(shtemp); # if O_CREAT == 0 if (xcreat(tmp, 0600) < 0) stderror(ERR_SYSTEM, tmp, strerror(errno)); # endif xclose(0); if (xopen(tmp, O_RDWR|O_CREAT|O_EXCL|O_TEMPORARY|O_LARGEFILE, 0600) == -1) { int oerrno = errno; # ifndef WINNT_NATIVE if (errno == EEXIST) { if (unlink(tmp) == -1) { xfree(shtemp); mbp = randsuf(); shtemp = Strspl(STRtmpsh, mbp); xfree(mbp); } goto again; } # endif /* WINNT_NATIVE */ (void) unlink(tmp); errno = oerrno; stderror(ERR_SYSTEM, tmp, strerror(errno)); } #endif /* HAVE_MKSTEMP */ (void) unlink(tmp); /* 0 0 inode! */ Dv[0] = term; Dv[1] = NULL; gflag = 0; trim(Dv); rscan(Dv, Dtestq); quoted = gflag; obp = obuf; obuf[BUFSIZE] = 0; inheredoc = 1; cleanup_push(&inheredoc, inheredoc_cleanup); #ifdef WINNT_NATIVE __dup_stdin = 1; #endif /* WINNT_NATIVE */ cleanup_push(&lbuf, Strbuf_cleanup); cleanup_push(&mbuf, Strbuf_cleanup); for (;;) { Char **words; /* * Read up a line */ lbuf.len = 0; for (;;) { c = readc(1); /* 1 -> Want EOF returns */ if (c == CHAR_ERR || c == '\n') break; if ((c &= TRIM) != 0) Strbuf_append1(&lbuf, (Char) c); } Strbuf_terminate(&lbuf); /* Catch EOF in the middle of a line. */ if (c == CHAR_ERR && lbuf.len != 0) c = '\n'; /* * Check for EOF or compare to terminator -- before expansion */ if (c == CHAR_ERR || eq(lbuf.s, term)) break; /* * If term was quoted or -n just pass it on */ if (quoted || noexec) { Strbuf_append1(&lbuf, '\n'); Strbuf_terminate(&lbuf); for (lbp = lbuf.s; (c = *lbp++) != 0;) { *obp++ = (Char) c; if (obp == OBUF_END) { tmp = short2str(obuf); (void) xwrite(0, tmp, strlen (tmp)); obp = obuf; } } continue; } /* * Term wasn't quoted so variable and then command expand the input * line */ Dcp = lbuf.s; Dvp = Dv + 1; mbuf.len = 0; for (;;) { c = DgetC(DODOL); if (c == DEOF) break; if ((c &= TRIM) == 0) continue; /* \ quotes \ $ ` here */ if (c == '\\') { c = DgetC(0); if (!any("$\\`", c)) unDgetC(c | QUOTE), c = '\\'; else c |= QUOTE; } Strbuf_append1(&mbuf, (Char) c); } Strbuf_terminate(&mbuf); /* * If any ` in line do command substitution */ mbp = mbuf.s; if (Strchr(mbp, '`') != NULL) { /* * 1 arg to dobackp causes substitution to be literal. Words are * broken only at newlines so that all blanks and tabs are * preserved. Blank lines (null words) are not discarded. */ words = dobackp(mbp, 1); } else /* Setup trivial vector similar to return of dobackp */ Dv[0] = mbp, Dv[1] = NULL, words = Dv; /* * Resurrect the words from the command substitution each separated by * a newline. Note that the last newline of a command substitution * will have been discarded, but we put a newline after the last word * because this represents the newline after the last input line! */ for (vp= words; *vp; vp++) { for (mbp = *vp; *mbp; mbp++) { *obp++ = *mbp & TRIM; if (obp == OBUF_END) { tmp = short2str(obuf); (void) xwrite(0, tmp, strlen (tmp)); obp = obuf; } } *obp++ = '\n'; if (obp == OBUF_END) { tmp = short2str(obuf); (void) xwrite(0, tmp, strlen (tmp)); obp = obuf; } } if (words != Dv) blkfree(words); } *obp = 0; tmp = short2str(obuf); (void) xwrite(0, tmp, strlen (tmp)); (void) lseek(0, (off_t) 0, L_SET); cleanup_until(&inheredoc); }
/* * Get a word. This routine is analogous to the routine * word() in sh.lex.c for the main lexical input. One difference * here is that we don't get a newline to terminate our expansion. * Rather, DgetC will return a DEOF when we hit the end-of-input. */ static int Dword(struct blk_buf *bb) { eChar c, c1; struct Strbuf *wbuf = Strbuf_alloc(); int dolflg; int sofar = 0; Char *str; cleanup_push(wbuf, Strbuf_free); for (;;) { c = DgetC(DODOL); switch (c) { case DEOF: if (sofar == 0) { cleanup_until(wbuf); return (0); } /* finish this word and catch the code above the next time */ unDredc(c); /*FALLTHROUGH*/ case '\n': goto end; case ' ': case '\t': continue; case '`': /* We preserve ` quotations which are done yet later */ Strbuf_append1(wbuf, (Char) c); /*FALLTHROUGH*/ case '\'': case '"': /* * Note that DgetC never returns a QUOTES character from an * expansion, so only true input quotes will get us here or out. */ c1 = c; dolflg = c1 == '"' ? DODOL : 0; for (;;) { c = DgetC(dolflg); if (c == c1) break; if (c == '\n' || c == DEOF) { cleanup_until(bb); stderror(ERR_UNMATCHED, (int)c1); } if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) { if (wbuf->len != 0 && (wbuf->s[wbuf->len - 1] & TRIM) == '\\') wbuf->len--; } switch (c1) { case '"': /* * Leave any `s alone for later. Other chars are all * quoted, thus `...` can tell it was within "...". */ Strbuf_append1(wbuf, c == '`' ? '`' : c | QUOTE); break; case '\'': /* Prevent all further interpretation */ Strbuf_append1(wbuf, c | QUOTE); break; case '`': /* Leave all text alone for later */ Strbuf_append1(wbuf, (Char) c); break; default: break; } } if (c1 == '`') Strbuf_append1(wbuf, '`'); sofar = 1; if (Dpack(wbuf) != 0) goto end; continue; case '\\': c = DgetC(0); /* No $ subst! */ if (c == '\n' || c == DEOF) continue; c |= QUOTE; break; default: break; } unDgetC(c); sofar = 1; if (Dpack(wbuf) != 0) goto end; } end: cleanup_ignore(wbuf); cleanup_until(wbuf); str = Strbuf_finish(wbuf); bb_append(bb, str); xfree(wbuf); return 1; }
/* * Form a shell temporary file (in unit 0) from the words * of the shell input up to a line the same as "term". * Unit 0 should have been closed before this call. */ void heredoc(tchar *term) { int c; tchar *Dv[2]; tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; int ocnt, lcnt, mcnt; tchar *lbp, *obp, *mbp; tchar **vp; bool quoted; tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X', 'X', 'X', 'X', 0}; int fd1; #ifdef TRACE tprintf("TRACE- heredoc()\n"); #endif if ((fd1 = mkstemp_(shtemp)) < 0) Perror(shtemp); (void) unlink_(shtemp); /* 0 0 inode! */ unsetfd(fd1); Dv[0] = term; Dv[1] = NOSTR; gflag = 0; trim(Dv); rscan(Dv, Dtestq); quoted = gflag; ocnt = BUFSIZ; obp = obuf; for (;;) { /* * Read up a line */ lbp = lbuf; lcnt = BUFSIZ - 4; for (;;) { c = readc(1); /* 1 -> Want EOF returns */ if (c < 0) { setname(term); bferr("<< terminator not found"); } if (c == '\n') break; if (c &= TRIM) { *lbp++ = c; if (--lcnt < 0) { setname(S_LESLES /* "<<" */); error("Line overflow"); } } } *lbp = 0; /* * Compare to terminator -- before expansion */ if (eq(lbuf, term)) { (void) write_(0, obuf, BUFSIZ - ocnt); (void) lseek(0, (off_t)0, 0); return; } /* * If term was quoted or -n just pass it on */ if (quoted || noexec) { *lbp++ = '\n'; *lbp = 0; for (lbp = lbuf; c = *lbp++; ) { *obp++ = c; if (--ocnt == 0) { (void) write_(0, obuf, BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } continue; } /* * Term wasn't quoted so variable and then command * expand the input line */ Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; for (;;) { c = DgetC(DODOL); if (c == DEOF) break; if ((c &= TRIM) == 0) continue; /* \ quotes \ $ ` here */ if (c == '\\') { c = DgetC(0); /* if (!any(c, "$\\`")) */ if ((c != '$') && (c != '\\') && (c != '`')) unDgetC(c | QUOTE), c = '\\'; else c |= QUOTE; } *mbp++ = c; if (--mcnt == 0) { setname(S_LESLES /* "<<" */); bferr("Line overflow"); } } *mbp++ = 0; /* * If any ` in line do command substitution */ mbp = mbuf; if (any('`', mbp)) { /* * 1 arg to dobackp causes substitution to be literal. * Words are broken only at newlines so that all blanks * and tabs are preserved. Blank lines (null words) * are not discarded. */ vp = dobackp(mbuf, 1); } else /* Setup trivial vector similar to return of dobackp */ Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv; /* * Resurrect the words from the command substitution * each separated by a newline. Note that the last * newline of a command substitution will have been * discarded, but we put a newline after the last word * because this represents the newline after the last * input line! */ for (; *vp; vp++) { for (mbp = *vp; *mbp; mbp++) { *obp++ = *mbp & TRIM; if (--ocnt == 0) { (void) write_(0, obuf, BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } *obp++ = '\n'; if (--ocnt == 0) { (void) write_(0, obuf, BUFSIZ); obp = obuf; ocnt = BUFSIZ; } } if (pargv) blkfree(pargv), pargv = 0; } }
/* * Get a word. This routine is analogous to the routine * word() in sh.lex.c for the main lexical input. One difference * here is that we don't get a newline to terminate our expansion. * Rather, DgetC will return a DEOF when we hit the end-of-input. */ int Dword(void) { int c, c1; static tchar *wbuf = NULL; static int wbufsiz = BUFSIZ; int wp = 0; bool dolflg; bool sofar = 0; #define DYNAMICBUFFER() \ do { \ if (wp >= wbufsiz) { \ wbufsiz += BUFSIZ; \ wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \ } \ } while (0) #ifdef TRACE tprintf("TRACE- Dword()\n"); #endif if (wbuf == NULL) wbuf = xalloc((wbufsiz+1) * sizeof (tchar)); loop: c = DgetC(DODOL); switch (c) { case DEOF: deof: if (sofar == 0) return (0); /* finish this word and catch the code above the next time */ unDredc(c); /* fall into ... */ case '\n': wbuf[wp] = 0; goto ret; case ' ': case '\t': goto loop; case '`': /* We preserve ` quotations which are done yet later */ wbuf[wp++] = c; case '\'': case '"': /* * Note that DgetC never returns a QUOTES character * from an expansion, so only true input quotes will * get us here or out. */ c1 = c; dolflg = c1 == '"' ? DODOL : 0; for (;;) { c = DgetC(dolflg); if (c == c1) break; if (c == '\n' || c == DEOF) error("Unmatched %c", (tchar) c1); if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE)) --wp; DYNAMICBUFFER(); switch (c1) { case '"': /* * Leave any `s alone for later. * Other chars are all quoted, thus `...` * can tell it was within "...". */ wbuf[wp++] = c == '`' ? '`' : c | QUOTE; break; case '\'': /* Prevent all further interpretation */ wbuf[wp++] = c | QUOTE; break; case '`': /* Leave all text alone for later */ wbuf[wp++] = c; break; } } if (c1 == '`') { DYNAMICBUFFER(); wbuf[wp++] = '`'; } goto pack; /* continue the word */ case '\\': c = DgetC(0); /* No $ subst! */ if (c == '\n' || c == DEOF) goto loop; c |= QUOTE; break; #ifdef MBCHAR /* Could be a space char from aux. codeset. */ default: if (isauxsp(c)) goto loop; #endif /* MBCHAR */ } unDgetC(c); pack: sofar = 1; /* pack up more characters in this word */ for (;;) { c = DgetC(DODOL); if (c == '\\') { c = DgetC(0); if (c == DEOF) goto deof; if (c == '\n') c = ' '; else c |= QUOTE; } if (c == DEOF) goto deof; if (cmap(c, _SP|_NL|_Q|_Q1) || isauxsp(c)) { /* sp \t\n'"` or aux. sp */ unDgetC(c); if (cmap(c, QUOTES)) goto loop; DYNAMICBUFFER(); wbuf[wp++] = 0; goto ret; } DYNAMICBUFFER(); wbuf[wp++] = c; } ret: Gcat(S_ /* "" */, wbuf); return (1); }