xref: /illumos-gate/usr/src/lib/libcurses/screen/idlok.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*LINTLIBRARY*/
43 
44 #include	<stdlib.h>
45 #include	"curses_inc.h"
46 
47 
48 /* Functions to make use of insert/delete line caps */
49 
50 #define	scrco	COLS
51 
52 typedef	struct
53 	{
54 	    int		_wy,	/* matching lines */
55 			_sy;
56 	} IDST;
57 static	IDST	*sid, *eid;		/* list of idln actions */
58 static	int	scrli,			/* screen dimensions */
59 		cy, cx;			/* current cursor positions */
60 static	bool	didcsr;			/* scrolling region was used */
61 static	int	_use_idln(void), _set_idln(void);
62 static	void	_do_idln(int, int, int, int);
63 
64 /* Set insert/delete line mode for win */
65 
66 int
67 idlok(WINDOW *win, bool bf)
68 {
69 	_useidln = _use_idln;
70 	_setidln = _set_idln;
71 
72 	SP->yesidln = (delete_line || parm_delete_line ||
73 	    (change_scroll_region && (parm_index || scroll_forward))) &&
74 	    (insert_line || parm_insert_line ||
75 	    (change_scroll_region && (parm_rindex || scroll_reverse)));
76 
77 	win->_use_idl = bf;
78 	return (OK);
79 }
80 
81 /*
82  * Set the places to do insert/delete lines
83  * Return the start line for such action.
84  */
85 
86 static int
87 _set_idln(void)
88 {
89 	/*
90 	 * The value we want to return is the lower line
91 	 * number of the top-most range.
92 	 *
93 	 * If there is more than one range of lines on which
94 	 * we're operating, _find_idln will get called more
95 	 * then once; we need to search all the IDST for the
96 	 * desired return value.
97 	 */
98 	{
99 		IDST *idp;
100 		int rval = scrli;
101 
102 		for (idp = sid; idp != eid; idp++) {
103 			int tmp;
104 
105 			if ((tmp = _MIN(idp->_wy, idp->_sy)) < rval)
106 				rval = tmp;
107 		}
108 		return (rval);
109 	}
110 }
111 
112 /* Use hardware line delete/insert */
113 
114 static int
115 _use_idln(void)
116 {
117 	int	tsy, bsy, idn, dir, nomore;
118 	IDST	*ip, *ep, *eip;
119 
120 	cy = curscr->_cury;
121 	cx = curscr->_curx;
122 	didcsr = FALSE;
123 
124 	/* first cycle do deletions, second cycle do insertions */
125 	for (dir = 1; dir > -2; dir -= 2) {
126 		if (dir > 0) {
127 			ip = sid;
128 			eip = eid;
129 		} else {
130 			ip = eid - 1;
131 			eip = sid - 1;
132 		}
133 
134 		nomore = TRUE;
135 		while (ip != eip) {
136 			/* skip deletions or insertions */
137 			if ((dir > 0 && ip->_wy > ip->_sy) ||
138 			    (dir < 0 && ip->_wy < ip->_sy)) {
139 				nomore = FALSE;
140 				ip += dir;
141 				continue;
142 			}
143 
144 			/* find a contiguous block */
145 			for (ep = ip+dir; ep != eip; ep += dir)
146 				if (ep->_wy != (ep - dir)->_wy + dir ||
147 				    ep->_sy != (ep - dir)->_sy + dir) {
148 				    break;
149 			}
150 			ep -= dir;
151 
152 			/* top and bottom lines of the affected region */
153 			if (dir > 0) {
154 				tsy = _MIN(ip->_wy, ip->_sy);
155 				bsy = _MAX(ep->_wy, ep->_sy) + 1;
156 			} else {
157 				tsy = _MIN(ep->_wy, ep->_sy);
158 				bsy = _MAX(ip->_wy, ip->_sy) + 1;
159 			}
160 
161 			/* amount to insert/delete */
162 			if ((idn = ip->_wy - ip->_sy) < 0)
163 				idn = -idn;
164 
165 			/* do the actual output */
166 			_do_idln(tsy, bsy, idn, dir == -1);
167 
168 			/* update change structure */
169 			(void) wtouchln(_virtscr, tsy, bsy - tsy, -1);
170 
171 			/* update screen image */
172 			/*LINTED*/
173 			curscr->_tmarg = (short)tsy;
174 			curscr->_bmarg = bsy - 1;
175 			/*LINTED*/
176 			curscr->_cury = (short)tsy;
177 			(void) winsdelln(curscr, dir > 0 ? -idn : idn);
178 			curscr->_tmarg = 0;
179 			curscr->_bmarg = scrli - 1;
180 
181 			/* for next while cycle */
182 			ip = ep + dir;
183 		}
184 
185 		if (nomore)
186 			break;
187 	}
188 
189 	/* reset scrolling region */
190 	if (didcsr) {
191 		_PUTS(tparm_p2(change_scroll_region, 0, scrli - 1), scrli);
192 		cy = cx = -1;
193 	}
194 
195 	/*LINTED*/
196 	curscr->_cury = (short)cy;
197 	/*LINTED*/
198 	curscr->_curx = (short)cx;
199 	return (OK);
200 }
201 
202 /* Do the actual insert/delete lines */
203 
204 static void
205 _do_idln(int tsy, int bsy, int idn, int doinsert)
206 {
207 	int	y, usecsr, yesscrl;
208 	short	*begns;
209 
210 	/* change scrolling region */
211 	yesscrl = usecsr = FALSE;
212 	if (tsy > 0 || bsy < scrli) {
213 		if (change_scroll_region) {
214 		    _PUTS(tparm_p2(change_scroll_region, tsy, bsy - 1),
215 			bsy - tsy);
216 		    cy = cx = -1;
217 		    yesscrl = usecsr = didcsr = TRUE;
218 		}
219 	} else {
220 		if (didcsr) {
221 		    _PUTS(tparm_p2(change_scroll_region, 0, scrli - 1), scrli);
222 		    cy = cx = -1;
223 		    didcsr = FALSE;
224 		}
225 		yesscrl = TRUE;
226 	}
227 
228 	if (doinsert) {
229 		/* memory below, clobber it now */
230 		if (memory_below && clr_eol &&
231 		    ((usecsr && non_dest_scroll_region) || bsy == scrli)) {
232 			for (y = bsy - idn, begns = _BEGNS + y;
233 			    y < bsy; ++y, ++begns)
234 				if (*begns < scrco) {
235 					(void) mvcur(cy, cx, y, 0);
236 					cy = y;
237 					cx = 0;
238 					_PUTS(clr_eol, 1);
239 				}
240 		}
241 
242 		/* if not change_scroll_region, delete, then insert */
243 		if (!usecsr && bsy < scrli) {
244 			/* delete appropriate number of lines */
245 			(void) mvcur(cy, cx, bsy - idn, 0);
246 			cy = bsy - idn;
247 			cx = 0;
248 			if (parm_delete_line && (idn > 1 || !delete_line))
249 				_PUTS(tparm_p1(parm_delete_line, idn),
250 				    scrli - cy);
251 			else
252 				for (y = 0; y < idn; ++y)
253 			_PUTS(delete_line, scrli - cy);
254 		}
255 
256 		/* now do insert */
257 		(void) mvcur(cy, cx, tsy, 0);
258 		cy = tsy;
259 		cx = 0;
260 		if (yesscrl) {
261 			if (!parm_rindex && (!scroll_reverse ||
262 			    (parm_insert_line && idn > 1))) {
263 				goto hardinsert;
264 			}
265 			if (parm_rindex && (idn > 1 || !scroll_reverse))
266 				_PUTS(tparm_p1(parm_rindex, idn), scrli - cy);
267 			else
268 				for (y = 0; y < idn; ++y)
269 					_PUTS(scroll_reverse, scrli - cy);
270 		} else {
271 hardinsert:
272 			if (parm_insert_line && (idn > 1 || !insert_line))
273 				_PUTS(tparm_p1(parm_insert_line, idn),
274 				    scrli - cy);
275 			else
276 				for (y = 0; y < idn; ++y)
277 					_PUTS(insert_line, scrli - cy);
278 		}
279 	} else {
280 		/* doing deletion */
281 		/* memory above, clobber it now */
282 		if (memory_above && clr_eol &&
283 		    ((usecsr && non_dest_scroll_region) || tsy == 0)) {
284 			for (y = 0, begns = _BEGNS + y + tsy;
285 			    y < idn; ++y, ++begns)
286 				if (*begns < scrco) {
287 					(void) mvcur(cy, cx, tsy + y, 0);
288 					cy = tsy + y;
289 					cx = 0;
290 					_PUTS(clr_eol, 1);
291 				}
292 		}
293 
294 		if (yesscrl) {
295 			if (!parm_index && (!scroll_forward ||
296 			    (parm_delete_line && idn > 1))) {
297 				goto harddelete;
298 			}
299 			(void) mvcur(cy, cx, bsy - 1, 0);
300 			cy = bsy - 1;
301 			cx = 0;
302 			if (parm_index && (idn > 1 || !scroll_forward))
303 				_PUTS(tparm_p1(parm_index, idn), scrli - cy);
304 			else
305 				for (y = 0; y < idn; ++y)
306 					_PUTS(scroll_forward, scrli - cy);
307 		} else {
308 harddelete:
309 			/* do deletion */
310 			(void) mvcur(cy, cx, tsy, 0);
311 			cy = tsy;
312 			cx = 0;
313 			if (parm_delete_line && (idn > 1 || !delete_line))
314 				_PUTS(tparm_p1(parm_delete_line, idn),
315 				    scrli - cy);
316 			else
317 				for (y = 0; y < idn; ++y)
318 				    _PUTS(delete_line, scrli - cy);
319 		}
320 
321 		/* if not change_scroll_region, do insert to restore bottom */
322 		if (!usecsr && bsy < scrli) {
323 			y = scrli - 1;
324 			begns = _BEGNS + y;
325 			for (; y >= bsy; --y, --begns)
326 				if (*begns < scrco)
327 					break;
328 			if (y >= bsy) {
329 				(void) mvcur(cy, cx, bsy - idn, 0);
330 				cy = bsy - idn;
331 				cx = 0;
332 				if (parm_insert_line &&
333 				    (idn > 1 || !insert_line))
334 					_PUTS(tparm_p1(parm_insert_line, idn),
335 					    scrli - cy);
336 				else
337 					for (y = 0; y < idn; ++y)
338 						_PUTS(insert_line, scrli - cy);
339 			}
340 		}
341 	}
342 }
343