1 /* @(#)screen.c 1.42 18/08/27 Copyright 1984-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)screen.c 1.42 18/08/27 Copyright 1984-2018 J. Schilling";
6 #endif
7 /*
8 * Screen update functions for VED
9 *
10 * Copyright (c) 1984-2018 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 /*
27 * The functions below are responsible for the fast screen update of VED.
28 * Main implementation goal was to make the screen uptate fast, ergonomic
29 * and free of jerks. The screen update of vi is not aceptable since
30 * inserting line by line makes the screen hard to read while scrolling.
31 * The screen update of emacs shows you jerking status lines and for that
32 * reason is hard to read too.
33 *
34 * If the article from James Gosling (ACM Sig-Plan Notices 1981 vol 16 p123-129
35 * still applies to EMACS, then its screen update method differs from the
36 * update method used by VED. Emacs tries to compute the updates for more
37 * than one change while VED only looks for one changed spot. However, the
38 * visible behaviour on screen looks very similar.
39 *
40 * Newer versions of 'emacs' try to imitate the basic screen update behaviour
41 * of VED by doing block insert lines, but are slower (emacs spends 4 times
42 * the CPU time in its equivalent screen update package than VED needs).
43 * Take extrame care when doing any modifications on this module.
44 * The basic functionality has not been changed since 1986. Although
45 * many minor changes (markwrap and some cursor positioning problems)
46 * have been done to make it behave more correctly.
47 *
48 * The basic idea is to use no retained memory to compare the current and
49 * the new screen but to try to compute the visual efects 'on the fly'.
50 * This allows to resize the screen to any size without any problems.
51 * To be able to compute sizes, a character string table and a corresponding
52 * character width table is used. VED may deal with lines that are even longer
53 * than the screen if folded and handles printing strings of arbitrary
54 * length for each character. To be able to do this, the routine typerest()
55 * will type any un-typed rest of a character string if there is the need to
56 * add charecters to the end of the screen because of a scroll up or
57 * delete operation.
58 * Typescn() is the interface function that may be used to do partial
59 * screen updates, typescreen() will handle to retype the whole screen
60 * unconditionally. Typescn() is only an internal interface for either
61 * dispup() or typescreen(). Dispup() is the external high level interface
62 * that takes care of doing optimizations like insert char, delete char
63 * and similar.
64 *
65 * Exported functions:
66 *
67 * update - Update the display for the result of a cursor
68 * movement. This may result in the need for an update
69 * of the screen content too.
70 * setwindow - Adjust the current window for optimal cursor position
71 * newwindow - Adjust the current window for optimal cursor position
72 * and retype the screen.
73 * getindent - Return visible indentation of current line,
74 * used by autoindent functionality.
75 * setpos - Re-compute the actual cursor position.
76 * setcursor - Set HW-cursor to 'cursor' position value.
77 * countpos - Count visible position difference for two byte
78 * offset positions in buffer.
79 * findcol - Find the place on current line that is at a specific
80 * visible column.
81 * dispup - Update display as a result of an insert or delete
82 * operation.
83 * realvp - Return 'real' vertial cursor position.
84 * realhp - Return 'real' horizontal cursor position.
85 * typescreen - unconditionally re-type the whole screen or
86 * parts of it
87 *
88 * Edit() calls update() after each action. Only functions that insert or
89 * delete parts of the visible screen need to call dispup() and - or
90 * a setpos() setcursor() sequence.
91 *
92 * To find out how much of the screen needs to be updated, findmatch() is used.
93 */
94
95 /*
96 * Ein Problem sind Terminals, bei denen b_auto_right_margin true ist.
97 * Sie setzen am Ende einer Zeile Den Cursor automatisch auf die naechste Zeile
98 * oder scrollen gar, wenn es sich um die letzte Bildschirmposition handelt.
99 *
100 * Da wird es schwierig, die letzte Bildschirmposition zu beschreiben.
101 * Ich sehe z.Zt. nur die M�glichkeit durch Verwendung von insert char oder
102 * insert line.
103 *
104 * Will man mit insert char arbeiten, dann wird zuerst das Letze Zeichen auf der
105 * vorletzten Position geschrieben und dann davor das vorletzte Zeichen
106 * eingef�gt.
107 * Vorteil: ruhiges Bild.
108 *
109 * Wenn man mit insert Line arbeitet, denn geht es z.B. mit folgendem
110 * Codefragment, welches aber den Nachteil hat, das das Bild springt und das es
111 * nicht funktioniert, wenn das verwendete Terminal wider Erwarten doch micht
112 * hochscrollt.
113 *
114 * if (b_auto_right_margin && hpos >= wp->llen) {
115 * MOVE_CURSOR(0, 0);
116 * INSERT_LINE(wp, 1);
117 * refreshmsg();
118 * }
119 *
120 * Da der ved versucht die Terminalabh�ngigen Dinge m�glichst vorsichtig zu
121 * verwenden, scheidet daher die letzte Methode aus.
122 *
123 * N.B.: Der vi ist auf maximale Performance bei 300 Baud optimiert, der
124 * ved auf maximale Performance bei hohen Datenraten.
125 */
126
127 #include "ved.h"
128 #include "movedot.h"
129 #include "buffer.h"
130 #include "terminal.h"
131
132 /*#define DEBUG*/
133 #ifdef DEBUG
134 #define DBG(a) (cdbg a)
135 #define FDBG(a) (flush(), cdbg a)
136 #define SDBG(a) (cdbg a, sleep(2))
137 #define FSDBG(a) (flush(), cdbg a, sleep(2))
138 #else
139 #define DBG(a)
140 #define FDBG(a)
141 #define SDBG(a)
142 #define FSDBG(a)
143 #endif
144
145 EXPORT cpos_t cursor; /* position of cursor in window hp not mapped*/
146 EXPORT cpos_t cpos; /* real pos of cursor on screen hp mapped */
147
148 #define MARKWRAP
149 /* XXX markwrap ist noch nicht implementiert */
150
151 LOCAL BOOL nl_ostop; /* stop output past wrap marker '\\' */
152
153 extern Uchar csize[]; /* The character sizes table */
154 extern Uchar *ctab[]; /* The character string table */
155
156 /*
157 * XXX static beseitigen! -> automatic.
158 */
159 LOCAL headr_t *passlink = 0; /* Used by getnext(). Both should be */
160 LOCAL int passoffset = 0; /* set with findpos() and left alone */
161
162 /*
163 * Get the next character in buffer.
164 *
165 * Getnext() needs acess to two variables: rpasslink and rpassoffset.
166 * Both should be in registers as a result of a previous call to
167 * findpos(pos, &passlink, &passoffset); and then left alone.
168 * Getnext() then will increment rpasslink and rpassoffset as needed and
169 * return the next character in the buffer on each call.
170 */
171
172 #define getnext(wp) rpasslink->cont[rpassoffset++]; \
173 \
174 while (rpassoffset >= rpasslink->size) { \
175 rpassoffset -= rpasslink->size; \
176 rpasslink = rpasslink->next; \
177 readybuffer(wp, rpasslink); \
178 }
179
180 #define peeknext() rpasslink->cont[rpassoffset]
181
182 /*
183 * On a Motorola 68000 there is no divsll and even on an 68020
184 * divu if much faster than divsll.
185 * Try to use divu as long as llen * psize is < 65535 (256 * 256).
186 * Otherwise define LONG_MOD.
187 */
188
189 #ifndef JOS
190 #if defined(mc68000) && !defined(LONG_MOD)
191 #define modu(a, b) ((unsigned short) \
192 (((unsigned short)(a)) % ((unsigned short)(b))))
193 #else
194 #define modu(a, b) ((a) % (b))
195 #endif /* mc68000 */
196 #endif /* JOS */
197
198 #ifndef modu
199 #define modu(a, b) ((a) % (b))
200 #endif
201
202 /*
203 * Check if we are done with matching the screen update.
204 * This is true if there was a linewrap and we are at the start of the line or
205 * if folding the lines would take us to the same virtual horizontal position.
206 */
207 #define nomatch(hp1, hp2) (linewrap ? (hp1) || (hp2) : \
208 modu(hp1, wp->llen) != modu(hp2, wp->llen))
209
210 LOCAL epos_t lastdot = -1L;
211
212 EXPORT void update __PR((ewin_t *wp));
213 EXPORT void setwindow __PR((ewin_t *wp));
214 EXPORT void newwindow __PR((ewin_t *wp));
215 LOCAL epos_t getnewwindow __PR((ewin_t *wp));
216 LOCAL BOOL setcurpos __PR((ewin_t *wp, epos_t ldot));
217 LOCAL BOOL onscreen __PR((ewin_t *wp, cpos_t * cp));
218 EXPORT int getindent __PR((ewin_t *wp));
219 EXPORT void setpos __PR((ewin_t *wp));
220 EXPORT BOOL setcursor __PR((ewin_t *wp));
221 LOCAL void mappos __PR((ewin_t *wp, cpos_t * cp));
222 EXPORT epos_t countpos __PR((ewin_t *wp, epos_t old, epos_t new,
223 cpos_t * cp));
224 LOCAL epos_t getcol __PR((ewin_t *wp, epos_t begin, int maxcol,
225 cpos_t * cp));
226 EXPORT epos_t findcol __PR((ewin_t *wp, int col, epos_t begin));
227 LOCAL epos_t findmatch __PR((ewin_t *wp, epos_t begin, cpos_t * a,
228 cpos_t * b));
229 EXPORT void dispup __PR((ewin_t *wp, epos_t old, epos_t new));
230 LOCAL void dispdel __PR((ewin_t *wp, epos_t old, epos_t new));
231 LOCAL void dispins __PR((ewin_t *wp, epos_t old, epos_t new));
232 EXPORT int realvp __PR((ewin_t *wp, cpos_t * cp));
233 EXPORT int realhp __PR((ewin_t *wp, cpos_t * cp));
234 LOCAL void typescn __PR((ewin_t *wp, epos_t begin, int col,
235 epos_t end));
236 LOCAL epos_t typescx __PR((ewin_t *wp, epos_t begin, int col,
237 epos_t end));
238 LOCAL void typerest __PR((ewin_t *wp, epos_t begin, cpos_t * cp));
239 EXPORT void typescreen __PR((ewin_t *wp, epos_t begin, int col,
240 epos_t end));
241 LOCAL BOOL outch __PR((ewin_t *wp, int c));
242 LOCAL BOOL outnl __PR((ewin_t *wp, BOOL nlflg));
243 LOCAL BOOL outtab __PR((ewin_t *wp));
244 LOCAL BOOL siaddchar __PR((ewin_t *wp, int c));
245 LOCAL void insert_pad __PR((ewin_t *wp, int size));
246
247
248 /*---------------------------------------------------------------------------
249 |
250 | Update window/cursor position to reflect the new position of dot
251 |
252 +---------------------------------------------------------------------------*/
253
254 EXPORT void
update(wp)255 update(wp)
256 ewin_t *wp;
257 {
258 if (wp->dot >= wp->window && setcurpos(wp, lastdot))
259 setcursor(wp);
260 else
261 setwindow(wp);
262 lastdot = wp->dot;
263 }
264
265
266 /*---------------------------------------------------------------------------
267 |
268 | Adjust window so that the cursor will be in an optimal position on screen
269 |
270 +---------------------------------------------------------------------------*/
271
272 EXPORT void
setwindow(wp)273 setwindow(wp)
274 ewin_t *wp;
275 {
276 epos_t save = wp->window;
277
278 DBG(("setwindow"));
279
280 if (save > wp->eof)
281 save = wp->eof;
282 wp->window = getnewwindow(wp);
283 MOVE_CURSOR(wp, 1, 0);
284 cursor.vp = 1;
285 cursor.hp = 0;
286 dispup(wp, save, wp->window);
287 setpos(wp);
288 setcursor(wp);
289 }
290
291
292 /*---------------------------------------------------------------------------
293 |
294 | Retype the whole screen after adjusting the window with an optimal curpos
295 |
296 +---------------------------------------------------------------------------*/
297
298 EXPORT void
newwindow(wp)299 newwindow(wp)
300 ewin_t *wp;
301 {
302 DBG(("newwindow"));
303
304 wp->window = getnewwindow(wp);
305 MOVE_CURSOR_ABS(wp, 1, 0);
306 cursor.vp = 1;
307 cursor.hp = 0;
308 typescreen(wp, wp->window, 0, wp->eof);
309 setpos(wp);
310 setcursor(wp);
311 lastdot = wp->dot;
312 }
313
314 #ifdef OLD
315
316 LOCAL epos_t
getnewwindow()317 getnewwindow()
318 {
319 return (revline(dot, optline));
320 }
321
322 #else
323
324
325 /*---------------------------------------------------------------------------
326 |
327 | Recompute the start of the window to have the cursor in a optimal position
328 |
329 +---------------------------------------------------------------------------*/
330
331 LOCAL epos_t
getnewwindow(wp)332 getnewwindow(wp)
333 ewin_t *wp;
334 {
335 cpos_t c;
336 register epos_t newwin;
337 register epos_t win = wp->dot;
338 register int vpos = 1;
339 register int vopt = wp->optline;
340 register int col;
341
342 if (win > wp->eof) {
343 writeerr(wp, "BAD DOT POS (>EOF)");
344 wp->dot = wp->eof;
345 return (getnewwindow(wp));
346 }
347 do {
348 c.vp = 1;
349 c.hp = 0;
350 newwin = revline(wp, win, (ecnt_t)2); /* eine Zeile zurueck */
351 countpos(wp, newwin, win, &c);
352 win = newwin;
353 vpos += realvp(wp, &c) - 1;
354 } while (vpos < vopt && newwin > 0);
355 if (vpos >= wp->psize) {
356 /*
357 * Should not happen .... but paranoia.
358 */
359 wp->pmargin = 0;
360 col = wp->llen/2;
361 newwin = wp->dot - col - 1;
362 while (findcol(wp, col, ++newwin) < wp->dot);
363 }
364 findwpos(wp, newwin);
365 return (newwin);
366 }
367 #endif
368
369
370 /*---------------------------------------------------------------------------
371 |
372 | Compute the position where the cursor should be depending on 'dot' pos.
373 |
374 +---------------------------------------------------------------------------*/
375
376 LOCAL BOOL
setcurpos(wp,ldot)377 setcurpos(wp, ldot)
378 ewin_t *wp;
379 epos_t ldot;
380 {
381 DBG(("setcurpos dot: %lld ldot: %lld", (Llong)wp->dot, (Llong)ldot));
382
383 if (ldot >= 0 && wp->dot >= ldot) {
384
385 countpos(wp, ldot, wp->dot, &cursor);
386 } else {
387 setpos(wp);
388 }
389 return (onscreen(wp, &cursor));
390 }
391
392
393 /*---------------------------------------------------------------------------
394 |
395 | Check if 'cp' will be visible on the current screen
396 |
397 +---------------------------------------------------------------------------*/
398
399 LOCAL BOOL
onscreen(wp,cp)400 onscreen(wp, cp)
401 ewin_t *wp;
402 cpos_t *cp;
403 {
404 register int v = realvp(wp, cp);
405
406 return (v <= wp->psize-wp->pmargin &&
407 (v != wp->psize-wp->pmargin || realhp(wp, cp) < wp->llen) &&
408 (v > wp->pmargin || wp->window == 0));
409 }
410
411
412 /*---------------------------------------------------------------------------
413 |
414 | Return the (visible) indentation of the current line
415 |
416 +---------------------------------------------------------------------------*/
417
418 EXPORT int
getindent(wp)419 getindent(wp)
420 ewin_t *wp;
421 {
422 cpos_t c;
423 BOOL save;
424 epos_t lbeg;
425 epos_t textbeg;
426 extern Uchar notwhitespace[];
427
428 c.vp = 1;
429 c.hp = 0;
430 lbeg = revline(wp, wp->dot, (ecnt_t)1); /* an den Anfang der Zeile */
431 save = wp->magic;
432 wp->magic = TRUE;
433 textbeg = search(wp, lbeg, notwhitespace, strlen(C notwhitespace), 0)
434 - 1;
435 wp->magic = save;
436 if (textbeg > wp->dot)
437 textbeg = wp->dot;
438 /* writeerr(wp, "%d %d %d", lbeg, textbeg, wp->dot);*/
439 countpos(wp, lbeg, textbeg, &c);
440 return (c.hp);
441 }
442
443
444 /*---------------------------------------------------------------------------
445 |
446 | Compute the position where the cursor should be, start at top of 'window'
447 |
448 +---------------------------------------------------------------------------*/
449
450 EXPORT void
setpos(wp)451 setpos(wp)
452 ewin_t *wp;
453 {
454 cursor.vp = 1;
455 cursor.hp = 0;
456 countpos(wp, wp->window, wp->dot, &cursor);
457 }
458
459
460 /*---------------------------------------------------------------------------
461 |
462 | Set the cursor to the position previously set up in struct curpos by setpos()
463 |
464 +---------------------------------------------------------------------------*/
465
466 EXPORT BOOL
setcursor(wp)467 setcursor(wp)
468 ewin_t *wp;
469 {
470 int v;
471
472 DBG(("setcursor caller: 0x%lX P: %d.%d C: %d.%d",
473 getcaller(), cpos.vp, cpos.hp, cursor.vp, cursor.hp));
474
475 if ((v = realvp(wp, &cursor)) <= wp->psize) {
476 MOVE_CURSOR(wp, v, realhp(wp, &cursor));
477
478 DBG(("setcursor P: %d.%d C: %d.%d",
479 cpos.vp, cpos.hp, cursor.vp, cursor.hp));
480
481 return (TRUE);
482 } else {
483 return (FALSE);
484 }
485 }
486
487
488 /*---------------------------------------------------------------------------
489 |
490 | Map cp->vp/cp->hp position description into description of the form vp/0
491 |
492 +---------------------------------------------------------------------------*/
493
494 LOCAL void
mappos(wp,cp)495 mappos(wp, cp)
496 ewin_t *wp;
497 register cpos_t *cp;
498 {
499 cp->vp = realvp(wp, cp) + 1;
500 cp->hp = 0;
501 }
502
503
504 /*---------------------------------------------------------------------------
505 |
506 | Update 'cp' to the cursor position when moving from old to new.
507 | Return position in file that is actually taken.
508 |
509 +---------------------------------------------------------------------------*/
510
511 EXPORT epos_t
countpos(wp,old,new,cp)512 countpos(wp, old, new, cp)
513 ewin_t *wp;
514 epos_t old;
515 epos_t new;
516 register cpos_t *cp;
517 {
518 register headr_t *rpasslink; /* state for getnext - these should */
519 register int rpassoffset; /* set by any caller and left alone */
520 register Uchar c;
521 register Uchar *rcsize;
522 register int rllen;
523 register int rpsize;
524 register epos_t cnt;
525
526 if (old >= new)
527 return (old);
528 rcsize = csize;
529 rllen = wp->llen;
530 rpsize = wp->psize;
531 findpos(wp, old, &passlink, &passoffset);
532 rpasslink = passlink;
533 rpassoffset = passoffset;
534
535 cnt = new - old;
536 while (cnt > 0) {
537 c = getnext(wp);
538 cnt--;
539 if (c == '\n') {
540 mappos(wp, cp);
541 if (cp->vp > rpsize)
542 break;
543 } else if (c == TAB) {
544 cp->hp = (cp->hp / wp->tabstop) * wp->tabstop +
545 wp->tabstop;
546 } else {
547 cp->hp += rcsize[c];
548 }
549 if (cp->hp >= rllen && realvp(wp, cp) > rpsize)
550 break;
551 }
552 return (new - cnt);
553 }
554
555
556 /*---------------------------------------------------------------------------
557 |
558 | Get 'cp' for maximun column in this line.
559 | Update 'cp' to the cursor position when moving from old to this column.
560 | Return position in file that is actually taken.
561 |
562 +---------------------------------------------------------------------------*/
563
564 LOCAL epos_t
getcol(wp,begin,maxcol,cp)565 getcol(wp, begin, maxcol, cp)
566 ewin_t *wp;
567 epos_t begin;
568 register int maxcol;
569 register cpos_t *cp;
570 {
571 register headr_t *rpasslink; /* state for getnext - these should */
572 register int rpassoffset; /* set by any caller and left alone */
573 register Uchar c;
574 register Uchar *rcsize;
575 register int ocol;
576 register int col;
577 register epos_t cnt;
578
579 if (begin >= wp->eof)
580 return (begin);
581 rcsize = csize;
582 findpos(wp, begin, &passlink, &passoffset);
583 rpasslink = passlink;
584 rpassoffset = passoffset;
585
586 cnt = wp->eof - begin;
587 col = realhp(wp, cp);
588 while (cnt > 0 && col <= maxcol) {
589 c = getnext(wp);
590 cnt--;
591 if (c == '\n') {
592 mappos(wp, cp);
593 col = realhp(wp, cp);
594 break;
595 } else if (c == TAB) {
596 ocol = cp->hp;
597 cp->hp = (cp->hp / wp->tabstop) * wp->tabstop +
598 wp->tabstop;
599 col += cp->hp - ocol;
600 } else {
601 cp->hp += rcsize[c];
602 col += rcsize[c];
603 }
604 }
605 return (wp->eof - cnt);
606 }
607
608
609 /*---------------------------------------------------------------------------
610 |
611 | Find the file offset that belongs to a specific visible screen column.
612 | Start position needs to be at the beginning of a line.
613 |
614 +---------------------------------------------------------------------------*/
615
616 EXPORT epos_t
findcol(wp,col,begin)617 findcol(wp, col, begin)
618 ewin_t *wp;
619 register int col;
620 register epos_t begin;
621 {
622 cpos_t a;
623
624 a.hp = 0;
625 a.vp = 1;
626
627 while (begin < wp->eof && a.hp < col) {
628 countpos(wp, begin, begin+1, &a);
629 /*
630 * If this line is too short, give up.
631 */
632 if (a.hp == 0)
633 break;
634 begin++;
635 }
636 return (begin);
637 }
638
639 LOCAL int tabcnt; /* # of tabs found by last findmatch call */
640 LOCAL BOOL linewrap; /* The changes caused a diffrent vpos */
641
642 /*---------------------------------------------------------------------------
643 |
644 | Find the minimum number of characters needed to print for updating the
645 | screen to a correct new state.
646 |
647 +---------------------------------------------------------------------------*/
648
649 LOCAL epos_t
findmatch(wp,begin,a,b)650 findmatch(wp, begin, a, b)
651 ewin_t *wp;
652 epos_t begin;
653 register cpos_t *a;
654 register cpos_t *b;
655 {
656 register headr_t *rpasslink; /* state for getnext - these should */
657 register int rpassoffset; /* set by any caller and left alone */
658 register Uchar c;
659 register Uchar *rcsize;
660 register Uchar size;
661 register epos_t cnt;
662
663 tabcnt = 0;
664 linewrap = a->vp != b->vp || a->hp/wp->llen != b->hp/wp->llen;
665 if (begin >= wp->eof)
666 return (begin);
667 rcsize = csize;
668 findpos(wp, begin, &passlink, &passoffset);
669 rpasslink = passlink;
670 rpassoffset = passoffset;
671
672 cnt = wp->eof - begin;
673 while (nomatch(a->hp, b->hp) && cnt > 0) {
674 c = getnext(wp);
675 cnt--;
676 if (c == '\n') {
677 mappos(wp, a);
678 mappos(wp, b);
679 return (wp->eof - cnt);
680 }
681 if (c == TAB) {
682 a->hp = (a->hp / wp->tabstop) * wp->tabstop +
683 wp->tabstop;
684 b->hp = (b->hp / wp->tabstop) * wp->tabstop +
685 wp->tabstop;
686 tabcnt++;
687 } else {
688 a->hp += size = rcsize[c];
689 b->hp += size;
690 }
691 }
692 return (wp->eof - cnt);
693 }
694
695
696 /*---------------------------------------------------------------------------
697 |
698 | Check if we are ready with matching the screen update.
699 | This is true if there was a linewrap and we are at the start of the line or
700 | if folding the lines would take us to the same virtual horizontal position.
701 |
702 +---------------------------------------------------------------------------*/
703
704 #ifndef nomatch
nomatch(hp1,hp2)705 nomatch(hp1, hp2)
706 {
707 if (linewrap)
708 return (hp1 || hp2);
709 else
710 return (modu(hp1, wp->llen) != modu(hp2, wp->llen));
711 }
712 #endif
713
714 LOCAL int gotshorter; /* There were visible deletions on screen */
715
716 /*---------------------------------------------------------------------------
717 |
718 | Update the display to reflect the effects of a insert or delete operation.
719 | 'old' is the file offset where the cursor currently is located.
720 | 'new' is the file offset where the cursor should be.
721 |
722 +---------------------------------------------------------------------------*/
723 EXPORT void
dispup(wp,old,new)724 dispup(wp, old, new)
725 ewin_t *wp;
726 epos_t old;
727 epos_t new;
728 {
729 FDBG((" dispup (%lld, %lld) P: %d.%d %s", (Llong)old, (Llong)new,
730 cpos.vp, cpos.hp,
731 (new > old)? "Delete":"Insert"));
732
733 if ((gotshorter = (new > old)) != 0) {
734 dispdel(wp, old, new);
735 } else {
736 dispins(wp, old, new);
737 }
738 }
739
740
741 /*---------------------------------------------------------------------------
742 |
743 | Update the display to reflect the effects of a delete operation.
744 | 'old' is where the deleted text starts now (before deleting)
745 | 'new' is where the remaining characters have been before doing the deletion.
746 |
747 +---------------------------------------------------------------------------*/
748
749 LOCAL void
dispdel(wp,old,new)750 dispdel(wp, old, new)
751 ewin_t *wp;
752 epos_t old;
753 epos_t new;
754 {
755 epos_t save = old;
756 epos_t skip;
757 int size;
758 int bottomv;
759 int bottomh;
760 int col = cursor.hp;
761 cpos_t o;
762 cpos_t n;
763
764 /*
765 * First iniatilize to current cursor position.
766 * Later, 'n' is updated to where the cursor should be,
767 * 'o' is updated to where the appropriate characters currently are.
768 */
769 o.vp = n.vp = cursor.vp;
770 o.hp = n.hp = cursor.hp;
771
772 /*
773 * Compute the visible size of deleted characters and the position
774 * on screen where typing these caracters would take us.
775 */
776 countpos(wp, old, new, &o);
777 size = o.hp - n.hp;
778
779 /*
780 * Check how many characters we would have to type until the
781 * screen remains the same as before deleting the characters.
782 */
783 old = findmatch(wp, new, &n, &o);
784
785 linewrap = realvp(wp, &o) != realvp(wp, &n);
786
787 /*
788 * If we did not find any tab and we only have to retype the rest of
789 * the current line use delete char.
790 * If there is no charater remaining after the current position
791 * don't use delete char.
792 */
793 if (old != 0 && o.hp == 0 && o.vp == realvp(wp, &cursor) + 1)
794 if (tabcnt == 0 && f_del_char)
795 if (size > 0 && size < (old-new)/2 && save+1 < old) {
796 DELETE_CHAR(wp, size);
797 old = new;
798
799 FSDBG(("DCdispdel(%lld, %lld) P: %d.%d",
800 (Llong)old, (Llong)new,
801 cpos.vp, cpos.hp));
802 }
803
804 /*
805 * Limit the number if deleted lines to 2/3 of the screen and
806 * require that at least one old line remains on screen.
807 */
808 if ((size = realvp(wp, &o) - realvp(wp, &n)) > 0 && new < wp->eof) {
809 if (f_del_line && size>>1 <= wp->psize/3+1 &&
810 size+cpos.vp < wp->psize-1 &&
811 cpos.vp < wp->psize) {
812 /*
813 * First redraw to end of current screen line.
814 */
815 n.vp = cursor.vp;
816 n.hp = cursor.hp;
817 skip = getcol(wp, new, wp->llen, &n);
818 if (skip < wp->eof) {
819 nl_ostop = TRUE;
820 typescn(wp, new, col, skip);
821 nl_ostop = FALSE;
822
823 FSDBG(("TSdispdel(%lld, %lld) P: %d.%d",
824 (Llong)old, (Llong)new,
825 cpos.vp, cpos.hp));
826
827 /* find end of screen */
828 new = countpos(wp, old, wp->eof, &o);
829 col = o.hp;
830 DELETE_LINE(wp, size);
831
832 FSDBG(("DLdispdel(%lld, %lld) P: %d.%d",
833 (Llong)old, (Llong)new,
834 cpos.vp, cpos.hp));
835
836 if (new == wp->eof) {
837 /*
838 * Das Ende der Datei ist bereits
839 * sichtbar, Bildschirmupdate beendet.
840 */
841 goto out;
842 /* need goto to print dbg */
843 }
844
845 FSDBG(("BVdispdel(%lld, %lld) O: %d.%d",
846 (Llong)old, (Llong)new,
847 o.vp, o.hp));
848 /*
849 * Berechnung der realen Cursorposition, ab
850 * der der Bildchirm beschrieben werden mu�.
851 */
852 bottomv = realvp(wp, &o);
853 bottomv = min(bottomv, wp->psize+1);
854 bottomh = bottomv > wp->psize ? 0 :
855 realhp(wp, &o);
856
857 if (b_auto_right_margin && !f_ins_char) {
858 /*
859 * In diesem Fall ist das letzte
860 * Zeichen auf dem Bildschirm nicht
861 * geschrieben worden.
862 */
863 if (bottomh == 0) {
864 bottomv--;
865 bottomh = wp->llen;
866 } else {
867 /*
868 * Das sollte nie passieren!
869 */
870 cdbg("bottomh: %d",
871 bottomh);
872 }
873 }
874 MOVE_CURSOR(wp, bottomv-size, bottomh);
875
876 FSDBG(("MCdispdel(%lld, %lld) P: %d.%d",
877 (Llong)old, (Llong)new,
878 cpos.vp, cpos.hp));
879
880 typerest(wp, new, &o);
881
882 FSDBG(("TRdispdel(%lld, %lld) P: %d.%d",
883 (Llong)old, (Llong)new,
884 cpos.vp, cpos.hp));
885 }
886 }
887 /*
888 * There is no delele-line feature or we don't want
889 * to use it, redraw to end.
890 */
891 old = wp->eof;
892 }
893 typescn(wp, new, col, old);
894 out:
895 FSDBG(("TSdispdel(%lld, %lld) P: %d.%d",
896 (Llong)old, (Llong)new,
897 cpos.vp, cpos.hp));
898 }
899
900
901 /*---------------------------------------------------------------------------
902 |
903 | Update the display to reflect the effects of an insert operation.
904 | 'new' is where the new (inserted characters) start
905 | 'old' is where the old characters will be after doing the insertion.
906 |
907 +---------------------------------------------------------------------------*/
908
909 LOCAL void
dispins(wp,old,new)910 dispins(wp, old, new)
911 ewin_t *wp;
912 epos_t old;
913 epos_t new;
914 {
915 epos_t save = old;
916 int size;
917 int col = cursor.hp;
918 cpos_t o;
919 cpos_t n;
920
921 /*
922 * First iniatilize to current cursor position.
923 * Later, 'n' is updated to where the cursor should be,
924 * 'o' is updated to where the appropriate characters currently are.
925 */
926 o.vp = n.vp = cursor.vp;
927 o.hp = n.hp = cursor.hp;
928
929 /*
930 * Compute the visible size of inserted characters and the position
931 * on screen where typing the caracters would take us.
932 */
933 countpos(wp, new, old, &n);
934 size = n.hp - o.hp;
935
936 /*
937 * Check how many characters we have to type until the screen
938 * remains the same as before inserting the characters.
939 */
940 old = findmatch(wp, old, &n, &o);
941
942 linewrap = realvp(wp, &o) != realvp(wp, &n);
943
944 /*
945 * If we did not find any tab and we only have to retype the rest of
946 * the current line use insert char.
947 * If there is no charater remaining after the current position
948 * don't use insert char.
949 */
950 if (old != wp->eof && n.hp == 0 && n.vp == realvp(wp, &cursor) + 1) {
951 if (tabcnt == 0 && f_ins_char) {
952 if (size > 0 && size < (old-new)/3 && save+1 < old) {
953 /* XXX Besser direkt Inhalt schreiben */
954 insert_pad(wp, size);
955
956 FSDBG(("ICdispins(%lld, %lld) P: %d.%d",
957 (Llong)old, (Llong)new,
958 cpos.vp, cpos.hp));
959
960 MOVE_CURSOR(wp, cpos.vp, cpos.hp - size);
961 old = save;
962
963 FSDBG(("MCdispins(%lld, %lld) P: %d.%d",
964 (Llong)old, (Llong)new,
965 cpos.vp, cpos.hp));
966 }
967 }
968 } else if (o.hp) {
969 mappos(wp, &o);
970 }
971
972 /*
973 * Limit the number if inserted lines to half the screen and
974 * require that at least one old line remains on screen.
975 */
976 if ((size = (realvp(wp, &n)-realvp(wp, &o)))*2 > wp->psize ||
977 size+cpos.vp >= wp->psize-1 ||
978 old == wp->eof) {
979 typescn(wp, new, col, wp->eof); /* Retype rest */
980
981 FSDBG(("TS1dispins(%lld, %lld) P: %d.%d",
982 (Llong)old, (Llong)new,
983 cpos.vp, cpos.hp));
984 } else {
985 /*
986 * We decided that is is worth to insert lines.
987 */
988 if (size > 0) {
989 if (f_ins_line) {
990 if (col > 0)
991 MOVE_CURSOR(wp, cpos.vp + 1, 0);
992 INSERT_LINE(wp, size);
993
994 FSDBG(("ILdispins(%lld, %lld) P: %d.%d",
995 (Llong)old, (Llong)new,
996 cpos.vp, cpos.hp));
997 if (col > 0)
998 setcursor(wp);
999 } else {
1000 old = wp->eof;
1001 }
1002 }
1003 typescn(wp, new, col, old);
1004
1005 FSDBG(("TS2dispins(%lld, %lld) P: %d.%d",
1006 (Llong)old, (Llong)new,
1007 cpos.vp, cpos.hp));
1008 }
1009 }
1010
1011
1012 /*---------------------------------------------------------------------------
1013 |
1014 | Return the 'real' vertical position of 'cp'.
1015 | When computing cursor position, the vertical position is only updated to
1016 | the correct visible value if we at the start of a line. This computes the
1017 | visible vertical position as an effect of possible folding of long lines.
1018 | Take care not to increment if hpos is 0.
1019 |
1020 +---------------------------------------------------------------------------*/
1021
1022 EXPORT int
realvp(wp,cp)1023 realvp(wp, cp)
1024 ewin_t *wp;
1025 register cpos_t *cp;
1026 {
1027 #ifdef MARKWRAP
1028 return (cp->hp >= (wp->llen+wp->markwrap) ?
1029 cp->vp + (cp->hp - wp->markwrap) / wp->llen : cp->vp);
1030 #else
1031 return (cp->hp > wp->llen ? cp->vp + (cp->hp - 1) / wp->llen : cp->vp);
1032 #endif
1033 }
1034
1035
1036 /*---------------------------------------------------------------------------
1037 |
1038 | Return the 'real' horizontal position of 'cp'.
1039 | When computing cursor position, the vertical position is only updated to
1040 | the correct visible value if we at the start of a line. This computes the
1041 | visible horizontal position as an effect of possible folding of long lines.
1042 | Take care not to increment if hpos is 0.
1043 |
1044 +---------------------------------------------------------------------------*/
1045
1046 EXPORT int
realhp(wp,cp)1047 realhp(wp, cp)
1048 ewin_t *wp;
1049 cpos_t *cp;
1050 {
1051 register int h = cp->hp;
1052
1053 #ifdef MARKWRAP
1054 return (h >= (wp->llen+wp->markwrap) ?
1055 (h - wp->markwrap) % wp->llen + wp->markwrap : h);
1056 #else
1057 return (h > wp->llen ? (h - 1) % wp->llen + 1 : h);
1058 #endif
1059 }
1060
1061
1062 /*---------------------------------------------------------------------------
1063 |
1064 | Type characters from 'x' to 'y' starting on column 'col'.
1065 | Stop if we reached 'eof' or the end of the screen.
1066 | Use typescx() to do the work, then set 'ewindow' to the last character
1067 | position on screen.
1068 |
1069 +---------------------------------------------------------------------------*/
1070
1071 LOCAL void
typescn(wp,begin,col,end)1072 typescn(wp, begin, col, end)
1073 ewin_t *wp;
1074 epos_t begin;
1075 int col;
1076 epos_t end;
1077 {
1078 epos_t lpos;
1079
1080 if ((lpos = typescx(wp, begin, col, end)) >= 0)
1081 wp->ewindow = lpos;
1082 if (wp->ewindow < wp->window) /* XXX ??? */
1083 wp->ewindow = wp->eof;
1084 }
1085
1086 LOCAL int lcol; /* Remembered last typed column. */
1087
1088 /*---------------------------------------------------------------------------
1089 |
1090 | Type characters from 'x' to 'y' starting on column 'col'.
1091 | Stop if we reached 'eof' or the end of the screen.
1092 | Return the offset of the last character typed if 'y' would not fit on screen
1093 | or -1 if the whole number of characters could be typed.
1094 | Should only be called from typescn().
1095 |
1096 +---------------------------------------------------------------------------*/
1097
1098 LOCAL epos_t
typescx(wp,begin,col,end)1099 typescx(wp, begin, col, end)
1100 ewin_t *wp;
1101 register epos_t begin;
1102 int col;
1103 epos_t end;
1104 {
1105 register headr_t *rpasslink; /* state for getnext - these should */
1106 register int rpassoffset; /* set by any caller and left alone */
1107 register Uchar c;
1108 register Uchar *s;
1109 register Uchar **rctab;
1110 register epos_t lposition; /* last pos in buffer to be typed */
1111
1112 rctab = ctab;
1113 findpos(wp, begin, &passlink, &passoffset);
1114 rpasslink = passlink;
1115 rpassoffset = passoffset;
1116
1117 lcol = col;
1118 lposition = min(end, wp->eof);
1119
1120 while (begin < lposition) {
1121 if (wp->markvalid && begin == wp->mark)
1122 onmark();
1123 c = getnext(wp);
1124 begin++;
1125 if (c == '\n') {
1126 if (!outnl(wp, begin < lposition || gotshorter ||
1127 linewrap || wp->visible))
1128 return (begin);
1129 } else if (c == '\r' && wp->dosmode && peeknext() == '\n') {
1130 /*EMPTY*/
1131 ;
1132 } else if (c == TAB) {
1133 if (!outtab(wp))
1134 return (begin);
1135 } else {
1136 s = rctab[c];
1137 while (*s)
1138 if (!outch(wp, *s++))
1139 return (begin);
1140 }
1141 if (markon)
1142 offmark();
1143 }
1144
1145 /*
1146 * If the last position to be typed is 'eof' take care of the EOF
1147 * marker.
1148 */
1149 if (lposition == wp->eof) {
1150 if (wp->mark == wp->eof && wp->markvalid) {
1151 onmark();
1152 addchar((Uchar) (wp->visible ? '>' : ' '));
1153 offmark();
1154 } else {
1155 addchar((Uchar) (wp->visible ? '>' : ' '));
1156 }
1157
1158 /*
1159 * If the file got shorter, erase the rest of the screen if
1160 * the change was visible on more than line orerase the rest
1161 * of the line if we only had to type one line.
1162 */
1163 if (gotshorter) {
1164 if (linewrap)
1165 CLEAR_TO_EOF_SCREEN(wp);
1166 else
1167 CLEAR_TO_EOF_LINE(wp);
1168 }
1169 }
1170 return (-1);
1171 }
1172
1173
1174 /*
1175 * Gibt den Rest eines Buchstabens aus,
1176 * wenn durch Hochscrollen der hintere Teil sichtbar wird.
1177 * Das passiert, wenn ein Buchstabe vorher nicht komplett auf dem
1178 * Bildschirm sichtbar war.
1179 *
1180 * Pos ist die Cursorposition hinter dem wickelnden char.
1181 * Wenn pos nicht hinter die letzte Zeile zeigt,
1182 * oder der Rest gr��er als der dort stehende Buchstabe ist,
1183 * wird nichts ausgegeben.
1184 */
1185 LOCAL void
typerest(wp,begin,cp)1186 typerest(wp, begin, cp)
1187 ewin_t *wp;
1188 register epos_t begin;
1189 register cpos_t *cp;
1190 {
1191 register headr_t *rpasslink; /* state for getnext - these should */
1192 register int rpassoffset; /* set by any caller and left alone */
1193 register Uchar c; /* wrapping character */
1194 register Uchar *s; /* string to output for 'c' */
1195 register int rest; /* number of untyped chars in 'c' */
1196 int p;
1197
1198 /*
1199 * Wenn die Zeile wickelt, dann ist realvp(cp) mindestens auf psize+1
1200 */
1201 if (realvp(wp, cp) - wp->psize <= 0)
1202 return;
1203
1204 p = wp->psize + 1 - cp->vp;
1205
1206 rest = cp->hp - p * wp->llen;
1207
1208 DBG(("typerest: cp: %d.%d psize: %d p: %d rest: %d",
1209 cp->vp, cp->hp, wp->psize, p, rest));
1210
1211 if (rest <= 0)
1212 return;
1213
1214 lcol = cp->hp - rest;
1215 findpos(wp, --begin, &passlink, &passoffset);
1216 rpasslink = passlink;
1217 rpassoffset = passoffset;
1218
1219 if (wp->markvalid && begin == wp->mark)
1220 onmark();
1221 c = getnext(wp);
1222 if (c == TAB) {
1223 if (!outtab(wp))
1224 return;
1225 } else {
1226 s = ctab[c];
1227 p = csize[c];
1228 if (rest > p)
1229 goto out;
1230 s += p - rest;
1231 while (*s)
1232 if (!outch(wp, *s++))
1233 return;
1234 }
1235 out:
1236 if (markon)
1237 offmark();
1238 }
1239
1240
1241 /*---------------------------------------------------------------------------
1242 |
1243 | The external interface to (re-)type the whole screen or parts of it.
1244 | Typescreen does no optimization like dispup().
1245 | The cursor must be set to the position where typing should start.
1246 | It first sets some variables to force typescn() to do no optimization.
1247 |
1248 +---------------------------------------------------------------------------*/
1249
1250 EXPORT void
typescreen(wp,begin,col,end)1251 typescreen(wp, begin, col, end)
1252 ewin_t *wp;
1253 register epos_t begin;
1254 int col;
1255 epos_t end;
1256 {
1257 gotshorter = TRUE;
1258 linewrap = FALSE;
1259 typescn(wp, begin, col, end);
1260 }
1261
1262 /*
1263 * lastchar & lastmark sind ein Versuch den letzten Buchstaben auf dem Schirm
1264 * zu merken, damit man ihn mit insert char zum Beschreiben der letzten
1265 * Bildschirmposition verwenden kann.
1266 * Das funktioniert aber nur, wenn die letzten Buchstaben auf dem Bildschirm
1267 * nacheinander ausgegeben werden.
1268 */
1269 LOCAL Uchar lastchar;
1270 LOCAL int lastmark;
1271
1272 /*---------------------------------------------------------------------------
1273 |
1274 | Output one character to the screen, take care of the screens's linelength
1275 | and pagesize. Mark a wrapping line with a backslash if wanted.
1276 | Return FALSE if the character was the last character that fit on screen.
1277 |
1278 +---------------------------------------------------------------------------*/
1279
1280 LOCAL BOOL
outch(wp,c)1281 outch(wp, c)
1282 ewin_t *wp;
1283 Uchar c;
1284 {
1285 /*cdbg("llen: %d xxx: %d\n", wp->llen, (wp->llen+markwrap-1));*/
1286 #ifdef MARKWRAP
1287 if (cpos.hp >= (wp->llen+wp->markwrap-1)) {
1288 Uchar lastc = wp->markwrap ? '\\' : c;
1289 #else
1290 if (cpos.hp >= wp->llen) {
1291 #endif
1292
1293 if (cpos.vp >= wp->psize) {
1294 if (!b_auto_right_margin) {
1295
1296 #ifdef MARKWRAP
1297 addchar(lastc);
1298 #else
1299 addchar((Uchar) '\\');
1300 #endif
1301 /*
1302 * nun ist cpos.hp > llen
1303 */
1304 } else {
1305 #ifdef MARKWRAP
1306 siaddchar(wp, lastc);
1307 #else
1308 siaddchar(wp, (Uchar) '\\');
1309 #endif
1310 }
1311 if (markon)
1312 offmark();
1313 return (FALSE);
1314 }
1315 /*
1316 * XXX hier ist der Fehler, da� der letzte Buchstabe nochmal auf der neuen
1317 * XXX Zeile ausgegeben wird.
1318 */
1319 #ifdef MARKWRAP
1320 addchar(lastc);
1321 #else
1322 addchar((Uchar) '\\');
1323 #endif
1324 /*
1325 * auch hier ist cpos.hp > llen
1326 */
1327 if (b_auto_right_margin) {
1328 /*
1329 * Flush mark buffer, then move cursor.
1330 */
1331 if (markon) {
1332 offmark();
1333 onmark();
1334 }
1335 MOVE_CURSOR_ABS(wp, cpos.vp, cpos.hp);
1336 }
1337 addchar((Uchar) '\n');
1338 if (nl_ostop)
1339 return (TRUE);
1340 #ifdef MARKWRAP
1341 if (!wp->markwrap)
1342 goto out;
1343 #endif
1344 }
1345 addchar(c);
1346 lastchar = c;
1347 lastmark = markon;
1348 out:
1349 lcol++;
1350 return (TRUE);
1351 }
1352
1353
1354 /*---------------------------------------------------------------------------
1355 |
1356 | Output a NL (^J) (depending on current mode [visible])
1357 |
1358 +---------------------------------------------------------------------------*/
1359
1360 LOCAL BOOL
outnl(wp,nlflg)1361 outnl(wp, nlflg)
1362 ewin_t *wp;
1363 BOOL nlflg;
1364 {
1365 if (!b_auto_right_margin || cpos.vp < wp->psize || cpos.hp < wp->llen)
1366 addchar((Uchar) (wp->visible ? '$' : ' '));
1367 else
1368 siaddchar(wp, (Uchar) (wp->visible ? '$' : ' '));
1369
1370 if (b_auto_right_margin && cpos.hp >= wp->llen) {
1371 MOVE_CURSOR_ABS(wp, cpos.vp, cpos.hp);
1372 }
1373 if (nlflg && cpos.hp <= wp->llen)
1374 CLEAR_TO_EOF_LINE(wp);
1375 if (cpos.vp >= wp->psize) {
1376 if (markon)
1377 offmark();
1378 return (FALSE);
1379 }
1380 if (nlflg)
1381 addchar((Uchar) '\n');
1382 lcol = 0;
1383 return (TRUE);
1384 }
1385
1386
1387 /*---------------------------------------------------------------------------
1388 |
1389 | Output a TAB (^I) in expanded form (depending on current mode)
1390 |
1391 +---------------------------------------------------------------------------*/
1392
1393 LOCAL BOOL
outtab(wp)1394 outtab(wp)
1395 ewin_t *wp;
1396 {
1397 register int rtabstop = wp->tabstop;
1398
1399 do {
1400 if (!outch(wp, (Uchar) (wp->visible ?
1401 (modu(lcol+1, rtabstop)?'.' : ':') :
1402 ' ')))
1403 return (FALSE);
1404 } while (modu(lcol, rtabstop));
1405 return (TRUE);
1406 }
1407
1408
1409 /*---------------------------------------------------------------------------
1410 |
1411 | Simulate addchar() at last screen position by using insert char.
1412 |
1413 +---------------------------------------------------------------------------*/
1414
1415 LOCAL BOOL
siaddchar(wp,c)1416 siaddchar(wp, c)
1417 ewin_t *wp;
1418 Uchar c;
1419 {
1420 char str[2];
1421 int smark = markon;
1422
1423 if (!f_ins_char)
1424 return (FALSE);
1425
1426 if (markon)
1427 offmark();
1428 CURSOR_LEFT(wp, 1);
1429 if (smark)
1430 onmark();
1431
1432 addchar(c);
1433
1434 if (markon)
1435 offmark();
1436
1437 str[0] = lastchar;
1438 str[1] = '\0';
1439 CURSOR_LEFT(wp, 1);
1440 INSERT_CHAR(wp, str);
1441
1442 if (lastmark) {
1443 CURSOR_LEFT(wp, 1);
1444 onmark();
1445 addchar(lastchar);
1446 offmark();
1447 }
1448 if (smark)
1449 onmark();
1450 return (TRUE);
1451 }
1452
1453
1454 /*---------------------------------------------------------------------------
1455 |
1456 | Insert a string of 'size' spaces
1457 |
1458 +---------------------------------------------------------------------------*/
1459
1460 LOCAL void
insert_pad(wp,size)1461 insert_pad(wp, size)
1462 ewin_t *wp;
1463 int size;
1464 {
1465 char padding[256];
1466 register int idx;
1467 register int amt = size;
1468
1469 while (size > 0) {
1470 if (amt >= sizeof (padding))
1471 amt = sizeof (padding) - 1;
1472
1473 for (idx = 0; idx < amt; )
1474 padding[idx++] = ' ';
1475 padding[idx] = '\0';
1476 INSERT_CHAR(wp, padding);
1477 size -= amt;
1478 }
1479 }
1480