STATIC void expbackq(shinstance *psh, union node *cmd, int quoted, int flag) { struct backcmd in; int i; char buf[128]; char *p; char *dest = psh->expdest; struct ifsregion saveifs, *savelastp; struct nodelist *saveargbackq; char lastc; int startloc = (int)(dest - stackblock(psh)); char const *syntax = quoted? DQSYNTAX : BASESYNTAX; int saveherefd; int quotes = flag & (EXP_FULL | EXP_CASE); #ifdef SH_DEAL_WITH_CRLF int pending_cr = 0; #endif INTOFF; saveifs = psh->ifsfirst; savelastp = psh->ifslastp; saveargbackq = psh->argbackq; saveherefd = psh->herefd; psh->herefd = -1; p = grabstackstr(psh, dest); evalbackcmd(psh, cmd, &in); ungrabstackstr(psh, p, dest); psh->ifsfirst = saveifs; psh->ifslastp = savelastp; psh->argbackq = saveargbackq; psh->herefd = saveherefd; p = in.buf; lastc = '\0'; for (;;) { if (--in.nleft < 0) { if (in.fd < 0) break; while ((i = shfile_read(&psh->fdtab, in.fd, buf, sizeof buf)) < 0 && errno == EINTR); TRACE((psh, "expbackq: read returns %d\n", i)); if (i <= 0) break; p = buf; in.nleft = i - 1; } lastc = *p++; #ifdef SH_DEAL_WITH_CRLF if (pending_cr) { pending_cr = 0; if (lastc != '\n') { if (quotes && syntax[(int)'\r'] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, '\r', dest); } } if (lastc == '\r') pending_cr = '\r'; else #endif if (lastc != '\0') { if (quotes && syntax[(int)lastc] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, lastc, dest); } } #ifdef SH_DEAL_WITH_CRLF if (pending_cr) { if (quotes && syntax[(int)'\r'] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, '\r', dest); } #endif /* Eat all trailing newlines */ p = stackblock(psh) + startloc; while (dest > p && dest[-1] == '\n') STUNPUTC(psh, dest); if (in.fd >= 0) shfile_close(&psh->fdtab, in.fd); if (in.buf) ckfree(psh, in.buf); if (in.jp) psh->back_exitstatus = waitforjob(psh, in.jp); if (quoted == 0) recordregion(psh, startloc, (int)(dest - stackblock(psh)), 0); TRACE((psh, "evalbackq: size=%d: \"%.*s\"\n", (dest - stackblock(psh)) - startloc, (dest - stackblock(psh)) - startloc, stackblock(psh) + startloc)); psh->expdest = dest; INTON; }
int readcmd(shinstance *psh, int argc, char **argv) { char **ap; char c; int rflag; char *prompt; const char *ifs; char *p; int startword; int status; int i; int is_ifs; int saveall = 0; rflag = 0; prompt = NULL; while ((i = nextopt(psh, "p:r")) != '\0') { if (i == 'p') prompt = psh->optionarg; else rflag = 1; } if (prompt && shfile_isatty(&psh->fdtab, 0)) { out2str(psh, prompt); output_flushall(psh); } if (*(ap = psh->argptr) == NULL) error(psh, "arg count"); if ((ifs = bltinlookup(psh, "IFS", 1)) == NULL) ifs = " \t\n"; status = 0; startword = 2; STARTSTACKSTR(psh, p); for (;;) { if (shfile_read(&psh->fdtab, 0, &c, 1) != 1) { status = 1; break; } if (c == '\0') continue; if (c == '\\' && !rflag) { if (shfile_read(&psh->fdtab, 0, &c, 1) != 1) { status = 1; break; } if (c != '\n') STPUTC(psh, c, p); continue; } if (c == '\n') break; if (strchr(ifs, c)) is_ifs = strchr(" \t\n", c) ? 1 : 2; else is_ifs = 0; if (startword != 0) { if (is_ifs == 1) { /* Ignore leading IFS whitespace */ if (saveall) STPUTC(psh, c, p); continue; } if (is_ifs == 2 && startword == 1) { /* Only one non-whitespace IFS per word */ startword = 2; if (saveall) STPUTC(psh, c, p); continue; } } if (is_ifs == 0) { /* append this character to the current variable */ startword = 0; if (saveall) /* Not just a spare terminator */ saveall++; STPUTC(psh, c, p); continue; } /* end of variable... */ startword = is_ifs; if (ap[1] == NULL) { /* Last variable needs all IFS chars */ saveall++; STPUTC(psh, c, p); continue; } STACKSTRNUL(psh, p); setvar(psh, *ap, stackblock(psh), 0); ap++; STARTSTACKSTR(psh, p); } STACKSTRNUL(psh, p); /* Remove trailing IFS chars */ for (; stackblock(psh) <= --p; *p = 0) { if (!strchr(ifs, *p)) break; if (strchr(" \t\n", *p)) /* Always remove whitespace */ continue; if (saveall > 1) /* Don't remove non-whitespace unless it was naked */ break; } setvar(psh, *ap, stackblock(psh), 0); /* Set any remaining args to "" */ while (*++ap != NULL) setvar(psh, *ap, nullstr, 0); return status; }