Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 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_vadj.c	1.11 (gritter) 3/4/05";
77
#endif
78
#endif
79
 
80
/* from ex_vadj.c	7.9 (Berkeley) 6/7/85 */
81
 
82
#include "ex.h"
83
#include "ex_tty.h"
84
#include "ex_vis.h"
85
 
86
/*
87
 * Routines to deal with management of logical versus physical
88
 * display, opening and redisplaying lines on the screen, and
89
 * use of intelligent terminal operations.  Routines to deal with
90
 * screen cleanup after a change.
91
 */
92
 
93
/*
94
 * Display a new line at physical line p, returning
95
 * the depth of the newly displayed line.  We may decide
96
 * to expand the window on an intelligent terminal if it is
97
 * less than a full screen by deleting a line above the top of the
98
 * window before doing an insert line to keep all the good text
99
 * on the screen in which case the line may actually end up
100
 * somewhere other than line p.
101
 */
102
void 
103
vopen(line *tp, int p)
104
{
105
	register int cnt;
106
	register struct vlinfo *vp, *vpc;
107
 
108
#ifdef ADEBUG
109
	if (trace != NULL)
110
		tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
111
#endif
112
	if (state != VISUAL) {
113
		if (vcnt)
114
			if (hold & HOLDROL)
115
				vup1();
116
			else
117
				vclean();
118
 
119
		/*
120
		 * Forget all that we once knew.
121
		 */
122
		vcnt = vcline = 0;
123
		p = WBOT; LASTLINE = WBOT + 1;
124
		state = bastate;
125
		WTOP = basWTOP;
126
		WLINES = basWLINES;
127
	}
128
	vpc = &vlinfo[vcline];
129
	for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
130
		vlcopy(vp[1], vp[0]);
131
	vcnt++;
132
	if (Pline == numbline)
133
		/*
134
		 * Dirtying all the lines is rather inefficient
135
		 * internally, but number mode is used rarely
136
		 * and so its not worth optimizing.
137
		 */
138
		vdirty(vcline+1, WECHO);
139
	getline(*tp);
140
 
141
	/*
142
	 * If we are opening at the top of the window, can try a window
143
	 * expansion at the top.
144
	 */
145
	if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
146
		cnt = p + vdepth() - LINE(1);
147
		if (cnt > 0) {
148
			p -= cnt;
149
			if (p < ZERO)
150
				p = ZERO;
151
			WTOP = p;
152
			WLINES = WBOT - WTOP + 1;
153
		}
154
	}
155
	vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
156
	cnt = vreopen(p, lineno(tp), vcline);
157
	if (vcline + 1 == vcnt)
158
		LINE(vcnt) = LINE(vcline) + cnt;
159
}
160
 
161
/*
162
 * Redisplay logical line l at physical line p with line number lineno.
163
 */
164
int 
165
vreopen(int p, int lineno, int l)
166
{
167
	register int d;
168
	register struct vlinfo *vp = &vlinfo[l];
169
 
170
	if (p < 0)
171
		error("Line too long to fit on screen");
172
	d = vp->vdepth;
173
	if (d == 0 || (vp->vflags & VDIRT))
174
		vp->vdepth = d = vdepth();
175
	vp->vliny = p, vp->vflags &= ~VDIRT;
176
 
177
	/*
178
	 * Try to win by making the screen larger rather than inserting
179
	 * a line and driving text off the bottom.
180
	 */
181
	p = vglitchup(l, 0);
182
 
183
	/*
184
	 * BUG:		Should consider using CE here to clear to end of line.
185
	 *		As it stands we always strike over the current text.
186
	 *		Since often the current text is the same as what
187
	 *		we are overstriking with, it tends not to show.
188
	 *		On the other hand if it is different and we end up
189
	 *		spacing out a lot of text, we could have won with
190
	 *		a CE.  This is probably worthwhile at low speed
191
	 *		only however, since clearly computation will be
192
	 *		necessary to determine which way to go.
193
	 */
194
	vigoto(p, 0);
195
	pline(lineno);
196
 
197
	/*
198
	 * When we are typing part of a line for hardcopy open, don't
199
	 * want to type the '$' marking an end of line if in list mode.
200
	 */
201
	if (hold & HOLDDOL)
202
		return (d);
203
	if (Putchar == listchar)
204
		putchar('$');
205
 
206
	/*
207
	 * Optimization of cursor motion may prevent screen rollup if the
208
	 * line has blanks/tabs at the end unless we force the cursor to appear
209
	 * on the last line segment.
210
	 */
211
	if (vp->vliny + d - 1 > WBOT)
212
		vcsync();
213
 
214
	/*
215
	 * Switch into hardcopy open mode if we are in one line (adm3)
216
	 * open mode and this line is now too long.  If in hardcopy
217
	 * open mode, then call sethard to move onto the next line
218
	 * with appropriate positioning.
219
	 */
220
	if (state == ONEOPEN) {
221
		WCOLS = OCOLUMNS;
222
		if (vdepth() > 1) {
223
			WCOLS = TUBECOLS;
224
			sethard();
225
		} else
226
			WCOLS = TUBECOLS;
227
	} else if (state == HARDOPEN)
228
		sethard();
229
 
230
	/*
231
	 * Unless we filled (completely) the last line we typed on,
232
	 * we have to clear to the end of the line
233
	 * in case stuff is left from before.
234
	 */
235
	if (vp->vliny + d > destline) {
236
		if (IN && destcol == WCOLS)
237
			vigoto(vp->vliny + d - 1, 0);
238
		vclreol();
239
	}
240
	return (d);
241
}
242
 
