/* * Perform expansions on an argument, placing the resulting list of arguments * in arglist. Parameter expansion, command substitution and arithmetic * expansion are always performed; additional expansions can be requested * via flag (EXP_*). * The result is left in the stack string. * When arglist is NULL, perform here document expansion. * * When doing something that may cause this to be re-entered, make sure * the stack string is empty via grabstackstr() and do not assume expdest * remains valid. */ void expandarg(union node *arg, struct arglist *arglist, int flag) { struct worddest exparg; struct nodelist *argbackq; if (fflag) flag &= ~EXP_GLOB; argbackq = arg->narg.backquote; exparg.list = arglist; exparg.state = WORD_IDLE; STARTSTACKSTR(expdest); argstr(arg->narg.text, &argbackq, flag, &exparg); if (arglist == NULL) { STACKSTRNUL(expdest); return; /* here document expanded */ } if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() || exparg.state == WORD_QUOTEMARK) { STPUTC('\0', expdest); if (flag & EXP_SPLIT) { if (flag & EXP_GLOB) expandmeta(grabstackstr(expdest), exparg.list); else appendarglist(exparg.list, grabstackstr(expdest)); } } if ((flag & EXP_SPLIT) == 0) appendarglist(arglist, grabstackstr(expdest)); }
static int subevalvar_misc(char *p, const char *var, int subtype, int startloc, int varflags) { char *startp; struct nodelist *saveargbackq = argbackq; int amount; argstr(p, EXP_TILDE, NULL); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; switch (subtype) { case VSASSIGN: setvar(var, startp, 0); amount = startp - expdest; STADJUST(amount, expdest); return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(out2, "%s\n", startp); error((char *)NULL); } error("%.*s: parameter %snot set", (int)(p - var - 1), var, (varflags & VSNUL) ? "null or " : ""); return 0; default: abort(); } }
int readcmd(int argc, char **argv) { char **ap; int backslash; char c; int rflag; char *prompt; char *p; int status; int i; rflag = 0; prompt = NULL; while ((i = nextopt("p:r")) != '\0') { if (i == 'p') prompt = optionarg; else rflag = 1; } if (prompt && isatty(0)) { out2str(prompt); #ifdef FLUSHERR flushall(); #endif } if (*(ap = argptr) == NULL) sh_error("arg count"); status = 0; backslash = 0; STARTSTACKSTR(p); for (;;) { if (read(0, &c, 1) != 1) { status = 1; break; } if (c == '\0') continue; if (backslash) { if (c == '\n') goto resetbs; STPUTC(CTLESC, p); goto put; } if (!rflag && c == '\\') { backslash++; continue; } if (c == '\n') break; put: STPUTC(c, p); resetbs: backslash = 0; } STACKSTRNUL(p); readcmd_handle_line(stackblock(), ap, p + 1 - (char *)stackblock()); return status; }
/* * Perform expansions on an argument, placing the resulting list of arguments * in arglist. Parameter expansion, command substitution and arithmetic * expansion are always performed; additional expansions can be requested * via flag (EXP_*). * The result is left in the stack string. * When arglist is NULL, perform here document expansion. * * Caution: this function uses global state and is not reentrant. * However, a new invocation after an interrupted invocation is safe * and will reset the global state for the new call. */ void expandarg(union node* arg, struct arglist* arglist, int32_t flag) { struct strlist* sp; cstring_t p; argbackq = arg->narg.backquote; STARTSTACKSTR(expdest); ifsfirst.next = NULL; ifslastp = NULL; argstr(arg->narg.text, flag); if (arglist == NULL) { STACKSTRNUL(expdest); return; /* here document expanded */ } STPUTC('\0', expdest); p = grabstackstr(expdest); exparg.lastp = &exparg.list; /* * TODO - EXP_REDIR */ if (flag & EXP_FULL) { ifsbreakup(p, &exparg); *exparg.lastp = NULL; exparg.lastp = &exparg.list; expandmeta(exparg.list, flag); } else { if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ rmescapes(p); sp = (struct strlist*)stalloc(sizeof(struct strlist)); sp->text = p; *exparg.lastp = sp; exparg.lastp = &sp->next; } while (ifsfirst.next != NULL) { pifsregion_t ifsp; INTOFF; ifsp = ifsfirst.next->next; ckfree(ifsfirst.next); ifsfirst.next = ifsp; INTON; } *exparg.lastp = NULL; if (exparg.list) { *arglist->lastp = exparg.list; arglist->lastp = exparg.lastp; } }
/* * Perform tilde expansion, placing the result in the stack string and * returning the next position in the input string to process. */ static const char * exptilde(const char *p, int flag) { char c; const char *startp = p; const char *user; struct passwd *pw; char *home; int len; for (;;) { c = *p; switch(c) { case CTLESC: /* This means CTL* are always considered quoted. */ case CTLVAR: case CTLBACKQ: case CTLBACKQ | CTLQUOTE: case CTLARI: case CTLENDARI: case CTLQUOTEMARK: return (startp); case ':': if ((flag & EXP_VARTILDE) == 0) break; /* FALLTHROUGH */ case '\0': case '/': case CTLENDVAR: len = p - startp - 1; STPUTBIN(startp + 1, len, expdest); STACKSTRNUL(expdest); user = expdest - len; if (*user == '\0') { home = lookupvar("HOME"); } else { pw = getpwnam(user); home = pw != NULL ? pw->pw_dir : NULL; } STADJUST(-len, expdest); if (home == NULL || *home == '\0') return (startp); strtodest(home, flag, VSNORMAL, 1, NULL); return (p); } p++; } }
/* * Perform expansions on an argument, placing the resulting list of arguments * in arglist. Parameter expansion, command substitution and arithmetic * expansion are always performed; additional expansions can be requested * via flag (EXP_*). * The result is left in the stack string. * When arglist is NULL, perform here document expansion. * * Caution: this function uses global state and is not reentrant. * However, a new invocation after an interrupted invocation is safe * and will reset the global state for the new call. */ void expandarg(union node *arg, struct arglist *arglist, int flag) { struct strlist *sp; char *p; argbackq = arg->narg.backquote; STARTSTACKSTR(expdest); ifsfirst.next = NULL; ifslastp = NULL; argstr(arg->narg.text, flag); if (arglist == NULL) { STACKSTRNUL(expdest); return; /* here document expanded */ } STPUTC('\0', expdest); p = grabstackstr(expdest); exparg.lastp = &exparg.list; if (flag & EXP_FULL) { ifsbreakup(p, &exparg); *exparg.lastp = NULL; exparg.lastp = &exparg.list; expandmeta(exparg.list); } else { sp = (struct strlist *)stalloc(sizeof (struct strlist)); sp->text = p; *exparg.lastp = sp; exparg.lastp = &sp->next; } while (ifsfirst.next != NULL) { struct ifsregion *ifsp; INTOFF; ifsp = ifsfirst.next->next; ckfree(ifsfirst.next); ifsfirst.next = ifsp; INTON; } *exparg.lastp = NULL; if (exparg.list) { *arglist->lastp = exparg.list; arglist->lastp = exparg.lastp; } }
STATIC const char * fc_replace(const char *s, char *p, char *r) { char *dest; int plen = strlen(p); STARTSTACKSTR(dest); while (*s) { if (*s == *p && strncmp(s, p, plen) == 0) { while (*r) STPUTC(*r++, dest); s += plen; *p = '\0'; /* so no more matches */ } else STPUTC(*s++, dest); } STACKSTRNUL(dest); dest = grabstackstr(dest); return (dest); }
static int subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) { char *startp; char *loc = NULL; char *q; int c = 0; struct nodelist *saveargbackq = argbackq; int amount; argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ? EXP_CASE : 0) | EXP_TILDE); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; if (str == NULL) str = stackblock() + strloc; switch (subtype) { case VSASSIGN: setvar(str, startp, 0); amount = startp - expdest; STADJUST(amount, expdest); varflags &= ~VSNUL; return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(out2, "%s\n", startp); error((char *)NULL); } error("%.*s: parameter %snot set", (int)(p - str - 1), str, (varflags & VSNUL) ? "null or " : ""); return 0; case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(str, startp, quotes)) { *loc = c; recordleft(str, loc, startp); return 1; } *loc = c; if (quotes && *loc == CTLESC) loc++; } return 0; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(str, startp, quotes)) { *loc = c; recordleft(str, loc, startp); return 1; } *loc = c; loc--; if (quotes && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(str, loc, quotes)) { amount = loc - expdest; STADJUST(amount, expdest); return 1; } loc--; if (quotes && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(str, loc, quotes)) { amount = loc - expdest; STADJUST(amount, expdest); return 1; } if (quotes && *loc == CTLESC) loc++; } return 0; default: abort(); } }
int readcmd(int argc, char **argv) { char **ap; char c; int rflag; char *prompt; char *p; int startloc; int newloc; int status; int i; rflag = 0; prompt = NULL; while ((i = nextopt("p:r")) != '\0') { if (i == 'p') prompt = optionarg; else rflag = 1; } if (prompt && isatty(0)) { out2str(prompt); #ifdef FLUSHERR flushall(); #endif } if (*(ap = argptr) == NULL) sh_error("arg count"); status = 0; STARTSTACKSTR(p); goto start; for (;;) { switch (read(0, &c, 1)) { case 1: break; default: if (errno == EINTR && !pendingsigs) continue; /* fall through */ case 0: status = 1; goto out; } if (c == '\0') continue; if (newloc >= startloc) { if (c == '\n') goto resetbs; goto put; } if (!rflag && c == '\\') { newloc = p - (char *)stackblock(); continue; } if (c == '\n') break; put: CHECKSTRSPACE(2, p); if (strchr(qchars, c)) USTPUTC(CTLESC, p); USTPUTC(c, p); if (newloc >= startloc) { resetbs: recordregion(startloc, newloc, 0); start: startloc = p - (char *)stackblock(); newloc = startloc - 1; } } out: recordregion(startloc, p - (char *)stackblock(), 0); STACKSTRNUL(p); readcmd_handle_line(p + 1, ap); return status; }
STATIC int subevalvar(shinstance *psh, char *p, char *str, int strloc, int subtype, int startloc, int varflags) { char *startp; char *loc = NULL; char *q; int c = 0; int saveherefd = psh->herefd; struct nodelist *saveargbackq = psh->argbackq; int amount; psh->herefd = -1; argstr(psh, p, 0); STACKSTRNUL(psh, psh->expdest); psh->herefd = saveherefd; psh->argbackq = saveargbackq; startp = stackblock(psh) + startloc; if (str == NULL) str = stackblock(psh) + strloc; switch (subtype) { case VSASSIGN: setvar(psh, str, startp, 0); amount = (int)(startp - psh->expdest); STADJUST(psh, amount, psh->expdest); varflags &= ~VSNUL; if (c != 0) *loc = c; return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(&psh->errout, "%s\n", startp); error(psh, (char *)NULL); } error(psh, "%.*s: parameter %snot set", p - str - 1, str, (varflags & VSNUL) ? "null or " : nullstr); /* NOTREACHED */ case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(psh, str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(psh, str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(psh, str, loc, varflags & VSQUOTE)) goto recordright; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(psh, str, loc, varflags & VSQUOTE)) goto recordright; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; default: sh_abort(psh); } recordleft: *loc = c; amount = (int)(((str - 1) - (loc - startp)) - psh->expdest); STADJUST(psh, amount, psh->expdest); while (loc != str - 1) *startp++ = *loc++; return 1; recordright: amount = (int)(loc - psh->expdest); STADJUST(psh, amount, psh->expdest); STPUTC(psh, '\0', psh->expdest); STADJUST(psh, -1, psh->expdest); return 1; }
int readcmd(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("p:r")) != '\0') { if (i == 'p') prompt = optionarg; else rflag = 1; } if (prompt && isatty(0)) { out2str(prompt); flushall(); } if (*(ap = argptr) == NULL) error("arg count"); if ((ifs = bltinlookup("IFS", 1)) == NULL) ifs = " \t\n"; status = 0; startword = 2; STARTSTACKSTR(p); for (;;) { if (read(0, &c, 1) != 1) { status = 1; break; } if (c == '\0') continue; if (c == '\\' && !rflag) { if (read(0, &c, 1) != 1) { status = 1; break; } if (c != '\n') STPUTC(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(c, p); continue; } if (is_ifs == 2 && startword == 1) { /* Only one non-whitespace IFS per word */ startword = 2; if (saveall) STPUTC(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(c, p); continue; } /* end of variable... */ startword = is_ifs; if (ap[1] == NULL) { /* Last variable needs all IFS chars */ saveall++; STPUTC(c, p); continue; } STACKSTRNUL(p); setvar(*ap, stackblock(), 0); ap++; STARTSTACKSTR(p); } STACKSTRNUL(p); /* Remove trailing IFS chars */ for (; stackblock() <= --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(*ap, stackblock(), 0); /* Set any remaining args to "" */ while (*++ap != NULL) setvar(*ap, nullstr, 0); return status; }
STATIC int subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags) { char *startp; char *loc = NULL; char *q; int c = 0; int saveherefd = herefd; struct nodelist *saveargbackq = argbackq; int amount, how; herefd = -1; switch (subtype) { case VSTRIMLEFT: case VSTRIMLEFTMAX: case VSTRIMRIGHT: case VSTRIMRIGHTMAX: how = (varflags & VSQUOTE) ? 0 : EXP_CASE; break; default: how = 0; break; } argstr(p, how); STACKSTRNUL(expdest); herefd = saveherefd; argbackq = saveargbackq; startp = stackblock() + startloc; if (str == NULL) str = stackblock() + strloc; switch (subtype) { case VSASSIGN: setvar(str, startp, 0); amount = startp - expdest; STADJUST(amount, expdest); varflags &= ~VSNUL; return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(&errout, "%s\n", startp); error(NULL); } error("%.*s: parameter %snot set", (int)(p - str - 1), str, (varflags & VSNUL) ? "null or " : nullstr); /* NOTREACHED */ case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(str, loc, varflags & VSQUOTE)) goto recordright; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(str, loc, varflags & VSQUOTE)) goto recordright; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; default: abort(); } recordleft: *loc = c; amount = ((str - 1) - (loc - startp)) - expdest; STADJUST(amount, expdest); while (loc != str - 1) *startp++ = *loc++; return 1; recordright: amount = loc - expdest; STADJUST(amount, expdest); STPUTC('\0', expdest); STADJUST(-1, expdest); return 1; }
static int32_t subevalvar(cstring_t p, cstring_t str, size_t strloc, uint32_t subtype, size_t startloc, uint32_t varflags, uint32_t quotes) { cstring_t startp; cstring_t loc = NULL; cstring_t q; char32_t c = 0; struct nodelist* saveargbackq = argbackq; size_t amount; argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ? EXP_CASE : 0) | EXP_TILDE); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; if (str == NULL) str = stackblock() + strloc; switch (subtype) { case VSASSIGN: setvar(str, startp, 0); amount = startp - expdest; STADJUST(amount, expdest); varflags &= ~VSNUL; return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(out2, "%s\n", startp); sherror((cstring_t)NULL); } sherror("%.*s: parameter %snot set", (int32_t)(p - str - 1), str, (varflags & VSNUL) ? "null or " : nullstr); NOTREACHED; case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(str, startp, quotes)) { *loc = (cchar_t)c; goto recordleft; } *loc = (cchar_t)c; if (quotes && *loc == CTLESC) loc++; } return 0; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(str, startp, quotes)) { *loc = (cchar_t)c; goto recordleft; } *loc = (cchar_t)c; loc--; if (quotes && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(str, loc, quotes)) { amount = loc - expdest; STADJUST(amount, expdest); return 1; } loc--; if (quotes && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(str, loc, quotes)) { amount = loc - expdest; STADJUST(amount, expdest); return 1; } if (quotes && *loc == CTLESC) loc++; } return 0; default: abort(); } recordleft: amount = ((str - 1) - (loc - startp)) - expdest; STADJUST(amount, expdest); while (loc != str - 1) *startp++ = *loc++; return 1; }
static void subevalvar_trim(char *p, int strloc, int subtype, int startloc) { char *startp; char *loc = NULL; char *str; int c = 0; struct nodelist *saveargbackq = argbackq; int amount; argstr(p, EXP_CASE | EXP_TILDE, NULL); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; str = stackblock() + strloc; switch (subtype) { case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(str, startp)) { *loc = c; recordleft(str, loc, startp); return; } *loc = c; } break; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(str, startp)) { *loc = c; recordleft(str, loc, startp); return; } *loc = c; loc--; } break; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(str, loc)) { amount = loc - expdest; STADJUST(amount, expdest); return; } loc--; } break; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(str, loc)) { amount = loc - expdest; STADJUST(amount, expdest); return; } } break; default: abort(); } amount = (expdest - stackblock() - strloc) + 1; STADJUST(-amount, expdest); }
int readcmd(int argc, char **argv) { char **ap; char c; int rflag; char *prompt; char *p; int startloc; int newloc; int status; int timeout; int i; fd_set set; struct timeval ts, t0, t1, to; ts.tv_sec = ts.tv_usec = 0; rflag = 0; timeout = 0; prompt = NULL; while ((i = nextopt("p:rt:")) != '\0') { switch(i) { case 'p': prompt = optionarg; break; case 't': p = strtotimeval(optionarg, &ts); if (*p || (!ts.tv_sec && !ts.tv_usec)) sh_error("invalid timeout"); timeout = 1; break; case 'r': rflag = 1; break; default: break; } } if (prompt && isatty(0)) { out2str(prompt); #ifdef FLUSHERR flushall(); #endif } if (*(ap = argptr) == NULL) sh_error("arg count"); status = 0; if (timeout) { gettimeofday(&t0, NULL); /* ts += t0; */ ts.tv_usec += t0.tv_usec; while (ts.tv_usec >= 1000000) { ts.tv_sec++; ts.tv_usec -= 1000000; } ts.tv_sec += t0.tv_sec; } STARTSTACKSTR(p); goto start; for (;;) { if (timeout) { gettimeofday(&t1, NULL); if (t1.tv_sec > ts.tv_sec || (t1.tv_sec == ts.tv_sec && t1.tv_usec >= ts.tv_usec)) { status = 1; break; /* Timeout! */ } /* to = ts - t1; */ if (ts.tv_usec >= t1.tv_usec) { to.tv_usec = ts.tv_usec - t1.tv_usec; to.tv_sec = ts.tv_sec - t1.tv_sec; } else { to.tv_usec = ts.tv_usec - t1.tv_usec + 1000000; to.tv_sec = ts.tv_sec - t1.tv_sec - 1; } FD_ZERO(&set); FD_SET(0, &set); if (select(1, &set, NULL, NULL, &to) != 1) { status = 1; break; /* Timeout! */ } } switch (read(0, &c, 1)) { case 1: break; default: if (errno == EINTR && !pendingsigs) continue; /* fall through */ case 0: status = 1; goto out; } if (c == '\0') continue; if (newloc >= startloc) { if (c == '\n') goto resetbs; goto put; } if (!rflag && c == '\\') { newloc = p - (char *)stackblock(); continue; } if (c == '\n') break; put: CHECKSTRSPACE(2, p); if (strchr(qchars, c)) USTPUTC(CTLESC, p); USTPUTC(c, p); if (newloc >= startloc) { resetbs: recordregion(startloc, newloc, 0); start: startloc = p - (char *)stackblock(); newloc = startloc - 1; } } out: recordregion(startloc, p - (char *)stackblock(), 0); STACKSTRNUL(p); readcmd_handle_line(p + 1, ap); return status; }