1 /*
2  * This code contains changes by
3  *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4  *
5  * Conditions 1, 2, and 4 and the no-warranty notice below apply
6  * to these changes.
7  *
8  *
9  * Copyright (c) 1980, 1993
10  * 	The Regents of the University of California.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  * 	This product includes software developed by the University of
23  * 	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *
41  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  *   Redistributions of source code and documentation must retain the
47  *    above copyright notice, this list of conditions and the following
48  *    disclaimer.
49  *   Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  *   All advertising materials mentioning features or use of this software
53  *    must display the following acknowledgement:
54  *      This product includes software developed or owned by Caldera
55  *      International, Inc.
56  *   Neither the name of Caldera International, Inc. nor the names of
57  *    other contributors may be used to endorse or promote products
58  *    derived from this software without specific prior written permission.
59  *
60  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72  */
73 
74 #ifndef	lint
75 #ifdef	DOSCCS
76 static char sccsid[] = "@(#)ex_vwind.c	1.9 (gritter) 11/23/04";
77 #endif
78 #endif
79 
80 /* from ex_vwind.c	7.3 (Berkeley) 6/7/85 */
81 
82 #include "ex.h"
83 #include "ex_tty.h"
84 #include "ex_vis.h"
85 
86 /*
87  * Routines to adjust the window, showing specified lines
88  * in certain positions on the screen, and scrolling in both
89  * directions.  Code here is very dependent on mode (open versus visual).
90  */
91 
92 /*
93  * Move in a nonlocal way to line addr.
94  * If it isn't on screen put it in specified context.
95  * New position for cursor is curs.
96  * Like most routines here, we vsave().
97  */
98 void
vmoveto(register line * addr,char * curs,int context)99 vmoveto(register line *addr, char *curs, int context)
100 {
101 
102 	markit(addr);
103 	vsave();
104 	vjumpto(addr, curs, context);
105 }
106 
107 /*
108  * Vjumpto is like vmoveto, but doesn't mark previous
109  * context or save linebuf as current line.
110  */
111 void
vjumpto(register line * addr,char * curs,int context)112 vjumpto(register line *addr, char *curs, int context)
113 {
114 
115 	noteit(0);
116 	if (context != 0)
117 		vcontext(addr, context);
118 	else
119 		vshow(addr, NOLINE);
120 	noteit(1);
121 	vnline(curs);
122 }
123 
124 /*
125  * Go up or down cnt (negative is up) to new position curs.
126  */
127 void
vupdown(register int cnt,char * curs)128 vupdown(register int cnt, char *curs)
129 {
130 
131 	if (cnt > 0)
132 		vdown(cnt, 0, 0);
133 	else if (cnt < 0)
134 		vup(-cnt, 0, 0);
135 	if (vcnt == 0)
136 		vrepaint(curs);
137 	else
138 		vnline(curs);
139 }
140 
141 /*
142  * Go up cnt lines, afterwards preferring to be ind
143  * logical lines from the top of the screen.
144  * If scroll, then we MUST use a scroll.
145  * Otherwise clear and redraw if motion is far.
146  */
147 void
vup(register int cnt,register int ind,int scroll)148 vup(register int cnt, register int ind, int scroll)
149 {
150 	register int i, tot;
151 
152 	if (dot == one) {
153 		beep();
154 		return;
155 	}
156 	vsave();
157 	i = lineDOT() - 1;
158 	if (cnt > i) {
159 		ind -= cnt - i;
160 		if (ind < 0)
161 			ind = 0;
162 		cnt = i;
163 	}
164 	if (!scroll && cnt <= vcline) {
165 		vshow(dot - cnt, NOLINE);
166 		return;
167 	}
168 	cnt -= vcline, dot -= vcline, vcline = 0;
169 	if (hold & HOLDWIG)
170 		goto contxt;
171 	if (state == VISUAL && !AL && !SR &&
172 	    cnt <= WTOP - ZERO && vfit(dot - cnt, cnt) <= WTOP - ZERO)
173 		goto okr;
174 	tot = WECHO - ZERO;
175 	if (state != VISUAL || (!AL && !SR) || (!scroll && (cnt > tot || vfit(dot - cnt, cnt) > tot / 3 + 1))) {
176 		if (ind > basWLINES / 2)
177 			ind = basWLINES / 3;
178 contxt:
179 		vcontext(dot + ind - cnt, '.');
180 		return;
181 	}
182 okr:
183 	vrollR(cnt);
184 	if (scroll) {
185 		vcline += ind, dot += ind;
186 		if (vcline >= vcnt)
187 			dot -= vcline - vcnt + 1, vcline = vcnt - 1;
188 		getDOT();
189 	}
190 }
191 
192 /*
193  * Like vup, but scrolling down.
194  */
195 void
vdown(register int cnt,register int ind,int scroll)196 vdown(register int cnt, register int ind, int scroll)
197 {
198 	register int i, tot;
199 
200 	if (dot == dol) {
201 		beep();
202 		return;
203 	}
204 	vsave();
205 	i = dol - dot;
206 	if (cnt > i) {
207 		ind -= cnt - i;
208 		if (ind < 0)
209 			ind = 0;
210 		cnt = i;
211 	}
212 	i = vcnt - vcline - 1;
213 	if (!scroll && cnt <= i) {
214 		vshow(dot + cnt, NOLINE);
215 		return;
216 	}
217 	cnt -= i, dot += i, vcline += i;
218 	if (hold & HOLDWIG)
219 		goto dcontxt;
220 	if (!scroll) {
221 		tot = WECHO - ZERO;
222 		if (state != VISUAL || cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) {
223 dcontxt:
224 			vcontext(dot + cnt, '.');
225 			return;
226 		}
227 	}
228 	if (cnt > 0)
229 		vroll(cnt);
230 	if (state == VISUAL && scroll) {
231 		vcline -= ind, dot -= ind;
232 		if (vcline < 0)
233 			dot -= vcline, vcline = 0;
234 		getDOT();
235 	}
236 }
237 
238 /*
239  * Show line addr in context where on the screen.
240  * Work here is in determining new top line implied by
241  * this placement of line addr, since we always draw from the top.
242  */
243 void
vcontext(register line * addr,int where)244 vcontext(register line *addr, int where)
245 {
246 	register line *top;
247 
248 	getline(*addr);
249 	if (state != VISUAL)
250 		top = addr;
251 	else switch (where) {
252 
253 	case '^':
254 		addr = vback(addr, basWLINES - vdepth());
255 		getline(*addr);
256 		/* fall into ... */
257 
258 	case '-':
259 		top = vback(addr, basWLINES - vdepth());
260 		getline(*addr);
261 		break;
262 
263 	case '.':
264 		top = vback(addr, basWLINES / 2 - vdepth());
265 		getline(*addr);
266 		break;
267 
268 	default:
269 		top = addr;
270 		break;
271 	}
272 	if (state == ONEOPEN && LINE(0) == WBOT)
273 		vup1();
274 	vcnt = vcline = 0;
275 	vclean();
276 	if (state == CRTOPEN)
277 		vup1();
278 	vshow(addr, top);
279 }
280 
281 /*
282  * Get a clean line.  If we are in a hard open
283  * we may be able to reuse the line we are on
284  * if it is blank.  This is a real win.
285  */
286 void
vclean(void)287 vclean(void)
288 {
289 
290 	if (state != VISUAL && state != CRTOPEN) {
291 		destcol = 0;
292 		if (!ateopr())
293 			vup1();
294 		vcnt = 0;
295 	}
296 }
297 
298 /*
299  * Show line addr with the specified top line on the screen.
300  * Top may be 0; in this case have vcontext compute the top
301  * (and call us recursively).  Eventually, we clear the screen
302  * (or its open mode equivalent) and redraw.
303  */
304 void
vshow(line * addr,line * top)305 vshow(line *addr, line *top)
306 {
307 	register int cnt = addr - dot;
308 	register int i = vcline + cnt;
309 	short oldhold = hold;
310 
311 	if (state != HARDOPEN && state != ONEOPEN && i >= 0 && i < vcnt) {
312 		dot = addr;
313 		getDOT();
314 		vcline = i;
315 		return;
316 	}
317 	if (state != VISUAL) {
318 		dot = addr;
319 		vopen(dot, WBOT);
320 		return;
321 	}
322 	if (top == 0) {
323 		vcontext(addr, '.');
324 		return;
325 	}
326 	dot = top;
327 	oldhold = hold;
328 	hold |= HOLDAT;
329 	vclear();
330 	vreset(0);
331 	vredraw(WTOP);
332 	/* error if vcline >= vcnt ! */
333 	vcline = addr - top;
334 	dot = addr;
335 	getDOT();
336 	hold = oldhold;
337 	vsync(LASTLINE);
338 }
339 
340 /*
341  * reset the state.
342  * If inecho then leave us at the beginning of the echo
343  * area;  we are called this way in the middle of a :e escape
344  * from visual, e.g.
345  */
346 void
vreset(int inecho)347 vreset(int inecho)
348 {
349 
350 	vcnt = vcline = 0;
351 	WTOP = basWTOP;
352 	WLINES = basWLINES;
353 	if (inecho)
354 		splitw = 1, vgoto(WECHO, 0);
355 }
356 
357 /*
358  * Starting from which line preceding tp uses almost (but not more
359  * than) cnt physical lines?
360  */
361 line *
vback(register line * tp,register int cnt)362 vback(register line *tp, register int cnt)
363 {
364 	register int d;
365 
366 	if (cnt > 0)
367 		for (; tp > one; tp--) {
368 			getline(tp[-1]);
369 			d = vdepth();
370 			if (d > cnt)
371 				break;
372 			cnt -= d;
373 		}
374 	return (tp);
375 }
376 
377 /*
378  * How much scrolling will it take to roll cnt lines starting at tp?
379  */
380 int
vfit(register line * tp,int cnt)381 vfit(register line *tp, int cnt)
382 {
383 	register int j;
384 
385 	j = 0;
386 	while (cnt > 0) {
387 		cnt--;
388 		getline(tp[cnt]);
389 		j += vdepth();
390 	}
391 	if (tp > dot)
392 		j -= WBOT - LASTLINE;
393 	return (j);
394 }
395 
396 /*
397  * Roll cnt lines onto the screen.
398  */
399 void
vroll(register int cnt)400 vroll(register int cnt)
401 {
402 	short oldhold = hold;
403 
404 #ifdef ADEBUG
405 	if (trace)
406 		tfixnl(), fprintf(trace, "vroll(%d)\n", cnt);
407 #endif
408 	if (state != VISUAL)
409 		hold |= HOLDAT|HOLDROL;
410 	if (WBOT == WECHO) {
411 		vcnt = 0;
412 		if (state == ONEOPEN)
413 			vup1();
414 	}
415 	for (; cnt > 0 && Peekkey != ATTN; cnt--) {
416 		dot++, vcline++;
417 		vopen(dot, LASTLINE);
418 		vscrap();
419 	}
420 	hold = oldhold;
421 	if (state == HARDOPEN)
422 		sethard();
423 	vsyncCL();
424 }
425 
426 /*
427  * Roll backwards (scroll up).
428  */
429 void
vrollR(register int cnt)430 vrollR(register int cnt)
431 {
432 	short oldhold = hold;
433 
434 #ifdef ADEBUG
435 	if (trace)
436 		tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT());
437 #endif
438 	if (WBOT == WECHO)
439 		vcnt = 0;
440 	heldech = 0;
441 	hold |= HOLDAT|HOLDECH;
442 	for (; cnt > 0 && Peekkey != ATTN; cnt--) {
443 		dot--;
444 		vopen(dot, WTOP);
445 		vscrap();
446 	}
447 	hold = oldhold;
448 	if (heldech)
449 		vclrech(0);
450 	vsync(LINE(vcnt-1));
451 }
452 
453 /*
454  * Go into cooked mode (allow interrupts) during
455  * a scroll if we are at less than 1200 baud and not
456  * a 'vi' command, of if we are in a 'vi' command and the
457  * scroll is more than 2 full screens.
458  *
459  * BUG:		An interrupt during a scroll in this way
460  *		dumps to command mode.
461  */
462 int
vcookit(register int cnt)463 vcookit(register int cnt)
464 {
465 
466 	return (cnt > 1 && (ospeed < B1200 && !initev || cnt > TLINES * 2));
467 }
468 
469 /*
470  * Determine displayed depth of current line.
471  */
472 int
vdepth(void)473 vdepth(void)
474 {
475 	register int d;
476 
477 	d = (column(NOSTR) + WCOLS - 1 + (Putchar == listchar) + IN) / WCOLS;
478 #ifdef ADEBUG
479 	if (trace)
480 		tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d);
481 #endif
482 	return (d == 0 ? 1 : d);
483 }
484 
485 /*
486  * Move onto a new line, with cursor at position curs.
487  */
488 void
vnline(char * curs)489 vnline(char *curs)
490 {
491 
492 	if (curs)
493 		wcursor = curs;
494 	else if (vmoving)
495 		wcursor = vfindcol(vmovcol);
496 	else
497 		wcursor = vskipwh(linebuf);
498 	cursor = linebuf;
499 	vmove(0);
500 }
501