243
/*
244
 * Real work for winning growing of window at top
245
 * when inserting in the middle of a partially full
246
 * screen on an intelligent terminal.  We have as argument
247
 * the logical line number to be inserted after, and the offset
248
 * from that line where the insert will go.
249
 * We look at the picture of depths and positions, and if we can
250
 * delete some (blank) lines from the top of the screen so that
251
 * later inserts will not push stuff off the bottom.
252
 */
253
int 
254
vglitchup(int l, int o)
255
{
256
	register struct vlinfo *vp = &vlinfo[l];
257
	register int need;
258
	register int p = vp->vliny;
259
	short oldhold = 0, oldheldech = 0;
260
	bool glitched = 0;
261
 
262
 	if (l < vcnt - 1) {
263
		need = p + vp->vdepth - (vp+1)->vliny;
264
		if (need > 0) {
265
			if (state == VISUAL && WTOP - ZERO >= need && AL && DL) {
266
				glitched++;
267
				WTOP -= need;
268
				WLINES = WBOT - WTOP + 1;
269
				p -= need;
270
				if (p + o == WTOP) {
271
					vp->vliny = WTOP;
272
					return (WTOP + o);
273
				}
274
				vdellin(WTOP, need, -1);
275
				oldheldech = heldech;
276
				oldhold = hold;
277
				hold |= HOLDECH;
278
			}
279
			vinslin((vp+1)->vliny, need, l);
280
			if (glitched) {
281
				hold = oldhold;
282
				heldech = oldheldech;
283
			}
284
		}
285
	} else
286
		vp[1].vliny = vp[0].vliny + vp->vdepth;
287
	return (p + o);
288
}
289
 
290
/*
291
 * Insert cnt blank lines before line p,
292
 * logically and (if supported) physically.
293
 */
294
void 
295
vinslin(register int p, register int cnt, int l)
296
{
297
	register int i;
298
	bool could = 1;
299
 
300
#ifdef ADEBUG
301
	if (trace)
302
		tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
303
#endif
304
	if (p + cnt > WBOT && CD) {
305
		/*
306
		 * Really quick -- clear to end of screen.
307
		 */
308
		cnt = WECHO + 1 - p;
309
		vgoto(p, 0), vputp(CD, cnt);
310
		vclrech(1);
311
		vadjAL(p, cnt);
312
	} else if (SR && p == WTOP && costSR < costAL) {
313
		/*
314
		 * Use reverse scroll mode of the terminal, at
315
		 * the top of the window.  Reverse linefeed works
316
		 * too, since we only use it from line WTOP.
317
		 */
318
		for (i = cnt; i > 0; i--) {
319
			vgoto(p, 0), vputp(SR, 0);
320
			if (i > 1 && (hold & HOLDAT) == 0)
321
				putchar('@');
322
			/*
323
			 * If we are at the top of the screen, and the
324
			 * terminal retains display above, then we
325
			 * should try to clear to end of line.
326
			 * Have to use CE since we don't remember what is
327
			 * actually on the line.
328
			 */
329
			if (CE && (DA || p != 0))
330
				vputp(CE, 1);
331
		}
332
		vadjAL(p, cnt);
333
	} else if (AL) {
334
		/*
335
		 * Use insert line.
336
		 */
337
		vgoto(p, 0);
338
		if (AL_PARM && (cnt>1 || *AL==0)) {
339
			/* insert cnt lines.  Should do @'s too. */
340
			vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p);
341
		}
342
		else if (xCS && *AL==0) {
343
			/* vt100 change scrolling region to fake AL */
344
			vputp(SC, 1);
345
			vputp(tgoto(xCS, TLINES-1,p), 1);
346
			vputp(RC, 1);	/* xCS homes stupid cursor */
347
			for (i=cnt; i>0; i--)
348
				vputp(SR, 1);	/* should do @'s */
349
			vputp(tgoto(xCS, TLINES-1,0), 1);
350
			vputp(RC, 1);	/* Once again put it back */
351
		}
352
		else {
353
			vputp(AL, WECHO + 1 - p);
354
			for (i = cnt - 1; i > 0; i--) {
355
				vgoto(outline+1, 0);
356
				vputp(AL, WECHO + 1 - outline);
357
				if ((hold & HOLDAT) == 0)
358
					putchar('@');
359
			}
360
		}
361
		vadjAL(p, cnt);
362
	} else
