/* * v_up -- [count]^P, [count]k, [count]- * Move up by lines. * * PUBLIC: int v_up(SCR *, VICMD *); */ int v_up(SCR *sp, VICMD *vp) { recno_t lno; lno = F_ISSET(vp, VC_C1SET) ? vp->count : 1; if (vp->m_start.lno <= lno) { v_sof(sp, &vp->m_start); return (1); } vp->m_stop.lno = vp->m_start.lno - lno; vp->m_final = vp->m_stop; return (0); }
/* * bword -- * Move backward by words. */ static int bword(SCR *sp, VICMD *vp, enum which type) { enum { INWORD, NOTWORD } state; VCS cs; u_long cnt; int nmw, omw; cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cs.cs_lno = vp->m_start.lno; cs.cs_cno = vp->m_start.cno; if (cs_init(sp, &cs)) return (1); /* * !!! * If in whitespace, or the previous character is whitespace, move * past it. (This doesn't count as a word move.) Stay at the * character before the current one, it sets word "state" for the * 'b' command. */ if (cs.cs_flags == 0 && !ISBLANK2(cs.cs_ch)) { if (cs_prev(sp, &cs)) return (1); if (cs.cs_flags == 0 && !ISBLANK2(cs.cs_ch)) goto start; } if (cs_bblank(sp, &cs)) return (1); /* * Cyclically move to the beginning of the previous word -- this * involves skipping over word characters and then any trailing * non-word characters. Note, for the 'b' command, the definition * of a word keeps switching. */ start: if (type == BIGWORD) while (cnt--) { nmw = ISMULTIWIDTH(sp, cs.cs_ch); for (;;) { omw = nmw; if (cs_prev(sp, &cs)) return (1); if (cs.cs_flags == CS_SOF) goto ret; if (cs.cs_flags != 0 || ISBLANK2(cs.cs_ch) || (nmw = ISMULTIWIDTH(sp, cs.cs_ch)) != omw) break; } /* * When we reach the end of the word before the last * word, we're done. If we changed state, move forward * one to the end of the next word. */ if (cnt == 0) { if (cs.cs_flags == 0 && cs_next(sp, &cs)) return (1); break; } /* Eat whitespace characters. */ if (nmw == omw && cs_bblank(sp, &cs)) return (1); if (cs.cs_flags == CS_SOF) goto ret; } else while (cnt--) { state = cs.cs_flags == 0 && inword(cs.cs_ch) ? INWORD : NOTWORD; nmw = ISMULTIWIDTH(sp, cs.cs_ch); for (;;) { omw = nmw; if (cs_prev(sp, &cs)) return (1); if (cs.cs_flags == CS_SOF) goto ret; if (cs.cs_flags != 0 || ISBLANK2(cs.cs_ch) || (nmw = ISMULTIWIDTH(sp, cs.cs_ch)) != omw) break; if (state == INWORD) { if (!inword(cs.cs_ch)) break; } else if (inword(cs.cs_ch)) break; } /* See comment above. */ if (cnt == 0) { if (cs.cs_flags == 0 && cs_next(sp, &cs)) return (1); break; } /* Eat whitespace characters. */ if (cs.cs_flags != 0 || ISBLANK2(cs.cs_ch)) if (cs_bblank(sp, &cs)) return (1); if (cs.cs_flags == CS_SOF) goto ret; } /* If we didn't move, we must be at SOF. */ ret: if (cs.cs_lno == vp->m_start.lno && cs.cs_cno == vp->m_start.cno) { v_sof(sp, &vp->m_start); return (1); } /* Set the end of the range for motion commands. */ vp->m_stop.lno = cs.cs_lno; vp->m_stop.cno = cs.cs_cno; /* * All commands move to the end of the range. Motion commands * adjust the starting point to the character before the current * one. * * !!! * The historic vi didn't get this right -- the `yb' command yanked * the right stuff and even updated the cursor value, but the cursor * was not actually updated on the screen. */ vp->m_final = vp->m_stop; if (ISMOTION(vp)) --vp->m_start.cno; return (0); }
/* * v_sectionb -- [count][[ * Move backward count sections/functions. * * PUBLIC: int v_sectionb(SCR *, VICMD *); */ int v_sectionb(SCR *sp, VICMD *vp) { size_t len; recno_t cnt, lno; CHAR_T *p; char *list, *lp; /* An empty file or starting from line 1 is always illegal. */ if (vp->m_start.lno <= 1) { v_sof(sp, NULL); return (1); } /* Get the macro list. */ if ((list = O_STR(sp, O_SECTIONS)) == NULL) return (1); cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; for (lno = vp->m_start.lno; !db_get(sp, --lno, 0, &p, &len);) { if (len == 0) continue; if (p[0] == '{') { if (!--cnt) goto adjust1; continue; } /* * !!! * Historic documentation (USD:15-11, 4.2) said that formfeed * characters (^L) in the first column delimited sections. * The historic code mentions formfeed characters, but never * implements them. Seems reasonable, do it. */ if (p[0] == '\014') { if (!--cnt) goto adjust1; continue; } if (p[0] != '.' || len < 2) continue; for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp)) if (lp[0] == p[1] && ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) && !--cnt) { adjust1: vp->m_stop.lno = lno; vp->m_stop.cno = 0; goto ret1; } } /* * If moving backward, reached SOF, which is a movement sink. * We already checked for starting there. */ vp->m_stop.lno = 1; vp->m_stop.cno = 0; /* * All commands move to the end of the range. * * !!! * Historic practice is the section cut was in line mode if it started * from column 0 and was in the backward direction. Otherwise, left * motion commands adjust the starting point to the character before * the current one. What makes this worse is that if it cut to line * mode it also went to the first non-<blank>. */ ret1: if (vp->m_start.cno == 0) { F_CLR(vp, VM_RCM_MASK); F_SET(vp, VM_RCM_SETFNB); --vp->m_start.lno; F_SET(vp, VM_LMODE); } else --vp->m_start.cno; vp->m_final = vp->m_stop; return (0); }