/* * v_curword -- * Get the word (or non-word) the cursor is on. * * PUBLIC: int v_curword __P((SCR *)); */ int v_curword(SCR *sp) { VI_PRIVATE *vip; size_t beg, end, len; int moved, state; CHAR_T *p; if (db_get(sp, sp->lno, DBG_FATAL, &p, &len)) return (1); /* * !!! * Historically, tag commands skipped over any leading whitespace * characters. Make this true in general when using cursor words. * If movement, getting a cursor word implies moving the cursor to * its beginning. Refresh now. * * !!! * Find the beginning/end of the keyword. Keywords are currently * used for cursor-word searching and for tags. Historical vi * only used the word in a tag search from the cursor to the end * of the word, i.e. if the cursor was on the 'b' in " abc ", the * tag was "bc". For consistency, we make cursor word searches * follow the same rule. */ for (moved = 0, beg = sp->cno; beg < len && ISSPACE((UCHAR_T)p[beg]); moved = 1, ++beg); if (beg >= len) { msgq(sp, M_BERR, "212|Cursor not in a word"); return (1); } if (moved) { sp->cno = beg; (void)vs_refresh(sp, 0); } /* Find the end of the word. */ for (state = inword(p[beg]), end = beg; ++end < len && state == inword(p[end]);); vip = VIP(sp); len = (end - beg); BINC_RETW(sp, vip->keyw, vip->klen, len+1); MEMMOVEW(vip->keyw, p + beg, len); vip->keyw[len] = '\0'; /* XXX */ return (0); }
/* * v_change -- [buffer][count]c[count]motion * [buffer][count]C * [buffer][count]S * Change command. * * PUBLIC: int v_change __P((SCR *, VICMD *)); */ int v_change(SCR *sp, VICMD *vp) { size_t blen, len; u_int32_t flags; int isempty, lmode, rval; CHAR_T *bp; CHAR_T *p; /* * 'c' can be combined with motion commands that set the resulting * cursor position, i.e. "cG". Clear the VM_RCM flags and make the * resulting cursor position stick, inserting text has its own rules * for cursor positioning. */ F_CLR(vp, VM_RCM_MASK); F_SET(vp, VM_RCM_SET); /* * Find out if the file is empty, it's easier to handle it as a * special case. */ if (vp->m_start.lno == vp->m_stop.lno && db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { if (!isempty) return (1); return (v_ia(sp, vp)); } flags = set_txt_std(sp, vp, 0); sp->showmode = SM_CHANGE; /* * Move the cursor to the start of the change. Note, if autoindent * is turned on, the cc command in line mode changes from the first * *non-blank* character of the line, not the first character. And, * to make it just a bit more exciting, the initial space is handled * as auto-indent characters. */ lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; if (lmode) { vp->m_start.cno = 0; if (O_ISSET(sp, O_AUTOINDENT)) { if (nonblank(sp, vp->m_start.lno, &vp->m_start.cno)) return (1); LF_SET(TXT_AICHARS); } } sp->lno = vp->m_start.lno; sp->cno = vp->m_start.cno; LOG_CORRECT; /* * If not in line mode and changing within a single line, copy the * text and overwrite it. */ if (!lmode && vp->m_start.lno == vp->m_stop.lno) { /* * !!! * Historic practice, c did not cut into the numeric buffers, * only the unnamed one. */ if (cut(sp, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, &vp->m_start, &vp->m_stop, lmode)) return (1); if (len == 0) LF_SET(TXT_APPENDEOL); LF_SET(TXT_EMARK | TXT_OVERWRITE); return (v_txt(sp, vp, &vp->m_stop, p, len, 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); } /* * It's trickier if in line mode or changing over multiple lines. If * we're in line mode delete all of the lines and insert a replacement * line which the user edits. If there was leading whitespace in the * first line being changed, we copy it and use it as the replacement. * If we're not in line mode, we delete the text and start inserting. * * !!! * Copy the text. Historic practice, c did not cut into the numeric * buffers, only the unnamed one. */ if (cut(sp, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, &vp->m_start, &vp->m_stop, lmode)) return (1); /* If replacing entire lines and there's leading text. */ if (lmode && vp->m_start.cno) { /* * Get a copy of the first line changed, and copy out the * leading text. */ if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len)) return (1); GET_SPACE_RETW(sp, bp, blen, vp->m_start.cno); MEMMOVEW(bp, p, vp->m_start.cno); } else bp = NULL; /* Delete the text. */ if (del(sp, &vp->m_start, &vp->m_stop, lmode)) return (1); /* If replacing entire lines, insert a replacement line. */ if (lmode) { if (db_insert(sp, vp->m_start.lno, bp, vp->m_start.cno)) return (1); sp->lno = vp->m_start.lno; len = sp->cno = vp->m_start.cno; } /* Get the line we're editing. */ if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { if (!isempty) return (1); len = 0; } /* Check to see if we're appending to the line. */ if (vp->m_start.cno >= len) LF_SET(TXT_APPENDEOL); rval = v_txt(sp, vp, NULL, p, len, 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags); if (bp != NULL) FREE_SPACEW(sp, bp, blen); return (rval); }
/* * ip_read -- * Read characters from the input. */ static input_t ip_read(SCR *sp, IP_PRIVATE *ipp, struct timeval *tp, int termread, int *nr) { GS *gp; fd_set rdfd; input_t rval; size_t blen; int maxfd; char *bp; int fd; const CHAR_T *wp; size_t wlen; gp = sp == NULL ? __global_list : sp->gp; bp = ipp->ibuf + ipp->iblen; blen = sizeof(ipp->ibuf) - ipp->iblen; fd = termread ? ipp->t_fd : ipp->i_fd; /* * 1: A read with an associated timeout, e.g., trying to complete * a map sequence. If input exists, we fall into #2. */ FD_ZERO(&rdfd); if (tp != NULL) { FD_SET(fd, &rdfd); switch (select(fd + 1, &rdfd, NULL, NULL, tp)) { case 0: return (INP_TIMEOUT); case -1: goto err; default: break; } } /* * 2: Wait for input. * * Select on the command input and scripting window file descriptors. * It's ugly that we wait on scripting file descriptors here, but it's * the only way to keep from locking out scripting windows. */ if (sp != NULL && F_ISSET(gp, G_SCRWIN)) { FD_ZERO(&rdfd); FD_SET(fd, &rdfd); maxfd = fd; if (sscr_check_input(sp, &rdfd, maxfd)) goto err; } /* * 3: Read the input. */ switch (*nr = read(fd, termread ? (char *)ipp->tbuf : bp, termread ? sizeof(ipp->tbuf)/sizeof(CHAR_T) : blen)) { case 0: /* EOF. */ rval = INP_EOF; break; case -1: /* Error or interrupt. */ err: rval = INP_ERR; msgq(sp, M_SYSERR, "input"); break; default: /* Input characters. */ if (sp == NULL) { rval = INP_ERR; msgq(sp, M_SYSERR, "Can't convert input with NULL screen"); break; } if (!termread) ipp->iblen += *nr; else { CHAR2INT(sp, (char *)ipp->tbuf, *nr, wp, wlen); MEMMOVEW(ipp->tbuf, wp, wlen); } rval = INP_OK; break; } return (rval); }
/* * sscr_exec -- * Take a line and hand it off to the shell. * * PUBLIC: int sscr_exec __P((SCR *, db_recno_t)); */ int sscr_exec(SCR *sp, db_recno_t lno) { SCRIPT *sc; db_recno_t last_lno; size_t blen, len, last_len, tlen; int isempty, matchprompt, rval; ssize_t nw; CHAR_T *bp = NULL; CHAR_T *p; /* If there's a prompt on the last line, append the command. */ if (db_last(sp, &last_lno)) return (1); if (db_get(sp, last_lno, DBG_FATAL, &p, &last_len)) return (1); if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { matchprompt = 1; GET_SPACE_RETW(sp, bp, blen, last_len + 128); MEMMOVEW(bp, p, last_len); } else matchprompt = 0; /* Get something to execute. */ if (db_eget(sp, lno, &p, &len, &isempty)) { if (isempty) goto empty; goto err1; } /* Empty lines aren't interesting. */ if (len == 0) goto empty; /* Delete any prompt. */ if (sscr_matchprompt(sp, p, len, &tlen)) { if (tlen == len) { empty: msgq(sp, M_BERR, "151|No command to execute"); goto err1; } p += (len - tlen); len = tlen; } /* Push the line to the shell. */ sc = sp->script; if ((size_t)(nw = write(sc->sh_master, p, len)) != len) goto err2; rval = 0; if (write(sc->sh_master, "\n", 1) != 1) { err2: if (nw == 0) errno = EIO; msgq(sp, M_SYSERR, "shell"); goto err1; } if (matchprompt) { ADD_SPACE_RETW(sp, bp, blen, last_len + len); MEMMOVEW(bp + last_len, p, len); if (db_set(sp, last_lno, bp, last_len + len)) err1: rval = 1; } if (matchprompt) FREE_SPACEW(sp, bp, blen); return (rval); }