363
		could = 0;
364
	vopenup(cnt, could, l);
365
}
366
 
367
/*
368
 * Logically open up after line l, cnt of them.
369
 * We need to know if it was done ``physically'' since in this
370
 * case we accept what the hardware gives us.  If we have to do
371
 * it ourselves (brute force) we will squish out @ lines in the process
372
 * if this will save us work.
373
 */
374
void 
375
vopenup(int cnt, int could, int l)
376
{
377
	register struct vlinfo *vc = &vlinfo[l + 1];
378
	register struct vlinfo *ve = &vlinfo[vcnt];
379
 
380
#ifdef ADEBUG
381
	if (trace)
382
		tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
383
#endif
384
	if (could)
385
		/*
386
		 * This will push @ lines down the screen,
387
		 * just as the hardware did.  Since the default
388
		 * for intelligent terminals is to never have @
389
		 * lines on the screen, this should never happen,
390
		 * and the code makes no special effort to be nice in this
391
		 * case, e.g. squishing out the @ lines by delete lines
392
		 * before doing append lines.
393
		 */
394
		for (; vc <= ve; vc++)
395
			vc->vliny += cnt;
396
	else {
397
		/*
398
		 * Will have to clean up brute force eventually,
399
		 * so push the line data around as little as possible.
400
		 */
401
		vc->vliny += cnt, vc->vflags |= VDIRT;
402
		while (vc < ve) {
403
			register int i = vc->vliny + vc->vdepth;
404
 
405
			vc++;
406
			if (i <= vc->vliny)
407
				break;
408
			vc->vliny = i, vc->vflags |= VDIRT;
409
		}
410
	}
411
	vscrap();
412
}
413
 
414
/*
415
 * Adjust data structure internally to account for insertion of
416
 * blank lines on the screen.
417
 */
418
void 
419
vadjAL(int p, int cnt)
420
{
421
	cell *tlines[TUBELINES];
422
	register int from, to;
423
 
424
#ifdef ADEBUG
425
	if (trace)
426
		tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
427
#endif
428
	copy(tlines, vtube, sizeof vtube);	/*SASSIGN*/
429
	for (from = p, to = p + cnt; to <= WECHO; from++, to++)
430
		vtube[to] = tlines[from];
431
	for (to = p; from <= WECHO; from++, to++) {
432
		vtube[to] = tlines[from];
433
		vclrcell(vtube[to], WCOLS);
434
	}
435
	/*
436
	 * Have to clear the echo area since its contents aren't
437
	 * necessarily consistent with the rest of the display.
438
	 */
439
	vclrech(0);
440
}
441
 
442
/*
443
 * Roll the screen up logically and physically
444
 * so that line dl is the bottom line on the screen.
445
 */
446
void 
447
vrollup(int dl)
448
{
449
	register int cnt;
450
	register int dc = destcol;
451
 
452
#ifdef ADEBUG
453
	if (trace)
454
		tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
455
#endif
456
	cnt = dl - (splitw ? WECHO : WBOT);
457
	if (splitw && (state == VISUAL || state == CRTOPEN))
458
		holdupd = 1;
459
	vmoveitup(cnt, 1);
460
	vscroll(cnt);
461
	destline = dl - cnt, destcol = dc;
462
}
463
 
