xref: /netbsd/external/bsd/nvi/dist/vi/vs_split.c (revision cc73507a)
1*cc73507aSchristos /*	$NetBSD: vs_split.c,v 1.7 2014/01/26 21:43:45 christos Exp $ */
23a571abcSchristos /*-
33a571abcSchristos  * Copyright (c) 1993, 1994
43a571abcSchristos  *	The Regents of the University of California.  All rights reserved.
53a571abcSchristos  * Copyright (c) 1993, 1994, 1995, 1996
63a571abcSchristos  *	Keith Bostic.  All rights reserved.
73a571abcSchristos  *
83a571abcSchristos  * See the LICENSE file for redistribution information.
93a571abcSchristos  */
103a571abcSchristos 
113a571abcSchristos #include "config.h"
123a571abcSchristos 
13*cc73507aSchristos #include <sys/cdefs.h>
14*cc73507aSchristos #if 0
153a571abcSchristos #ifndef lint
163a571abcSchristos static const char sccsid[] = "Id: vs_split.c,v 10.42 2001/06/25 15:19:38 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:38 ";
173a571abcSchristos #endif /* not lint */
18*cc73507aSchristos #else
19*cc73507aSchristos __RCSID("$NetBSD: vs_split.c,v 1.7 2014/01/26 21:43:45 christos Exp $");
20*cc73507aSchristos #endif
213a571abcSchristos 
223a571abcSchristos #include <sys/types.h>
233a571abcSchristos #include <sys/queue.h>
243a571abcSchristos #include <sys/time.h>
253a571abcSchristos 
263a571abcSchristos #include <bitstring.h>
273a571abcSchristos #include <errno.h>
283a571abcSchristos #include <limits.h>
293a571abcSchristos #include <stdio.h>
303a571abcSchristos #include <stdlib.h>
313a571abcSchristos #include <string.h>
323a571abcSchristos 
333a571abcSchristos #include "../common/common.h"
343a571abcSchristos #include "vi.h"
353a571abcSchristos 
363a571abcSchristos typedef enum { HORIZ_FOLLOW, HORIZ_PRECEDE, VERT_FOLLOW, VERT_PRECEDE } jdir_t;
373a571abcSchristos 
3808d478e3Schristos static SCR	*vs_getbg __P((SCR *, const char *));
393a571abcSchristos static void      vs_insert __P((SCR *sp, WIN *wp));
403a571abcSchristos static int	 vs_join __P((SCR *, SCR **, jdir_t *));
413a571abcSchristos 
423a571abcSchristos /*
433a571abcSchristos  * vs_split --
443a571abcSchristos  *	Create a new screen, horizontally.
453a571abcSchristos  *
463a571abcSchristos  * PUBLIC: int vs_split __P((SCR *, SCR *, int));
473a571abcSchristos  */
483a571abcSchristos int
vs_split(SCR * sp,SCR * new,int ccl)493a571abcSchristos vs_split(SCR *sp, SCR *new, int ccl)
503a571abcSchristos 
513a571abcSchristos 	        		/* Colon-command line split. */
523a571abcSchristos {
533a571abcSchristos 	GS *gp;
543a571abcSchristos 	SMAP *smp;
553a571abcSchristos 	size_t half;
563a571abcSchristos 	int issmallscreen, splitup;
573a571abcSchristos 
583a571abcSchristos 	gp = sp->gp;
593a571abcSchristos 
603a571abcSchristos 	/* Check to see if it's possible. */
613a571abcSchristos 	/* XXX: The IS_ONELINE fix will change this, too. */
623a571abcSchristos 	if (sp->rows < 4) {
633a571abcSchristos 		msgq(sp, M_ERR,
643a571abcSchristos 		    "222|Screen must be larger than %d lines to split", 4 - 1);
653a571abcSchristos 		return (1);
663a571abcSchristos 	}
673a571abcSchristos 
683a571abcSchristos 	/* Wait for any messages in the screen. */
693a571abcSchristos 	vs_resolve(sp, NULL, 1);
703a571abcSchristos 
713a571abcSchristos 	/* Get a new screen map. */
723a571abcSchristos 	CALLOC(sp, _HMAP(new), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
733a571abcSchristos 	if (_HMAP(new) == NULL)
743a571abcSchristos 		return (1);
753a571abcSchristos 	_HMAP(new)->lno = sp->lno;
763a571abcSchristos 	_HMAP(new)->coff = 0;
773a571abcSchristos 	_HMAP(new)->soff = 1;
783a571abcSchristos 
793a571abcSchristos 	/* Split the screen in half. */
803a571abcSchristos 	half = sp->rows / 2;
813a571abcSchristos 	if (ccl && half > 6)
823a571abcSchristos 		half = 6;
833a571abcSchristos 
843a571abcSchristos 	/*
853a571abcSchristos 	 * Small screens: see vs_refresh.c section 6a.  Set a flag so
863a571abcSchristos 	 * we know to fix the screen up later.
873a571abcSchristos 	 */
883a571abcSchristos 	issmallscreen = IS_SMALL(sp);
893a571abcSchristos 
903a571abcSchristos 	/* The columns in the screen don't change. */
913a571abcSchristos 	new->coff = sp->coff;
923a571abcSchristos 	new->cols = sp->cols;
933a571abcSchristos 
943a571abcSchristos 	/*
953a571abcSchristos 	 * Split the screen, and link the screens together.  If creating a
963a571abcSchristos 	 * screen to edit the colon command line or the cursor is in the top
973a571abcSchristos 	 * half of the current screen, the new screen goes under the current
983a571abcSchristos 	 * screen.  Else, it goes above the current screen.
993a571abcSchristos 	 *
1003a571abcSchristos 	 * Recalculate current cursor position based on sp->lno, we're called
1013a571abcSchristos 	 * with the cursor on the colon command line.  Then split the screen
1023a571abcSchristos 	 * in half and update the shared information.
1033a571abcSchristos 	 */
1043a571abcSchristos 	splitup =
10508d478e3Schristos 	    !ccl && (vs_sm_cursor(sp, &smp) ? 0 : (size_t)(smp - HMAP) + 1) >= half;
1063a571abcSchristos 	if (splitup) {				/* Old is bottom half. */
1073a571abcSchristos 		new->rows = sp->rows - half;	/* New. */
1083a571abcSchristos 		new->roff = sp->roff;
1093a571abcSchristos 		sp->rows = half;		/* Old. */
1103a571abcSchristos 		sp->roff += new->rows;
1113a571abcSchristos 
1123a571abcSchristos 		/*
1133a571abcSchristos 		 * If the parent is the bottom half of the screen, shift
1143a571abcSchristos 		 * the map down to match on-screen text.
1153a571abcSchristos 		 */
1163a571abcSchristos 		memcpy(_HMAP(sp), _HMAP(sp) + new->rows,
1173a571abcSchristos 		    (sp->t_maxrows - new->rows) * sizeof(SMAP));
1183a571abcSchristos 	} else {				/* Old is top half. */
1193a571abcSchristos 		new->rows = half;		/* New. */
1203a571abcSchristos 		sp->rows -= half;		/* Old. */
1213a571abcSchristos 		new->roff = sp->roff + sp->rows;
1223a571abcSchristos 	}
1233a571abcSchristos 
1243a571abcSchristos 	/* Adjust maximum text count. */
1253a571abcSchristos 	sp->t_maxrows = IS_ONELINE(sp) ? 1 : sp->rows - 1;
1263a571abcSchristos 	new->t_maxrows = IS_ONELINE(new) ? 1 : new->rows - 1;
1273a571abcSchristos 
1283a571abcSchristos 	/*
1293a571abcSchristos 	 * Small screens: see vs_refresh.c, section 6a.
1303a571abcSchristos 	 *
1313a571abcSchristos 	 * The child may have different screen options sizes than the parent,
1323a571abcSchristos 	 * so use them.  Guarantee that text counts aren't larger than the
1333a571abcSchristos 	 * new screen sizes.
1343a571abcSchristos 	 */
1353a571abcSchristos 	if (issmallscreen) {
1363a571abcSchristos 		/* Fix the text line count for the parent. */
1373a571abcSchristos 		if (splitup)
1383a571abcSchristos 			sp->t_rows -= new->rows;
1393a571abcSchristos 
1403a571abcSchristos 		/* Fix the parent screen. */
1413a571abcSchristos 		if (sp->t_rows > sp->t_maxrows)
1423a571abcSchristos 			sp->t_rows = sp->t_maxrows;
1433a571abcSchristos 		if (sp->t_minrows > sp->t_maxrows)
1443a571abcSchristos 			sp->t_minrows = sp->t_maxrows;
1453a571abcSchristos 
1463a571abcSchristos 		/* Fix the child screen. */
1473a571abcSchristos 		new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW);
1483a571abcSchristos 		if (new->t_rows > new->t_maxrows)
1493a571abcSchristos 			new->t_rows = new->t_maxrows;
1503a571abcSchristos 		if (new->t_minrows > new->t_maxrows)
1513a571abcSchristos 			new->t_minrows = new->t_maxrows;
1523a571abcSchristos 	} else {
1533a571abcSchristos 		sp->t_minrows = sp->t_rows = IS_ONELINE(sp) ? 1 : sp->rows - 1;
1543a571abcSchristos 
1553a571abcSchristos 		/*
1563a571abcSchristos 		 * The new screen may be a small screen, even if the parent
1573a571abcSchristos 		 * was not.  Don't complain if O_WINDOW is too large, we're
1583a571abcSchristos 		 * splitting the screen so the screen is much smaller than
1593a571abcSchristos 		 * normal.
1603a571abcSchristos 		 */
1613a571abcSchristos 		new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW);
1623a571abcSchristos 		if (new->t_rows > new->rows - 1)
1633a571abcSchristos 			new->t_minrows = new->t_rows =
1643a571abcSchristos 			    IS_ONELINE(new) ? 1 : new->rows - 1;
1653a571abcSchristos 	}
1663a571abcSchristos 
1673a571abcSchristos 	/* Adjust the ends of the new and old maps. */
1683a571abcSchristos 	_TMAP(sp) = IS_ONELINE(sp) ?
1693a571abcSchristos 	    _HMAP(sp) : _HMAP(sp) + (sp->t_rows - 1);
1703a571abcSchristos 	_TMAP(new) = IS_ONELINE(new) ?
1713a571abcSchristos 	    _HMAP(new) : _HMAP(new) + (new->t_rows - 1);
1723a571abcSchristos 
1733a571abcSchristos 	/* Reset the length of the default scroll. */
1743a571abcSchristos 	if ((sp->defscroll = sp->t_maxrows / 2) == 0)
1753a571abcSchristos 		sp->defscroll = 1;
1763a571abcSchristos 	if ((new->defscroll = new->t_maxrows / 2) == 0)
1773a571abcSchristos 		new->defscroll = 1;
1783a571abcSchristos 
1793a571abcSchristos 	/* Fit the screen into the logical chain. */
1803a571abcSchristos 	vs_insert(new, sp->wp);
1813a571abcSchristos 
1823a571abcSchristos 	/* Tell the display that we're splitting. */
1833a571abcSchristos 	(void)gp->scr_split(sp, new);
1843a571abcSchristos 
1853a571abcSchristos 	/*
1863a571abcSchristos 	 * Initialize the screen flags:
1873a571abcSchristos 	 *
1883a571abcSchristos 	 * If we're in vi mode in one screen, we don't have to reinitialize.
1893a571abcSchristos 	 * This isn't just a cosmetic fix.  The path goes like this:
1903a571abcSchristos 	 *
1913a571abcSchristos 	 *	return into vi(), SC_SSWITCH set
1923a571abcSchristos 	 *	call vs_refresh() with SC_STATUS set
1933a571abcSchristos 	 *	call vs_resolve to display the status message
1943a571abcSchristos 	 *	call vs_refresh() because the SC_SCR_VI bit isn't set
1953a571abcSchristos 	 *
1963a571abcSchristos 	 * Things go downhill at this point.
1973a571abcSchristos 	 *
1983a571abcSchristos 	 * Draw the new screen from scratch, and add a status line.
1993a571abcSchristos 	 */
2003a571abcSchristos 	F_SET(new,
2013a571abcSchristos 	    SC_SCR_REFORMAT | SC_STATUS |
2023a571abcSchristos 	    F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX));
2033a571abcSchristos 	return (0);
2043a571abcSchristos }
2053a571abcSchristos 
2063a571abcSchristos /*
2073a571abcSchristos  * vs_vsplit --
2083a571abcSchristos  *	Create a new screen, vertically.
2093a571abcSchristos  *
2103a571abcSchristos  * PUBLIC: int vs_vsplit __P((SCR *, SCR *));
2113a571abcSchristos  */
2123a571abcSchristos int
vs_vsplit(SCR * sp,SCR * new)2133a571abcSchristos vs_vsplit(SCR *sp, SCR *new)
2143a571abcSchristos {
2153a571abcSchristos 	GS *gp;
2163a571abcSchristos 	size_t cols;
2173a571abcSchristos 
2183a571abcSchristos 	gp = sp->gp;
2193a571abcSchristos 
2203a571abcSchristos 	/* Check to see if it's possible. */
2213a571abcSchristos 	if (sp->cols / 2 <= MINIMUM_SCREEN_COLS) {
2223a571abcSchristos 		msgq(sp, M_ERR,
2233a571abcSchristos 		    "288|Screen must be larger than %d columns to split",
2243a571abcSchristos 		    MINIMUM_SCREEN_COLS * 2);
2253a571abcSchristos 		return (1);
2263a571abcSchristos 	}
2273a571abcSchristos 
2283a571abcSchristos 	/* Wait for any messages in the screen. */
2293a571abcSchristos 	vs_resolve(sp, NULL, 1);
2303a571abcSchristos 
2313a571abcSchristos 	/* Get a new screen map. */
2323a571abcSchristos 	CALLOC(sp, _HMAP(new), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
2333a571abcSchristos 	if (_HMAP(new) == NULL)
2343a571abcSchristos 		return (1);
2353a571abcSchristos 	_HMAP(new)->lno = sp->lno;
2363a571abcSchristos 	_HMAP(new)->coff = 0;
2373a571abcSchristos 	_HMAP(new)->soff = 1;
2383a571abcSchristos 
2393a571abcSchristos 	/*
2403a571abcSchristos 	 * Split the screen in half; we have to sacrifice a column to delimit
2413a571abcSchristos 	 * the screens.
2423a571abcSchristos 	 *
2433a571abcSchristos 	 * XXX
2443a571abcSchristos 	 * We always split to the right... that makes more sense to me, and
2453a571abcSchristos 	 * I don't want to play the stupid games that I play when splitting
2463a571abcSchristos 	 * horizontally.
2473a571abcSchristos 	 *
2483a571abcSchristos 	 * XXX
2493a571abcSchristos 	 * We reserve a column for the screen, "knowing" that curses needs
2503a571abcSchristos 	 * one.  This should be worked out with the display interface.
2513a571abcSchristos 	 */
2523a571abcSchristos 	cols = sp->cols / 2;
2533a571abcSchristos 	new->cols = sp->cols - cols - 1;
2543a571abcSchristos 	sp->cols = cols;
2553a571abcSchristos 	new->coff = sp->coff + cols + 1;
2563a571abcSchristos 	sp->cno = 0;
2573a571abcSchristos 
2583a571abcSchristos 	/* Nothing else changes. */
2593a571abcSchristos 	new->rows = sp->rows;
2603a571abcSchristos 	new->t_rows = sp->t_rows;
2613a571abcSchristos 	new->t_maxrows = sp->t_maxrows;
2623a571abcSchristos 	new->t_minrows = sp->t_minrows;
2633a571abcSchristos 	new->roff = sp->roff;
2643a571abcSchristos 	new->defscroll = sp->defscroll;
2653a571abcSchristos 	_TMAP(new) = _HMAP(new) + (new->t_rows - 1);
2663a571abcSchristos 
2673a571abcSchristos 	/* Fit the screen into the logical chain. */
2683a571abcSchristos 	vs_insert(new, sp->wp);
2693a571abcSchristos 
2703a571abcSchristos 	/* Tell the display that we're splitting. */
2713a571abcSchristos 	(void)gp->scr_split(sp, new);
2723a571abcSchristos 
2733a571abcSchristos 	/* Redraw the old screen from scratch. */
2743a571abcSchristos 	F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);
2753a571abcSchristos 
2763a571abcSchristos 	/*
2773a571abcSchristos 	 * Initialize the screen flags:
2783a571abcSchristos 	 *
2793a571abcSchristos 	 * If we're in vi mode in one screen, we don't have to reinitialize.
2803a571abcSchristos 	 * This isn't just a cosmetic fix.  The path goes like this:
2813a571abcSchristos 	 *
2823a571abcSchristos 	 *	return into vi(), SC_SSWITCH set
2833a571abcSchristos 	 *	call vs_refresh() with SC_STATUS set
2843a571abcSchristos 	 *	call vs_resolve to display the status message
2853a571abcSchristos 	 *	call vs_refresh() because the SC_SCR_VI bit isn't set
2863a571abcSchristos 	 *
2873a571abcSchristos 	 * Things go downhill at this point.
2883a571abcSchristos 	 *
2893a571abcSchristos 	 * Draw the new screen from scratch, and add a status line.
2903a571abcSchristos 	 */
2913a571abcSchristos 	F_SET(new,
2923a571abcSchristos 	    SC_SCR_REFORMAT | SC_STATUS |
2933a571abcSchristos 	    F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX));
2943a571abcSchristos 	return (0);
2953a571abcSchristos }
2963a571abcSchristos 
2973a571abcSchristos /*
2983a571abcSchristos  * vs_insert --
2993a571abcSchristos  *	Insert the new screen into the correct place in the logical
3003a571abcSchristos  *	chain.
3013a571abcSchristos  */
3023a571abcSchristos static void
vs_insert(SCR * sp,WIN * wp)3033a571abcSchristos vs_insert(SCR *sp, WIN *wp)
3043a571abcSchristos {
3053a571abcSchristos 	SCR *tsp;
3063a571abcSchristos 
3073a571abcSchristos 	sp->wp = wp;
3083a571abcSchristos 
3093a571abcSchristos 	/* Move past all screens with lower row numbers. */
3100b5c88f5Schristos 	TAILQ_FOREACH(tsp, &wp->scrq, q)
3113a571abcSchristos 		if (tsp->roff >= sp->roff)
3123a571abcSchristos 			break;
3133a571abcSchristos 	/*
3143a571abcSchristos 	 * Move past all screens with the same row number and lower
3153a571abcSchristos 	 * column numbers.
3163a571abcSchristos 	 */
3170b5c88f5Schristos 	for (; tsp != NULL; tsp = TAILQ_NEXT(tsp, q))
3183a571abcSchristos 		if (tsp->roff != sp->roff || tsp->coff > sp->coff)
3193a571abcSchristos 			break;
3203a571abcSchristos 
3213a571abcSchristos 	/*
3223a571abcSchristos 	 * If we reached the end, this screen goes there.  Otherwise,
3233a571abcSchristos 	 * put it before or after the screen where we stopped.
3243a571abcSchristos 	 */
3250b5c88f5Schristos 	if (tsp == NULL) {
3260b5c88f5Schristos 		TAILQ_INSERT_TAIL(&wp->scrq, sp, q);
3273a571abcSchristos 	} else if (tsp->roff < sp->roff ||
3283a571abcSchristos 	    (tsp->roff == sp->roff && tsp->coff < sp->coff)) {
3290b5c88f5Schristos 		TAILQ_INSERT_AFTER(&wp->scrq, tsp, sp, q);
3303a571abcSchristos 	} else
3310b5c88f5Schristos 		TAILQ_INSERT_BEFORE(tsp, sp, q);
3323a571abcSchristos }
3333a571abcSchristos 
3343a571abcSchristos /*
3353a571abcSchristos  * vs_discard --
3363a571abcSchristos  *	Discard the screen, folding the real-estate into a related screen,
3373a571abcSchristos  *	if one exists, and return that screen.
3383a571abcSchristos  *
3393a571abcSchristos  * PUBLIC: int vs_discard __P((SCR *, SCR **));
3403a571abcSchristos  */
3413a571abcSchristos int
vs_discard(SCR * sp,SCR ** spp)3423a571abcSchristos vs_discard(SCR *sp, SCR **spp)
3433a571abcSchristos {
3443a571abcSchristos 	GS *gp;
3453a571abcSchristos 	SCR *tsp, **lp, *list[100];
3463a571abcSchristos 	jdir_t jdir;
3473a571abcSchristos 
3483a571abcSchristos 	gp = sp->gp;
3493a571abcSchristos 
3503a571abcSchristos 	/*
3513a571abcSchristos 	 * Save the old screen's cursor information.
3523a571abcSchristos 	 *
3533a571abcSchristos 	 * XXX
3543a571abcSchristos 	 * If called after file_end(), and the underlying file was a tmp
3553a571abcSchristos 	 * file, it may have gone away.
3563a571abcSchristos 	 */
3573a571abcSchristos 	if (sp->frp != NULL) {
3583a571abcSchristos 		sp->frp->lno = sp->lno;
3593a571abcSchristos 		sp->frp->cno = sp->cno;
3603a571abcSchristos 		F_SET(sp->frp, FR_CURSORSET);
3613a571abcSchristos 	}
3623a571abcSchristos 
3633a571abcSchristos 	/* If no other screens to join, we're done. */
3643a571abcSchristos 	if (!IS_SPLIT(sp)) {
3653a571abcSchristos 		(void)gp->scr_discard(sp, NULL);
3663a571abcSchristos 
3673a571abcSchristos 		if (spp != NULL)
3683a571abcSchristos 			*spp = NULL;
3693a571abcSchristos 		return (0);
3703a571abcSchristos 	}
3713a571abcSchristos 
3723a571abcSchristos 	/*
3733a571abcSchristos 	 * Find a set of screens that cover one of the screen's borders.
3743a571abcSchristos 	 * Check the vertical axis first, for no particular reason.
3753a571abcSchristos 	 *
3763a571abcSchristos 	 * XXX
3773a571abcSchristos 	 * It's possible (I think?), to create a screen that shares no full
3783a571abcSchristos 	 * border with any other set of screens, so we can't discard it.  We
3793a571abcSchristos 	 * just complain at the user until they clean it up.
3803a571abcSchristos 	 */
3813a571abcSchristos 	if (vs_join(sp, list, &jdir))
3823a571abcSchristos 		return (1);
3833a571abcSchristos 
3843a571abcSchristos 	/*
3853a571abcSchristos 	 * Modify the affected screens.  Redraw the modified screen(s) from
3863a571abcSchristos 	 * scratch, setting a status line.  If this is ever a performance
3873a571abcSchristos 	 * problem we could play games with the map, but I wrote that code
3883a571abcSchristos 	 * before and it was never clean or easy.
3893a571abcSchristos 	 *
3903a571abcSchristos 	 * Don't clean up the discarded screen's information.  If the screen
3913a571abcSchristos 	 * isn't exiting, we'll do the work when the user redisplays it.
3923a571abcSchristos 	 */
3933a571abcSchristos 	switch (jdir) {
3943a571abcSchristos 	case HORIZ_FOLLOW:
3953a571abcSchristos 	case HORIZ_PRECEDE:
3963a571abcSchristos 		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
3973a571abcSchristos 			/*
3983a571abcSchristos 			 * Small screens: see vs_refresh.c section 6a.  Adjust
3993a571abcSchristos 			 * text line info, unless it's a small screen.
4003a571abcSchristos 			 *
4013a571abcSchristos 			 * Reset the length of the default scroll.
4023a571abcSchristos 			 *
4033a571abcSchristos 			 * Reset the map references.
4043a571abcSchristos 			 */
4053a571abcSchristos 			tsp->rows += sp->rows;
4063a571abcSchristos 			if (!IS_SMALL(tsp))
4073a571abcSchristos 				tsp->t_rows = tsp->t_minrows = tsp->rows - 1;
4083a571abcSchristos 			tsp->t_maxrows = tsp->rows - 1;
4093a571abcSchristos 
4103a571abcSchristos 			tsp->defscroll = tsp->t_maxrows / 2;
4113a571abcSchristos 
4123a571abcSchristos 			*(_HMAP(tsp) + (tsp->t_rows - 1)) = *_TMAP(tsp);
4133a571abcSchristos 			_TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1);
4143a571abcSchristos 
4153a571abcSchristos 			switch (jdir) {
4163a571abcSchristos 			case HORIZ_FOLLOW:
4173a571abcSchristos 				tsp->roff = sp->roff;
4183a571abcSchristos 				vs_sm_fill(tsp, OOBLNO, P_TOP);
4193a571abcSchristos 				break;
4203a571abcSchristos 			case HORIZ_PRECEDE:
4213a571abcSchristos 				vs_sm_fill(tsp, OOBLNO, P_BOTTOM);
4223a571abcSchristos 				break;
4233a571abcSchristos 			default:
4243a571abcSchristos 				abort();
4253a571abcSchristos 			}
4263a571abcSchristos 			F_SET(tsp, SC_STATUS);
4273a571abcSchristos 		}
4283a571abcSchristos 		break;
4293a571abcSchristos 	case VERT_FOLLOW:
4303a571abcSchristos 	case VERT_PRECEDE:
4313a571abcSchristos 		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
4323a571abcSchristos 			if (jdir == VERT_FOLLOW)
4333a571abcSchristos 				tsp->coff = sp->coff;
4343a571abcSchristos 			tsp->cols += sp->cols + 1;	/* XXX: DIVIDER */
4353a571abcSchristos 			vs_sm_fill(tsp, OOBLNO, P_TOP);
4363a571abcSchristos 			F_SET(tsp, SC_STATUS);
4373a571abcSchristos 		}
4383a571abcSchristos 		break;
4393a571abcSchristos 	default:
4403a571abcSchristos 		abort();
4413a571abcSchristos 	}
4423a571abcSchristos 
4433a571abcSchristos 	/* Find the closest screen that changed and move to it. */
4443a571abcSchristos 	tsp = list[0];
4453a571abcSchristos 	if (spp != NULL)
4463a571abcSchristos 		*spp = tsp;
4473a571abcSchristos 
4483a571abcSchristos 	/* Tell the display that we're discarding a screen. */
4493a571abcSchristos 	(void)gp->scr_discard(sp, list);
4503a571abcSchristos 
4513a571abcSchristos 	return (0);
4523a571abcSchristos }
4533a571abcSchristos 
4543a571abcSchristos /*
4553a571abcSchristos  * vs_join --
4563a571abcSchristos  *	Find a set of screens that covers a screen's border.
4573a571abcSchristos  */
4583a571abcSchristos static int
vs_join(SCR * sp,SCR ** listp,jdir_t * jdirp)4593a571abcSchristos vs_join(SCR *sp, SCR **listp, jdir_t *jdirp)
4603a571abcSchristos {
4613a571abcSchristos 	WIN *wp;
4623a571abcSchristos 	SCR **lp, *tsp;
4633a571abcSchristos 	int first;
4643a571abcSchristos 	size_t tlen;
4653a571abcSchristos 
4663a571abcSchristos 	wp = sp->wp;
4673a571abcSchristos 
4683a571abcSchristos 	/* Check preceding vertical. */
4690b5c88f5Schristos 	lp = listp;
4700b5c88f5Schristos 	tlen = sp->rows;
4710b5c88f5Schristos 	TAILQ_FOREACH(tsp, &wp->scrq, q) {
4723a571abcSchristos 		if (sp == tsp)
4733a571abcSchristos 			continue;
4743a571abcSchristos 		/* Test if precedes the screen vertically. */
4753a571abcSchristos 		if (tsp->coff + tsp->cols + 1 != sp->coff)
4763a571abcSchristos 			continue;
4773a571abcSchristos 		/*
4783a571abcSchristos 		 * Test if a subset on the vertical axis.  If overlaps the
4793a571abcSchristos 		 * beginning or end, we can't join on this axis at all.
4803a571abcSchristos 		 */
4813a571abcSchristos 		if (tsp->roff > sp->roff + sp->rows)
4823a571abcSchristos 			continue;
4833a571abcSchristos 		if (tsp->roff < sp->roff) {
4843a571abcSchristos 			if (tsp->roff + tsp->rows >= sp->roff)
4853a571abcSchristos 				break;
4863a571abcSchristos 			continue;
4873a571abcSchristos 		}
4883a571abcSchristos 		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
4893a571abcSchristos 			break;
4903a571abcSchristos #ifdef DEBUG
4913a571abcSchristos 		if (tlen < tsp->rows)
4923a571abcSchristos 			abort();
4933a571abcSchristos #endif
4943a571abcSchristos 		tlen -= tsp->rows;
4953a571abcSchristos 		*lp++ = tsp;
4963a571abcSchristos 	}
4973a571abcSchristos 	if (tlen == 0) {
4983a571abcSchristos 		*lp = NULL;
4993a571abcSchristos 		*jdirp = VERT_PRECEDE;
5003a571abcSchristos 		return (0);
5013a571abcSchristos 	}
5023a571abcSchristos 
5033a571abcSchristos 	/* Check following vertical. */
5040b5c88f5Schristos 	lp = listp;
5050b5c88f5Schristos 	tlen = sp->rows;
5060b5c88f5Schristos 	TAILQ_FOREACH(tsp, &wp->scrq, q) {
5073a571abcSchristos 		if (sp == tsp)
5083a571abcSchristos 			continue;
5093a571abcSchristos 		/* Test if follows the screen vertically. */
5103a571abcSchristos 		if (tsp->coff != sp->coff + sp->cols + 1)
5113a571abcSchristos 			continue;
5123a571abcSchristos 		/*
5133a571abcSchristos 		 * Test if a subset on the vertical axis.  If overlaps the
5143a571abcSchristos 		 * beginning or end, we can't join on this axis at all.
5153a571abcSchristos 		 */
5163a571abcSchristos 		if (tsp->roff > sp->roff + sp->rows)
5173a571abcSchristos 			continue;
5183a571abcSchristos 		if (tsp->roff < sp->roff) {
5193a571abcSchristos 			if (tsp->roff + tsp->rows >= sp->roff)
5203a571abcSchristos 				break;
5213a571abcSchristos 			continue;
5223a571abcSchristos 		}
5233a571abcSchristos 		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
5243a571abcSchristos 			break;
5253a571abcSchristos #ifdef DEBUG
5263a571abcSchristos 		if (tlen < tsp->rows)
5273a571abcSchristos 			abort();
5283a571abcSchristos #endif
5293a571abcSchristos 		tlen -= tsp->rows;
5303a571abcSchristos 		*lp++ = tsp;
5313a571abcSchristos 	}
5323a571abcSchristos 	if (tlen == 0) {
5333a571abcSchristos 		*lp = NULL;
5343a571abcSchristos 		*jdirp = VERT_FOLLOW;
5353a571abcSchristos 		return (0);
5363a571abcSchristos 	}
5373a571abcSchristos 
5383a571abcSchristos 	/* Check preceding horizontal. */
5390b5c88f5Schristos 	first = 0;
5400b5c88f5Schristos 	lp = listp;
5410b5c88f5Schristos 	tlen = sp->cols;
5420b5c88f5Schristos 	TAILQ_FOREACH(tsp, &wp->scrq, q) {
5433a571abcSchristos 		if (sp == tsp)
5443a571abcSchristos 			continue;
5453a571abcSchristos 		/* Test if precedes the screen horizontally. */
5463a571abcSchristos 		if (tsp->roff + tsp->rows != sp->roff)
5473a571abcSchristos 			continue;
5483a571abcSchristos 		/*
5493a571abcSchristos 		 * Test if a subset on the horizontal axis.  If overlaps the
5503a571abcSchristos 		 * beginning or end, we can't join on this axis at all.
5513a571abcSchristos 		 */
5523a571abcSchristos 		if (tsp->coff > sp->coff + sp->cols)
5533a571abcSchristos 			continue;
5543a571abcSchristos 		if (tsp->coff < sp->coff) {
5553a571abcSchristos 			if (tsp->coff + tsp->cols >= sp->coff)
5563a571abcSchristos 				break;
5573a571abcSchristos 			continue;
5583a571abcSchristos 		}
5593a571abcSchristos 		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
5603a571abcSchristos 			break;
5613a571abcSchristos #ifdef DEBUG
5623a571abcSchristos 		if (tlen < tsp->cols)
5633a571abcSchristos 			abort();
5643a571abcSchristos #endif
5653a571abcSchristos 		tlen -= tsp->cols + first;
5663a571abcSchristos 		first = 1;
5673a571abcSchristos 		*lp++ = tsp;
5683a571abcSchristos 	}
5693a571abcSchristos 	if (tlen == 0) {
5703a571abcSchristos 		*lp = NULL;
5713a571abcSchristos 		*jdirp = HORIZ_PRECEDE;
5723a571abcSchristos 		return (0);
5733a571abcSchristos 	}
5743a571abcSchristos 
5753a571abcSchristos 	/* Check following horizontal. */
5760b5c88f5Schristos 	first = 0;
5770b5c88f5Schristos 	lp = listp;
5780b5c88f5Schristos 	tlen = sp->cols;
5790b5c88f5Schristos 	TAILQ_FOREACH(tsp, &wp->scrq, q) {
5803a571abcSchristos 		if (sp == tsp)
5813a571abcSchristos 			continue;
5823a571abcSchristos 		/* Test if precedes the screen horizontally. */
5833a571abcSchristos 		if (tsp->roff != sp->roff + sp->rows)
5843a571abcSchristos 			continue;
5853a571abcSchristos 		/*
5863a571abcSchristos 		 * Test if a subset on the horizontal axis.  If overlaps the
5873a571abcSchristos 		 * beginning or end, we can't join on this axis at all.
5883a571abcSchristos 		 */
5893a571abcSchristos 		if (tsp->coff > sp->coff + sp->cols)
5903a571abcSchristos 			continue;
5913a571abcSchristos 		if (tsp->coff < sp->coff) {
5923a571abcSchristos 			if (tsp->coff + tsp->cols >= sp->coff)
5933a571abcSchristos 				break;
5943a571abcSchristos 			continue;
5953a571abcSchristos 		}
5963a571abcSchristos 		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
5973a571abcSchristos 			break;
5983a571abcSchristos #ifdef DEBUG
5993a571abcSchristos 		if (tlen < tsp->cols)
6003a571abcSchristos 			abort();
6013a571abcSchristos #endif
6023a571abcSchristos 		tlen -= tsp->cols + first;
6033a571abcSchristos 		first = 1;
6043a571abcSchristos 		*lp++ = tsp;
6053a571abcSchristos 	}
6063a571abcSchristos 	if (tlen == 0) {
6073a571abcSchristos 		*lp = NULL;
6083a571abcSchristos 		*jdirp = HORIZ_FOLLOW;
6093a571abcSchristos 		return (0);
6103a571abcSchristos 	}
6113a571abcSchristos 	return (1);
6123a571abcSchristos }
6133a571abcSchristos 
6143a571abcSchristos /*
6153a571abcSchristos  * vs_fg --
6163a571abcSchristos  *	Background the current screen, and foreground a new one.
6173a571abcSchristos  *
6183a571abcSchristos  * PUBLIC: int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
6193a571abcSchristos  */
6203a571abcSchristos int
vs_fg(SCR * sp,SCR ** nspp,CHAR_T * name,int newscreen)6213a571abcSchristos vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen)
6223a571abcSchristos {
6233a571abcSchristos 	GS *gp;
6243a571abcSchristos 	WIN *wp;
6253a571abcSchristos 	SCR *nsp;
62608d478e3Schristos 	const char *np;
6273a571abcSchristos 	size_t nlen;
6283a571abcSchristos 
6293a571abcSchristos 	gp = sp->gp;
6303a571abcSchristos 	wp = sp->wp;
6313a571abcSchristos 
6323a571abcSchristos 	if (name)
6333a571abcSchristos 	    INT2CHAR(sp, name, STRLEN(name) + 1, np, nlen);
6343a571abcSchristos 	else
6353a571abcSchristos 	    np = NULL;
6363a571abcSchristos 	if (newscreen)
6373a571abcSchristos 		/* Get the specified background screen. */
6383a571abcSchristos 		nsp = vs_getbg(sp, np);
6393a571abcSchristos 	else
6403a571abcSchristos 		/* Swap screens. */
6413a571abcSchristos 		if (vs_swap(sp, &nsp, np))
6423a571abcSchristos 			return (1);
6433a571abcSchristos 
6443a571abcSchristos 	if ((*nspp = nsp) == NULL) {
6453a571abcSchristos 		msgq_wstr(sp, M_ERR, name,
6463a571abcSchristos 		    name == NULL ?
6473a571abcSchristos 		    "223|There are no background screens" :
6483a571abcSchristos 		    "224|There's no background screen editing a file named %s");
6493a571abcSchristos 		return (1);
6503a571abcSchristos 	}
6513a571abcSchristos 
6523a571abcSchristos 	if (newscreen) {
6533a571abcSchristos 		/* Remove the new screen from the background queue. */
6540b5c88f5Schristos 		TAILQ_REMOVE(&gp->hq, nsp, q);
6553a571abcSchristos 
6563a571abcSchristos 		/* Split the screen; if we fail, hook the screen back in. */
6573a571abcSchristos 		if (vs_split(sp, nsp, 0)) {
6580b5c88f5Schristos 			TAILQ_INSERT_TAIL(&gp->hq, nsp, q);
6593a571abcSchristos 			return (1);
6603a571abcSchristos 		}
6613a571abcSchristos 	} else {
6623a571abcSchristos 		/* Move the old screen to the background queue. */
6630b5c88f5Schristos 		TAILQ_REMOVE(&wp->scrq, sp, q);
6640b5c88f5Schristos 		TAILQ_INSERT_TAIL(&gp->hq, sp, q);
6653a571abcSchristos 	}
6663a571abcSchristos 	return (0);
6673a571abcSchristos }
6683a571abcSchristos 
6693a571abcSchristos /*
6703a571abcSchristos  * vs_bg --
6713a571abcSchristos  *	Background the screen, and switch to the next one.
6723a571abcSchristos  *
6733a571abcSchristos  * PUBLIC: int vs_bg __P((SCR *));
6743a571abcSchristos  */
6753a571abcSchristos int
vs_bg(SCR * sp)6763a571abcSchristos vs_bg(SCR *sp)
6773a571abcSchristos {
6783a571abcSchristos 	GS *gp;
6793a571abcSchristos 	WIN *wp;
6803a571abcSchristos 	SCR *nsp;
6813a571abcSchristos 
6823a571abcSchristos 	gp = sp->gp;
6833a571abcSchristos 	wp = sp->wp;
6843a571abcSchristos 
6853a571abcSchristos 	/* Try and join with another screen. */
6863a571abcSchristos 	if (vs_discard(sp, &nsp))
6873a571abcSchristos 		return (1);
6883a571abcSchristos 	if (nsp == NULL) {
6893a571abcSchristos 		msgq(sp, M_ERR,
6903a571abcSchristos 		    "225|You may not background your only displayed screen");
6913a571abcSchristos 		return (1);
6923a571abcSchristos 	}
6933a571abcSchristos 
6943a571abcSchristos 	/* Move the old screen to the background queue. */
6950b5c88f5Schristos 	TAILQ_REMOVE(&wp->scrq, sp, q);
6960b5c88f5Schristos 	TAILQ_INSERT_TAIL(&gp->hq, sp, q);
6973a571abcSchristos 
6983a571abcSchristos 	/* Toss the screen map. */
6993a571abcSchristos 	free(_HMAP(sp));
7003a571abcSchristos 	_HMAP(sp) = NULL;
7013a571abcSchristos 
7023a571abcSchristos 	/* Switch screens. */
7033a571abcSchristos 	sp->nextdisp = nsp;
7043a571abcSchristos 	F_SET(sp, SC_SSWITCH);
7053a571abcSchristos 
7063a571abcSchristos 	return (0);
7073a571abcSchristos }
7083a571abcSchristos 
7093a571abcSchristos /*
7103a571abcSchristos  * vs_swap --
7113a571abcSchristos  *	Swap the current screen with a backgrounded one.
7123a571abcSchristos  *
71308d478e3Schristos  * PUBLIC: int vs_swap __P((SCR *, SCR **, const char *));
7143a571abcSchristos  */
7153a571abcSchristos int
vs_swap(SCR * sp,SCR ** nspp,const char * name)71608d478e3Schristos vs_swap(SCR *sp, SCR **nspp, const char *name)
7173a571abcSchristos {
7183a571abcSchristos 	GS *gp;
7193a571abcSchristos 	WIN *wp;
7203a571abcSchristos 	SCR *nsp, *list[2];
7213a571abcSchristos 
7223a571abcSchristos 	gp = sp->gp;
7233a571abcSchristos 	wp = sp->wp;
7243a571abcSchristos 
7253a571abcSchristos 	/* Get the specified background screen. */
7263a571abcSchristos 	if ((*nspp = nsp = vs_getbg(sp, name)) == NULL)
7273a571abcSchristos 		return (0);
7283a571abcSchristos 
7293a571abcSchristos 	/*
7303a571abcSchristos 	 * Save the old screen's cursor information.
7313a571abcSchristos 	 *
7323a571abcSchristos 	 * XXX
7333a571abcSchristos 	 * If called after file_end(), and the underlying file was a tmp
7343a571abcSchristos 	 * file, it may have gone away.
7353a571abcSchristos 	 */
7363a571abcSchristos 	if (sp->frp != NULL) {
7373a571abcSchristos 		sp->frp->lno = sp->lno;
7383a571abcSchristos 		sp->frp->cno = sp->cno;
7393a571abcSchristos 		F_SET(sp->frp, FR_CURSORSET);
7403a571abcSchristos 	}
7413a571abcSchristos 
7423a571abcSchristos 	/* Switch screens. */
7433a571abcSchristos 	sp->nextdisp = nsp;
7443a571abcSchristos 	F_SET(sp, SC_SSWITCH);
7453a571abcSchristos 
7463a571abcSchristos 	/* Initialize terminal information. */
7473a571abcSchristos 	VIP(nsp)->srows = VIP(sp)->srows;
7483a571abcSchristos 
7493a571abcSchristos 	/* Initialize screen information. */
7503a571abcSchristos 	nsp->cols = sp->cols;
7513a571abcSchristos 	nsp->rows = sp->rows;	/* XXX: Only place in vi that sets rows. */
7523a571abcSchristos 	nsp->roff = sp->roff;
7533a571abcSchristos 
7543a571abcSchristos 	/*
7553a571abcSchristos 	 * Small screens: see vs_refresh.c, section 6a.
7563a571abcSchristos 	 *
7573a571abcSchristos 	 * The new screens may have different screen options sizes than the
7583a571abcSchristos 	 * old one, so use them.  Make sure that text counts aren't larger
7593a571abcSchristos 	 * than the new screen sizes.
7603a571abcSchristos 	 */
7613a571abcSchristos 	if (IS_SMALL(nsp)) {
7623a571abcSchristos 		nsp->t_minrows = nsp->t_rows = O_VAL(nsp, O_WINDOW);
7633a571abcSchristos 		if (nsp->t_rows > sp->t_maxrows)
7643a571abcSchristos 			nsp->t_rows = nsp->t_maxrows;
7653a571abcSchristos 		if (nsp->t_minrows > sp->t_maxrows)
7663a571abcSchristos 			nsp->t_minrows = nsp->t_maxrows;
7673a571abcSchristos 	} else
7683a571abcSchristos 		nsp->t_rows = nsp->t_maxrows = nsp->t_minrows = nsp->rows - 1;
7693a571abcSchristos 
7703a571abcSchristos 	/* Reset the length of the default scroll. */
7713a571abcSchristos 	nsp->defscroll = nsp->t_maxrows / 2;
7723a571abcSchristos 
7733a571abcSchristos 	/* Allocate a new screen map. */
7743a571abcSchristos 	CALLOC_RET(nsp, _HMAP(nsp), SMAP *, SIZE_HMAP(nsp), sizeof(SMAP));
7753a571abcSchristos 	_TMAP(nsp) = _HMAP(nsp) + (nsp->t_rows - 1);
7763a571abcSchristos 
7773a571abcSchristos 	/* Fill the map. */
7783a571abcSchristos 	nsp->wp = sp->wp;
7793a571abcSchristos 	if (vs_sm_fill(nsp, nsp->lno, P_FILL))
7803a571abcSchristos 		return (1);
7813a571abcSchristos 
7823a571abcSchristos 	/*
7833a571abcSchristos 	 * The new screen replaces the old screen in the parent/child list.
7843a571abcSchristos 	 * We insert the new screen after the old one.  If we're exiting,
7853a571abcSchristos 	 * the exit will delete the old one, if we're foregrounding, the fg
7863a571abcSchristos 	 * code will move the old one to the background queue.
7873a571abcSchristos 	 */
7880b5c88f5Schristos 	TAILQ_REMOVE(&gp->hq, nsp, q);
7890b5c88f5Schristos 	TAILQ_INSERT_AFTER(&wp->scrq, sp, nsp, q);
7903a571abcSchristos 
7913a571abcSchristos 	/*
7923a571abcSchristos 	 * Don't change the screen's cursor information other than to
7933a571abcSchristos 	 * note that the cursor is wrong.
7943a571abcSchristos 	 */
7953a571abcSchristos 	F_SET(VIP(nsp), VIP_CUR_INVALID);
7963a571abcSchristos 
7973a571abcSchristos 	/* Draw the new screen from scratch, and add a status line. */
7983a571abcSchristos 	F_SET(nsp, SC_SCR_REDRAW | SC_STATUS);
7993a571abcSchristos 
8003a571abcSchristos 	list[0] = nsp; list[1] = NULL;
8013a571abcSchristos 	(void)gp->scr_discard(sp, list);
8023a571abcSchristos 
8033a571abcSchristos 	return (0);
8043a571abcSchristos }
8053a571abcSchristos 
8063a571abcSchristos /*
8073a571abcSchristos  * vs_resize --
8083a571abcSchristos  *	Change the absolute size of the current screen.
8093a571abcSchristos  *
8103a571abcSchristos  * PUBLIC: int vs_resize __P((SCR *, long, adj_t));
8113a571abcSchristos  */
8123a571abcSchristos int
vs_resize(SCR * sp,long int count,adj_t adj)8133a571abcSchristos vs_resize(SCR *sp, long int count, adj_t adj)
8143a571abcSchristos {
8153a571abcSchristos 	GS *gp;
8163a571abcSchristos 	SCR *g, *s, *prev, *next, *list[3] = {NULL, NULL, NULL};
8173a571abcSchristos 	size_t g_off, s_off;
8183a571abcSchristos 
8193a571abcSchristos 	gp = sp->gp;
8203a571abcSchristos 
8213a571abcSchristos 	/*
8223a571abcSchristos 	 * Figure out which screens will grow, which will shrink, and
8233a571abcSchristos 	 * make sure it's possible.
8243a571abcSchristos 	 */
8253a571abcSchristos 	if (count == 0)
8263a571abcSchristos 		return (0);
8273a571abcSchristos 	if (adj == A_SET) {
82808d478e3Schristos 		if (sp->t_maxrows == (size_t)count)
8293a571abcSchristos 			return (0);
83008d478e3Schristos 		if (sp->t_maxrows > (size_t)count) {
8313a571abcSchristos 			adj = A_DECREASE;
8323a571abcSchristos 			count = sp->t_maxrows - count;
8333a571abcSchristos 		} else {
8343a571abcSchristos 			adj = A_INCREASE;
8353a571abcSchristos 			count = count - sp->t_maxrows;
8363a571abcSchristos 		}
8373a571abcSchristos 	}
8383a571abcSchristos 
8393a571abcSchristos 	/* Find first overlapping screen */
8400b5c88f5Schristos 	for (next = TAILQ_NEXT(sp, q);
8410b5c88f5Schristos 	     next != NULL &&
8423a571abcSchristos 	     (next->coff >= sp->coff + sp->cols ||
8433a571abcSchristos 	      next->coff + next->cols <= sp->coff);
8440b5c88f5Schristos 	     next = TAILQ_NEXT(next, q))
8450b5c88f5Schristos 		continue;
8463a571abcSchristos 	/* See if we can use it */
8470b5c88f5Schristos 	if (next != NULL &&
8483a571abcSchristos 	    (sp->coff != next->coff || sp->cols != next->cols))
8490b5c88f5Schristos 		next = NULL;
8500b5c88f5Schristos 	for (prev = TAILQ_PREV(sp, _scrh, q);
8510b5c88f5Schristos 	     prev != NULL &&
8523a571abcSchristos 	     (prev->coff >= sp->coff + sp->cols ||
8533a571abcSchristos 	      prev->coff + prev->cols <= sp->coff);
8540b5c88f5Schristos 	     prev = TAILQ_PREV(prev, _scrh, q))
8550b5c88f5Schristos 		continue;
8560b5c88f5Schristos 	if (prev != NULL &&
8573a571abcSchristos 	    (sp->coff != prev->coff || sp->cols != prev->cols))
8580b5c88f5Schristos 		prev = NULL;
8593a571abcSchristos 
8603a571abcSchristos 	g_off = s_off = 0;
8613a571abcSchristos 	if (adj == A_DECREASE) {
8623a571abcSchristos 		if (count < 0)
8633a571abcSchristos 			count = -count;
8643a571abcSchristos 		s = sp;
86508d478e3Schristos 		if (s->t_maxrows < MINIMUM_SCREEN_ROWS + (size_t)count)
8663a571abcSchristos 			goto toosmall;
8670b5c88f5Schristos 		if ((g = prev) == NULL) {
8680b5c88f5Schristos 			if ((g = next) == NULL)
8693a571abcSchristos 				goto toobig;
8703a571abcSchristos 			g_off = -count;
8713a571abcSchristos 		} else
8723a571abcSchristos 			s_off = count;
8733a571abcSchristos 	} else {
8743a571abcSchristos 		g = sp;
8750b5c88f5Schristos 		if ((s = next) != NULL &&
87608d478e3Schristos 		    s->t_maxrows >= MINIMUM_SCREEN_ROWS + (size_t)count)
8773a571abcSchristos 				s_off = count;
8783a571abcSchristos 		else
8793a571abcSchristos 			s = NULL;
8803a571abcSchristos 		if (s == NULL) {
8810b5c88f5Schristos 			if ((s = prev) == NULL) {
8823a571abcSchristos toobig:				msgq(sp, M_BERR, adj == A_DECREASE ?
8833a571abcSchristos 				    "227|The screen cannot shrink" :
8843a571abcSchristos 				    "228|The screen cannot grow");
8853a571abcSchristos 				return (1);
8863a571abcSchristos 			}
88708d478e3Schristos 			if (s->t_maxrows < MINIMUM_SCREEN_ROWS + (size_t)count) {
8883a571abcSchristos toosmall:			msgq(sp, M_BERR,
8893a571abcSchristos 				    "226|The screen can only shrink to %d rows",
8903a571abcSchristos 				    MINIMUM_SCREEN_ROWS);
8913a571abcSchristos 				return (1);
8923a571abcSchristos 			}
8933a571abcSchristos 			g_off = -count;
8943a571abcSchristos 		}
8953a571abcSchristos 	}
8963a571abcSchristos 
8973a571abcSchristos 	/*
8983a571abcSchristos 	 * Fix up the screens; we could optimize the reformatting of the
8993a571abcSchristos 	 * screen, but this isn't likely to be a common enough operation
9003a571abcSchristos 	 * to make it worthwhile.
9013a571abcSchristos 	 */
9023a571abcSchristos 	s->rows += -count;
9033a571abcSchristos 	s->roff += s_off;
9043a571abcSchristos 	g->rows += count;
9053a571abcSchristos 	g->roff += g_off;
9063a571abcSchristos 
9073a571abcSchristos 	g->t_rows += count;
9083a571abcSchristos 	if (g->t_minrows == g->t_maxrows)
9093a571abcSchristos 		g->t_minrows += count;
9103a571abcSchristos 	g->t_maxrows += count;
9113a571abcSchristos 	_TMAP(g) += count;
9123a571abcSchristos 	F_SET(g, SC_SCR_REFORMAT | SC_STATUS);
9133a571abcSchristos 
9143a571abcSchristos 	s->t_rows -= count;
9153a571abcSchristos 	s->t_maxrows -= count;
9163a571abcSchristos 	if (s->t_minrows > s->t_maxrows)
9173a571abcSchristos 		s->t_minrows = s->t_maxrows;
9183a571abcSchristos 	_TMAP(s) -= count;
9193a571abcSchristos 	F_SET(s, SC_SCR_REFORMAT | SC_STATUS);
9203a571abcSchristos 
9213a571abcSchristos 	/* XXXX */
9223a571abcSchristos 	list[0] = g; list[1] = s;
9233a571abcSchristos 	gp->scr_discard(0, list);
9243a571abcSchristos 
9253a571abcSchristos 	return (0);
9263a571abcSchristos }
9273a571abcSchristos 
9283a571abcSchristos /*
9293a571abcSchristos  * vs_getbg --
9303a571abcSchristos  *	Get the specified background screen, or, if name is NULL, the first
9313a571abcSchristos  *	background screen.
9323a571abcSchristos  */
9333a571abcSchristos static SCR *
vs_getbg(SCR * sp,const char * name)93408d478e3Schristos vs_getbg(SCR *sp, const char *name)
9353a571abcSchristos {
9363a571abcSchristos 	GS *gp;
9373a571abcSchristos 	SCR *nsp;
9383a571abcSchristos 	char *p;
9393a571abcSchristos 
9403a571abcSchristos 	gp = sp->gp;
9413a571abcSchristos 
9423a571abcSchristos 	/* If name is NULL, return the first background screen on the list. */
9433a571abcSchristos 	if (name == NULL) {
9440b5c88f5Schristos 		return TAILQ_FIRST(&gp->hq);
9453a571abcSchristos 	}
9463a571abcSchristos 
9473a571abcSchristos 	/* Search for a full match. */
9480b5c88f5Schristos 	TAILQ_FOREACH(nsp, &gp->hq, q)
9493a571abcSchristos 		if (!strcmp(nsp->frp->name, name))
9503a571abcSchristos 			break;
9510b5c88f5Schristos 	if (nsp != NULL)
9523a571abcSchristos 		return (nsp);
9533a571abcSchristos 
9543a571abcSchristos 	/* Search for a last-component match. */
9550b5c88f5Schristos 	TAILQ_FOREACH(nsp, &gp->hq, q) {
9563a571abcSchristos 		if ((p = strrchr(nsp->frp->name, '/')) == NULL)
9573a571abcSchristos 			p = nsp->frp->name;
9583a571abcSchristos 		else
9593a571abcSchristos 			++p;
9603a571abcSchristos 		if (!strcmp(p, name))
9613a571abcSchristos 			break;
9623a571abcSchristos 	}
9630b5c88f5Schristos 	return nsp;
9643a571abcSchristos }
965