[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 |
|
---|
| 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 |
|
---|