464
void 
465
vup1(void)
466
{
467
 
468
	vrollup(WBOT + 1);
469
}
470
 
471
/*
472
 * Scroll the screen up cnt lines physically.
473
 * If doclr is true, do a clear eol if the terminal
474
 * has standout (to prevent it from scrolling up)
475
 */
476
void 
477
vmoveitup(register int cnt, int doclr)
478
{
479
 
480
	if (cnt == 0)
481
		return;
482
#ifdef ADEBUG
483
	if (trace)
484
		tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
485
#endif
486
	if (doclr && (SO || SE))
487
		vclrech(0);
488
	if (SF) {
489
		destline = WECHO;
490
		destcol = (NONL ? 0 : outcol % WCOLS);
491
		fgoto();
492
		while (cnt > 0)
493
			vputp(SF, 0), cnt--;
494
		return;
495
	}
496
	destline = WECHO + cnt;
497
	destcol = (NONL ? 0 : outcol % WCOLS);
498
	fgoto();
499
	if (state == ONEOPEN || state == HARDOPEN) {
500
		outline = destline = 0;
501
		vclrcell(vtube[0], WCOLS);
502
	}
503
}
504
 
505
/*
506
 * Scroll the screen up cnt lines logically.
507
 */
508
void 
509
vscroll(register int cnt)
510
{
511
	register int from, to;
512
	cell *tlines[TUBELINES];
513
 
514
#ifdef ADEBUG
515
	if (trace)
516
		fprintf(trace, "vscroll(%d)\n", cnt);
517
#endif
518
	if (cnt < 0 || cnt > TUBELINES)
519
		error(catgets(catd, 1, 219, "Internal error: vscroll"));
520
	if (cnt == 0)
521
		return;
522
	copy(tlines, vtube, sizeof vtube);
523
	for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++)
524
		vtube[to] = tlines[from];
525
	for (from = ZERO; to <= WECHO; to++, from++) {
526
		vtube[to] = tlines[from];
527
		vclrcell(vtube[to], WCOLS);
528
	}
529
	for (from = 0; from <= vcnt; from++)
530
		LINE(from) -= cnt;
531
}
532
 
533
/*
534
 * Discard logical lines due to physical wandering off the screen.
535
 */
536
void 
537
vscrap(void)
538
{
539
	register int i, j;
540
 
541
#ifdef ADEBUG
542
	if (trace)
543
		tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
544
#endif
545
	if (splitw)
546
		return;
547
	if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) {
548
		WTOP = LINE(0);
549
		WLINES = WBOT - WTOP + 1;
550
	}
551
	for (j = 0; j < vcnt; j++)
552
		if (LINE(j) >= WTOP) {
553
			if (j == 0)
554
				break;
555
			/*
556
			 * Discard the first j physical lines off the top.
557
			 */
558
			vcnt -= j, vcline -= j;
559
			for (i = 0; i <= vcnt; i++)
560
				vlcopy(vlinfo[i], vlinfo[i + j]);
561
			break;
562
		}
563
	/*
564
	 * Discard lines off the bottom.
565
	 */
566
	if (vcnt) {
567
		for (j = 0; j <= vcnt; j++)
568
			if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
569
				vcnt = j;
570
				break;
571
			}
572
		LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
573
	}
574
#ifdef ADEBUG
575
	if (trace)
576
		tvliny();
577
#endif
578
	/*
579
	 * May have no lines!
580
	 */
581
}
582
 
583
/*
584
 * Repaint the screen, with cursor at curs, aftern an arbitrary change.
585
 * Handle notification on large changes.
586
 */
587
void 
588
vrepaint(char *curs)
589
{
590
 
591
	wdot = NOLINE;
592
	/*
593
	 * In open want to notify first.
594
	 */
595
	noteit(0);
596
	vscrap();
597
 
598
	/*
599
	 * Deal with a totally useless display.
600
	 */
601
	if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
602
		register line *odol = dol;
603
 
604
		vcnt = 0;
605
		if (holdupd)
606
			if (state == VISUAL)
607
				ignore(peekkey());
608
			else
609
				vup1();
610
		holdupd = 0;
611
		if (odol == zero)
612
			fixzero();
613
		vcontext(dot, '.');
614
		noteit(1);
615
		if (noteit(1) == 0 && odol == zero) {
616
			CATCH
617
				error(catgets(catd, 1, 220,
618
						"No lines in buffer"));
619
			ENDCATCH
620
			linebuf[0] = 0;
621
			splitw = 0;
622
		}
623
		vnline(curs);
624
		return;
625
	}
