/* * sscr_input -- * Read any waiting shell input. * * PUBLIC: int sscr_input(SCR *); */ int sscr_input(SCR *sp) { GS *gp; struct pollfd *pfd; int nfds, rval; gp = sp->gp; rval = 0; /* Allocate space for pfd. */ nfds = 0; TAILQ_FOREACH(sp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) nfds++; if (nfds == 0) return (0); pfd = calloc(nfds, sizeof(struct pollfd)); if (pfd == NULL) { msgq(sp, M_SYSERR, "malloc"); return (1); } /* Setup events bitmasks. */ nfds = 0; TAILQ_FOREACH(sp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) { pfd[nfds].fd = sp->script->sh_master; pfd[nfds].events = POLLIN; nfds++; } loop: /* Check for input. */ switch (poll(pfd, nfds, 0)) { case -1: msgq(sp, M_SYSERR, "poll"); rval = 1; /* FALLTHROUGH */ case 0: goto done; default: break; } /* Read the input. */ nfds = 0; TAILQ_FOREACH(sp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) { if ((pfd[nfds].revents & POLLHUP) && sscr_end(sp)) goto done; if ((pfd[nfds].revents & POLLIN) && sscr_insert(sp)) goto done; nfds++; } goto loop; done: free(pfd); return (rval); }
/* * sscr_getprompt -- * Eat lines printed by the shell until a line with no trailing * carriage return comes; set the prompt from that line. */ static int sscr_getprompt(SCR *sp) { struct timeval tv; fd_set fdset; int master; /* Wait up to a second for characters to read. */ tv.tv_sec = 5; tv.tv_usec = 0; master = sp->script->sh_master; FD_ZERO(&fdset); FD_SET(master, &fdset); switch (select(master + 1, &fdset, NULL, NULL, &tv)) { case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "select"); break; case 0: /* Timeout */ msgq(sp, M_ERR, "Error: timed out"); break; case 1: /* Characters to read. */ return (sscr_insert(sp) || sp->script == NULL); } sscr_end(sp); return (1); }
/* * ex_screen_end -- * End a vi screen. * * PUBLIC: int ex_screen_end __P((SCR *)); */ int ex_screen_end(SCR *sp) { EX_PRIVATE *exp; int rval; if ((exp = EXP(sp)) == NULL) return (0); rval = 0; /* Close down script connections. */ if (F_ISSET(sp, SC_SCRIPT) && sscr_end(sp)) rval = 1; if (argv_free(sp)) rval = 1; if (exp->ibp != NULL) free(exp->ibp); if (exp->lastbcomm != NULL) free(exp->lastbcomm); if (ex_tag_free(sp)) rval = 1; /* Free private memory. */ free(exp); sp->ex_private = NULL; return (rval); }
/* * sscr_check_input - * Check for input from command input or scripting windows. * * PUBLIC: int sscr_check_input(SCR *sp); */ int sscr_check_input(SCR *sp) { GS *gp; SCR *tsp; struct pollfd *pfd; int nfds, rval; gp = sp->gp; rval = 0; /* Allocate space for pfd. */ nfds = 1; TAILQ_FOREACH(tsp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) nfds++; pfd = calloc(nfds, sizeof(struct pollfd)); if (pfd == NULL) { msgq(sp, M_SYSERR, "malloc"); return (1); } /* Setup events bitmasks. */ pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; nfds = 1; TAILQ_FOREACH(tsp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) { pfd[nfds].fd = sp->script->sh_master; pfd[nfds].events = POLLIN; nfds++; } loop: /* Check for input. */ switch (poll(pfd, nfds, INFTIM)) { case -1: msgq(sp, M_SYSERR, "poll"); rval = 1; /* FALLTHROUGH */ case 0: goto done; default: break; } /* Only insert from the scripting windows if no command input */ if (!(pfd[0].revents & POLLIN)) { nfds = 1; TAILQ_FOREACH(tsp, &gp->dq, q) if (F_ISSET(sp, SC_SCRIPT)) { if ((pfd[nfds].revents & POLLHUP) && sscr_end(sp)) goto done; if ((pfd[nfds].revents & POLLIN) && sscr_insert(sp)) goto done; nfds++; } goto loop; }
/* * sscr_setprompt -- * * Set the prompt to the last line we got from the shell. * */ static int sscr_setprompt(SCR *sp, char *buf, size_t len) { SCRIPT *sc; sc = sp->script; if (sc->sh_prompt) free(sc->sh_prompt); MALLOC(sp, sc->sh_prompt, len + 1); if (sc->sh_prompt == NULL) { sscr_end(sp); return (1); } memmove(sc->sh_prompt, buf, len); sc->sh_prompt_len = len; sc->sh_prompt[len] = '\0'; return (0); }
/* * sscr_setprompt -- * * Set the prompt to the last line we got from the shell. * */ static int sscr_setprompt(SCR *sp, CHAR_T *buf, size_t len) { SCRIPT *sc; const char *np; size_t nlen; sc = sp->script; if (sc->sh_prompt) free(sc->sh_prompt); MALLOC(sp, sc->sh_prompt, char *, len + 1); if (sc->sh_prompt == NULL) { sscr_end(sp); return (1); } INT2CHAR(sp, buf, len, np, nlen); memmove(sc->sh_prompt, np, nlen); sc->sh_prompt_len = len; sc->sh_prompt[len] = '\0'; return (0); }
/* * sscr_insert -- * Take a line from the shell and insert it into the file. */ static int sscr_insert(SCR *sp) { CHAR_T *endp, *p, *t; SCRIPT *sc; struct pollfd pfd[1]; recno_t lno; size_t blen, len, tlen; u_int value; int nr, rval; char *bp; /* Find out where the end of the file is. */ if (db_last(sp, &lno)) return (1); #define MINREAD 1024 GET_SPACE_RET(sp, bp, blen, MINREAD); endp = bp; /* Read the characters. */ rval = 1; sc = sp->script; more: switch (nr = read(sc->sh_master, endp, MINREAD)) { case 0: /* EOF; shell just exited. */ sscr_end(sp); rval = 0; goto ret; case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "shell"); goto ret; default: endp += nr; break; } /* Append the lines into the file. */ for (p = t = bp; p < endp; ++p) { value = KEY_VAL(sp, *p); if (value == K_CR || value == K_NL) { len = p - t; if (db_append(sp, 1, lno++, t, len)) goto ret; t = p + 1; } } if (p > t) { len = p - t; /* * If the last thing from the shell isn't another prompt, wait * up to 1/10 of a second for more stuff to show up, so that * we don't break the output into two separate lines. Don't * want to hang indefinitely because some program is hanging, * confused the shell, or whatever. */ if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { pfd[0].fd = sc->sh_master; pfd[0].events = POLLIN; if (poll(pfd, 1, 100) > 0) { memmove(bp, t, len); endp = bp + len; goto more; } } if (sscr_setprompt(sp, t, len)) return (1); if (db_append(sp, 1, lno++, t, len)) goto ret; } /* The cursor moves to EOF. */ sp->lno = lno; sp->cno = len ? len - 1 : 0; rval = vs_refresh(sp, 1); ret: FREE_SPACE(sp, bp, blen); return (rval); }
/* * sscr_getprompt -- * Eat lines printed by the shell until a line with no trailing * carriage return comes; set the prompt from that line. */ static int sscr_getprompt(SCR *sp) { CHAR_T *endp, *p, *t, buf[1024]; SCRIPT *sc; struct pollfd pfd[1]; recno_t lline; size_t llen, len; u_int value; int nr; endp = buf; len = sizeof(buf); /* Wait up to a second for characters to read. */ sc = sp->script; pfd[0].fd = sc->sh_master; pfd[0].events = POLLIN; switch (poll(pfd, 1, 5 * 1000)) { case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "poll"); goto prompterr; case 0: /* Timeout */ msgq(sp, M_ERR, "Error: timed out"); goto prompterr; default: /* Characters to read. */ break; } /* Read the characters. */ more: len = sizeof(buf) - (endp - buf); switch (nr = read(sc->sh_master, endp, len)) { case 0: /* EOF. */ msgq(sp, M_ERR, "Error: shell: EOF"); goto prompterr; case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "shell"); goto prompterr; default: endp += nr; break; } /* If any complete lines, push them into the file. */ for (p = t = buf; p < endp; ++p) { value = KEY_VAL(sp, *p); if (value == K_CR || value == K_NL) { if (db_last(sp, &lline) || db_append(sp, 0, lline, t, p - t)) goto prompterr; t = p + 1; } } if (p > buf) { memmove(buf, t, endp - t); endp = buf + (endp - t); } if (endp == buf) goto more; /* Wait up 1/10 of a second to make sure that we got it all. */ switch (poll(pfd, 1, 100)) { case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "poll"); goto prompterr; case 0: /* Timeout */ break; default: /* Characters to read. */ goto more; } /* Timed out, so theoretically we have a prompt. */ llen = endp - buf; endp = buf; /* Append the line into the file. */ if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) { prompterr: sscr_end(sp); return (1); } return (sscr_setprompt(sp, buf, llen)); }
/* * sscr_insert -- * Take a line from the shell and insert it into the file. */ static int sscr_insert(SCR *sp) { struct timeval tv; char *endp, *p, *t; SCRIPT *sc; fd_set rdfd; db_recno_t lno; size_t len; ssize_t nr; char bp[1024]; const CHAR_T *ip; size_t ilen = 0; /* Find out where the end of the file is. */ if (db_last(sp, &lno)) return (1); endp = bp; /* Read the characters. */ sc = sp->script; more: switch (nr = read(sc->sh_master, endp, bp + sizeof(bp) - endp)) { case 0: /* EOF; shell just exited. */ sscr_end(sp); return (0); case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "shell"); return (1); default: endp += nr; break; } /* Append the lines into the file. */ for (p = t = bp; p < endp; ++p) { if (*p == '\r' || *p == '\n') { len = p - t; if (CHAR2INT(sp, t, len, ip, ilen) || db_append(sp, 1, lno++, ip, ilen)) return (1); t = p + 1; } } /* * If the last thing from the shell isn't another prompt, wait up to * 1/10 of a second for more stuff to show up, so that we don't break * the output into two separate lines. Don't want to hang indefinitely * because some program is hanging, confused the shell, or whatever. * Note that sc->sh_prompt can be NULL here. */ len = p - t; if (sc->sh_prompt == NULL || len != sc->sh_prompt_len || memcmp(t, sc->sh_prompt, len) != 0) { tv.tv_sec = 0; tv.tv_usec = 100000; FD_ZERO(&rdfd); FD_SET(sc->sh_master, &rdfd); if (select(sc->sh_master + 1, &rdfd, NULL, NULL, &tv) == 1) { if (len == sizeof(bp)) { if (CHAR2INT(sp, t, len, ip, ilen) || db_append(sp, 1, lno++, ip, ilen)) return (1); endp = bp; } else { memmove(bp, t, len); endp = bp + len; } goto more; } if (sscr_setprompt(sp, t, len)) return (1); } /* Append the remains into the file, and the cursor moves to EOF. */ if (len > 0) { if (CHAR2INT(sp, t, len, ip, ilen) || db_append(sp, 1, lno++, ip, ilen)) return (1); sp->cno = ilen - 1; } else sp->cno = 0; sp->lno = lno; return (vs_refresh(sp, 1)); }
/* * sscr_getprompt -- * Eat lines printed by the shell until a line with no trailing * carriage return comes; set the prompt from that line. */ static int sscr_getprompt(SCR *sp) { struct timeval tv; CHAR_T *endp, *p, *t, buf[1024]; SCRIPT *sc; fd_set fdset; db_recno_t lline; size_t llen, len; e_key_t value; int nr; FD_ZERO(&fdset); endp = buf; len = sizeof(buf); /* Wait up to a second for characters to read. */ tv.tv_sec = 5; tv.tv_usec = 0; sc = sp->script; FD_SET(sc->sh_master, &fdset); switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "select"); goto prompterr; case 0: /* Timeout */ msgq(sp, M_ERR, "Error: timed out"); goto prompterr; case 1: /* Characters to read. */ break; } /* Read the characters. */ more: len = sizeof(buf) - (endp - buf); switch (nr = read(sc->sh_master, endp, len)) { case 0: /* EOF. */ msgq(sp, M_ERR, "Error: shell: EOF"); goto prompterr; case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "shell"); goto prompterr; default: endp += nr; break; } /* If any complete lines, push them into the file. */ for (p = t = buf; p < endp; ++p) { value = KEY_VAL(sp, *p); if (value == K_CR || value == K_NL) { if (db_last(sp, &lline) || db_append(sp, 0, lline, t, p - t)) goto prompterr; t = p + 1; } } if (p > buf) { MEMMOVE(buf, t, endp - t); endp = buf + (endp - t); } if (endp == buf) goto more; /* Wait up 1/10 of a second to make sure that we got it all. */ tv.tv_sec = 0; tv.tv_usec = 100000; switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { case -1: /* Error or interrupt. */ msgq(sp, M_SYSERR, "select"); goto prompterr; case 0: /* Timeout */ break; case 1: /* Characters to read. */ goto more; } /* Timed out, so theoretically we have a prompt. */ llen = endp - buf; endp = buf; /* Append the line into the file. */ if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) { prompterr: sscr_end(sp); return (1); } return (sscr_setprompt(sp, buf, llen)); }