source: trunk/minix/commands/elle/eedisp.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 50.8 KB
RevLine 
[9]1/* ELLE - Copyright 1982, 1987 by Ken Harrenstien, SRI International
2 * This software is quasi-public; it may be used freely with
3 * like software, but may NOT be sold or made part of licensed
4 * products without permission of the author.
5 */
6/* EEDISP Redisplay and screen image routines
7 */
8
9#if 0
10
11Note that there are several different types of "efficiency" criteria
12involved with respect to display updating:
13 (1) Terminal speed: minimize # characters output.
14 (2) Program speed: minimize CPU time used.
15 (3) Program size: minimize code and memory usage.
16 (4) Program modularity: minimize "hooks" between edit/display rtns.
17The current algorithms necessarily represent a compromise among all of
18these objectives.
19
20 The cursor is always located at CUR_DOT in the buffer CUR_BUF
21of the current window CUR_WIN. This may not be true during function
22execution, but is always true at the top-level loop of command
23execution and redisplay. In order to minimize update overhead, there
24are various flags or variables that the edit functions can use to
25communicate with "redisplay" and tell it how extensive the updates
26really need to be.
27
28 The entire known screen is always represented by a linked list
29of "windows"; updating the entire screen consists of separately
30updating every window on the list. Windows can only be defined
31horizontally (as a range of lines), and must not overlap. Each window
32has a buffer associated with it; the redisplay routines are responsible
33for displaying the contents of this buffer.
34
35 The lowest level data structure for the screen consists of an
36array of SCR_LINE structures, one for each possible physical screen
37line. Each line structure has some flags, and pointers to three different
38representations of what should be on the line:
39 (1) SL_BOFF, SL_LEN - Defines the range of the buffer data which
40 this screen line should represent.
41 If the flag SL_EOL is set, this range ends with (and includes)
42 an EOL character.
43 (2) SL_LINE, SL_COL - Always keeps a copy of the current physical
44 screen line image. Each byte is a character which occupies
45 only one column position on the screen.
46 If the flag SL_CSO is set, the line is in standout mode.
47 (3) SL_NLIN, SL_NCOL - The desired "new" screen line image.
48 This is only valid if the SL_MOD flag is set for the line,
49 indicating that these variables are set and point to the
50 new image of what the screen line should be.
51 If the flag SL_NSO is set, the new line should be in standout
52 mode.
53
54 Lastly there is a variable SL_CONT, which is needed for
55continuation of too-long logical lines over several physical lines. If
56SL_CONT is:
57 0 = logical line fits entirely on the screen.
58 Either SL_EOL is set, or this line is ended by EOF
59 (end of the buffer).
60 1 = logical line is too long, but the last buffer char fits
61 entirely on this physical line. SL_EOL is never set.
62 >1 = logical line is too long, and the last buffer char
63 "overruns" the end of the physical image; that is, part of
64 its representation is at the end of this line, but the
65 rest of it is at the start of the next line. This can
66 only happen with "big" characters like TAB, ^A, ~^A, etc.
67 that need more than one column of representation.
68 There are SL_CONT-1 chars of overrun stored at the
69 end of SL_LINE (SL_NLIN if SL_MOD is set).
70 SL_EOL is never set.
71
72Note that if a line contains any overrun, and the next line is also
73part of the same window, the next line''s screen image will start with
74the SL_CONT-1 chars of overrun, rather than with the representation of
75that line''s first buffer char.
76
77 The "EOL" character on Unix systems is normally the new-line
78character '\n' (ASCII LF). However, on other systems EOL may be
79indicated by a two-character CR-LF sequence, with either CR or LF alone
80considered to be "stray". For this reason, the buffer flag B_EOLCRLF
81exists to control handling and display of EOLs. If the flag is off,
82the EOL mode is LF, and there are no problems of splitting up characters.
83If the flag is on, however, the EOL mode is CRLF and the following rules
84hold:
85 EOL is the sequence CR-LF only.
86 LF without preceding CR is a "stray" LF, displayed as ^J.
87 CR without following LF is a "stray" CR, displayed as ^M.
88 Stray LFs and CRs do not terminate a logical line.
89 "End of Line" as a position is the dot just before the CR of a CR-LF.
90 "Beg of Line" as a position is the dot just after the LF of a CR-LF.
91 If the current dot is between a CR and LF, it is positioned at
92 the beginning of the physical screen line.
93
94
95SL_LINE and SL_COL are always accurate at every stage of processing.
96The other variables are accurate only after fix_wind has been called
97to "fix up" the line structures within a window. If either
98RD_WINRES or RD_TMOD is set, none of these "other variables" should
99be depended on. Any functions which are screen-relative (d_ type)
100must be sure that fix_wind is called if necessary, and must give
101preference to the "new" representation in SL_NLINE and SL_NCOL if
102SL_MOD is set.
103
104The flag RD_UPDWIN will be set by fix_wind if any lines have been
105modified. Because fix_wind does not perform any actual display update,
106it is possible for functions to continue operating on the buffer and
107screen image without requiring that changes be displayed until there is
108nothing else left to do. The routine upd_wind performs the actual
109terminal I/O necessary to update all the screen lines which have SL_MOD
110set. Although the process of updating each line is currently
111non-interruptible, it is possible for upd_wind to interrupt itself
112between line updates if it detects that user input has happened, and it will
113return with the window only partially updated. The screen image state
114will be completely consistent, however, and the RD_UPDWIN flag will
115remain set.
116
117Communication between the editing functions and the redisplay routines
118is limited as much as possible to the flags in the global RD_TYPE.
119Each window has its own copy of these flags in W_REDP, so that if
120windows are changed, the update hints for that window will be
121preserved. The flags that can be set are listed below. Those marked
122with "*" are global in nature; all others apply only within a single
123window (normally the current window).
124
125* RD_SCREEN - Total refresh. Clears entire screen and redisplays all
126 windows.
127* RD_MODE - Mode line has changed, update it.
128* RD_CHKALL - Check ALL windows for any redisplay flags, and perform
129 any updates necessary. Otherwise only the current (or specified)
130 window flags are checked.
131* RD_WINDS - Updates all windows. Like RD_WINRES applied to all windows.
132 RD_WINRES - Update window (assume completely changed).
133 RD_TMOD - Text changed in this window. The range of changes is
134 specified by W_BMOD and W_EMOD in combination with W_OLDZ.
135 Redisplay checking will limit itself to this range.
136 These vars are set by buf_tmod in the main command loop, and
137 reset by fix_wind when the window is fixed up.
138 RD_MOVE - Cursor has moved within current window; may have moved outside
139 the window. W_DOT or CUR_DOT specifies where it should be.
140 RD_ILIN - Hint: Line insert done. Currently no function sets this.
141 RD_DLIN - Hint: Line delete done. Currently no function sets this.
142
143Internal flags:
144 RD_UPDWIN - Window needs updating. Used by fix_wind and upd_wind only.
145 Set when window has been "fixed up" and at least one screen
146 line was modified.
147 RD_FIXWIN - Supposed to mean window needs fixing (via call to fix_wind).
148 Not really used.
149
150Not implemented, may never be, but comments retained:
151 RD_WINCLR - Clear window (not entire screen)
152 RD_NEWWIN - Window has moved. (not needed? Random stuff here)
153 a. to follow cursor; redisplay selects a new TOPLDOT.
154 b. randomly; new TOPLDOT furnished, use unless cursor out (then a).
155 c. find new TOPLDOT as directed (move up/down N screen lines)
156 For now, assume that (c) doesn''t apply (ie C-V uses (b) and sets
157 TOPLDOT itself). So fix_wind selects new one only if cursor
158 won''t fit. topldot takes precedence over sl_boff.
159
160#endif /*COMMENT*/
161
162
163/* Declarations and stuff */
164
165#include "elle.h"
166
167static int sctr();
168
169
170int trm_mode; /* 0 = TTY in normal, non-edit mode.
171 * 1 = TTY in edit mode.
172 * -1 = TTY detached (hung up).
173 * This flag is only used by the 3 routines below,
174 * plus hup_exit.
175 */
176
177/* REDP_INIT() - Called once-only at startup to initialize redisplay
178 * and terminal
179 */
180redp_init ()
181{
182 trm_mode = 0; /* Ensure flag says not in edit mode */
183 ts_init(); /* Get sys term info, set up stuff */
184 if (trm_ospeed == 0) /* Default speed to 9600 if unknown */
185 trm_ospeed = 13;
186 t_init(); /* Identify term type, set term-dep stuff */
187 set_scr(); /* Set up software screen image */
188 set_tty(); /* Enter editing mode! */
189 redp(RD_SCREEN|RD_MODE); /* Force full re-display, new mode line */
190}
191
192/* SET_TTY() - Set up terminal modes for editing */
193
194set_tty()
195{ if(trm_mode) return; /* Ignore if detached or in edit mode */
196 trm_mode++;
197 ts_enter(); /* Set up system's ideas about terminal */
198 t_enter(); /* Set terminal up for editing */
199}
200
201/* CLEAN_EXIT() - Restore original terminal modes.
202 * Returns previous state.
203 */
204clean_exit ()
205{ register int prevstate = trm_mode;
206
207 if(prevstate > 0) /* Ignore unless in editing mode */
208 { trm_mode = 0;
209 t_curpos(scr_ht-1, 0); /* Go to screen bottom */
210 t_exit(); /* Clean up the terminal */
211 tbufls(); /* Force out all buffered output */
212 ts_exit(); /* Restore system's old term state */
213#if ! IMAGEN
214 writez(1,"\n"); /* Get fresh line using OS output */
215#endif /*-IMAGEN*/
216 }
217 return prevstate;
218}
219
220/* SET_SCR() - Allocate screen image, set up screenline pointer table */
221
222set_scr()
223{ register struct scr_line **scrp, *stp;
224 register scrsiz;
225 char *sbuf;
226
227 scr_wd0 = scr_wid - 1;
228 scrsiz = scr_ht*(scr_wid+MAXCHAR);
229 if( scr_ht > MAXHT || scr_wid > MAXLINE)
230 { clean_exit();
231 printf("ELLE: %dx%d screen too big\n",scr_ht,scr_wid);
232 exit(1);
233 }
234 if((stp = (struct scr_line *) calloc(scr_ht*sizeof(struct scr_line)
235 + scrsiz*2,1)) == 0)
236 { clean_exit();
237 printf("ELLE: not enough memory\n");
238 exit(1);
239 }
240 sbuf = (char *)stp + scr_ht*sizeof(struct scr_line);
241 for(scrp = &scr[0]; scrp < &scr[scr_ht]; sbuf += scr_wid+MAXCHAR)
242 { stp->sl_line = sbuf;
243 stp->sl_nlin = sbuf + scrsiz;
244 *scrp++ = stp++;
245 }
246}
247
248
249/* REDISPLAY()
250 * Main function of redisplay routines. Called every time ELLE
251 * forces update of the terminal screen. "rd_type" contains hints
252 * as to what has changed or needs updating, to avoid wasting time
253 * on things which don't need attention.
254 */
255redisplay ()
256{ register struct window *w;
257 register i;
258 struct window *make_mode();
259
260 w = cur_win;
261 w->w_redp |= rd_type&RDS_WINFLGS; /* Set cur_win's flags */
262 rd_type &= ~RDS_WINFLGS; /* Leave only globals */
263
264 if (rd_type & RD_SCREEN) /* Clear and refresh? */
265 {
266 t_clear (); /* Clear the screen */
267 for(i = scr_ht; --i >= 0;) /* Clear screen image */
268 scr[i]->sl_col = 0;
269 if(w != ask_win) /* If not in ask-window */
270 { chg_win(ask_win);
271 e_reset(); /* Then flush its contents */
272 chg_win(w);
273 }
274 redp(RD_WINDS); /* Update all windows */
275 rd_type &= ~RD_SCREEN; /* If redisplay is interrupted, */
276 /* don't do it all over again */
277 }
278 if (rd_type & RD_WINDS) /* Update all windows? */
279 { redp(RD_CHKALL);
280 for (w = win_head; w; w = w -> w_next) /* For each win */
281 w->w_redp |= RD_WINRES;
282 rd_type &= ~RD_WINDS;
283 }
284 if (rd_type & RD_CHKALL) /* Check all windows for changes? */
285 { for (w = win_head; w; w = w->w_next) /* For each win */
286 if(!(w->w_flags&W_MODE)) /* skip mode wins */
287 if(w->w_redp && upd_wind(w))
288 return; /* May be interrupted */
289
290 }
291
292 /* See if ask-window needs updating (to avoid RD_CHKALL in SAY) */
293 if((w = ask_win)->w_redp && upd_wind(w))
294 return; /* May be interrupted */
295
296 /* Check current window for changes */
297 if((w = cur_win)->w_redp && upd_wind(w))
298 return; /* May be interrupted */
299
300 /* Now update mode line(s) if necessary */
301 if(rd_type&RD_MODE)
302 {
303 fupd_wind(w = make_mode(user_win));
304#if FX_2MODEWINDS
305 if (sep_win /* If 2 windows */
306 && (sep_win->w_flags&W_MODE) /* and 2 mode windows */
307 && (sep_win->w_redp || mode_win->w_redp)) /* Check */
308 fupd_wind(make_mode(oth_win)); /* Must update both */
309#endif
310 }
311
312 /* Finally, leave cursor in right place. */
313 if(upd_curs(cur_dot)==0) /* If something screwed up, */
314 errbarf("Cursor out of window"); /* Complain, */
315 /* and leave cursor at bot */
316 rd_type = 0;
317 tbufls(); /* Force out all terminal output */
318}
319
320fupd_wind(w) /* Force window update */
321register struct window *w;
322{
323 w->w_redp |= RD_WINRES;
324 if(fix_wind(w))
325 upd_wind(w);
326}
327
328
329/*
330 * UPD_CURS
331 * Move screen cursor to position of specified dot within current window.
332 * Returns 0 if dot was not within window (and cursor was not moved),
333 * otherwise returns 1 for success.
334 */
335upd_curs(adot)
336chroff adot;
337{ register struct scr_line *s;
338 register int y, x;
339 chroff savdot;
340
341 if((y = d_line(adot)) < 0)
342 return(0); /* Fail, not within window */
343 s = scr[y]; /* Now have line that dot is on */
344
345 /* Get proper offset for any continuation chars from prev line */
346 if(y > cur_win->w_pos)
347 { if((x = scr[y-1]->sl_cont) > 0)
348 x--;
349 }
350 else x = 0;
351
352 savdot = e_dot();
353 e_go(s->sl_boff);
354 if((x = d_ncols((int)(adot - s->sl_boff),x)) < 0)
355 { /* If lost, assume it's because we are just after a char
356 ** which has its representation continued onto next line.
357 ** Move cursor to end of that continuation.
358 ** d_line should have ensured that this is safe, but
359 ** we double-check just to make sure.
360 */
361 if((x = s->sl_cont) > 0) /* Set X to end of cont */
362 --x;
363 /* and on next line down */
364 if(++y >= (cur_win->w_pos + cur_win->w_ht))
365 { e_go(savdot); /* Failed, below window */
366 return(0);
367 }
368 }
369 e_go(savdot);
370 t_move(y, x); /* Move cursor cleverly */
371 return(1); /* Return success! */
372}
373
374/* Return line # for given dot, -1 if out of current window */
375d_line(cdot)
376chroff cdot;
377{ register struct scr_line *s;
378 register struct window *w;
379 register int i;
380 chroff savdot;
381 int bot;
382
383 w = cur_win;
384 i = w->w_pos;
385 bot = i + w->w_ht;
386 for(; i < bot; i++)
387 { s = scr[i];
388 if(cdot <= s->sl_boff)
389 goto gotl;
390 }
391 /* End of window, repeat test specially for last line */
392 savdot = s->sl_boff + (chroff)s->sl_len;
393 if(cdot > savdot) /* If past last char of last line */
394 return(-1); /* then clearly outside */
395 --i; /* Make i match s (bottom line) */
396 if(savdot != cdot) /* If not exactly at end */
397 return(i); /* Then we're inside for sure */
398 goto linbet;
399
400gotl: if(s->sl_boff != cdot) /* Are we on line boundary? */
401 { if(i <= w->w_pos) /* No, off top of window? */
402 return(-1); /* Above top, out for sure */
403 return(--i);
404 }
405
406 /* Here, dot is exactly on line boundary, have to decide which
407 * line it really belongs to.
408 * Get S = pointer to line which cursor is at the end of.
409 */
410 if(i <= w->w_pos) /* Quick chk of trivial case, empty buffer */
411 return(i);
412 s = scr[--i];
413linbet:
414 if((s->sl_flg&SL_EOL) /* If line has LF */
415 || (s->sl_cont > 1)) /* or a continued char */
416 if(++i >= bot) /* Then cursor is on next line */
417 return(-1);
418 return(i);
419}
420
421
422/* D_NCOLS - auxiliary for UPD_CURS. (also called by indtion() in EEFD)
423** We are positioned at a place in the current buffer corresponding to
424** the beginning of the screen line, and given:
425** lcnt - # of chars in buffer to move forward over
426** ccol - current column position
427** Returns the new column position. There are some special cases:
428** Hits EOF: returns normally (new column position)
429** Hits EOL: returns -1
430** Position is past end of screen: returns -1
431** The buffer position has changed, but this is irrelevant as upd_curs
432** restores it just after the call.
433*/
434d_ncols(lcnt, ccol)
435int lcnt;
436int ccol;
437{ register int col, i;
438 register SBBUF *sb;
439 int c;
440 char tmp[MAXCHAR*2]; /* MAXCHAR is enough, but *2 just in case */
441
442 col = ccol;
443 sb = (SBBUF *) cur_buf;
444 if((i = lcnt) > 0)
445 do { if((c = sb_getc(sb)) == EOF)
446 break;
447 /* Check to see if we've run into an EOL */
448#if FX_EOLMODE
449 if(c == CR)
450 { if(eolcrlf(sb))
451 { if((c = sb_getc(sb)) == LF) /* EOL? */
452 /* Real EOL. Fail unless point
453 ** is between CR and LF, in which case
454 ** we return 0 (left margin).
455 */
456 return (i==1 ? 0 : -1);
457 /* Stray CR, back up & fall thru */
458 if(c != EOF)
459 sb_backc(sb);
460 c = CR;
461 }
462 } else if (c == LF)
463 { if(!eolcrlf(sb)) /* Real EOL? */
464 return -1; /* Yes, fail */
465 /* If EOL mode is CRLF then hitting a LF
466 ** can only happen for stray LFs (the
467 ** previous check for CR takes care of
468 ** CRLFs, and we never start scanning
469 ** from the middle of a CRLF.
470 ** Drop thru to show stray LF.
471 */
472 }
473#else
474 if(c == LF)
475 return(-1);
476#endif /*-FX_EOLMODE*/
477 col += sctr(c, tmp, col);
478 } while(--i);
479 if(col > scr_wd0)
480 return(-1);
481 return(col);
482}
483
484/* D_LUPD - called from command level to completely redisplay a
485 * specific line on the screen.
486 */
487d_lupd(w, idx)
488struct window *w; /* Window this line belongs to, if known */
489int idx;
490{ t_curpos(idx, 0);
491 t_docleol(); /* Zap physical screen line */
492 scr[idx]->sl_col = 0; /* Reflect it on phys screen image */
493 if(w) /* Mark window for updating */
494 w->w_redp |= RD_WINRES;
495 else redp(RD_WINDS); /* No window given, assume global */
496 redp(RD_MOVE); /* Cursor has moved */
497}
498
499/* Clear a window completely the "quickest possible way" */
500clear_wind(w)
501register struct window *w;
502{
503 register int i = w->w_pos; /* Top line of window */
504 register int bot = i + w->w_ht; /* Bottom line (plus 1) of window */
505
506 for ( ; i < bot; ++i)
507 d_lupd(w, i); /* Zap that line */
508}
509
510
511/* FIX_WIND - Sets up window screen image. Does not generate any
512 * terminal output, but completely specifies what the new screen
513 * image should look like.
514 * Only the following 4 flags (lumped together in RDS_DOFIX)
515 * provoke fix_wind to do something:
516 * RD_MOVE - cursor has moved, must make sure still within
517 * window, and select new one if not.
518 * RD_TMOD - Text has been changed somewhere.
519 * RD_FIXWIN - Something requested that fix_wind fix things.
520 * Normally this is set when a new w_topldot is set.
521 * RD_WINRES - Window needs to be completely regenerated.
522 * Results:
523 * Verifies that the current dot for the window (w_dot) exists.
524 * If it is past the end of buffer, it is reset to EOB, and if this is
525 * the current window, also updates cur_dot. Otherwise, w_dot is never
526 * adjusted; it is fix_wind's responsibility to make sure that the window
527 * displays w_dot.
528 * Verifies that current w_topldot setting will result in cursor
529 * (specified by w_dot) appearing within window. If not, resets w_topldot
530 * to an appropriate value (1/3 of way down from top, unless
531 * moving up in which case 1/3 of way up from bottom).
532 * Makes sure that sl_boff, sl_len, sl_flg, and sl_cont
533 * are set properly for all lines in window. SL_MOD is set
534 * for any lines requiring screen updates; these lines
535 * also have sl_nlin and sl_ncol properly set.
536 * Note that sl_line and sl_col are NOT updated or changed, because
537 * the physical screen has not been altered!
538 *
539 * Returns 0 if no physical screen updates are needed (other than
540 * cursor moving and mode line updating).
541 * Returns 1 if screen updates are needed; RD_UPDWIN is set in w_redp,
542 * indicating that UPD_WIND should be called.
543 */
544
545fix_wind (win)
546struct window *win;
547{
548 register struct window *w;
549 register int i;
550 register struct scr_line *s;
551 chroff cdot, bdelta, updot, sdot, newz;
552 chroff savdot;
553 struct buffer *savbuf;
554 int bot, nlmod, savi, contf, ocontf, randomflg;
555 int newpct;
556
557 if(!(w = win))
558 return(0);
559 if(!(w->w_redp&RDS_DOFIX)) /* Anything we need to do? */
560 return(0); /* Nope, just ignore */
561
562 /* Find current dot for this window, and set up other stuff */
563 cdot = (w == cur_win) ? cur_dot : w->w_dot;
564 bot = w->w_pos + w->w_ht;
565 savbuf = cur_buf;
566 cur_buf = w->w_buf;
567 savdot = e_dot();
568 nlmod = 0; /* No screen image changes so far */
569
570 /* Dot (ie cursor) is before current top? If so, must move
571 * backwards to find a new topldot. Note also that buffer may have
572 * changed so that either cdot or topldot points past EOF.
573 */
574 if(w->w_topldot > cdot)
575 { /* Yes, must search backwards scrht/3 screen lines */
576 /* from cdot in order to find topldot. */
577 /* Don't bother updating scr stuff beforehand since we'll
578 * have to revise everything anyway and can do it on the fly.
579 */
580 i = (ev_mvpct * w->w_ht) / 100;
581 goto skipdn;
582
583 finddn: i = ((100 - ev_mvpct) * w->w_ht) / 100;
584 skipdn: if(i <= 0) i = 1; /* Ensure # is reasonable */
585 else if(i >= w->w_ht) i = w->w_ht-1;
586 e_go(cdot); /* Start here (may normalize to EOF)*/
587 d_backup(i ? i : 1); /* Try to back up cleverly */
588 w->w_topldot = e_dot();
589 randomflg = 0; /* We have some idea where we are */
590 fixall: /* Entry point for later recheck, with randomflg==1 */
591 newz = e_blen();
592 if(newz < cdot) /* Part of buf may have gone away */
593 { /* So normalize dot to EOF */
594 w->w_dot = cdot = newz;
595 if(w == cur_win) /* Special check for fixing */
596 cur_dot = newz; /* up cur_dot too! */
597 goto finddn; /* and get a new top-of-window loc */
598 }
599 retry: i = w->w_pos;
600 contf = 0;
601 s = 0;
602 for(; i < bot; i++)
603 { nlmod++;
604 fix_line(scr[i], s); /* s = 0 the first time */
605 s = scr[i];
606#if FX_SOWIND
607 if(w->w_flags & W_STANDOUT)
608 s->sl_flg |= SL_NSO;
609 else s->sl_flg &= ~SL_NSO;
610#endif
611 }
612 if(inwinp(w,cdot)) /* Ensure in window */
613 goto mdone;
614 if(randomflg) /* If jumped randomly, */
615 { i = (ev_nwpct * w->w_ht) / 100;
616 goto skipdn; /* Try to select new window */
617 }
618
619 /* We tried to back up and went too far. */
620 if(cdot < w->w_topldot) /* Verify place is ahead */
621 { errbarf("fix_wind failed"); /* Didn't back up?? */
622 goto finddn;
623 }
624 /* Move down one line and try again */
625 if(w->w_ht > 1)
626 w->w_topldot = scr[w->w_pos+1]->sl_boff;
627 else
628 { s = scr[w->w_pos];
629 w->w_topldot = s->sl_boff + s->sl_len;
630 }
631 e_go(w->w_topldot);
632 goto retry;
633 }
634
635 /* At some future point, could separate out processing for
636 * RD_WINRES and RD_FIXWIN. Latter flag implies only w_topldot
637 * has changed (new window selected). Former implies whole
638 * buffer has been munged, and everything is completely redone.
639 */
640 if(w->w_redp&(RD_WINRES|RD_FIXWIN)) /* If re-figuring whole window */
641 { e_go(w->w_topldot); /* Start here, and */
642 randomflg = 1; /* set up flag saying random jump */
643 goto fixall; /* and go crunch all lines. */
644 }
645 if((w->w_redp&RD_TMOD)==0) /* If claims no text mods, */
646 { if(inwinp(w,cdot)==0) /* Just verify cursor loc. */
647 goto finddn; /* Sigh.... */
648 newz = w->w_oldz; /* Win, set up for exit. */
649 goto done;
650 }
651 /* Here only when RD_TMOD is set, indicating changes are
652 * between range variables.
653 */
654 /* Find upper bound of any mods. This is a little gross in the
655 * speed dept and some faster way should perhaps be devised.
656 * In particular the main loop should incrementally keep track of
657 * buffer size, and should set a flag RD_TEXT if anything has
658 * actually been changed. Edit routines should have lots of
659 * flags available to tell main loop more precisely what they did,
660 * so main loop can take care of updating b/emod and stuff.
661 */
662 if((newz = e_blen()) == 0)
663 goto finddn; /* Ensure blank window is cleared */
664 bdelta = newz - w->w_oldz;
665 if((updot = newz) > w->w_emod)
666 updot -= w->w_emod;
667 if(bdelta == 0 && (updot == w->w_bmod))
668 goto inwinq;
669
670 /* Could also check for updot < w_topldot (changes above win)
671 * or sl_boff+sl_len < w_bmod (changes below win) but those
672 * cases are probably pretty rare.
673 */
674 /* First find line where changes start */
675 for(i = w->w_pos; i < bot; i++)
676 { s = scr[i];
677 if(w->w_bmod <= s->sl_boff) /* Changes prior to this? */
678 break;
679 }
680 if(i >= bot) /* Test last line specially */
681 { if(w->w_bmod > (s->sl_boff + (chroff)s->sl_len))
682 goto inwinq; /* Outside window */
683 /* Last line changed, hack it */
684 }
685 if(i > w->w_pos /* If we have a prev line */
686 && (s->sl_len == 0 /* and we're at EOF, */
687 || w->w_bmod != s->sl_boff /* or not at start of line */
688 || scr[i-1]->sl_cont)) /* or prev line is continuation */
689 s = scr[--i]; /* then it's prev line we want */
690
691 /* I has index for screen line changes begin on; S has ptr.
692 * This piece of code handles case where buffer has been modified
693 * starting at BMOD, and BDELTA chars have been inserted/deleted;
694 * range of changes ends at UPDOT.
695 */
696 savi = i;
697 while(++i < bot)
698 scr[i]->sl_boff += bdelta;
699 i = savi;
700
701 /* Now start with 1st changed line and start figuring new line
702 * lengths. Stop when hit end, or past updot and boff is correct
703 * for start of line.
704 */
705 /* can improve this by jumping out when past emod, and testing for
706 * an EOL - then know stuff has to match someplace, so look for that.
707 * could then simply update lengths or something?
708 */
709 if(i > w->w_pos) /* Find # cols already there from prev line*/
710 contf = scr[i-1]->sl_cont;
711 else contf = 0;
712 ocontf = 1; /* Fake it so always update 1st line*/
713 e_go(sdot = s->sl_boff);
714 for(; i < bot; i++)
715 { s = scr[i];
716 if(updot <= sdot /* If past changed stuff */
717 && sdot == s->sl_boff /* and locs are lined up */
718 && contf == 0 /* and previous line clean */
719 && ocontf == 0) /* (both old and new images) */
720 break; /* Then done. */
721 nlmod++;
722 ocontf = s->sl_cont; /* Save old-image contf value */
723 fix_line(s, (i > w->w_pos) ? scr[i-1] : 0);
724#if FX_SOWIND
725 if(w->w_flags & W_STANDOUT)
726 s->sl_flg |= SL_NSO;
727 else s->sl_flg &= ~SL_NSO;
728#endif
729 sdot = e_dot();
730 contf = s->sl_cont; /* Get new-image contf value */
731 }
732 if(inwinp(w,cdot)) /* OK, screen fixed, see if cursor inside */
733 goto mdone;
734 goto finddn;
735
736 /* Test if still in window and dispatch appropriately */
737inwinq: if(inwinp(w,cdot))
738 goto done;
739 else goto finddn;
740
741 /* Come here when done, after mods made to window.
742 * Calculate new %-of-buffer position for window's view, and
743 * see if it's changed from current %.
744 */
745mdone: if(w != cur_win) goto done; /* If not current window, ignore */
746 s = scr[bot-1];
747 if((s->sl_boff + (chroff)s->sl_len) >= newz)
748 if(w->w_topldot) newpct = 150; /* BOT */
749 else newpct = 200; /* ALL */
750 else if(w->w_topldot == 0)
751 newpct = -1; /* TOP */
752 else /* NOTE: This won't work if topldot is huge */
753 newpct = (w->w_topldot*100)/newz; /* nn% */
754 if(newpct != w->w_pct) /* OK, now compare with old % */
755 { w->w_pct = newpct; /* Different, must set and */
756 redp(RD_MODE); /* invoke redisplay of mode line! */
757 }
758
759done: w->w_bmod = -1; /* To indicate vars not set */
760 w->w_oldz = newz;
761 w->w_redp &= ~RDS_DOFIX; /* Clear flags that invoked us */
762 if(nlmod)
763 w->w_redp |= RD_UPDWIN; /* Say stuff to be updated */
764 e_go(savdot);
765 cur_buf = savbuf;
766 return(nlmod);
767}
768
769/* INWINP - Returns true if given dot is inside given window.
770 */
771inwinp(win,cdot)
772struct window *win;
773chroff cdot;
774{ register struct scr_line *s;
775 register struct window *w;
776 chroff sdot;
777
778 w = win;
779 if(cdot < w->w_topldot)
780 return(0);
781 s = scr[(w->w_pos + w->w_ht) - 1];
782 sdot = s->sl_boff + (chroff)s->sl_len;
783 if(cdot < sdot)
784 return(1); /* Yup, inside window. */
785 if(cdot > sdot)
786 return(0);
787
788 /* Dot is exactly at end of window, must check further. */
789 if(s->sl_len /* If line exists, */
790 && ((s->sl_flg&SL_EOL) /* and ends in LF, */
791 || s->sl_cont > 1)) /* or sl_cont > 1, lose. */
792 return(0);
793 return(1); /* Else inside, win. */
794}
795
796
797/*
798 * UPD_WIND
799 * If argument 0, assumes cur_win and DOESN'T interrupt if input
800 * detected.
801 */
802
803upd_wind(win)
804struct window *win;
805{ register int i, n;
806 register struct scr_line *s;
807 struct window *w;
808 int top, bot, dspf, num, isave, noicost, nodcost, iline, dline;
809#if FX_SOWIND
810 int oldso;
811#endif
812#if IMAGEN
813 int origdspf;
814 char redpmsg[128];
815#endif /*IMAGEN*/
816
817 if((w=win)==0)
818 w = cur_win;
819 dspf = w->w_redp; /* Get update flags for window */
820#if IMAGEN
821 origdspf = dspf;
822#endif /*IMAGEN*/
823 if(w == cur_win) /* If updating current window, */
824 dspf |= rd_type; /* merge in global flags */
825 if((dspf &= RDS_WINFLGS) == 0) /* Well, it might happen sometimes */
826 goto zdone;
827 w->w_redp = dspf;
828 if(dspf&(RD_WINRES|RD_TMOD|RD_MOVE|RD_FIXWIN))
829 { fix_wind(w); /* May set some flags, so */
830 dspf = w->w_redp; /* get them back... */
831 }
832 if((dspf&RD_UPDWIN)==0) /* Must ask for update! */
833 goto zdone;
834#if IMAGEN
835 if (dbg_redp)
836 { sprintf(redpmsg,
837 "buffer: %14s, rd_type: %06o, w_redp: %06o, dspf: %06o",
838 w->w_buf->b_name, rd_type, origdspf, dspf);
839 barf2(redpmsg);
840 }
841#endif /*IMAGEN*/
842
843 /* Assume screen structure set up by FIX_WIND, just go
844 * effect change for every line modified.
845 */
846#if FX_SOWIND
847 oldso = t_dostandout((w->w_flags&W_STANDOUT)? 1:0);
848#endif
849 top = w->w_pos;
850 bot = top + w->w_ht;
851 for(i = top; i < bot; ++i)
852 if((s = scr[i])->sl_flg&SL_MOD)
853 { if(win && tinwait()) /* If OK, stop if any chars typed */
854 { tbufls();
855 w->w_redp = dspf;
856#if FX_SOWIND
857 t_dostandout(oldso);
858#endif
859 return(1); /* Return immediately, say int'd */
860 }
861 if(slineq(s,s)) /* Compare old with new */
862 goto ldone; /* Lines equal, no update needed */
863
864#if IMAGEN
865 /* If hint says redo entirely */
866 if (dspf & RD_REDO)
867 { s->sl_flg |= SL_REDO; /* Do "fast update" */
868 goto nodel; /* Just go update line */
869 }
870#endif /*IMAGEN*/
871 if((trm_flags&TF_IDLIN)==0)
872 goto nodel; /* Just go update line */
873
874
875 /* Check for I/D line. If no hints exist, check for both
876 * insert and delete.
877 */
878 if((dspf&(RD_ILIN|RD_DLIN))==0)
879 dspf |= RD_ILIN|RD_DLIN;
880 noicost = 0;
881 nodcost = 0;
882
883 /* Check for insert line. See if the current old screen
884 * line is duplicated among any of the new lines which
885 * follow it. If a match is found, keep looking and add
886 * up the number of characters in the matching lines.
887 */
888 if(dspf&RD_ILIN)
889 {
890 /* See if this old screen line is needed elsewhere */
891 if(s->sl_col == 0) /* Ignore if blank */
892 goto noins;
893
894 for(n = i+1; n < bot; n++)
895 { if((scr[n]->sl_flg&SL_MOD)==0)
896 break;
897 if(slineq(s, scr[n])) /* Old, new */
898 { if(!noicost) iline = n; /* 1st time */
899 noicost += s->sl_col;
900 s++;
901 }
902 else if(noicost) break;
903 }
904 if(!noicost) /* If no match, forget it */
905 goto noins; /* S will not have changed. */
906 s = scr[i]; /* Restore S */
907 n = iline; /* Have matches, get index
908 * of first matching line */
909
910 /* Heuristic to decide whether to perform
911 * insert-line operation. Kind of stupid, but
912 * good enough for now.
913 */
914 num = (n-i)*(tvc_ldn+tvc_lin) + (tvc_li + tvc_ld);
915 if((n-i) >= (scr_ht-(ECHOLINES+3))
916 /* Don't move lines all the
917 * way down full screen! */
918 || num >= noicost) /* Compare cost with estimated
919 * cost of not doing insert.*/
920 goto noins;
921
922 /* Insert lines! */
923 dspf &= ~RD_ILIN;
924 inslin(i, n - i, w);
925 for(; i < n; i++) /* Update intervening lines */
926 upd_line (i);
927 goto ldone;
928 }
929noins:
930
931 /* Check for delete line. See if the new screen line
932 * is duplicated among any of the old lines already on
933 * the screen. If a match is found, keep looking and add
934 * up the number of characters in the matching lines.
935 */
936 if(dspf&RD_DLIN)
937 {
938 /* See if the new line already exists elsewhere */
939 if(s->sl_ncol == 0) /* Ignore blank lines */
940 goto nodel;
941 for (n = i + 1; n < bot; n++)
942 { if((scr[n]->sl_flg&SL_MOD)==0)
943 break;
944 if(slineq(scr[n],s)) /* Old, new */
945 { if(!nodcost) dline = n; /* 1st time */
946 nodcost += s->sl_ncol;
947 s++;
948 }
949 else if(nodcost) break;
950 }
951 if(!nodcost) /* If no match, forget it */
952 goto nodel; /* S will not have changed. */
953 s = scr[i]; /* Restore S */
954 n = dline; /* Index of 1st match */
955
956 /* Heuristic to decide whether to perform
957 * delete-line operation. Same hack as for
958 * insert-line.
959 */
960 num = (n-i)*(tvc_ldn+tvc_lin) + (tvc_li + tvc_ld);
961 if((n-i) >= (scr_ht-(ECHOLINES+3))
962 || num >= nodcost)
963 goto nodel;
964
965 /* Delete lines! */
966 dspf &= ~RD_DLIN;
967 dellin(i, n - i, w);
968 goto ldone;
969 }
970nodel:
971 /* All failed, so just update line */
972 upd_line(i);
973ldone: s->sl_flg &= ~SL_MOD; /* Clear mod flag */
974 }
975done:
976#if FX_SOWIND
977 t_dostandout(oldso); /* Back to previous mode */
978#endif
979zdone: w->w_redp = 0;
980 return(0); /* Say completed */
981}
982
983
984
985/*
986 * SLINEQ - Compare old, new screen image lines. If new line doesn't
987 * have the modified flag set, use its old image.
988 * If the standout mode differs, always fails.
989 */
990
991slineq(olds, news)
992struct scr_line *olds;
993struct scr_line *news;
994{ register char *cpo, *cpn;
995 register int cnt;
996
997 cpo = (char *)news;
998 if(((struct scr_line *)cpo)->sl_flg&SL_MOD)
999 { cnt = ((struct scr_line *)cpo)->sl_ncol;
1000 cpn = ((struct scr_line *)cpo)->sl_nlin;
1001#if FX_SOWIND /* Mode of old must match mode of new */
1002 if(((olds->sl_flg & SL_CSO)==0) !=
1003 ((((struct scr_line *)cpo)->sl_flg & SL_NSO)==0))
1004 return 0;
1005#endif
1006 }
1007 else
1008 { cnt = ((struct scr_line *)cpo)->sl_col;
1009 cpn = ((struct scr_line *)cpo)->sl_line;
1010#if FX_SOWIND /* Modes of current lines must match */
1011 if((olds->sl_flg & SL_CSO) !=
1012 (((struct scr_line *)cpo)->sl_flg & SL_CSO))
1013 return 0;
1014#endif
1015 }
1016
1017 /* Crufty match stuff */
1018 if(cnt != olds->sl_col)
1019 return(0);
1020 if(cnt)
1021 { cpo = olds->sl_line;
1022 do { if(*cpo++ != *cpn++)
1023 return(0);
1024 } while(--cnt);
1025 }
1026 return(1);
1027}
1028
1029
1030/* UPD_LINE(lineno) - Effects the update of a physical screen line,
1031 * assuming that the screen line structure for that line has been
1032 * properly set up by fix_wind. It cannot be interrupted by typein.
1033 * Does a lot of work to check out optimization for char I/D.
1034 * Someday it could also check out the possibility of doing a CLEOL at
1035 * some point to reduce the number of spaces that need to be output.
1036 */
1037
1038upd_line(y)
1039int y;
1040{ register i;
1041 register char *sci, *cp;
1042 struct scr_line *s;
1043
1044 int xpos; /* actual screen position */
1045 int c, c2, p2, cmpcost, delcost;
1046 int savc, ocol, ncol;
1047 char *savcp, *savsci;
1048#if FX_SOWIND
1049 int oldso, newso;
1050 int writall = 0;
1051#endif
1052
1053 s = scr[y];
1054 savsci = sci = s->sl_line; /* What is currently on the screen */
1055#if IMAGEN
1056 if (s->sl_flg & SL_REDO)
1057 { /* Check for line-redo flag */
1058 s->sl_flg &= ~SL_REDO; /* Clear it: we are handling it */
1059 writall = 1; /* Re-do this line completely */
1060 t_move(y, 0);
1061 t_docleol();
1062 s->sl_col = 0;
1063 }
1064#endif /*IMAGEN*/
1065
1066#if FX_SOWIND
1067 /* See whether modes of the lines are the same or not. */
1068 newso = (s->sl_flg & SL_NSO)!=0; /* Get new mode (true if SO)*/
1069 if(((s->sl_flg & SL_CSO)!=0) != newso)
1070 { t_move(y, 0); /* Not same, must zap existing line */
1071 t_docleol();
1072 s->sl_col = 0;
1073 writall = newso; /* Output all if SO is new mode */
1074 }
1075 oldso = t_dostandout(newso); /* Get in right mode */
1076#endif
1077
1078 ocol = s->sl_col;
1079 savcp = cp = s->sl_nlin;
1080 ncol = s->sl_ncol;
1081
1082 /* Find leading equalness */
1083 i = ocol;
1084 if(i > ncol) i = ncol; /* Use minimum count */
1085 if(i)
1086 { do { if(*cp++ != *sci++)
1087 { --cp;
1088 break;
1089 }
1090 } while(--i);
1091 i = cp - savcp;
1092 sci = savsci; /* Restore ptr to beg of cur line */
1093 }
1094
1095 /* From here on, "i" is now the x-coordinate (column addr)
1096 * of the first position that doesn't match. "cp" points to
1097 * the first nonmatching char in the new line image.
1098 */
1099#if COHERENT /* Has direct video interface capability */
1100 if(trm_flags&TF_DIRVID)
1101 { if(ncol < ocol)
1102 { /* Flesh out new line to completely replace old */
1103 fillsp(&s->sl_nlin[ncol], ocol-ncol);
1104 ncol = ocol;
1105 }
1106 /* Spit out changed stuff. t_direct will handle the
1107 * case where i == ncol (ie no changes needed).
1108 */
1109 t_direct(y,i,cp,ncol-i);
1110 goto done;
1111 }
1112#endif /*COHERENT*/
1113
1114 if(i == ncol) /* Matched up to end of new line? */
1115 goto idone; /* Yes, can skip big loop! */
1116
1117#if FX_SOWIND
1118 if(writall) /* If simply writing everything...*/
1119 { t_move(y, 0);
1120 tputn(cp, ncol); /* Output them all */
1121 curs_col = ncol; /* Update cursor position */
1122 goto idone; /* then wrap up! */
1123 }
1124#endif
1125
1126 /* Now must fill out remainder of old line with blanks. */
1127 if(ocol < scr_wid)
1128 {
1129#if FX_SOWIND
1130 if(newso) fillset(&sci[ocol], scr_wid-ocol, 0);
1131 else
1132#endif
1133 fillsp(&sci[ocol],scr_wid-ocol); /* Fill out */
1134 }
1135
1136 /****** Main update loop. ******/
1137 for (; i < ncol; i++)
1138 { c = *cp++; /* Note *CP will point to next */
1139 if(c == sci[i])
1140 continue;
1141 if(i >= ocol) /* Past EOL of old line? */
1142 {
1143putin: sci[i] = c;
1144 if(y != curs_lin || i != curs_col)
1145 t_move(y, i);
1146 tput(c);
1147 curs_col++;
1148 continue;
1149 }
1150
1151 if((trm_flags&TF_IDCHR)==0) /* Replace */
1152 goto putin;
1153
1154 /* Do checking to see whether char I/D operations should
1155 * be invoked. This code is quite CPU intensive and
1156 * can cause noticeable pauses if run on a slow CPU with
1157 * a fast (9600) terminal line. The optimization tradeoff
1158 * seems worthwhile most of the time, however.
1159 */
1160 cmpcost = 0; /* Default is don't compare */
1161 if(ncol == ocol) /* If line lengths same, must chk */
1162 {
1163/* if(ncol >= scr_wid) */ /* If line overrun, compare */
1164 cmpcost++;
1165 }
1166#if 0
1167If ncol == ocol, have problem with tabs:
1168 If don''t use I/D char, but tabs exist, lots of wasteful update.
1169 If DO use I/D char, and no tabs exist, potential for mistakenly
1170 using I/D when didn''t have to. Not too bad, though?
1171 If DO use I/D char, then mild screw when inserting/deleting
1172 just before a tab, since could have just overwritten,
1173 but I/D insists on jerking things around.
1174 Insert test:
1175 If old char was space, replace? Problem: will cause cursor
1176 jump if really should have shifted a long run of spaces.
1177 But that is probably okay.
1178 Delete test:
1179 If new char is space, replace? again, will cause cursor jump
1180 with long run of spaces.
1181#endif /*COMMENT*/
1182
1183 if(ncol < ocol || cmpcost) /* Try delete-char */
1184 {
1185 /* Search old for match of c and nextc */
1186dodel: savc = c;
1187 if(i >= ncol-1)
1188 goto putin;
1189 c2 = *cp;
1190 if(c == SP && ncol == ocol)
1191 goto tryins;
1192 p2 = i;
1193 for(;;)
1194 { if(c == sci[i] && c2 == sci[i+1])
1195 break;
1196 if(++i < ocol)
1197 continue;
1198 i = p2;
1199 if(cmpcost) {cmpcost = 0; goto tryins;}
1200 goto putin;
1201 }
1202 /* Find # chars that match (i.e. will be saved) */
1203 for(c=1; (i+c < ncol) && (sci[i+c] == cp[c-1]); c++);
1204 delcost = tvc_cd + tvc_cdn*(i - p2);
1205 if(delcost >= c)
1206 { c = savc;
1207 i = p2;
1208 if(cmpcost) { cmpcost = 0; goto tryins;}
1209 goto putin; /* Punt */
1210 }
1211 if(cmpcost)
1212 { c = savc; i = p2;
1213 goto tryins;
1214 }
1215 t_move(y, p2);
1216 c = i - p2; /* Find # chars to flush */
1217 strncpy(&sci[p2],&sci[i], ocol-i);
1218 ocol -= c;
1219 fillsp(&sci[ocol], c);
1220 i = p2; /* Restore i */
1221 t_delchr(c); /* Flush this many cols */
1222 continue;
1223 }
1224
1225 /* Try ins-char */
1226 /* Search new for match of i and i+1 */
1227 /* Note this cannot be used while in standout mode, since
1228 ** the new spaces created will probably be in the wrong mode.
1229 */
1230tryins:
1231#if FX_SOWIND
1232 if(newso) goto putin;
1233#endif
1234 if(i+1 >= ocol)
1235 goto putin;
1236
1237 savc = c;
1238 savcp = cp;
1239 c2 = sci[i+1];
1240 if(sci[i] == SP && ncol == ocol)
1241 goto putin;
1242 xpos = i; /* save current col */
1243 i++;
1244 for(;;)
1245 { if(i >= ncol) goto puntx;
1246 c = *cp++;
1247inlp2: if(c != sci[xpos])
1248 { if(i > scr_wid) goto puntx;
1249 i++;
1250 continue;
1251 }
1252 if(i >= ncol) goto puntx;
1253 c = *cp++;
1254 if(c != c2)
1255 { i++; /* Allow for previous c */
1256 goto inlp2; /* which is always 1 */
1257 }
1258 break;
1259 }
1260 if(i >= scr_wid) goto puntx;
1261
1262 /* Find how many chars match (i.e. will be saved) */
1263 for(c = 2; xpos+c < ncol && sci[xpos+c] == *cp++; c++);
1264 if((p2 = tvc_ci + tvc_cin*(i - xpos)) >= c)
1265 goto puntx; /* Not worth it... */
1266 if(cmpcost && p2 >= delcost)
1267 goto puntx; /* Do delchr instead */
1268
1269 /* We've decided to insert some chars! */
1270 i -= xpos; /* Get # char positions to insert */
1271 cp = savcp; /* Get ptr to newline string */
1272 --cp; /* Point at 1st char to insert */
1273 /* Make room in scr array */
1274 inspc(&sci[xpos],
1275 &sci[(ocol+i >= scr_wid) ? scr_wid-i : ocol], i);
1276 ocol += i; /* Update size of old line */
1277 strncpy(&sci[xpos], cp, i); /* Copy all inserted chars */
1278
1279 t_move(y, xpos); /* Now ensure in right place */
1280 t_inschr(i, cp); /* and insert string onto screen! */
1281
1282 cp += i; /* Update source ptr */
1283 cp++; /* Point to next char */
1284 i += xpos;
1285 continue; /* Now continue loop! */
1286
1287 puntx: i = xpos;
1288 c = savc;
1289 cp = savcp;
1290 if(cmpcost) { cmpcost = 0; goto dodel;}
1291 goto putin;
1292 }
1293
1294 /* All done putting up new stuff. Now see if any remaining old
1295 ** stuff needs to be cleared from end of line.
1296 */
1297idone: if(i < ocol) /* if still have text to right, */
1298 { t_move(y,i); /* move there */
1299 t_docleol(); /* and clear old stuff. */
1300 }
1301
1302done: s->sl_line = s->sl_nlin; /* Replace old image by new */
1303 s->sl_col = s->sl_ncol;
1304 s->sl_nlin = sci;
1305 s->sl_flg &= ~SL_MOD;
1306#if FX_SOWIND /* Copy standout mode to current */
1307 if(newso) s->sl_flg |= SL_CSO;
1308 else s->sl_flg &= ~SL_CSO;
1309#endif
1310}
1311
1312#if FX_SOWIND
1313fillset(str,cnt,c)
1314char *str;
1315int cnt;
1316int c;
1317{ register int n;
1318 register char *cp;
1319 if((n = cnt) <= 0) return;
1320 cp = str;
1321 do{ *cp++ = c;
1322 } while(--n);
1323}
1324#endif
1325
1326fillsp(str,cnt)
1327char *str;
1328int cnt;
1329{ register int n;
1330 register char *cp;
1331 if((n = cnt) <= 0) return;
1332 cp = str;
1333 do{ *cp++ = SP;
1334 } while(--n);
1335}
1336inspc(cp0, cpl, cnt)
1337char *cp0, *cpl;
1338int cnt;
1339{ register char *cp, *cp2;
1340 register n;
1341 if((n = cnt) <= 0) return;
1342 cp = cpl; /* ptr to last+1 char in string */
1343 cp2 = cp+n; /* ptr to loc+1 to move to */
1344 n = cp - cp0; /* # chars to move */
1345 do *--cp2 = *--cp;
1346 while(--n);
1347 n = cnt; /* Now fill gap with spaces */
1348 do *cp++ = SP;
1349 while(--n);
1350}
1351
1352
1353/* FIX_LINE - Fixes up new screen image for a single line. Does not
1354 * do any actual terminal I/O, and does not change the old screen
1355 * image. Assumes that previous line (if any is furnished) has
1356 * already been properly set up.
1357 */
1358
1359int sctreol = 0; /* Ugly crock for talking to sctrin() */
1360 /* 0 = no EOL seen, 1 = EOL seen, -1 = EOF seen */
1361fix_line(slp, olds)
1362struct scr_line *slp;
1363struct scr_line *olds;
1364{ register struct scr_line *s;
1365 register int col, scrw;
1366 char *cp;
1367 int ch;
1368
1369 col = 0;
1370 scrw = scr_wid;
1371 cp = slp->sl_nlin;
1372 if((s = olds) && (col = s->sl_cont))
1373 { if(--col)
1374 strncpy(cp, (s->sl_flg&SL_MOD) ?
1375 &s->sl_nlin[scrw]
1376 : &s->sl_line[scrw], col);
1377 cp += col;
1378 }
1379 scrw--; /* Note now using scr_wd0 !! */
1380 s = slp;
1381 s->sl_boff = e_dot();
1382 col = sctrin(cp, scrw, col);
1383 if (col < scrw || sctreol) /* Does line need continuation mark? */
1384 s->sl_cont = 0; /* No, say no cont chars */
1385 else {
1386 /* Yes, find # cols of overflow. If not 0, must be > 0 */
1387 /* and char is a biggie. Make room for continuation chars */
1388 if(col -= scrw)
1389 inspc(&s->sl_nlin[scrw],&s->sl_nlin[scrw+col], 1);
1390 s->sl_cont = col+1; /* # cont chars, plus 1 */
1391 s->sl_nlin[scrw] = CI_CLINE; /* Display "contin" mark */
1392 col = scrw+1;
1393 }
1394
1395 s->sl_ncol = col;
1396 s->sl_len = e_dot() - s->sl_boff;
1397 s->sl_flg |= (SL_MOD|SL_EOL); /* Say new, and assume line has EOL */
1398 if(sctreol <= 0) /* unless it doesn't really */
1399 s->sl_flg &= ~SL_EOL; /* in which case turn off flag */
1400 return;
1401}
1402
1403/* SCTRIN - auxiliary for FIX_LINE.
1404 * lim - # cols chars are allowed to use
1405 * ccol - current column (0 = bol)
1406 * Returns when see EOL or EOF, or
1407 * when all columns have been filled up. Retval-ccol = # overflow.
1408 * Note that any overflow is indivisible (i.e. a char with a
1409 * multi-col representation is responsible for the overflow).
1410 * So, overflow = 0 means next char would be in 1st non-ex column
1411 * and overflow > 0 means last char read has extra columns, but
1412 * it did start within bounds.
1413 */
1414sctrin(to, lim, ccol)
1415char *to;
1416int lim;
1417int ccol;
1418{ register SBBUF *sb;
1419 register col, cnt;
1420
1421 sb = (SBBUF *) cur_buf;
1422 col = ccol;
1423 sctreol = 0; /* No EOL or EOF seen */
1424 do
1425 { cnt = sb_getc(sb);
1426 if(cnt == EOF)
1427 { --sctreol; /* Say EOF seen! */
1428 return(col);
1429 }
1430#if FX_EOLMODE
1431 if(cnt == CR) /* Possible EOL? */
1432 { if(eolcrlf(sb))
1433 { if((cnt = sb_getc(sb)) == LF) /* Real EOL? */
1434 { sctreol++;
1435 return col; /* Yes, return */
1436 }
1437 /* Stray CR, back up & fall thru */
1438 if(cnt != EOF)
1439 sb_backc(sb);
1440 cnt = CR; /* Show stray CR */
1441 }
1442 } else if (cnt == LF)
1443 { if(!eolcrlf(sb)) /* Real EOL? */
1444 { sctreol++;
1445 return col; /* Yes, return */
1446 }
1447 /* If EOL mode is CRLF then hitting a LF
1448 ** can only happen for stray LFs (the
1449 ** previous check for CR takes care of
1450 ** CRLFs, and we never start scanning
1451 ** from the middle of a CRLF.
1452 ** Drop thru to show stray LF.
1453 */
1454 }
1455#else
1456 if(cnt == LF)
1457 { sctreol++; /* Say EOL seen */
1458 return col;
1459 }
1460#endif /*_FX_EOLMODE*/
1461 cnt = sctr(cnt, to, col);
1462 to += cnt;
1463 col += cnt;
1464 } while(col < lim);
1465
1466 /* If we're stopping because last char put us precisely at the
1467 ** end of the line, make a further check to see whether an EOL
1468 ** is next. If so, we can include that in the line since it
1469 ** doesn't need any more columns for representation!
1470 */
1471 if (col == lim) /* If stopping exactly at edge of screen */
1472 switch (sb_getc(sb)) /* Check out next char */
1473 { case EOF:
1474 --sctreol; /* Yes, note EOF seen */
1475 break; /* and can return immed */
1476#if FX_EOLMODE
1477 case CR: /* Possible EOL? */
1478 if(eolcrlf(sb))
1479 { if((cnt = sb_getc(sb)) == LF) /* Real EOL? */
1480 { sctreol++; /* Yes, set flag */
1481 break; /* and return */
1482 }
1483 /* Stray CR, back up & fall thru */
1484 if(cnt != EOF) /* Back up char that */
1485 sb_backc(sb); /* came after the CR */
1486 sb_rgetc(sb); /* Then back over CR */
1487 break;
1488 }
1489 sb_backc(sb);
1490 break;
1491 case LF:
1492 if(!eolcrlf(sb)) /* Real EOL? */
1493 { sctreol++; /* Yes, set flag */
1494 break; /* and return */
1495 }
1496 /* If EOL mode is CRLF then hitting a LF
1497 ** can only happen for stray LFs (the
1498 ** previous check for CR takes care of
1499 ** CRLFs, and we never start scanning
1500 ** from the middle of a CRLF.
1501 ** Drop thru into default to back up over LF.
1502 */
1503#else
1504 case LF:
1505 sctreol++; /* Say EOL seen */
1506 break; /* and return */
1507#endif /*-FX_EOLMODE*/
1508 default:
1509 sb_backc(sb); /* Back up over random char */
1510 break;
1511 }
1512 return(col);
1513}
1514
1515
1516/* SCTR - Screen Char TRanslation routine.
1517** This routine is completely responsible for the way a buffer char is
1518** displayed on the screen. Given a char and the current column position,
1519** it stores the representation using the given pointer and returns
1520** the number of chars (columns) used by the representation.
1521** Normal printing chars (plus space) are simply themselves.
1522** TAB is a variable number of spaces depending on the column pos.
1523** (we use standard tabstops of 8)
1524** All control chars are uparrow followed by a printing char.
1525** e.g. ctrl-A = ^A
1526** This includes ESC which is ^[.
1527** DEL is shown as ^?.
1528** Chars with the 8th bit set have the prefix CI_META (currently ~) and
1529** the rest of the representation is as above (except for TAB).
1530** Chars with the 9th bit set have the prefix CI_TOP (currently |) and
1531** the rest of the representation is as above (except for TAB).
1532** This only exists for systems with 9-bit chars such as TOPS-20.
1533*/
1534
1535static int
1536sctr(ch, to, ccol)
1537int ch; /* Buffer char to translate */
1538char *to; /* Place to deposit translation in */
1539int ccol; /* Current column position */
1540{ register char *cp;
1541 register c, n;
1542
1543 c = ch;
1544 if(037 < c && c < 0177) /* Most common case */
1545 { *to = c;
1546 return(1);
1547 }
1548 cp = to;
1549 if(c == TAB) /* Next most common case */
1550 { n = 010 - (ccol&07); /* Tab stops are every 8 cols */
1551 ccol = n; /* Save value */
1552 do *cp++ = SP;
1553 while (--n);
1554 return(ccol);
1555 }
1556 ccol = 1; /* Re-use var */
1557#if TOPS20
1558 if(c&0400) /* 9th bit set? */
1559 { *cp++ = CI_TOP;
1560 ccol++;
1561 }
1562#endif /*TOPS20*/
1563 if(c&0200)
1564 { *cp++ = CI_META;
1565 ccol++;
1566 }
1567 if((c &= 0177) <= 037 || c == 0177)
1568 { *cp++ = CI_CNTRL;
1569 c ^= 0100; /* Transform cntrl char */
1570 ccol++;
1571 }
1572 *cp = c;
1573 return(ccol);
1574}
1575
1576
1577/* INSLIN(line, N, wind) - Insert lines
1578 * DELLIN(line, N, wind) - Delete lines
1579 * Both routines insert/delete N lines at "line" in window "wind"
1580 * and update the screen image accordingly.
1581 */
1582
1583inslin (line, n, win)
1584int line; /* line number to insert BEFORE */
1585int n; /* number of lines to insert */
1586struct window *win; /* window we are in */
1587{ register int i;
1588 register int bot;
1589 register char **savp;
1590 char *savscr[MAXHT];
1591
1592 bot = win -> w_ht + win -> w_pos;
1593 t_curpos (line, 0);
1594 t_inslin (n, bot); /* do the insertion on the screen */
1595 savp = &savscr[0];
1596 for (i = 1; i <= n; i++) /* free lines that fall off-screen */
1597 *savp++ = scr[bot - i]->sl_line;
1598
1599 for (i = bot - 1; i >= line + n; i--) /* move down lines */
1600 { scr[i]->sl_line = scr[i - n]->sl_line; /* below the insertion */
1601 scr[i]->sl_col = scr[i - n]->sl_col;
1602 }
1603 savp = &savscr[0];
1604 for (i = line + n - 1; i >= line; i--)
1605 /* blank lines where inserted */
1606 { scr[i]->sl_line = *savp++;
1607 scr[i]->sl_col = 0;
1608 }
1609 for(i = line; i < bot; ++i)
1610 scr[i]->sl_flg |= SL_MOD;
1611}
1612
1613dellin (line, n, win)
1614int line; /* first line to be deleted */
1615int n; /* number of lines to be deleted */
1616struct window *win; /* window we are in */
1617{ register int i;
1618 register int bot;
1619 register char **savp;
1620 char *savscr[MAXHT];
1621
1622 bot = win -> w_ht + win -> w_pos;
1623
1624 t_curpos (line, 0);
1625 t_dellin (n, bot); /* do the deletion on the screen */
1626 savp = &savscr[0];
1627 for (i = line; i < line + n; i++) /* free the deleted lines */
1628 *savp++ = scr[i]->sl_line;
1629 for (i = line; i < bot - n; i++) /* move lines up to fill */
1630 { scr[i]->sl_line = scr[i + n]->sl_line; /* deleted spaces */
1631 scr[i]->sl_col = scr[i + n]->sl_col;
1632 }
1633
1634 savp = &savscr[0];
1635 for (i = bot - n; i < bot; i++) /* blank lines at bottom */
1636 { scr[i]->sl_line = *savp++;
1637 scr[i]->sl_col = 0;
1638 }
1639 for(i = line; i < bot; ++i)
1640 scr[i]->sl_flg |= SL_MOD;
1641}
1642
1643
1644/* T_ Terminal functions - these are similar to the terminal-dependent
1645 * routines in EETERM (which they call) but rely on some knowledge of
1646 * the screen image in order to do their job cleverly.
1647 */
1648
1649#if FX_SOWIND
1650
1651/* T_DOSTANDOUT(on) - Turn standout mode on or off, cleverly.
1652** Returns previous state.
1653*/
1654static int curso = 0; /* Current state (initially off) */
1655int
1656t_dostandout(on)
1657int on;
1658{
1659 int oldso;
1660
1661 if ((oldso = curso) != on) /* If desired state doesn't match, */
1662 { t_standout(on); /* invoke new state. */
1663 curso = on;
1664 }
1665 return oldso;
1666}
1667#endif
1668
1669
1670t_move(y,x)
1671register int y,x;
1672{ register int d;
1673
1674 if(y != curs_lin) /* No vertical smarts yet */
1675 { t_curpos(y, x);
1676 return;
1677 }
1678 if((d = (x - curs_col)) >= 0) /* Find diff in column position */
1679 { if(d == 0) return; /* If none, nothing to do! */
1680
1681 /* Moving right. If distance is less than abs-move cost,
1682 * do clever right-move by copying screen image */
1683 if(d < tvc_pos)
1684#if FX_SOWIND /* Ensure not in standout mode */
1685 if((scr[y]->sl_flg&(SL_CSO|SL_NSO))==0)
1686#endif
1687 {
1688 tputn(&scr[y]->sl_line[curs_col], d);
1689 curs_col = x;
1690 return;
1691 }
1692 }
1693 /* Moving to left, try to do clever left-move by backspacing
1694 * instead of using abs move.
1695 */
1696 else if((d = -d)*tvc_bs < tvc_pos)
1697 { do { t_backspace();
1698 } while(--d);
1699 return;
1700 }
1701 /* No luck with cleverness, just move. */
1702 t_curpos(y, x);
1703}
1704
1705t_docleol()
1706{ register struct scr_line *s;
1707 register int cnt, ocol;
1708
1709 if(trm_flags&TF_CLEOL) t_cleol(); /* Winning */
1710 else /* Losing */
1711 { s = scr[curs_lin];
1712 if((cnt = s->sl_col - curs_col) > 0)
1713 {
1714#if FX_SOWIND
1715 int oldso = t_dostandout(0);
1716#endif
1717 ocol = curs_col;
1718 do { tput(SP); curs_col++;
1719 } while(--cnt);
1720#if FX_SOWIND
1721 t_dostandout(oldso);
1722#endif
1723 t_move(curs_lin, ocol);
1724 }
1725 }
1726}
1727
Note: See TracBrowser for help on using the repository browser.