626
 
627
	/*
628
	 * Have some useful displayed text; refresh it.
629
	 */
630
	getDOT();
631
 
632
	/*
633
	 * This is for boundary conditions in open mode.
634
	 */
635
	if (FLAGS(0) & VDIRT)
636
		vsync(WTOP);
637
 
638
	/*
639
	 * If the current line is after the last displayed line
640
	 * or the bottom of the screen, then special effort is needed
641
	 * to get it on the screen.  We first try a redraw at the
642
	 * last line on the screen, hoping it will fill in where @
643
	 * lines are now.  If this doesn't work, then roll it onto
644
	 * the screen.
645
	 */
646
	if (vcline >= vcnt || LINE(vcline) > WBOT) {
647
		short oldhold = hold;
648
		hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
649
		if (vcline >= vcnt) {
650
			register int i = vcline - vcnt + 1;
651
 
652
			dot -= i;
653
			vcline -= i;
654
			vroll(i);
655
		} else
656
			vsyncCL();
657
	} else
658
		vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
659
 
660
	/*
661
	 * Notification on large change for visual
662
	 * has to be done last or we may lose
663
	 * the echo area with redisplay.
664
	 */
665
	noteit(1);
666
 
667
	/*
668
	 * Finally.  Move the cursor onto the current line.
669
	 */
670
	vnline(curs);
671
}
672
 
673
/*
674
 * Fully cleanup the screen, leaving no @ lines except at end when
675
 * line after last won't completely fit.  The routine vsync is
676
 * more conservative and much less work on dumb terminals.
677
 */
678
void 
679
vredraw(register int p)
680
{
681
	register int l;
682
	register line *tp;
683
	char temp[LBSIZE];
684
	bool anydl = 0;
685
	short oldhold = hold;
686
 
687
#ifdef ADEBUG
688
	if (trace)
689
		tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
690
#endif
691
	if (holdupd) {
692
		holdupd = 3;
693
		return;
694
	}
695
	if (state == HARDOPEN || splitw)
696
		return;
697
	if (p < 0 /* || p > WECHO */)
698
		error(catgets(catd, 1, 221, "Internal error: vredraw"));
699
 
700
	/*
701
	 * Trim the ragged edges (lines which are off the screen but
702
	 * not yet logically discarded), save the current line, and
703
	 * search for first logical line affected by the redraw.
704
	 */
705
	vscrap();
706
	CP(temp, linebuf);
707
	l = 0;
708
	tp = dot - vcline;
709
	if (vcnt == 0)
710
		LINE(0) = WTOP;
711
	while (l < vcnt && LINE(l) < p)
712
		l++, tp++;
713
 
714
	/*
715
	 * We hold off echo area clearing during the redraw in deference
716
	 * to a final clear of the echo area at the end if appropriate.
717
	 */
718
	heldech = 0;
719
	hold |= HOLDECH;
720
	for (; l < vcnt && Peekkey != ATTN; l++) {
721
		if (l == vcline)
722
			strcLIN(temp);
723
		else
724
			getline(*tp);
725
 
726
		/*
727
		 * Delete junk between displayed lines.
728
		 */
729
		if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
730
			if (anydl == 0 && DB && CD) {
731
				hold = oldhold;
732
				vclrech(0);
733
				anydl = 1;
734
				hold |= HOLDECH;
735
				heldech = 0;
736
			}
737
			vdellin(p, LINE(l) - p, l);
738
		}
739
 
740
		/*
741
		 * If line image is not know to be up to date, then
742
		 * redisplay it;  else just skip onward.
743
		 */
744
		LINE(l) = p;
745
		if (FLAGS(l) & VDIRT) {
746
			DEPTH(l) = vdepth();
747
			if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
748
				vscrap();
749
				break;
750
			}
751
			FLAGS(l) &= ~VDIRT;
752
			vreopen(p, lineno(tp), l);
753
			p = LINE(l) + DEPTH(l);
754
		} else
755
			p += DEPTH(l);
756
		tp++;
757
	}
758
 
