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