1 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
4 static char rcsid
[] = "$Header$";
20 STATIC
char * do_line();
23 * Fill n lines of the screen, each with "str".
27 fillscr(n
,str
) char *str
; int n
; {
35 * Skip "n" screenlines of line "p", and return what's left of it.
39 skiplines(p
,n
) char *p
; int n
; {
43 scr_info
.currentpos
--;
50 * "n" = 1 if it is a real redraw, 0 if one page must be displayed.
51 * It is also called when yap receives a stop signal.
56 register struct scr_info
*p
= &scr_info
;
60 if (n
&& p
->currentpos
) {
63 (VOID
) display(p
->firstline
,p
->nf
,i
,1);
67 * Compute return value for the routines "display" and "scrollf".
68 * This return value indicates wether we are at the end of file
69 * or at the start, or both.
70 * "s" contains that part of the last line that was not displayed.
74 compretval(s
) char *s
; {
76 register struct scr_info
*p
= &scr_info
;
79 if (!s
|| (!*s
&& !getline(p
->lastline
+1, 1))) {
82 if (p
->firstline
== 1 && !p
->nf
) {
90 * Display nlines, starting at line n, not displaying the first
91 * nd screenlines of n.
92 * If reallydispl = 0, the actual displaying is not performed,
93 * only the computing associated with it is done.
97 display(n
,nd
,nlines
,reallydispl
)
98 long n
; int nd
; register int nlines
; int reallydispl
; {
100 register struct scr_info
*s
= &scr_info
;
101 register char *p
; /* pointer to line to be displayed */
103 if (startcomm
) { /* No displaying on a command from the
104 * yap command line. In this case, displaying
105 * will be done after executing the command,
114 if (reallydispl
) { /* move cursor to starting point */
116 putline(currentfile
);
130 * Now, do computations and display
137 p
= skiplines(getline(n
,1),nd
);
138 while (nlines
&& p
) {
140 * While there is room,
141 * and there is something left to display ...
145 if (*(p
= do_line(p
,reallydispl
)) == '\0') {
147 * File-line finished, get next one ...
151 s
->tail
= s
->tail
->next
;
158 s
->currentpos
+= nlines
;
160 fillscr(nlines
, "~\r\n");
161 fillscr(maxpagesize
- s
->currentpos
, "\r\n");
164 return compretval(p
);
168 * Scroll forwards n lines.
172 scrollf(n
,reallydispl
) int n
; int reallydispl
; {
174 register struct scr_info
*s
= &scr_info
;
180 * First, find out how many screenlines of the last line were already
181 * on the screen, and possibly above it.
184 if (n
<= 0 || (status
& EOFILE
)) return status
;
185 if (startcomm
) reallydispl
= 0;
187 * Find out where to begin displaying
190 if ((ll
= s
->lastline
) == s
->firstline
) i
+= s
->nf
;
191 p
= skiplines(getline(ll
, 1), i
);
193 * Now, place the cursor at the first free line
195 if (reallydispl
&& !stupid
) {
197 mgoto(s
->currentpos
);
200 * Now display lines, keeping track of which lines are on the screen.
202 while (n
-- > 0) { /* There are still rows to be displayed */
203 if (!*p
) { /* End of line, get next one */
204 if (!(p
= getline(++ll
, 1))) {
206 * No lines left. At end of file
210 s
->tail
= s
->tail
->next
;
214 if (s
->currentpos
>= maxpagesize
) {
216 * No room, delete first screen-line
220 if (--(s
->head
->cnt
) == 0) {
222 * The first file-line on the screen is wiped
223 * out completely; update administration
227 s
->head
= s
->head
->next
;
228 assert(s
->head
->cnt
> 0);
232 p
= do_line(p
, reallydispl
);
234 return compretval(p
);
238 * Scroll back n lines
242 scrollb(n
, reallydispl
) int n
, reallydispl
; {
244 register struct scr_info
*s
= &scr_info
;
245 register char *p
; /* Holds string to be displayed */
248 register long ln
; /* a line number */
249 register int nodispl
;
250 int cannotscroll
; /* stupid or no insert-line */
253 * First, find out where to start
255 if ((count
= n
) <= 0 || (status
& START
)) return status
;
256 if (startcomm
) reallydispl
= 0;
257 cannotscroll
= stupid
|| (!*AL
&& !*SR
);
260 while (count
) { /* While scrolling back ... */
263 * There were screen-lines of s->firstline that were not
265 * We can use them now, but only "count" of them.
267 if (i
> count
) i
= count
;
272 else { /* Get previous line */
273 if (ln
== 1) break; /* isn't there ... */
274 p
= getline(--ln
, 1);
276 * Make it the first line of the screen and compute
277 * how many screenlines it takes. These lines are not
278 * displayed, but nodispl is set to this count, so
279 * that it will be nonzero next time around
282 do { /* Find out how many screenlines */
289 if ((i
= s
->currentpos
) > maxpagesize
) i
= maxpagesize
;
290 if (reallydispl
&& hardcopy
) i
= n
;
292 * Now that we know where to start, we can use "display" to do the
293 * rest of the computing for us, and maybe even the displaying ...
298 reallydispl
&& cannotscroll
);
299 if (cannotscroll
|| !reallydispl
) {
301 * Yes, "display" did the displaying, or we did'nt have to
303 * I like it, but the user obviously does not.
304 * Let him buy another (smarter) terminal ...
309 * Now, all we have to do is the displaying. And we are dealing with
310 * a smart terminal (it can insert lines or scroll back).
314 * Insert lines all at once
316 for (i
= n
; i
; i
--) {
319 * Grumble..., terminal retains lines below, so we have
320 * to clear the lines that we push off the screen
336 p
= skiplines(getline(ln
= s
->firstline
, 1), s
->nf
);
337 for (i
= 0; i
< n
; i
++) {
341 p
= getline(++ln
, 1);
349 * If reallydispl > 0 then display it.
353 do_line(str
, reallydispl
) register char *str
; int reallydispl
; {
356 register char *p
= buf
;
357 register int pos
= COLS
;
360 register int do_ul
= 0, do_hl
= 0;
361 int lastmode
= 0, lasthlmode
= 0;
364 while (*str
&& pos
> 0) {
365 if (*str
< ' ' && (c1
= match(str
,&c2
,sppat
)) > 0) {
367 * We found a string that matches, and thus must be
370 if ((pos
- c2
) <= 0) {
389 if (*str
== '\b' && *(str
+1) != 0
390 && (c
!= '_' || *(str
+2) == '\b')) {
391 while (*str
== '\b' && *(str
+1) != 0) {
399 * Find underline sequences ...
401 if (c
== '_' && *str
== '\b') {
406 if (*str
== '\b' && *(str
+1) == '_') {
411 if (reallydispl
&& do_hl
!= lasthlmode
) {
418 if (reallydispl
&& do_ul
!= lastmode
) {
421 if (do_ul
) underline();
422 else end_underline();
426 if (c
>= ' ' && c
< 0177) {
428 if (reallydispl
&& do_ul
&& *UC
&& pos
> 0) {
430 * Underlining apparently is done one
431 * character at a time.
442 c1
= 8 - ((COLS
- pos
) & 07);
444 * Actually, if COLS is a multiple of 8, this can be
447 * But of course, we don't know that for sure.
449 if (pos
- c1
< 0) break;
454 * Expand tabs. We cannot let the
455 * kernel take care of this
457 * 1. There can be tabs in cursor
458 * addressing strings,
459 * 2. We probably do it better.
474 * Now we have a control character, which takes two positions
485 if (pos
> 0 || (pos
<= 0 && (!AM
|| XN
))) {
489 * The next should be here! I.e. it may not be before printing
490 * the newline. This has to do with XN. We don't know exactly
491 * WHEN the terminal will stop ignoring the newline.
492 * I have for example a terminal (Ampex a230) that will
493 * continue to ignore the newline after a clear to end of line
494 * sequence, but not after an end_underline sequence.
503 scr_info
.currentpos
++;
509 setmark(cnt
) long cnt
; { /* Set a mark on the current page */
510 register struct scr_info
*p
= &scr_info
;
512 p
->savfirst
= p
->firstline
;
518 tomark(cnt
) long cnt
; { /* Go to the mark */
519 register struct scr_info
*p
= &scr_info
;
521 (VOID
) display(p
->savfirst
,p
->savnf
,pagesize
,1);
526 exgmark(cnt
) long cnt
; { /* Exchange mark and current page */
527 register struct scr_info
*p
= &scr_info
;
528 register long svfirst
;
531 svfirst
= p
->firstline
;
534 p
->savfirst
= svfirst
;
539 d_clean() { /* Clean up */
540 register struct scr_info
*p
= &scr_info
;