759
	/*
760
	 * That takes care of lines which were already partially displayed.
761
	 * Now try to fill the rest of the screen with text.
762
	 */
763
	if (state == VISUAL && p <= WBOT) {
764
		int ovcline = vcline;
765
 
766
		vcline = l;
767
		for (; tp <= dol && Peekkey != ATTN; tp++) {
768
			getline(*tp);
769
			if (p + vdepth() - 1 > WBOT)
770
				break;
771
			vopen(tp, p);
772
			p += DEPTH(vcline);
773
			vcline++;
774
		}
775
		vcline = ovcline;
776
	}
777
 
778
	/*
779
	 * Thats all the text we can get on.
780
	 * Now rest of lines (if any) get either a ~ if they
781
	 * are past end of file, or an @ if the next line won't fit.
782
	 */
783
	for (; p <= WBOT && Peekkey != ATTN; p++)			
784
		vclrlin(p, tp);
785
	strcLIN(temp);
786
	hold = oldhold;
787
	if (heldech)
788
		vclrech(0);
789
#ifdef ADEBUG
790
	if (trace)
791
		tvliny();
792
#endif
793
}
794
 
795
/*
796
 * Do the real work in deleting cnt lines starting at line p from
797
 * the display.  First affected line is line l.
798
 */
799
void 
800
vdellin(int p, int cnt, int l)
801
{
802
	register int i;
803
 
804
	if (cnt == 0)
805
		return;
806
	if (DL == NOSTR || cnt < 0) {
807
		/*
808
		 * Can't do it; just remember that line l is munged.
809
		 */
810
		FLAGS(l) |= VDIRT;
811
		return;
812
	}
813
#ifdef ADEBUG
814
	if (trace)
815
		tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
816
#endif
817
	/*
818
	 * Send the deletes to the screen and then adjust logical
819
	 * and physical internal data structures.
820
	 */
821
	vgoto(p, 0);
822
	if (DL_PARM && (cnt>1 || *DL==0)) {
823
		vputp(tgoto(DL_PARM, p, cnt), WECHO-p);
824
	}
825
	else if (xCS && *DL==0) {
826
		/* vt100: fake DL by changing scrolling region */
827
		vputp(SC, 1);	/* Save since xCS homes stupid cursor */
828
		vputp(tgoto(xCS, TLINES-1, p), 1);
829
		vputp(tgoto(CM, 0, TLINES-1), 1);/* Go to lower left corner */
830
		for (i=0; i<cnt; i++)		/* .. and scroll cnt times */
831
			putch('\n');		/* should check NL too */
832
		vputp(tgoto(xCS, TLINES-1, 0), 1);/* restore scrolling region */
833
		vputp(RC, 1);			/* put cursor back */
834
	}
835
	else {
836
		for (i = 0; i < cnt; i++)
837
			vputp(DL, WECHO - p);
838
	}
839
	vadjDL(p, cnt);
840
	vcloseup(l, cnt);
841
}
842
/*
843
 * Adjust internal physical screen image to account for deleted lines.
844
 */
845
void 
846
vadjDL(int p, int cnt)
847
{
848
	cell *tlines[TUBELINES];
849
	register int from, to;
850
 
851
#ifdef ADEBUG
852
	if (trace)
853
		tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
854
#endif
855
	/*
856
	 * Would like to use structured assignment but early
857
	 * v7 compiler (released with phototypesetter for v6)
858
	 * can't hack it.
859
	 */
860
	copy(tlines, vtube, sizeof vtube);	/*SASSIGN*/
861
	for (from = p + cnt, to = p; from <= WECHO; from++, to++)
862
		vtube[to] = tlines[from];
863
	for (from = p; to <= WECHO; from++, to++) {
864
		vtube[to] = tlines[from];
865
		vclrcell(vtube[to], WCOLS);
866
	}
867
}
868
/*
869
 * Sync the screen, like redraw but more lazy and willing to leave
870
 * @ lines on the screen.  VsyncCL syncs starting at the current line.
871
 * In any case, if the redraw option is set then all syncs map to redraws
872
 * as if vsync didn't exist.
873
 */
874
void 
875
vsyncCL(void)
876
{
877
 
878
	vsync(LINE(vcline));
879
}
880
 
881
void 
882
vsync(register int p)
883
{
884
 
885
	if (value(REDRAW))
886
		vredraw(p);
887
	else
888
		vsync1(p);
889
}
890
 
