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 |
|
---|
11 | Note that there are several different types of "efficiency" criteria
|
---|
12 | involved 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.
|
---|
17 | The current algorithms necessarily represent a compromise among all of
|
---|
18 | these objectives.
|
---|
19 |
|
---|
20 | The cursor is always located at CUR_DOT in the buffer CUR_BUF
|
---|
21 | of the current window CUR_WIN. This may not be true during function
|
---|
22 | execution, but is always true at the top-level loop of command
|
---|
23 | execution and redisplay. In order to minimize update overhead, there
|
---|
24 | are various flags or variables that the edit functions can use to
|
---|
25 | communicate with "redisplay" and tell it how extensive the updates
|
---|
26 | really need to be.
|
---|
27 |
|
---|
28 | The entire known screen is always represented by a linked list
|
---|
29 | of "windows"; updating the entire screen consists of separately
|
---|
30 | updating every window on the list. Windows can only be defined
|
---|
31 | horizontally (as a range of lines), and must not overlap. Each window
|
---|
32 | has a buffer associated with it; the redisplay routines are responsible
|
---|
33 | for displaying the contents of this buffer.
|
---|
34 |
|
---|
35 | The lowest level data structure for the screen consists of an
|
---|
36 | array of SCR_LINE structures, one for each possible physical screen
|
---|
37 | line. Each line structure has some flags, and pointers to three different
|
---|
38 | representations 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
|
---|
55 | continuation of too-long logical lines over several physical lines. If
|
---|
56 | SL_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 |
|
---|
72 | Note that if a line contains any overrun, and the next line is also
|
---|
73 | part of the same window, the next line''s screen image will start with
|
---|
74 | the SL_CONT-1 chars of overrun, rather than with the representation of
|
---|
75 | that line''s first buffer char.
|
---|
76 |
|
---|
77 | The "EOL" character on Unix systems is normally the new-line
|
---|
78 | character '\n' (ASCII LF). However, on other systems EOL may be
|
---|
79 | indicated by a two-character CR-LF sequence, with either CR or LF alone
|
---|
80 | considered to be "stray". For this reason, the buffer flag B_EOLCRLF
|
---|
81 | exists to control handling and display of EOLs. If the flag is off,
|
---|
82 | the EOL mode is LF, and there are no problems of splitting up characters.
|
---|
83 | If the flag is on, however, the EOL mode is CRLF and the following rules
|
---|
84 | hold:
|
---|
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 |
|
---|
95 | SL_LINE and SL_COL are always accurate at every stage of processing.
|
---|
96 | The other variables are accurate only after fix_wind has been called
|
---|
97 | to "fix up" the line structures within a window. If either
|
---|
98 | RD_WINRES or RD_TMOD is set, none of these "other variables" should
|
---|
99 | be depended on. Any functions which are screen-relative (d_ type)
|
---|
100 | must be sure that fix_wind is called if necessary, and must give
|
---|
101 | preference to the "new" representation in SL_NLINE and SL_NCOL if
|
---|
102 | SL_MOD is set.
|
---|
103 |
|
---|
104 | The flag RD_UPDWIN will be set by fix_wind if any lines have been
|
---|
105 | modified. Because fix_wind does not perform any actual display update,
|
---|
106 | it is possible for functions to continue operating on the buffer and
|
---|
107 | screen image without requiring that changes be displayed until there is
|
---|
108 | nothing else left to do. The routine upd_wind performs the actual
|
---|
109 | terminal I/O necessary to update all the screen lines which have SL_MOD
|
---|
110 | set. Although the process of updating each line is currently
|
---|
111 | non-interruptible, it is possible for upd_wind to interrupt itself
|
---|
112 | between line updates if it detects that user input has happened, and it will
|
---|
113 | return with the window only partially updated. The screen image state
|
---|
114 | will be completely consistent, however, and the RD_UPDWIN flag will
|
---|
115 | remain set.
|
---|
116 |
|
---|
117 | Communication between the editing functions and the redisplay routines
|
---|
118 | is limited as much as possible to the flags in the global RD_TYPE.
|
---|
119 | Each window has its own copy of these flags in W_REDP, so that if
|
---|
120 | windows are changed, the update hints for that window will be
|
---|
121 | preserved. The flags that can be set are listed below. Those marked
|
---|
122 | with "*" are global in nature; all others apply only within a single
|
---|
123 | window (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 |
|
---|
143 | Internal 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 |
|
---|
150 | Not 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 |
|
---|
167 | static int sctr();
|
---|
168 | |
---|
169 |
|
---|
170 | int 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 | */
|
---|
180 | redp_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 |
|
---|
194 | set_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 | */
|
---|
204 | clean_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 |
|
---|
222 | set_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 | */
|
---|
255 | redisplay ()
|
---|
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 |
|
---|
320 | fupd_wind(w) /* Force window update */
|
---|
321 | register 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 | */
|
---|
335 | upd_curs(adot)
|
---|
336 | chroff 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 */
|
---|
375 | d_line(cdot)
|
---|
376 | chroff 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 |
|
---|
400 | gotl: 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];
|
---|
413 | linbet:
|
---|
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 | */
|
---|
434 | d_ncols(lcnt, ccol)
|
---|
435 | int lcnt;
|
---|
436 | int 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 | */
|
---|
487 | d_lupd(w, idx)
|
---|
488 | struct window *w; /* Window this line belongs to, if known */
|
---|
489 | int 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" */
|
---|
500 | clear_wind(w)
|
---|
501 | register 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 |
|
---|
545 | fix_wind (win)
|
---|
546 | struct 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 */
|
---|
737 | inwinq: 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 | */
|
---|
745 | mdone: 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 |
|
---|
759 | done: 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 | */
|
---|
771 | inwinp(win,cdot)
|
---|
772 | struct window *win;
|
---|
773 | chroff 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 |
|
---|
803 | upd_wind(win)
|
---|
804 | struct 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 | }
|
---|
929 | noins:
|
---|
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 | }
|
---|
970 | nodel:
|
---|
971 | /* All failed, so just update line */
|
---|
972 | upd_line(i);
|
---|
973 | ldone: s->sl_flg &= ~SL_MOD; /* Clear mod flag */
|
---|
974 | }
|
---|
975 | done:
|
---|
976 | #if FX_SOWIND
|
---|
977 | t_dostandout(oldso); /* Back to previous mode */
|
---|
978 | #endif
|
---|
979 | zdone: 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 |
|
---|
991 | slineq(olds, news)
|
---|
992 | struct scr_line *olds;
|
---|
993 | struct 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 |
|
---|
1038 | upd_line(y)
|
---|
1039 | int 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 | {
|
---|
1143 | putin: 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
|
---|
1167 | If 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 */
|
---|
1186 | dodel: 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 | */
|
---|
1230 | tryins:
|
---|
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++;
|
---|
1247 | inlp2: 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 | */
|
---|
1297 | idone: 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 |
|
---|
1302 | done: 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
|
---|
1313 | fillset(str,cnt,c)
|
---|
1314 | char *str;
|
---|
1315 | int cnt;
|
---|
1316 | int 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 |
|
---|
1326 | fillsp(str,cnt)
|
---|
1327 | char *str;
|
---|
1328 | int 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 | }
|
---|
1336 | inspc(cp0, cpl, cnt)
|
---|
1337 | char *cp0, *cpl;
|
---|
1338 | int 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 |
|
---|
1359 | int sctreol = 0; /* Ugly crock for talking to sctrin() */
|
---|
1360 | /* 0 = no EOL seen, 1 = EOL seen, -1 = EOF seen */
|
---|
1361 | fix_line(slp, olds)
|
---|
1362 | struct scr_line *slp;
|
---|
1363 | struct 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 | */
|
---|
1414 | sctrin(to, lim, ccol)
|
---|
1415 | char *to;
|
---|
1416 | int lim;
|
---|
1417 | int 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 |
|
---|
1535 | static int
|
---|
1536 | sctr(ch, to, ccol)
|
---|
1537 | int ch; /* Buffer char to translate */
|
---|
1538 | char *to; /* Place to deposit translation in */
|
---|
1539 | int 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 |
|
---|
1583 | inslin (line, n, win)
|
---|
1584 | int line; /* line number to insert BEFORE */
|
---|
1585 | int n; /* number of lines to insert */
|
---|
1586 | struct 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 |
|
---|
1613 | dellin (line, n, win)
|
---|
1614 | int line; /* first line to be deleted */
|
---|
1615 | int n; /* number of lines to be deleted */
|
---|
1616 | struct 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 | */
|
---|
1654 | static int curso = 0; /* Current state (initially off) */
|
---|
1655 | int
|
---|
1656 | t_dostandout(on)
|
---|
1657 | int 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 |
|
---|
1670 | t_move(y,x)
|
---|
1671 | register 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 |
|
---|
1705 | t_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 |
|
---|