119304Speter/*-
219304Speter * Copyright (c) 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1390022Ssheldonh#if 0
1419304Speterstatic const char sccsid[] = "@(#)vs_line.c	10.19 (Berkeley) 9/26/96";
1590022Ssheldonh#endif
1690022Ssheldonhstatic const char rcsid[] =
1790022Ssheldonh  "$FreeBSD$";
1819304Speter#endif /* not lint */
1919304Speter
2019304Speter#include <sys/types.h>
2119304Speter#include <sys/queue.h>
2219304Speter#include <sys/time.h>
2319304Speter
2419304Speter#include <bitstring.h>
2519304Speter#include <limits.h>
2619304Speter#include <stdio.h>
2719304Speter#include <string.h>
2819304Speter
2919304Speter#include "../common/common.h"
3019304Speter#include "vi.h"
3119304Speter
3219304Speter#ifdef VISIBLE_TAB_CHARS
3319304Speter#define	TABCH	'-'
3419304Speter#else
3519304Speter#define	TABCH	' '
3619304Speter#endif
3719304Speter
3819304Speter/*
3919304Speter * vs_line --
4019304Speter *	Update one line on the screen.
4119304Speter *
4219304Speter * PUBLIC: int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
4319304Speter */
4419304Speterint
4519304Spetervs_line(sp, smp, yp, xp)
4619304Speter	SCR *sp;
4719304Speter	SMAP *smp;
4819304Speter	size_t *xp, *yp;
4919304Speter{
5019304Speter	CHAR_T *kp;
5119304Speter	GS *gp;
5219304Speter	SMAP *tsmp;
5319304Speter	size_t chlen, cno_cnt, cols_per_screen, len, nlen;
5419304Speter	size_t offset_in_char, offset_in_line, oldx, oldy;
5519304Speter	size_t scno, skip_cols, skip_screens;
5690026Ssheldonh	int ch, dne, is_cached, is_partial, is_tab, no_draw;
5719304Speter	int list_tab, list_dollar;
5819304Speter	char *p, *cbp, *ecbp, cbuf[128];
5919304Speter
6019304Speter#if defined(DEBUG) && 0
6119304Speter	TRACE(sp, "vs_line: row %u: line: %u off: %u\n",
6219304Speter	    smp - HMAP, smp->lno, smp->off);
6319304Speter#endif
6419304Speter	/*
6519304Speter	 * If ex modifies the screen after ex output is already on the screen,
6619304Speter	 * don't touch it -- we'll get scrolling wrong, at best.
6719304Speter	 */
6890026Ssheldonh	no_draw = 0;
6919304Speter	if (!F_ISSET(sp, SC_TINPUT_INFO) && VIP(sp)->totalcount > 1)
7090026Ssheldonh		no_draw = 1;
7119304Speter	if (F_ISSET(sp, SC_SCR_EXWROTE) && smp - HMAP != LASTLINE(sp))
7290026Ssheldonh		no_draw = 1;
7319304Speter
7419304Speter	/*
7519304Speter	 * Assume that, if the cache entry for the line is filled in, the
7619304Speter	 * line is already on the screen, and all we need to do is return
7719304Speter	 * the cursor position.  If the calling routine doesn't need the
7819304Speter	 * cursor position, we can just return.
7919304Speter	 */
8019304Speter	is_cached = SMAP_CACHE(smp);
8190026Ssheldonh	if (yp == NULL && (is_cached || no_draw))
8219304Speter		return (0);
8319304Speter
8419304Speter	/*
8519304Speter	 * A nasty side effect of this routine is that it returns the screen
8619304Speter	 * position for the "current" character.  Not pretty, but this is the
8719304Speter	 * only routine that really knows what's out there.
8819304Speter	 *
8919304Speter	 * Move to the line.  This routine can be called by vs_sm_position(),
9019304Speter	 * which uses it to fill in the cache entry so it can figure out what
9119304Speter	 * the real contents of the screen are.  Because of this, we have to
9219304Speter	 * return to whereever we started from.
9319304Speter	 */
9419304Speter	gp = sp->gp;
9519304Speter	(void)gp->scr_cursor(sp, &oldy, &oldx);
9619304Speter	(void)gp->scr_move(sp, smp - HMAP, 0);
9719304Speter
9819304Speter	/* Get the line. */
9919304Speter	dne = db_get(sp, smp->lno, 0, &p, &len);
10019304Speter
10119304Speter	/*
10219304Speter	 * Special case if we're printing the info/mode line.  Skip printing
10319304Speter	 * the leading number, as well as other minor setup.  The only time
10419304Speter	 * this code paints the mode line is when the user is entering text
10519304Speter	 * for a ":" command, so we can put the code here instead of dealing
10619304Speter	 * with the empty line logic below.  This is a kludge, but it's pretty
10719304Speter	 * much confined to this module.
10819304Speter	 *
10919304Speter	 * Set the number of columns for this screen.
11019304Speter	 * Set the number of chars or screens to skip until a character is to
11119304Speter	 * be displayed.
11219304Speter	 */
11319304Speter	cols_per_screen = sp->cols;
11419304Speter	if (O_ISSET(sp, O_LEFTRIGHT)) {
11519304Speter		skip_screens = 0;
11619304Speter		skip_cols = smp->coff;
11719304Speter	} else {
11819304Speter		skip_screens = smp->soff - 1;
11919304Speter		skip_cols = skip_screens * cols_per_screen;
12019304Speter	}
12119304Speter
12219304Speter	list_tab = O_ISSET(sp, O_LIST);
12319304Speter	if (F_ISSET(sp, SC_TINPUT_INFO))
12419304Speter		list_dollar = 0;
12519304Speter	else {
12619304Speter		list_dollar = list_tab;
12719304Speter
12819304Speter		/*
12919304Speter		 * If O_NUMBER is set, the line doesn't exist and it's line
13019304Speter		 * number 1, i.e., an empty file, display the line number.
13119304Speter		 *
13219304Speter		 * If O_NUMBER is set, the line exists and the first character
13319304Speter		 * on the screen is the first character in the line, display
13419304Speter		 * the line number.
13519304Speter		 *
13619304Speter		 * !!!
13719304Speter		 * If O_NUMBER set, decrement the number of columns in the
13819304Speter		 * first screen.  DO NOT CHANGE THIS -- IT'S RIGHT!  The
13919304Speter		 * rest of the code expects this to reflect the number of
14019304Speter		 * columns in the first screen, regardless of the number of
14119304Speter		 * columns we're going to skip.
14219304Speter		 */
14319304Speter		if (O_ISSET(sp, O_NUMBER)) {
14419304Speter			cols_per_screen -= O_NUMBER_LENGTH;
14519304Speter			if ((!dne || smp->lno == 1) && skip_cols == 0) {
14638022Sbde				nlen = snprintf(cbuf, sizeof(cbuf),
14738022Sbde				    O_NUMBER_FMT, (u_long)smp->lno);
14819304Speter				(void)gp->scr_addstr(sp, cbuf, nlen);
14919304Speter			}
15019304Speter		}
15119304Speter	}
15219304Speter
15319304Speter	/*
15419304Speter	 * Special case non-existent lines and the first line of an empty
15519304Speter	 * file.  In both cases, the cursor position is 0, but corrected
15619304Speter	 * as necessary for the O_NUMBER field, if it was displayed.
15719304Speter	 */
15819304Speter	if (dne || len == 0) {
15919304Speter		/* Fill in the cursor. */
16019304Speter		if (yp != NULL && smp->lno == sp->lno) {
16119304Speter			*yp = smp - HMAP;
16219304Speter			*xp = sp->cols - cols_per_screen;
16319304Speter		}
16419304Speter
16519304Speter		/* If the line is on the screen, quit. */
16690026Ssheldonh		if (is_cached || no_draw)
16719304Speter			goto ret1;
16819304Speter
16919304Speter		/* Set line cache information. */
17019304Speter		smp->c_sboff = smp->c_eboff = 0;
17119304Speter		smp->c_scoff = smp->c_eclen = 0;
17219304Speter
17319304Speter		/*
17419304Speter		 * Lots of special cases for empty lines, but they only apply
17519304Speter		 * if we're displaying the first screen of the line.
17619304Speter		 */
17719304Speter		if (skip_cols == 0)
17819304Speter			if (dne) {
17919304Speter				if (smp->lno == 1) {
18019304Speter					if (list_dollar) {
18119304Speter						ch = '$';
18219304Speter						goto empty;
18319304Speter					}
18419304Speter				} else {
18519304Speter					ch = '~';
18619304Speter					goto empty;
18719304Speter				}
18819304Speter			} else
18919304Speter				if (list_dollar) {
19019304Speter					ch = '$';
19119304Speterempty:					(void)gp->scr_addstr(sp,
19219304Speter					    KEY_NAME(sp, ch), KEY_LEN(sp, ch));
19319304Speter				}
19419304Speter
19519304Speter		(void)gp->scr_clrtoeol(sp);
19619304Speter		(void)gp->scr_move(sp, oldy, oldx);
19719304Speter		return (0);
19819304Speter	}
19919304Speter
20019304Speter	/*
20119304Speter	 * If we just wrote this or a previous line, we cached the starting
20219304Speter	 * and ending positions of that line.  The way it works is we keep
20319304Speter	 * information about the lines displayed in the SMAP.  If we're
20419304Speter	 * painting the screen in the forward direction, this saves us from
20519304Speter	 * reformatting the physical line for every line on the screen.  This
20619304Speter	 * wins big on binary files with 10K lines.
20719304Speter	 *
20819304Speter	 * Test for the first screen of the line, then the current screen line,
20919304Speter	 * then the line behind us, then do the hard work.  Note, it doesn't
21019304Speter	 * do us any good to have a line in front of us -- it would be really
21119304Speter	 * hard to try and figure out tabs in the reverse direction, i.e. how
21219304Speter	 * many spaces a tab takes up in the reverse direction depends on
21319304Speter	 * what characters preceded it.
21419304Speter	 *
21519304Speter	 * Test for the first screen of the line.
21619304Speter	 */
21719304Speter	if (skip_cols == 0) {
21819304Speter		smp->c_sboff = offset_in_line = 0;
21919304Speter		smp->c_scoff = offset_in_char = 0;
22019304Speter		p = &p[offset_in_line];
22119304Speter		goto display;
22219304Speter	}
22319304Speter
22419304Speter	/* Test to see if we've seen this exact line before. */
22519304Speter	if (is_cached) {
22619304Speter		offset_in_line = smp->c_sboff;
22719304Speter		offset_in_char = smp->c_scoff;
22819304Speter		p = &p[offset_in_line];
22919304Speter
23019304Speter		/* Set cols_per_screen to 2nd and later line length. */
23119304Speter		if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen)
23219304Speter			cols_per_screen = sp->cols;
23319304Speter		goto display;
23419304Speter	}
23519304Speter
23619304Speter	/* Test to see if we saw an earlier part of this line before. */
23719304Speter	if (smp != HMAP &&
23819304Speter	    SMAP_CACHE(tsmp = smp - 1) && tsmp->lno == smp->lno) {
23919304Speter		if (tsmp->c_eclen != tsmp->c_ecsize) {
24019304Speter			offset_in_line = tsmp->c_eboff;
24119304Speter			offset_in_char = tsmp->c_eclen;
24219304Speter		} else {
24319304Speter			offset_in_line = tsmp->c_eboff + 1;
24419304Speter			offset_in_char = 0;
24519304Speter		}
24619304Speter
24719304Speter		/* Put starting info for this line in the cache. */
24819304Speter		smp->c_sboff = offset_in_line;
24919304Speter		smp->c_scoff = offset_in_char;
25019304Speter		p = &p[offset_in_line];
25119304Speter
25219304Speter		/* Set cols_per_screen to 2nd and later line length. */
25319304Speter		if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen)
25419304Speter			cols_per_screen = sp->cols;
25519304Speter		goto display;
25619304Speter	}
25719304Speter
25819304Speter	scno = 0;
25919304Speter	offset_in_line = 0;
26019304Speter	offset_in_char = 0;
26119304Speter
26219304Speter	/* Do it the hard way, for leftright scrolling screens. */
26319304Speter	if (O_ISSET(sp, O_LEFTRIGHT)) {
26419304Speter		for (; offset_in_line < len; ++offset_in_line) {
26519304Speter			chlen = (ch = *(u_char *)p++) == '\t' && !list_tab ?
26619304Speter			    TAB_OFF(scno) : KEY_LEN(sp, ch);
26719304Speter			if ((scno += chlen) >= skip_cols)
26819304Speter				break;
26919304Speter		}
27019304Speter
27119304Speter		/* Set cols_per_screen to 2nd and later line length. */
27219304Speter		cols_per_screen = sp->cols;
27319304Speter
27419304Speter		/* Put starting info for this line in the cache. */
27590023Ssheldonh		if (offset_in_line >= len) {
27619304Speter			smp->c_sboff = offset_in_line;
27790023Ssheldonh			smp->c_scoff = 255;
27890023Ssheldonh		} else if (scno != skip_cols) {
27990023Ssheldonh			smp->c_sboff = offset_in_line;
28019304Speter			smp->c_scoff =
28119304Speter			    offset_in_char = chlen - (scno - skip_cols);
28219304Speter			--p;
28319304Speter		} else {
28419304Speter			smp->c_sboff = ++offset_in_line;
28519304Speter			smp->c_scoff = 0;
28619304Speter		}
28719304Speter	}
28819304Speter
28919304Speter	/* Do it the hard way, for historic line-folding screens. */
29019304Speter	else {
29119304Speter		for (; offset_in_line < len; ++offset_in_line) {
29219304Speter			chlen = (ch = *(u_char *)p++) == '\t' && !list_tab ?
29319304Speter			    TAB_OFF(scno) : KEY_LEN(sp, ch);
29419304Speter			if ((scno += chlen) < cols_per_screen)
29519304Speter				continue;
29619304Speter			scno -= cols_per_screen;
29719304Speter
29819304Speter			/* Set cols_per_screen to 2nd and later line length. */
29919304Speter			cols_per_screen = sp->cols;
30019304Speter
30119304Speter			/*
30219304Speter			 * If crossed the last skipped screen boundary, start
30319304Speter			 * displaying the characters.
30419304Speter			 */
30519304Speter			if (--skip_screens == 0)
30619304Speter				break;
30719304Speter		}
30819304Speter
30919304Speter		/* Put starting info for this line in the cache. */
31019304Speter		if (scno != 0) {
31119304Speter			smp->c_sboff = offset_in_line;
31219304Speter			smp->c_scoff = offset_in_char = chlen - scno;
31319304Speter			--p;
31419304Speter		} else {
31519304Speter			smp->c_sboff = ++offset_in_line;
31619304Speter			smp->c_scoff = 0;
31719304Speter		}
31819304Speter	}
31919304Speter
32019304Speterdisplay:
32119304Speter	/*
32219304Speter	 * Set the number of characters to skip before reaching the cursor
32319304Speter	 * character.  Offset by 1 and use 0 as a flag value.  Vs_line is
32419304Speter	 * called repeatedly with a valid pointer to a cursor position.
32519304Speter	 * Don't fill anything in unless it's the right line and the right
32619304Speter	 * character, and the right part of the character...
32719304Speter	 */
32819304Speter	if (yp == NULL ||
32919304Speter	    smp->lno != sp->lno || sp->cno < offset_in_line ||
33019304Speter	    offset_in_line + cols_per_screen < sp->cno) {
33119304Speter		cno_cnt = 0;
33219304Speter		/* If the line is on the screen, quit. */
33390026Ssheldonh		if (is_cached || no_draw)
33419304Speter			goto ret1;
33519304Speter	} else
33619304Speter		cno_cnt = (sp->cno - offset_in_line) + 1;
33719304Speter
33819304Speter	/* This is the loop that actually displays characters. */
33919304Speter	ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
34019304Speter	for (is_partial = 0, scno = 0;
34119304Speter	    offset_in_line < len; ++offset_in_line, offset_in_char = 0) {
34219304Speter		if ((ch = *(u_char *)p++) == '\t' && !list_tab) {
34319304Speter			scno += chlen = TAB_OFF(scno) - offset_in_char;
34419304Speter			is_tab = 1;
34519304Speter		} else {
34619304Speter			scno += chlen = KEY_LEN(sp, ch) - offset_in_char;
34719304Speter			is_tab = 0;
34819304Speter		}
34919304Speter
35019304Speter		/*
35119304Speter		 * Only display up to the right-hand column.  Set a flag if
35219304Speter		 * the entire character wasn't displayed for use in setting
35319304Speter		 * the cursor.  If reached the end of the line, set the cache
35419304Speter		 * info for the screen.  Don't worry about there not being
35519304Speter		 * characters to display on the next screen, its lno/off won't
35619304Speter		 * match up in that case.
35719304Speter		 */
35819304Speter		if (scno >= cols_per_screen) {
35919304Speter			if (is_tab == 1) {
36019304Speter				chlen -= scno - cols_per_screen;
36119304Speter				smp->c_ecsize = smp->c_eclen = chlen;
36219304Speter				scno = cols_per_screen;
36319304Speter			} else {
36419304Speter				smp->c_ecsize = chlen;
36519304Speter				chlen -= scno - cols_per_screen;
36619304Speter				smp->c_eclen = chlen;
36719304Speter
36819304Speter				if (scno > cols_per_screen)
36919304Speter					is_partial = 1;
37019304Speter			}
37119304Speter			smp->c_eboff = offset_in_line;
37219304Speter
37319304Speter			/* Terminate the loop. */
37419304Speter			offset_in_line = len;
37519304Speter		}
37619304Speter
37719304Speter		/*
37819304Speter		 * If the caller wants the cursor value, and this was the
37919304Speter		 * cursor character, set the value.  There are two ways to
38019304Speter		 * put the cursor on a character -- if it's normal display
38119304Speter		 * mode, it goes on the last column of the character.  If
38219304Speter		 * it's input mode, it goes on the first.  In normal mode,
38319304Speter		 * set the cursor only if the entire character was displayed.
38419304Speter		 */
38519304Speter		if (cno_cnt &&
38619304Speter		    --cno_cnt == 0 && (F_ISSET(sp, SC_TINPUT) || !is_partial)) {
38719304Speter			*yp = smp - HMAP;
38819304Speter			if (F_ISSET(sp, SC_TINPUT))
38919304Speter				*xp = scno - chlen;
39019304Speter			else
39119304Speter				*xp = scno - 1;
39219304Speter			if (O_ISSET(sp, O_NUMBER) &&
39319304Speter			    !F_ISSET(sp, SC_TINPUT_INFO) && skip_cols == 0)
39419304Speter				*xp += O_NUMBER_LENGTH;
39519304Speter
39619304Speter			/* If the line is on the screen, quit. */
39790026Ssheldonh			if (is_cached || no_draw)
39819304Speter				goto ret1;
39919304Speter		}
40019304Speter
40119304Speter		/* If the line is on the screen, don't display anything. */
40290026Ssheldonh		if (is_cached || no_draw)
40319304Speter			continue;
40419304Speter
40519304Speter#define	FLUSH {								\
40619304Speter	*cbp = '\0';							\
40719304Speter	(void)gp->scr_addstr(sp, cbuf, cbp - cbuf);			\
40819304Speter	cbp = cbuf;							\
40919304Speter}
41019304Speter		/*
41119304Speter		 * Display the character.  We do tab expansion here because
41219304Speter		 * the screen interface doesn't have any way to set the tab
41319304Speter		 * length.  Note, it's theoretically possible for chlen to
41419304Speter		 * be larger than cbuf, if the user set a impossibly large
41519304Speter		 * tabstop.
41619304Speter		 */
41719304Speter		if (is_tab)
41819304Speter			while (chlen--) {
41919304Speter				if (cbp >= ecbp)
42019304Speter					FLUSH;
42119304Speter				*cbp++ = TABCH;
42219304Speter			}
42319304Speter		else {
42419304Speter			if (cbp + chlen >= ecbp)
42519304Speter				FLUSH;
42619304Speter			for (kp = KEY_NAME(sp, ch) + offset_in_char; chlen--;)
42719304Speter				*cbp++ = *kp++;
42819304Speter		}
42919304Speter	}
43019304Speter
43119304Speter	if (scno < cols_per_screen) {
43219304Speter		/* If didn't paint the whole line, update the cache. */
43319304Speter		smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch);
43419304Speter		smp->c_eboff = len - 1;
43519304Speter
43619304Speter		/*
43719304Speter		 * If not the info/mode line, and O_LIST set, and at the
43819304Speter		 * end of the line, and the line ended on this screen,
43919304Speter		 * add a trailing $.
44019304Speter		 */
44119304Speter		if (list_dollar) {
44219304Speter			++scno;
44319304Speter
44419304Speter			chlen = KEY_LEN(sp, '$');
44519304Speter			if (cbp + chlen >= ecbp)
44619304Speter				FLUSH;
44719304Speter			for (kp = KEY_NAME(sp, '$'); chlen--;)
44819304Speter				*cbp++ = *kp++;
44919304Speter		}
45019304Speter
45119304Speter		/* If still didn't paint the whole line, clear the rest. */
45219304Speter		if (scno < cols_per_screen)
45319304Speter			(void)gp->scr_clrtoeol(sp);
45419304Speter	}
45519304Speter
45619304Speter	/* Flush any buffered characters. */
45719304Speter	if (cbp > cbuf)
45819304Speter		FLUSH;
45919304Speter
46019304Speterret1:	(void)gp->scr_move(sp, oldy, oldx);
46119304Speter	return (0);
46219304Speter}
46319304Speter
46419304Speter/*
46519304Speter * vs_number --
46619304Speter *	Repaint the numbers on all the lines.
46719304Speter *
46819304Speter * PUBLIC: int vs_number __P((SCR *));
46919304Speter */
47019304Speterint
47119304Spetervs_number(sp)
47219304Speter	SCR *sp;
47319304Speter{
47419304Speter	GS *gp;
47519304Speter	SMAP *smp;
47619304Speter	VI_PRIVATE *vip;
47719304Speter	size_t len, oldy, oldx;
47819304Speter	int exist;
47919304Speter	char nbuf[10];
48019304Speter
48119304Speter	gp = sp->gp;
48219304Speter	vip = VIP(sp);
48319304Speter
48419304Speter	/* No reason to do anything if we're in input mode on the info line. */
48519304Speter	if (F_ISSET(sp, SC_TINPUT_INFO))
48619304Speter		return (0);
48719304Speter
48819304Speter	/*
48919304Speter	 * Try and avoid getting the last line in the file, by getting the
49019304Speter	 * line after the last line in the screen -- if it exists, we know
49119304Speter	 * we have to to number all the lines in the screen.  Get the one
49219304Speter	 * after the last instead of the last, so that the info line doesn't
49319304Speter	 * fool us.  (The problem is that file_lline will lie, and tell us
49419304Speter	 * that the info line is the last line in the file.) If that test
49519304Speter	 * fails, we have to check each line for existence.
49619304Speter	 */
49719304Speter	exist = db_exist(sp, TMAP->lno + 1);
49819304Speter
49919304Speter	(void)gp->scr_cursor(sp, &oldy, &oldx);
50019304Speter	for (smp = HMAP; smp <= TMAP; ++smp) {
50119304Speter		/* Numbers are only displayed for the first screen line. */
50219304Speter		if (O_ISSET(sp, O_LEFTRIGHT)) {
50319304Speter			if (smp->coff != 0)
50419304Speter				continue;
50519304Speter		} else
50619304Speter			if (smp->soff != 1)
50719304Speter				continue;
50819304Speter
50919304Speter		/*
51019304Speter		 * The first line of an empty file gets numbered, otherwise
51119304Speter		 * number any existing line.
51219304Speter		 */
51319304Speter		if (smp->lno != 1 && !exist && !db_exist(sp, smp->lno))
51419304Speter			break;
51519304Speter
51619304Speter		(void)gp->scr_move(sp, smp - HMAP, 0);
51738022Sbde		len = snprintf(nbuf, sizeof(nbuf),
51838022Sbde		    O_NUMBER_FMT, (u_long)smp->lno);
51919304Speter		(void)gp->scr_addstr(sp, nbuf, len);
52019304Speter	}
52119304Speter	(void)gp->scr_move(sp, oldy, oldx);
52219304Speter	return (0);
52319304Speter}
524