891
/*
892
 * The guts of a sync.  Similar to redraw but
893
 * just less ambitous.
894
 */
895
void 
896
vsync1(register int p)
897
{
898
	register int l;
899
	char temp[LBSIZE];
900
	register struct vlinfo *vp = &vlinfo[0];
901
	short oldhold = hold;
902
 
903
#ifdef ADEBUG
904
	if (trace)
905
		tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
906
#endif
907
	if (holdupd) {
908
		if (holdupd < 3)
909
			holdupd = 2;
910
		return;
911
	}
912
	if (state == HARDOPEN || splitw)
913
		return;
914
	vscrap();
915
	CP(temp, linebuf);
916
	if (vcnt == 0)
917
		LINE(0) = WTOP;
918
	l = 0;
919
	while (l < vcnt && vp->vliny < p)
920
		l++, vp++;
921
	heldech = 0;
922
	hold |= HOLDECH;
923
	while (p <= WBOT && Peekkey != ATTN) {
924
		/*
925
		 * Want to put a line here if not in visual and first line
926
		 * or if there are lies left and this line starts before
927
		 * the current line, or if this line is piled under the
928
		 * next line (vreplace does this and we undo it).
929
		 */
930
		if (l == 0 && state != VISUAL ||
931
		    (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
932
			if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
933
				if (l == vcline)
934
					strcLIN(temp);
935
				else
936
					getline(dot[l - vcline]);
937
				/*
938
				 * Be careful that a long line doesn't cause the
939
				 * screen to shoot up.
940
				 */
941
				if (l != vcline && (vp->vflags & VDIRT)) {
942
					vp->vdepth = vdepth();
943
					vp->vflags &= ~VDIRT;
944
					if (p + vp->vdepth - 1 > WBOT)
945
						break;
946
				}
947
				vreopen(p, lineDOT() + (l - vcline), l);
948
			}
949
			p = vp->vliny + vp->vdepth;
950
			vp++;
951
			l++;
952
		} else
953
			/*
954
			 * A physical line between logical lines,
955
			 * so we settle for an @ at the beginning.
956
			 */
957
			vclrlin(p, dot + (l - vcline)), p++;
958
	}
959
	strcLIN(temp);
960
	hold = oldhold;
961
	if (heldech)
962
		vclrech(0);
963
}
964
 
965
/*
966
 * Subtract (logically) cnt physical lines from the 
967
 * displayed position of lines starting with line l.
968
 */
969
void 
970
vcloseup(int l, register int cnt)
971
{
972
	register int i;
973
 
974
#ifdef ADEBUG
975
	if (trace)
976
		tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
977
#endif
978
	for (i = l + 1; i <= vcnt; i++)
979
		LINE(i) -= cnt;
980
}
981
 
982
/*
983
 * Workhorse for rearranging line descriptors on changes.
984
 * The idea here is that, starting with line l, cnt lines
985
 * have been replaced with newcnt lines.  All of these may
986
 * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
987
 * since we may be called from an undo after the screen has
988
 * moved a lot.  Thus we have to be careful.
989
 *
990
 * Many boundary conditions here.
991
 */
