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 /*LINTLIBRARY*/
41 
42 #include	<stdlib.h>
43 #include	"curses_inc.h"
44 
45 
46 /* Functions to make use of insert/delete line caps */
47 
48 #define	scrco	COLS
49 
50 typedef	struct
51 	{
52 	    int		_wy,	/* matching lines */
53 			_sy;
54 	} IDST;
55 static	IDST	*sid, *eid;		/* list of idln actions */
56 static	int	scrli,			/* screen dimensions */
57 		cy, cx;			/* current cursor positions */
58 static	bool	didcsr;			/* scrolling region was used */
59 static	int	_use_idln(void), _set_idln(void);
60 static	void	_do_idln(int, int, int, int);
61 
62 /* Set insert/delete line mode for win */
63 
64 int
idlok(WINDOW * win,bool bf)65 idlok(WINDOW *win, bool bf)
66 {
67 	_useidln = _use_idln;
68 	_setidln = _set_idln;
69 
70 	SP->yesidln = (delete_line || parm_delete_line ||
71 	    (change_scroll_region && (parm_index || scroll_forward))) &&
72 	    (insert_line || parm_insert_line ||
73 	    (change_scroll_region && (parm_rindex || scroll_reverse)));
74 
75 	win->_use_idl = bf;
76 	return (OK);
77 }
78 
79 /*
80  * Set the places to do insert/delete lines
81  * Return the start line for such action.
82  */
83 
84 static int
_set_idln(void)85 _set_idln(void)
86 {
87 	/*
88 	 * The value we want to return is the lower line
89 	 * number of the top-most range.
90 	 *
91 	 * If there is more than one range of lines on which
92 	 * we're operating, _find_idln will get called more
93 	 * then once; we need to search all the IDST for the
94 	 * desired return value.
95 	 */
96 	{
97 		IDST *idp;
98 		int rval = scrli;
99 
100 		for (idp = sid; idp != eid; idp++) {
101 			int tmp;
102 
103 			if ((tmp = _MIN(idp->_wy, idp->_sy)) < rval)
104 				rval = tmp;
105 		}
106 		return (rval);
107 	}
108 }
109 
110 /* Use hardware line delete/insert */
111 
112 static int
_use_idln(void)113 _use_idln(void)
114 {
115 	int	tsy, bsy, idn, dir, nomore;
116 	IDST	*ip, *ep, *eip;
117 
118 	cy = curscr->_cury;
119 	cx = curscr->_curx;
120 	didcsr = FALSE;
121 
122 	/* first cycle do deletions, second cycle do insertions */
123 	for (dir = 1; dir > -2; dir -= 2) {
124 		if (dir > 0) {
125 			ip = sid;
126 			eip = eid;
127 		} else {
128 			ip = eid - 1;
129 			eip = sid - 1;
130 		}
131 
132 		nomore = TRUE;
133 		while (ip != eip) {
134 			/* skip deletions or insertions */
135 			if ((dir > 0 && ip->_wy > ip->_sy) ||
136 			    (dir < 0 && ip->_wy < ip->_sy)) {
137 				nomore = FALSE;
138 				ip += dir;
139 				continue;
140 			}
141 
142 			/* find a contiguous block */
143 			for (ep = ip+dir; ep != eip; ep += dir)
144 				if (ep->_wy != (ep - dir)->_wy + dir ||
145 				    ep->_sy != (ep - dir)->_sy + dir) {
146 				    break;
147 			}
148 			ep -= dir;
149 
150 			/* top and bottom lines of the affected region */
151 			if (dir > 0) {
152 				tsy = _MIN(ip->_wy, ip->_sy);
153 				bsy = _MAX(ep->_wy, ep->_sy) + 1;
154 			} else {
155 				tsy = _MIN(ep->_wy, ep->_sy);
156 				bsy = _MAX(ip->_wy, ip->_sy) + 1;
157 			}
158 
159 			/* amount to insert/delete */
160 			if ((idn = ip->_wy - ip->_sy) < 0)
161 				idn = -idn;
162 
163 			/* do the actual output */
164 			_do_idln(tsy, bsy, idn, dir == -1);
165 
166 			/* update change structure */
167 			(void) wtouchln(_virtscr, tsy, bsy - tsy, -1);
168 
169 			/* update screen image */
170 			/*LINTED*/
171 			curscr->_tmarg = (short)tsy;
172 			curscr->_bmarg = bsy - 1;
173 			/*LINTED*/
174 			curscr->_cury = (short)tsy;
175 			(void) winsdelln(curscr, dir > 0 ? -idn : idn);
176 			curscr->_tmarg = 0;
177 			curscr->_bmarg = scrli - 1;
178 
179 			/* for next while cycle */
180 			ip = ep + dir;
181 		}
182 
183 		if (nomore)
184 			break;
185 	}
186 
187 	/* reset scrolling region */
188 	if (didcsr) {
189 		_PUTS(tparm_p2(change_scroll_region, 0, scrli - 1), scrli);
190 		cy = cx = -1;
191 	}
192 
193 	/*LINTED*/
194 	curscr->_cury = (short)cy;
195 	/*LINTED*/
196 	curscr->_curx = (short)cx;
197 	return (OK);
198 }
199 
200 /* Do the actual insert/delete lines */
201 
202 static void
_do_idln(int tsy,int bsy,int idn,int doinsert)203 _do_idln(int tsy, int bsy, int idn, int doinsert)
204 {
205 	int	y, usecsr, yesscrl;
206 	short	*begns;
207 
208 	/* change scrolling region */
209 	yesscrl = usecsr = FALSE;
210 	if (tsy > 0 || bsy < scrli) {
211 		if (change_scroll_region) {
212 		    _PUTS(tparm_p2(change_scroll_region, tsy, bsy - 1),
213 			bsy - tsy);
214 		    cy = cx = -1;
215 		    yesscrl = usecsr = didcsr = TRUE;
216 		}
217 	} else {
218 		if (didcsr) {
219 		    _PUTS(tparm_p2(change_scroll_region, 0, scrli - 1), scrli);
220 		    cy = cx = -1;
221 		    didcsr = FALSE;
222 		}
223 		yesscrl = TRUE;
224 	}
225 
226 	if (doinsert) {
227 		/* memory below, clobber it now */
228 		if (memory_below && clr_eol &&
229 		    ((usecsr && non_dest_scroll_region) || bsy == scrli)) {
230 			for (y = bsy - idn, begns = _BEGNS + y;
231 			    y < bsy; ++y, ++begns)
232 				if (*begns < scrco) {
233 					(void) mvcur(cy, cx, y, 0);
234 					cy = y;
235 					cx = 0;
236 					_PUTS(clr_eol, 1);
237 				}
238 		}
239 
240 		/* if not change_scroll_region, delete, then insert */
241 		if (!usecsr && bsy < scrli) {
242 			/* delete appropriate number of lines */
243 			(void) mvcur(cy, cx, bsy - idn, 0);
244 			cy = bsy - idn;
245 			cx = 0;
246 			if (parm_delete_line && (idn > 1 || !delete_line))
247 				_PUTS(tparm_p1(parm_delete_line, idn),
248 				    scrli - cy);
249 			else
250 				for (y = 0; y < idn; ++y)
251 			_PUTS(delete_line, scrli - cy);
252 		}
253 
254 		/* now do insert */
255 		(void) mvcur(cy, cx, tsy, 0);
256 		cy = tsy;
257 		cx = 0;
258 		if (yesscrl) {
259 			if (!parm_rindex && (!scroll_reverse ||
260 			    (parm_insert_line && idn > 1))) {
261 				goto hardinsert;
262 			}
263 			if (parm_rindex && (idn > 1 || !scroll_reverse))
264 				_PUTS(tparm_p1(parm_rindex, idn), scrli - cy);
265 			else
266 				for (y = 0; y < idn; ++y)
267 					_PUTS(scroll_reverse, scrli - cy);
268 		} else {
269 hardinsert:
270 			if (parm_insert_line && (idn > 1 || !insert_line))
271 				_PUTS(tparm_p1(parm_insert_line, idn),
272 				    scrli - cy);
273 			else
274 				for (y = 0; y < idn; ++y)
275 					_PUTS(insert_line, scrli - cy);
276 		}
277 	} else {
278 		/* doing deletion */
279 		/* memory above, clobber it now */
280 		if (memory_above && clr_eol &&
281 		    ((usecsr && non_dest_scroll_region) || tsy == 0)) {
282 			for (y = 0, begns = _BEGNS + y + tsy;
283 			    y < idn; ++y, ++begns)
284 				if (*begns < scrco) {
285 					(void) mvcur(cy, cx, tsy + y, 0);
286 					cy = tsy + y;
287 					cx = 0;
288 					_PUTS(clr_eol, 1);
289 				}
290 		}
291 
292 		if (yesscrl) {
293 			if (!parm_index && (!scroll_forward ||
294 			    (parm_delete_line && idn > 1))) {
295 				goto harddelete;
296 			}
297 			(void) mvcur(cy, cx, bsy - 1, 0);
298 			cy = bsy - 1;
299 			cx = 0;
300 			if (parm_index && (idn > 1 || !scroll_forward))
301 				_PUTS(tparm_p1(parm_index, idn), scrli - cy);
302 			else
303 				for (y = 0; y < idn; ++y)
304 					_PUTS(scroll_forward, scrli - cy);
305 		} else {
306 harddelete:
307 			/* do deletion */
308 			(void) mvcur(cy, cx, tsy, 0);
309 			cy = tsy;
310 			cx = 0;
311 			if (parm_delete_line && (idn > 1 || !delete_line))
312 				_PUTS(tparm_p1(parm_delete_line, idn),
313 				    scrli - cy);
314 			else
315 				for (y = 0; y < idn; ++y)
316 				    _PUTS(delete_line, scrli - cy);
317 		}
318 
319 		/* if not change_scroll_region, do insert to restore bottom */
320 		if (!usecsr && bsy < scrli) {
321 			y = scrli - 1;
322 			begns = _BEGNS + y;
323 			for (; y >= bsy; --y, --begns)
324 				if (*begns < scrco)
325 					break;
326 			if (y >= bsy) {
327 				(void) mvcur(cy, cx, bsy - idn, 0);
328 				cy = bsy - idn;
329 				cx = 0;
330 				if (parm_insert_line &&
331 				    (idn > 1 || !insert_line))
332 					_PUTS(tparm_p1(parm_insert_line, idn),
333 					    scrli - cy);
334 				else
335 					for (y = 0; y < idn; ++y)
336 						_PUTS(insert_line, scrli - cy);
337 			}
338 		}
339 	}
340 }
341