Ejemplo n.º 1
0
/*
 * 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);
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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);
}