992
void 
993
vreplace(int l, int cnt, int newcnt)
994
{
995
	register int from, to, i;
996
	bool savenote = 0;
997
 
998
#ifdef ADEBUG
999
	if (trace) {
1000
		tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
1001
		tvliny();
1002
	}
1003
#endif
1004
	if (l >= vcnt)
1005
		return;
1006
	if (l < 0) {
1007
		if (l + cnt < 0) {
1008
			/*
1009
			 * Nothing on the screen is relevant.
1010
			 * Settle for redrawing from scratch (later).
1011
			 */
1012
			vcnt = 0;
1013
			return;
1014
		}
1015
		/*
1016
		 * Normalize l to top of screen; the add is
1017
		 * really a subtract from cnt since l is negative.
1018
		 */
1019
		cnt += l;
1020
		l = 0;
1021
 
1022
		/*
1023
		 * Unseen lines were affect so notify (later).
1024
		 */
1025
		savenote++;
1026
	}
1027
 
1028
	/*
1029
	 * These shouldn't happen
1030
	 * but would cause great havoc.
1031
	 */
1032
	if (cnt < 0)
1033
		cnt = 0;
1034
	if (newcnt < 0)
1035
		newcnt = 0;
1036
 
1037
	/*
1038
	 * Surely worthy of note if more than report
1039
	 * lines were changed.
1040
	 */
1041
	if (cnt > value(REPORT) || newcnt > value(REPORT))
1042
		savenote++;
1043
 
1044
	/*
1045
	 * Same number of lines affeted as on screen, and we
1046
	 * can insert and delete lines.  Thus we just type
1047
	 * over them, since otherwise we will push them
1048
	 * slowly off the screen, a clear lose.
1049
	 */
1050
	if (cnt == newcnt || vcnt - l == newcnt && AL && DL) {
1051
		if (cnt > 1 && l + cnt > vcnt)
1052
			savenote++;
1053
		vdirty(l, newcnt);
1054
	} else {
1055
		/*
1056
		 * Lines are going away, squish them out.
1057
		 */
1058
		if (cnt > 0) {
1059
			/*
1060
			 * If non-displayed lines went away,
1061
			 * always notify.
1062
			 */
1063
			if (cnt > 1 && l + cnt > vcnt)
1064
				savenote++;
1065
			if (l + cnt >= vcnt)
1066
				cnt = vcnt - l;
1067
			else
1068
				for (from = l + cnt, to = l; from <= vcnt; to++, from++)
1069
					vlcopy(vlinfo[to], vlinfo[from]);
1070
			vcnt -= cnt;
1071
		}
1072
		/*
1073
		 * Open up space for new lines appearing.
1074
		 * All new lines are piled in the same place,
1075
		 * and will be unpiled by vredraw/vsync, which
1076
		 * inserts lines in front as it unpiles.
1077
		 */
1078
		if (newcnt > 0) {
1079
			/*
1080
			 * Newlines are appearing which may not show,
1081
			 * so notify (this is only approximately correct
1082
			 * when long lines are present).
1083
			 */
1084
			if (newcnt > 1 && l + newcnt > vcnt + 1)
1085
				savenote++;
1086
 
1087
			/*
1088
			 * If there will be more lines than fit, then
1089
			 * just throw way the rest of the stuff on the screen.
1090
			 */
1091
			if (l + newcnt > WBOT && AL && DL) {
1092
				vcnt = l;
1093
				goto skip;
1094
			}
1095
			from = vcnt, to = vcnt + newcnt;
1096
			i = TUBELINES - to;
1097
			if (i < 0)
1098
				from += i, to += i;
1099
			vcnt = to;
1100
			for (; from >= l; from--, to--)
1101
				vlcopy(vlinfo[to], vlinfo[from]);
1102
			for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
1103
				LINE(to) = LINE(from);
1104
				DEPTH(to) = 0;
1105
				FLAGS(to) = VDIRT;
1106
			}
1107
		}
1108
	}
1109
skip:
1110
	if (Pline == numbline && cnt != newcnt)
1111
		/*
1112
		 * When lines positions are shifted, the numbers
1113
		 * will be wrong.
1114
		 */
1115
		vdirty(l, WECHO);
1116
	if (!savenote)
1117
		notecnt = 0;
1118
#ifdef ADEBUG
1119
	if (trace)
1120
		tvliny();
1121
#endif
1122
}
1123
 
1124
/*
1125
 * Start harcopy open.
1126
 * Print an image of the line to the left of the cursor
1127
 * under the full print of the line and position the cursor.
1128
 * If we are in a scroll ^D within hardcopy open then all this
1129
 * is suppressed.
1130
 */
1131
void 
1132
sethard(void)
1133
{
1134
 
1135
	if (state == VISUAL)
1136
		return;
1137
	rubble = 0;
1138
	state = HARDOPEN;
1139
	if (hold & HOLDROL)
1140
		return;
1141
	vup1();
1142
	LINE(0) = WBOT;
1143
	if (Pline == numbline)
1144
		vgoto(WBOT, 0), printf("%6d  ", lineDOT());
1145
}
1146
 
1147
/*
1148
 * Mark the lines starting at base for i lines
1149
 * as dirty so that they will be checked for correct
1150
 * display at next sync/redraw.
1151
 */
1152
void 
1153
vdirty(register int base, register int i)
1154
{
1155
	register int l;
1156
 
1157
	for (l = base; l < vcnt; l++) {
1158
		if (--i < 0)
1159
			return;
1160
		FLAGS(l) |= VDIRT;
1161
	}
1162
}