home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / xvi / part06 < prev    next >
Encoding:
Text File  |  1992-10-22  |  55.9 KB  |  2,446 lines

  1. Newsgroups: comp.sources.misc
  2. From: jmd@cyclone.bt.co.uk (John Downey)
  3. Subject:  v33i015:  xvi - portable multi-window vi-like editor, Part06/18
  4. Message-ID: <1992Oct23.181305.238@sparky.imd.sterling.com>
  5. X-Md4-Signature: 43bffc1302d05b2deead1f2dd5c9cda1
  6. Date: Fri, 23 Oct 1992 18:13:05 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jmd@cyclone.bt.co.uk (John Downey)
  10. Posting-number: Volume 33, Issue 15
  11. Archive-name: xvi/part06
  12. Environment: Unix, MS-DOS, OS/2, QNX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  xvi/src/ibmpc_a.asm xvi/src/screen.c
  19. # Wrapped by kent@sparky on Thu Oct 22 09:03:42 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 6 (of 18)."'
  23. if test -f 'xvi/src/ibmpc_a.asm' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'xvi/src/ibmpc_a.asm'\"
  25. else
  26.   echo shar: Extracting \"'xvi/src/ibmpc_a.asm'\" \(19731 characters\)
  27.   sed "s/^X//" >'xvi/src/ibmpc_a.asm' <<'END_OF_FILE'
  28. X; Copyright (c) 1990,1991,1992 Chris and John Downey
  29. X_TEXT    segment word public 'CODE'
  30. X    db    "@(#)ibmpc_a.asm    2.1 (Chris & John Downey) 7/29/92"
  31. X    db    0
  32. X_TEXT    ends
  33. X
  34. X;***
  35. X;
  36. X; program name:
  37. X;    xvi
  38. X; function:
  39. X;    PD version of UNIX "vi" editor, with extensions.
  40. X; module name:
  41. X;    ibmpc_a.asm
  42. X; module function:
  43. X;    Assembly language part of terminal interface module for IBM PC
  44. X;    compatibles running MS-DOS.
  45. X;
  46. X;    This code has been assembled with Microsoft's Macro Assembler
  47. X;    (MASM) version 5.1, & is compatible with code generated by
  48. X;    MS-DOS C compilers using the normal large memory model calling
  49. X;    conventions. This includes the Microsoft & Zortech compilers.
  50. X;
  51. X;    If we're running on a mono system, or one with an EGA or VGA,
  52. X;    & we were started in a text mode, we can achieve much faster
  53. X;    display output by writing directly to the frame buffer; we can
  54. X;    also save the previous screen contents & restore them when we
  55. X;    exit or run a sub-shell, which can be useful. If we have a
  56. X;    CGA, or we were started in a graphics mode, we just use the
  57. X;    functions supplied by the PC BIOS, which are slower, but good
  58. X;    enough for most purposes. On a modern 80386-based system, the
  59. X;    difference in speed is hardly noticeable.
  60. X; history:
  61. X;
  62. X;    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  63. X;    Originally by Tim Thompson (twitch!tjt)
  64. X;    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  65. X;    Heavily modified by Chris & John Downey
  66. X;***
  67. X
  68. Xinclude 8086mm.inc
  69. X
  70. X;
  71. X; If SWAPSCREEN is defined, we attempt to save the previous screen
  72. X; image & restore it when we exit or run another process. If you don't
  73. X; want this to happen, just comment out the line below.
  74. X;
  75. XSWAPSCREEN    equ    1
  76. X
  77. X;
  78. X; If you don't want mouse input handling, comment out the line below.
  79. X;
  80. XMOUSE        equ    1
  81. X
  82. X    C_extern _malloc
  83. X    C_extern _cparams
  84. X
  85. X    public    _alert
  86. X    public    _erase_display
  87. X    public    _erase_line
  88. X    public    _flush_output
  89. X    public    _hidemouse
  90. X    public    _mousestatus
  91. X    public    _outchar
  92. X    public    _outstr
  93. X    public    _scroll_up
  94. X    public    _scroll_down
  95. X    public    _set_colour
  96. X    public    _showmouse
  97. X    public    _tty_endv
  98. X    public    _tty_goto
  99. X    public    _tty_open
  100. X    public    _tty_startv
  101. X
  102. X;
  103. X; Segment addresses for PC text mode frame buffer.
  104. X;
  105. XVMONOSEG    =    0b000h    ; Mono frame buffer.
  106. XVCOLOURSEG    =    0b800h    ; Colour frame buffer.
  107. X
  108. X;
  109. X; BIOS video functions.
  110. X;
  111. Xvbios        macro    ahval, alval
  112. X    ifnb    <ahval>
  113. X        ifnb <alval>
  114. X        mov    ax, (ahval shl 8) + alval
  115. X        else
  116. X        mov    ah, ahval
  117. X        endif
  118. X    endif
  119. X        int    10h
  120. X        endm
  121. X;
  122. X; BIOS video function numbers.
  123. X;
  124. XB_MOVECURSOR    =    2    ; Move cursor.
  125. XB_UPSCROLL    =    6    ; Scroll window up.
  126. XB_DOWNSCROLL    =    7    ; Scroll window down.
  127. XB_WRITECHAR    =    9    ; Write character & attribute at
  128. X                ; current position.
  129. XB_TTYWRITE    =    0eh    ; Teletype-style write.
  130. XB_GETMODE    =    0fh    ; Get video mode.
  131. XB_SETPALETTE    =    10h    ; Set palette registers.
  132. XB_EGACGEN    =    11h    ; EGA character generator.
  133. XB_VCONFIG    =    12h    ; Video subsystem configuration.
  134. X
  135. X;
  136. X; Subfunction (of function 10h) for setting overscan register.
  137. X;
  138. XB_OVERSCAN    =    1
  139. X
  140. X;
  141. X; Subfunctions for EGA character generator.
  142. X;
  143. XB_EGATEST    =    30h
  144. XB_8X8FONT    =    12h
  145. XB_8X14FONT    =    11h
  146. X
  147. X;
  148. X; BIOS function to use alternate print screen routine.
  149. X;
  150. Xaltpscreen    macro
  151. X        mov    bl, 20h
  152. X        vbios    B_VCONFIG
  153. X        endm
  154. X
  155. X;
  156. X; BIOS function to get equipment list.
  157. X;
  158. Xbiosequip    macro
  159. X        int    11h
  160. X        endm
  161. X;
  162. X; Value returned by biosequip (in ax) to indicate a mono display.
  163. X;
  164. XEQUIP_MONO    =    30h
  165. X
  166. X;
  167. X; Default number of rows in text modes.
  168. X;
  169. XDEF_T_ROWS    =    25
  170. X
  171. X;
  172. X; Video modes.
  173. X;
  174. XBWT25X80    =    2    ; 25 x 80 black & white (CGA) text.
  175. XCT25X80        =    3    ; 25 x 80 colour text.
  176. XMT25X80        =    7    ; 25 x 80 monochrome (MDA) text.
  177. X
  178. X;
  179. X; I/O ports.
  180. X;
  181. XTIMER_2        =    42h    ; Timer channel 2.
  182. XTIMER_3        =    43h    ; Timer channel 3.
  183. XPORT_B        =    61h    ; 8255 port B.
  184. X
  185. X;
  186. X; Interrupt used by Microsoft mouse driver.
  187. X;
  188. XMSMINT        =    33h
  189. X
  190. X;
  191. X; Call mouse driver.
  192. X;
  193. Xmsmouse        macro    funcnum
  194. X    ifnb    <funcnum>
  195. X        mov    ax, funcnum
  196. X    endif
  197. X        int    MSMINT
  198. X        endm
  199. X;
  200. X; Mouse driver function numbers.
  201. X;
  202. XMSM_SHOW    =    1
  203. XMSM_HIDE    =    2
  204. XMSM_GETSTATUS    =    3
  205. XMSM_SETYLIMITS    =    8
  206. X
  207. X;
  208. X; Values for mouseflag.
  209. X;
  210. XMF_NOMOUSE    =    -1
  211. XMF_INITIAL    =    0
  212. XMF_OK        =    1
  213. XMF_VISIBLE    =    2
  214. X
  215. X;
  216. X; Segment containing interrupt vector table.
  217. X;
  218. XINTVECTAB    segment at 0
  219. X        ;
  220. X        ; Vector used by Microsoft mouse driver.
  221. X        ;
  222. X        org (MSMINT * 4)
  223. Xmsvecoff    dw    ?
  224. Xmsvecseg    dw    ?
  225. XINTVECTAB    ends
  226. X
  227. X;
  228. X; BIOS variable data segment.
  229. X;
  230. XBVSEG        =    40h
  231. X
  232. XBIOSDATA    segment at BVSEG
  233. X        ;
  234. X        ; Low word of timer variable.
  235. X        ;
  236. X        org    6ch
  237. Xb_timer_low    dw    ?
  238. X        ;
  239. X        ; Variable giving number of screen rows - 1.
  240. X        ;
  241. X        org    84h
  242. Xb_rowsvar    db    ?
  243. XBIOSDATA    ends
  244. X
  245. X_TEXT        segment word public 'CODE'
  246. X        assume    nothing
  247. X        assume    cs: _TEXT
  248. X
  249. X        even
  250. X    ifdef    SWAPSCREEN
  251. Xsaveptr        label    dword    ; Pointer to saved screen image.
  252. Xsvboff        dw    0
  253. Xsvbseg        dw    0
  254. Xscrwords    dw    ?    ; Number of 2-byte words in saved
  255. X                ; screen image.
  256. X    endif    ; SWAPSCREEN
  257. Xvbase        dw    0    ; Segment address of frame buffer. If
  258. X                ; this is 0, we don't access the frame
  259. X                ; buffer directly.
  260. Xvcolumn        label    byte
  261. Xvpos        dw    ?    ; Virtual screen position.
  262. Xscrsize        label    word    ; Screen dimensions.
  263. Xncolumns    db    ?    ; Low byte of scrsize.
  264. Xnrows        db    ?    ; High byte of scrsize.
  265. Xwritemethod    dw    offset bioswrite
  266. X                ; Pointer to function we use for
  267. X                ; outputting characters to the screen.
  268. Xstartmode    db    ?
  269. Xega        db    0    ; Flag indicating presence of EGA/VGA.
  270. Xvcolour        db    ?    ; Virtual colour.
  271. X    ifdef    MOUSE
  272. Xmouseflag    db    MF_INITIAL
  273. X                ; This is changed by _tty_startv to
  274. X                ; MF_OK if we have a mouse driver
  275. X                ; installed, or MF_NOMOUSE if we
  276. X                ; haven't.
  277. X    else    ; MOUSE
  278. Xmouseflag    db    MF_NOMOUSE
  279. X    endif    ; MOUSE
  280. X
  281. X    ifdef    SWAPSCREEN
  282. X    ;
  283. X    ; These routines deal with saving the previous screen image &
  284. X    ; restoring it.
  285. X    ;
  286. Xsavescreen:
  287. X        cmp    vbase, 0
  288. X        je    dontcopy
  289. X        push    si
  290. X        push    di
  291. X        push    ds
  292. X        les    di, saveptr
  293. X        mov    ax, es
  294. X        or    ax, di
  295. X        jz    cps_pop
  296. X        mov    ds, vbase
  297. X        clear    si
  298. X        jmp short copyscreen
  299. X
  300. Xrestorescreen    proc    near
  301. X        cmp    vbase, 0
  302. X        je    dontcopy
  303. X        push    si
  304. X        push    di
  305. X        push    ds
  306. X        mov    es, vbase
  307. X        clear    di
  308. X        lds    si, saveptr
  309. X        mov    ax, ds
  310. X        or    ax, si
  311. X        jz    cps_pop
  312. Xcopyscreen:
  313. X        mov    cx, scrwords
  314. X        cld
  315. X        rep    movsw
  316. Xcps_pop:
  317. X        pop    ds
  318. X        pop    di
  319. X        pop    si
  320. Xdontcopy:
  321. X        ret
  322. Xrestorescreen    endp
  323. X    endif    ; SWAPSCREEN
  324. X
  325. X        even
  326. X_flush_output:
  327. X        ;
  328. X        ; void flush_output(void);
  329. X        ;
  330. X        ; Update real cursor position.
  331. X        ;
  332. X        push    bp
  333. X        mov    dx, vpos
  334. X        clear    bh        ; Display page 0.
  335. X        vbios    B_MOVECURSOR
  336. X        pop    bp
  337. X        C_ret
  338. X
  339. X        even
  340. X_erase_line:
  341. X        ;
  342. X        ; void erase_line(void);
  343. X        ;
  344. X        ; Erase to end of line.
  345. X        ;
  346. X        ; Don't update cursor position.
  347. X        ;
  348. X        mov    cl, ncolumns    ; Get width of screen.
  349. X        mov    al, vcolumn    ; Get current column.
  350. X        sub    cl, al        ; Number of spaces to write ...
  351. X        jz    noerase        ; ... except if it's 0 ...
  352. X        clear    ch
  353. X        mov    al, ' '
  354. X        cld
  355. X        call    [writemethod]
  356. Xnoerase:
  357. X        C_ret
  358. X
  359. X_erase_display:
  360. X        ;
  361. X        ; void erase_display(void);
  362. X        ;
  363. X        ; Erase entire display by using BIOS scroll screen
  364. X        ; function to scroll all the lines in the display.
  365. X        ;
  366. X        ; Don't update cursor position.
  367. X        ;
  368. X        call    _cparams    ; This is in ibmpc_c.c.
  369. X        mov    bh, al        ; Get colour for blank screen.
  370. X        push    bp
  371. X        clear    cx        ; Top left row & column (0).
  372. X        mov    al, nrows    ; Number of lines (0).
  373. X        mov    dx, scrsize
  374. X        dec    dh        ; Bottom right row.
  375. X        dec    dl        ; Bottom right column.
  376. X        vbios    B_UPSCROLL
  377. X        pop    bp
  378. X        C_ret
  379. X
  380. X        even
  381. X_showmouse:
  382. X        ;
  383. X        ; void showmouse(void);
  384. X        ;
  385. X        ; Show mouse cursor.
  386. X        ;
  387. X        ; If we don't seem to have a mouse driver, or we think
  388. X        ; the cursor is already visible, don't do anything.
  389. X        ;
  390. X        cmp    mouseflag, MF_OK
  391. X        jne    m_invalid
  392. X        mov    ax, MSM_SHOW
  393. X        mov    mouseflag, MF_VISIBLE
  394. Xm_valid:
  395. X        msmouse
  396. Xm_invalid:
  397. X        C_ret
  398. X
  399. X        even
  400. X_hidemouse:
  401. X        ;
  402. X        ; void hidemouse(void);
  403. X        ;
  404. X        ; Hide mouse cursor.
  405. X        ;
  406. X        ; If we don't seem to have a mouse driver, or we don't
  407. X        ; think the cursor is visible, don't do anything.
  408. X        ;
  409. X        cmp    mouseflag, MF_VISIBLE
  410. X        jne    m_invalid
  411. X        mov    ax, MSM_HIDE
  412. X        mov    mouseflag, MF_OK
  413. X        jmp short m_valid
  414. X
  415. X_mousestatus:
  416. X        ;
  417. X        ; unsigned mousestatus(unsigned *xpos, unsigned *ypos);
  418. X        ;
  419. X        ; Return mouse button status, with current mouse
  420. X        ; co-ordinates in *xpos & *ypos.
  421. X        ;
  422. X        push    bp
  423. X        mov    bp, sp
  424. X        cmp    mouseflag, MF_OK
  425. X        jge    getstatus    ; if it's MF_OK or MF_VISIBLE
  426. X        clear    ax        ; Button status = 0.
  427. X        cwd            ; y co-ordinate = 0.
  428. X        mov    cx, ax        ; x co-ordinate = 0.
  429. X        jmp short ms_finish
  430. Xgetstatus:
  431. X        msmouse MSM_GETSTATUS
  432. X        mov    ax, bx        ; Return button status in ax.
  433. Xms_finish:
  434. X        ;
  435. X        ; Stack frame:
  436. X        ;
  437. X        ;   bp + CPTRSIZE + DPTRSIZE + 2
  438. X        ;        ypos pointer
  439. X        ;
  440. X        ;   bp + CPTRSIZE + 2
  441. X        ;        xpos pointer
  442. X        ;
  443. X        ;   bp + 2    return address
  444. X        ;
  445. X        ;   bp        caller's bp
  446. X        ;
  447. X    if DPTRSIZE eq 4
  448. X        push    ds
  449. X    endif
  450. X        ptrasg    <[bp + CPTRSIZE + 2]>, cx
  451. X                ; x co-ordinate.
  452. X        assume    ds: nothing
  453. X        ptrasg    <[bp + CPTRSIZE + DPTRSIZE + 2]>, dx
  454. X                ; y co-ordinate.
  455. X    if DPTRSIZE eq 4
  456. X        pop    ds
  457. X    endif
  458. X        pop    bp
  459. X        C_ret
  460. X
  461. X_tty_open:
  462. X        ;
  463. X        ; void tty_open(unsigned int *prows, unsigned int *pcolumns);
  464. X        ;
  465. X        ; Initialize display. Parameters point to variables in
  466. X        ; caller's default data segment giving dimensions of
  467. X        ; screen. We also maintain our own record of these
  468. X        ; values in scrsize, in this segment.
  469. X        ;
  470. X        push    bp
  471. X        push    ds
  472. X        mov    ax, cs
  473. X        mov    ds, ax
  474. X        assume    ds: _TEXT
  475. X        clear    dx
  476. X        mov    bx, dx
  477. X        vbios    B_EGACGEN, B_EGATEST    ; Do we have an EGA/VGA?
  478. X        tst    dl
  479. X        jz    notega
  480. X        inc    dl        ; Yes: dl is number of rows - 1.
  481. X        inc    ega
  482. X        jmp short testmode
  483. Xnotega:
  484. X        mov    dl, DEF_T_ROWS    ; No: assume 25 rows.
  485. Xtestmode:
  486. X        vbios    B_GETMODE
  487. X        mov    bp, sp
  488. X        mov    cx, cs
  489. X        ;
  490. X        ; Register usage at this point:
  491. X        ;
  492. X        ;    al    current display mode
  493. X        ;    ah    number of text columns
  494. X        ;    cx    our code segment
  495. X        ;    dl    number of text rows
  496. X        ;    bp    pointer (relative to ss) to stack frame
  497. X        ;
  498. X        ; Stack frame:
  499. X        ;
  500. X        ;   bp + CPTRSIZE + DPTRSIZE + 4
  501. X        ;        pointer to screen columns variable
  502. X        ;
  503. X        ;   bp + CPTRSIZE + 4
  504. X        ;        pointer to screen rows variable
  505. X        ;
  506. X        ;   bp + 4    return address
  507. X        ;
  508. X        ;   bp + 2    caller's bp
  509. X        ;
  510. X        ;   bp        caller's ds
  511. X        ;
  512. X        mov    ncolumns, ah
  513. X        mov    nrows, dl
  514. X    if DPTRSIZE eq 2
  515. X        mov    ds, [bp]
  516. X        assume    ds: nothing
  517. X    endif
  518. X        clear    dh        ; Clear high byte of rows.
  519. X        ptrasg    <[bp + CPTRSIZE + 4]>, dx
  520. X                    ; Return rows to caller.
  521. X        assume    ds: nothing
  522. X        mov    dl, ah
  523. X        ptrasg    <[bp + CPTRSIZE + DPTRSIZE + 4]>, dx
  524. X        mov    ds, cx        ; Point ds to our code segment again.
  525. X        assume    ds: _TEXT
  526. X        mov    startmode, al
  527. X        cmp    al, MT25X80    ; Mono text mode?
  528. X        jne    notmda
  529. X        biosequip
  530. X        and    ax, EQUIP_MONO    ; Is it a real mono system?
  531. X        cmp    ax, EQUIP_MONO
  532. X        jne    notmda        ; No.
  533. X        mov    vbase, VMONOSEG
  534. X        jmp short directvideo
  535. Xnotmda:
  536. X        cmp    al, CT25X80    ; Is it a graphics mode?
  537. X        ja    o_finish    ; Yes.
  538. X        cmp    ega, 0        ; Do we have an EGA or VGA?
  539. X        je    o_finish    ; No.
  540. X        mov    vbase, VCOLOURSEG
  541. Xdirectvideo:
  542. X        mov    writemethod, offset fastwrite
  543. X    ifdef    SWAPSCREEN
  544. X        mov    ax, scrsize
  545. X        dec    ah        ; (number of rows - 1) ...
  546. X        mul    ah        ; times (number of columns) ...
  547. X        mov    scrwords, ax    ; = number of screen
  548. X                    ; characters to save ...
  549. X        shl    ax, 1        ; times 2 = number of bytes to save.
  550. X        mov    ds, [bp]    ; Restore ds for C library.
  551. X        assume    ds: nothing
  552. X        push    ax
  553. X        call    _malloc
  554. X        inc    sp
  555. X        inc    sp
  556. X    if DPTRSIZE eq 2
  557. X        cwd            ; if (ax == 0) dx = 0;
  558. X        tst    ax        ; if (malloc() returned NULL) ...
  559. X        jz    dxok        ; ... dx should also be 0.
  560. X        mov    dx, ds        ; ds now points to C data segment,
  561. X                    ; not our code segment.
  562. Xdxok:
  563. X    endif    ; DPTRSIZE eq 2
  564. X        mov    svboff, ax
  565. X        mov    svbseg, dx
  566. X    endif    ; SWAPSCREEN
  567. Xo_finish:
  568. X        pop    ds
  569. X        assume    ds: nothing
  570. X        pop    bp
  571. X        C_ret
  572. X
  573. X_tty_startv:
  574. X        ;
  575. X        ; void tty_startv();
  576. X        ;
  577. X        ; If we've run a child process, & the mode has
  578. X        ; changed, we do our level best to restore it to what
  579. X        ; it was before: otherwise we're in trouble because
  580. X        ; the screen dimensions have probably changed.
  581. X        ;
  582. X        push    bp
  583. X        push    ds
  584. X        mov    ax, cs
  585. X        mov    ds, ax
  586. X        assume    ds: _TEXT
  587. X        vbios    B_GETMODE
  588. X        mov    dx, scrsize
  589. X        cmp    al, startmode    ; Has mode changed since we started?
  590. X        jne    changemode
  591. X        cmp    ah, dl        ; Current number of columns is
  592. X                    ; in ah; check that it hasn't
  593. X                    ; changed.
  594. X        je    modeok        ; It hasn't.
  595. Xchangemode:
  596. X        mov    al, startmode
  597. X        clear    ah        ; Function 0 (set mode).
  598. X        vbios
  599. X        mov    al, startmode
  600. Xmodeok:
  601. X        cmp    ega, 0
  602. X        je    sv_save
  603. X        ;
  604. X        ; If we have an EGA/VGA, the number of rows may have
  605. X        ; changed even though the mode hasn't, because
  606. X        ; fonts with different sizes can be loaded.
  607. X        ;
  608. X        cmp    al, BWT25X80
  609. X        je    checkrows
  610. X        cmp    al, CT25X80
  611. X        je    checkrows
  612. X        cmp    al, MT25X80
  613. X        jne    sv_save
  614. Xcheckrows:                ; Check number of rows.
  615. X        mov    ax, BVSEG
  616. X        mov    es, ax
  617. X        assume    es: BIOSDATA
  618. X        mov    al, b_rowsvar
  619. X        inc    al
  620. X        cmp    al, dh
  621. X        jae    sv_save
  622. X        altpscreen
  623. X        assume    es: nothing
  624. X        mov    ax, (B_EGACGEN shl 8) + B_8X14FONT
  625. X                    ; Use default EGA font.
  626. X        cmp    dh, DEF_T_ROWS
  627. X        jbe    setegafont
  628. X        mov    ax, (B_EGACGEN shl 8) + B_8X8FONT
  629. X                    ; Use small font.
  630. Xsetegafont:
  631. X        clear    bl        ; Table 0 in character generator RAM.
  632. X        vbios
  633. Xsv_save:
  634. X    ifdef    SWAPSCREEN
  635. X        call    savescreen
  636. X    endif    ; SWAPSCREEN
  637. X    ifdef    MOUSE
  638. X        cmp    mouseflag, MF_INITIAL
  639. X        js    sv_finish    ; MF_NOMOUSE?
  640. X        jne    mousereset    ; MF_OK or MF_VISIBLE?
  641. X        clear    ax
  642. X        mov    es, ax
  643. X        assume    es: INTVECTAB
  644. X        mov    ax, msvecoff    ; Check the actual interrupt
  645. X        or    ax, msvecseg    ; vector for the mouse driver.
  646. X        jz    sv_nomouse    ; If it's 0, we can't call it.
  647. Xmousereset:
  648. X        assume    es: nothing
  649. X        clear    ax        ; Function 0 (initialize mouse
  650. X        msmouse            ; driver).
  651. X        tst    ax
  652. X        jz    sv_nomouse        ; Failure.
  653. X        mov    mouseflag, MF_OK    ; Success.
  654. X        ;
  655. X        ; Set vertical limits for mouse movement according to
  656. X        ; the number of screen rows; apparently the Microsoft
  657. X        ; driver sometimes gets this wrong.
  658. X        ;
  659. X        mov    dl, nrows    ; Let dx = (nrows - 1) * 8.
  660. X        dec    dl
  661. X        clear    dh
  662. X        mov    cl, 3
  663. X        shl    dx, cl
  664. X        clear    cx
  665. X        msmouse MSM_SETYLIMITS
  666. X        jmp short sv_finish
  667. Xsv_nomouse:
  668. X        mov    mouseflag, MF_NOMOUSE
  669. X    endif    ; MOUSE
  670. Xsv_finish:
  671. X        pop    ds
  672. X        assume    ds: nothing
  673. X        pop    bp
  674. X        C_ret
  675. X
  676. X_tty_endv:
  677. X        ;
  678. X        ; void tty_endv();
  679. X        ;
  680. X        ; We're about to exit or run another process. Restore
  681. X        ; previous screen if appropriate, update real cursor
  682. X        ; position & reset mouse driver to its default state
  683. X        ; if required.
  684. X        ;
  685. X    ifdef    SWAPSCREEN
  686. X        ;
  687. X        ; At this stage, sys_endv() should have just gone to
  688. X        ; the bottom line, set the colour to
  689. X        ; Pn(P_systemcolour) & cleared the line. We shouldn't
  690. X        ; disturb its work, so restorescreen just restores the
  691. X        ; top (nrows - 1) lines. This is controlled by the
  692. X        ; scrwords variable.
  693. X        ;
  694. X        call    restorescreen
  695. X    endif    ; SWAPSCREEN
  696. X        Cn_call _flush_output
  697. X        cmp    mouseflag, MF_INITIAL
  698. X        jle    ev_finish
  699. X        clear    ax
  700. X        msmouse
  701. Xev_finish:
  702. X        C_ret
  703. X
  704. X        even
  705. X_tty_goto:
  706. X        ;
  707. X        ; void tty_goto(int row, int column);
  708. X        ;
  709. X        ; Change virtual screen position.
  710. X        ;
  711. X        mov    bx, sp
  712. X        mov    ah, byte ptr ss:[bx + CPTRSIZE]
  713. X        mov    al, byte ptr ss:[bx + CPTRSIZE + 2]
  714. X        mov    vpos, ax
  715. X        C_ret
  716. X
  717. X_set_colour:
  718. X        ;
  719. X        ; void set_colour(int colour);
  720. X        ;
  721. X        ; Change virtual screen colour.
  722. X        ;
  723. X        mov    bx, sp
  724. X        mov    al, byte ptr ss:[bx + CPTRSIZE]
  725. X        mov    vcolour, al
  726. X        C_ret
  727. X
  728. X;
  729. X; These two routines are functionally equivalent; they are only called
  730. X; by indirection through the "writemethod" pointer.
  731. X;
  732. X        even
  733. Xfastwrite    proc    near
  734. X        ;
  735. X        ; Write single character, or a number of repetitions
  736. X        ; of the same character, to the screen. Character is
  737. X        ; in al, number of repetitions in cx.
  738. X        ;
  739. X        ; This writes directly to the text mode frame buffer.
  740. X        ;
  741. X        ; Note that:
  742. X        ;
  743. X        ;    - the direction flag must be clear.
  744. X        ;
  745. X        ;    - cx is destroyed.
  746. X        ;
  747. X        push    di
  748. X        mov    es, vbase
  749. X        mov    dx, vpos    ; Get offset into frame buffer.
  750. X        mov    bl, ncolumns
  751. X        xchg    ax, bx        ; al is now number of columns;
  752. X                    ; bl is character to write ...
  753. X        mul    dh        ; ax is now (current row *
  754. X                    ;         number of columns) ...
  755. X        clear    dh
  756. X        add    ax, dx        ; Add current column (dl).
  757. X        shl    ax, 1        ; Multiply by 2 to get word offset.
  758. X        mov    di, ax
  759. X        mov    al, bl        ; Retrieve character to write.
  760. X        mov    ah, vcolour
  761. X        rep    stosw        ; Do the actual copying.
  762. X        pop    di
  763. X        ret
  764. Xfastwrite    endp
  765. X
  766. X        even
  767. Xbioswrite    proc    near
  768. X        ;
  769. X        ; Write single character, or a number of repetitions
  770. X        ; of the same character, to the screen. Character is
  771. X        ; in al, number of repetitions in cx.
  772. X        ;
  773. X        ; This uses the BIOS B_WRITECHAR function.
  774. X        ;
  775. X        push    bp
  776. X        clear    bh        ; Display page 0.
  777. X        mov    dx, vpos
  778. X        push    ax
  779. X        vbios    B_MOVECURSOR
  780. X        pop    ax
  781. X        mov    bl, vcolour
  782. X        vbios    B_WRITECHAR
  783. X        pop    bp
  784. X        ret
  785. Xbioswrite    endp
  786. X
  787. X        even
  788. Xvpadjust    proc    near
  789. X        ;
  790. X        ; Adjust virtual cursor position.
  791. X        ;
  792. X        mov    ax, scrsize
  793. X        mov    dx, vpos
  794. X        inc    dl        ; Increment column.
  795. X        cmp    dl, al
  796. X        jb    adjust
  797. X        clear    dl        ; Wrap round to next line.
  798. X        inc    dh
  799. X        cmp    dh, ah
  800. X        jnb    vpa_finish
  801. Xadjust:
  802. X        mov    vpos, dx
  803. Xvpa_finish:
  804. X        ret
  805. Xvpadjust    endp
  806. X
  807. X        even
  808. X_outchar:
  809. X        ;
  810. X        ; void outchar(int character);
  811. X        ;
  812. X        ; Display one character.
  813. X        ;
  814. X        mov    bx, sp
  815. X        mov    al, byte ptr ss:[bx + CPTRSIZE]
  816. X        mov    cx, 1
  817. X        cld
  818. X        call    [writemethod]
  819. X        call    vpadjust
  820. X        C_ret
  821. X
  822. X        even
  823. X_outstr:
  824. X        ;
  825. X        ; void outstr(char *string);
  826. X        ;
  827. X        ; Display C string.
  828. X        ;
  829. X        mov    bx, sp
  830. X        push    si
  831. X
  832. X    if DPTRSIZE eq 4
  833. X        push    ds
  834. X        lds    si, ss:[bx + CPTRSIZE]
  835. X        assume    ds: nothing
  836. X    else
  837. X        mov    si, [bx + CPTRSIZE]
  838. X    endif
  839. X        cld
  840. Xgetnextc:
  841. X        lodsb            ; Get next character in al.
  842. X        tst    al        ; Are we at the terminating '\0'?
  843. X        jz    endstring
  844. X        mov    cx, 1
  845. X        call    [writemethod]
  846. X        call    vpadjust
  847. X        jmp    getnextc
  848. X        even
  849. Xendstring:
  850. X    if DPTRSIZE eq 4
  851. X        pop    ds
  852. X    endif
  853. X        pop    si
  854. X        C_ret
  855. X
  856. Xscrollah:
  857. X        ;
  858. X        ; void scroll_up(unsigned startline,
  859. X        ;         unsigned endline,
  860. X        ;         unsigned nlines);
  861. X        ;
  862. X        ; void scroll_down(unsigned startline,
  863. X        ;           unsigned endline,
  864. X        ;           unsigned nlines);
  865. X        ;
  866. X        push    bp
  867. X        mov    bp, sp
  868. X        mov    al, byte ptr [bp + CPTRSIZE + 6]
  869. X                        ; Number of lines.
  870. X        tst    al            ; If 0 lines ...
  871. X        jz    noscroll        ; ... do nothing.
  872. X        clear    cl            ; Top left column (0).
  873. X        mov    ch, byte ptr [bp + CPTRSIZE + 2]
  874. X                        ; Top left row.
  875. X        mov    dl, ncolumns        ; Bottom right column.
  876. X        dec    dl
  877. X        mov    dh, byte ptr [bp + CPTRSIZE + 4]
  878. X                        ; Bottom right row.
  879. X        mov    bh, vcolour        ; Colour for blank lines.
  880. X        vbios
  881. Xnoscroll:
  882. X        pop    bp
  883. X        C_ret
  884. X
  885. X_scroll_up:
  886. X        ;
  887. X        ; Scroll region of screen up.
  888. X        ;
  889. X        mov    ah, B_UPSCROLL
  890. X        jmp    scrollah
  891. X
  892. X_scroll_down:
  893. X        ;
  894. X        ; Scroll region of screen down.
  895. X        ;
  896. X        mov    ah, B_DOWNSCROLL
  897. X        jmp    scrollah
  898. X
  899. X_alert:
  900. X        ;
  901. X        ; void alert(void);
  902. X        ;
  903. X        call    _cparams
  904. X        ;
  905. X        ; cparams() gives us the current text colour in al,
  906. X        ; the status line colour in ah & a visual bell flag in
  907. X        ; dx; if this is non-zero, we use a visual bell
  908. X        ; instead of an audible bell.
  909. X        ;
  910. X        push    bp
  911. X        tst    dx
  912. X        pushf        ; Save processor flags on stack.
  913. X                ; Zero flag means use audible bell.
  914. X        jz    ab_on
  915. X        ;
  916. X        ; Visual bell. Set overscan colour to the background
  917. X        ; component of the current text colour (or, if this is
  918. X        ; black, the background component of the current
  919. X        ; status line colour) temporarily.
  920. X        ;
  921. X        ; To get the backround component, we have to shift the
  922. X        ; value right 4 bits.
  923. X        ;
  924. X        mov    cl, 4
  925. X        shr    al, cl        ; Get text background colour.
  926. X        mov    bh, al
  927. X        tst    al
  928. X        jnz    gotcolour    ; Text background colour isn't black.
  929. X        shr    ah, cl        ; Get status line background colour.
  930. X        mov    bh, ah
  931. Xgotcolour:
  932. X        vbios    B_SETPALETTE, B_OVERSCAN
  933. X        jmp short asdelay
  934. Xab_on:
  935. X        ;
  936. X        ; Audible bell. Make speaker sound by programming the
  937. X        ; timer chip & the 8255 directly.
  938. X        ;
  939. X        cli
  940. X        mov    dx, TIMER_3
  941. X        mov    al, 0b6h
  942. X        out    dx, al        ; Select timer channel 2 mode.
  943. X        dec    dx
  944. X        ;
  945. X        ; Send frequency data to timer. This gives us a
  946. X        ; frequency of about 2 kHz.
  947. X        ;
  948. X        mov    al, 99h        ; Low byte of timer interval.
  949. X        out    dx, al
  950. X        mov    al, 2        ; High byte of timer interval.
  951. X        out    dx, al
  952. X        mov    dx, PORT_B
  953. X        in    al, dx        ; Get status of port B.
  954. X        mov    ah, al        ; Store it in ah.
  955. X        or    al, 3
  956. X        out    dx, al        ; Turn speaker on.
  957. X        sti
  958. X        ;
  959. X        ; Delay for 3 clock ticks (about 1/9 - 1/6 sec.).
  960. X        ;
  961. X        ; Don't change ah or dx.
  962. X        ;
  963. Xasdelay:
  964. X        mov    cx, 3
  965. X        mov    bx, BVSEG
  966. X        mov    es, bx
  967. X        assume    es: BIOSDATA
  968. Xtloop:
  969. X        mov    bx, b_timer_low
  970. Xwaittick:
  971. X        cmp    bx, b_timer_low
  972. X        je    waittick
  973. X        loop    tloop
  974. X        ;
  975. X        ; Delay loop has now finished.
  976. X        ;
  977. X        popf            ; Retrieve flags from stack.
  978. X        jz    ab_off        ; Zero flag means use audible bell.
  979. X        clear    bh        ; Set border colour to black.
  980. X        vbios    B_SETPALETTE, B_OVERSCAN
  981. X        jmp short ab_finish
  982. Xab_off:
  983. X        mov    al, ah        ; Previous status of port B.
  984. X        and    al, not 3
  985. X        out    dx, al        ; Turn speaker off.
  986. Xab_finish:
  987. X        pop    bp
  988. X        assume    es: nothing
  989. X        C_ret
  990. X
  991. X_TEXT        ends
  992. X        end
  993. END_OF_FILE
  994.   if test 19731 -ne `wc -c <'xvi/src/ibmpc_a.asm'`; then
  995.     echo shar: \"'xvi/src/ibmpc_a.asm'\" unpacked with wrong size!
  996.   fi
  997.   # end of 'xvi/src/ibmpc_a.asm'
  998. fi
  999. if test -f 'xvi/src/screen.c' -a "${1}" != "-c" ; then 
  1000.   echo shar: Will not clobber existing file \"'xvi/src/screen.c'\"
  1001. else
  1002.   echo shar: Extracting \"'xvi/src/screen.c'\" \(32878 characters\)
  1003.   sed "s/^X//" >'xvi/src/screen.c' <<'END_OF_FILE'
  1004. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  1005. X#ifndef lint
  1006. Xstatic char *sccsid = "@(#)screen.c    2.3 (Chris & John Downey) 9/4/92";
  1007. X#endif
  1008. X
  1009. X/***
  1010. X
  1011. X* program name:
  1012. X    xvi
  1013. X* function:
  1014. X    PD version of UNIX "vi" editor, with extensions.
  1015. X* module name:
  1016. X    screen.c
  1017. X* module function:
  1018. X    Screen handling functions.
  1019. X* history:
  1020. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  1021. X    Originally by Tim Thompson (twitch!tjt)
  1022. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  1023. X    Heavily modified by Chris & John Downey
  1024. X
  1025. X***/
  1026. X
  1027. X#include "xvi.h"
  1028. X
  1029. X/*
  1030. X * Size of command buffer - we won't allow anything more
  1031. X * to be typed when we get to this limit.
  1032. X */
  1033. X#define    CMDSZ    80
  1034. X
  1035. X/*
  1036. X * The following is used to optimise screen updating; we
  1037. X * keep a record of the real screen state and compare it
  1038. X * with the new version before actually doing any updating.
  1039. X *
  1040. X * The l_line part is guaranteed to be always null-terminated.
  1041. X */
  1042. Xtypedef    struct    line_struct    {
  1043. X    char        *l_line;    /* storage for characters in line */
  1044. X    int            l_used;        /* number of bytes actually used */
  1045. X    unsigned int    l_flags;    /* information bits */
  1046. X} Sline;
  1047. X
  1048. X/*
  1049. X * Bit definitions for l_flags.
  1050. X */
  1051. X#define    L_TEXT        0x01        /* is an ordinary text line */
  1052. X#define    L_MARKER    0x02        /* is a marker line ('@' or '~') */
  1053. X#define    L_DIRTY        0x04        /* has been modified */
  1054. X#define    L_MESSAGE    0x08        /* is a message line */
  1055. X#define    L_COMMAND    0x10        /* is a command line */
  1056. X#define    L_READONLY    0x20        /* message line for readonly buffer */
  1057. X
  1058. X#define    L_STATUS    (L_MESSAGE | L_COMMAND)        /* is a status line */
  1059. X
  1060. Xstatic    Sline    *new_screen;        /* screen being updated */
  1061. Xstatic    Sline    *real_screen;        /* state of real screen */
  1062. X
  1063. X/*
  1064. X * Status line glitch handling.
  1065. X *
  1066. X * Some terminals leave a space when changing colour. The number of spaces
  1067. X * left is returned by the v_colour_cost() method within the VirtScr, and
  1068. X * stored in the colour_cost variable herein - this is not perfect, it should
  1069. X * really be in the Xviwin structure, but what the hell.
  1070. X *
  1071. X * "st_spare_cols" is the number of columns which are not used at the
  1072. X * end of the status line; this is to prevent wrapping on this line,
  1073. X * as this can do strange things to some terminals.
  1074. X */
  1075. X
  1076. Xstatic    int    colour_cost = 0;
  1077. Xstatic    int    st_spare_cols = 1;
  1078. X
  1079. Xstatic    int    line_to_new P((Xviwin *, Line *, int, long));
  1080. Xstatic    void    file_to_new P((Xviwin *));
  1081. Xstatic    void    new_to_screen P((VirtScr *, int, int));
  1082. Xstatic    void    do_sline P((Xviwin *));
  1083. Xstatic    void    clrline P((int));
  1084. X
  1085. X/*
  1086. X * This routine must be called to set up the screen memory -
  1087. X * if it is not, we will probably get a core dump.
  1088. X *
  1089. X * Note that, at the moment, it must be called with a whole-screen
  1090. X * window, i.e. the first window, and only that window, so that the
  1091. X * nrows and ncols fields represent the whole screen.
  1092. X */
  1093. X/*ARGSUSED*/
  1094. Xvoid
  1095. Xinit_screen(win)
  1096. XXviwin    *win;
  1097. X{
  1098. X    static char        *real_area, *new_area;
  1099. X    register int    count;
  1100. X    VirtScr        *vs;
  1101. X
  1102. X    vs = win->w_vs;
  1103. X
  1104. X    colour_cost = VScolour_cost(vs);
  1105. X    st_spare_cols = 1 + (colour_cost * 2);
  1106. X
  1107. X    /*
  1108. X     * If we're changing the size of the screen, free the old stuff.
  1109. X     */
  1110. X    if (real_screen != NULL) {
  1111. X    free((char *) real_screen);
  1112. X    free((char *) new_screen);
  1113. X    free(real_area);
  1114. X    free(new_area);
  1115. X    }
  1116. X
  1117. X    /*
  1118. X     * Allocate space for the lines, and for the structure holding
  1119. X     * information about each line. Notice that we allocate an
  1120. X     * extra byte at the end of each line for null termination.
  1121. X     */
  1122. X    real_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
  1123. X    new_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
  1124. X    real_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
  1125. X    new_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
  1126. X
  1127. X    if (real_screen == NULL || new_screen == NULL ||
  1128. X    real_area == NULL || new_area == NULL) {
  1129. X    /* What to do now? */
  1130. X    sys_exit(0);
  1131. X    }
  1132. X
  1133. X    /*
  1134. X     * Now assign all the rows ...
  1135. X     */
  1136. X    for (count = 0; count < VSrows(vs); count++) {
  1137. X    register Sline    *rp, *np;
  1138. X    register int    offset;
  1139. X
  1140. X    rp = &real_screen[count];
  1141. X    np = &new_screen[count];
  1142. X
  1143. X    offset = count * (VScols(vs) + 1);
  1144. X
  1145. X    rp->l_line = real_area + offset;
  1146. X    np->l_line = new_area + offset;
  1147. X    rp->l_line[0] = np->l_line[0] = '\0';
  1148. X    rp->l_used = np->l_used = 0;
  1149. X    rp->l_flags = np->l_flags = 0;
  1150. X    }
  1151. X}
  1152. X
  1153. X/*
  1154. X * Set the L_DIRTY bit for a given line in both real_screen &
  1155. X * new_screen if the stored representations are in fact different:
  1156. X * otherwise clear it.
  1157. X */
  1158. Xstatic void
  1159. Xmark_dirty(row)
  1160. X    int        row;
  1161. X{
  1162. X    Sline    *rp;
  1163. X    Sline    *np;
  1164. X    int        used;
  1165. X
  1166. X    rp = &real_screen[row];
  1167. X    np = &new_screen[row];
  1168. X    if (
  1169. X
  1170. X    (rp->l_flags & ~L_DIRTY) != (np->l_flags & ~L_DIRTY)
  1171. X    ||
  1172. X    (used = rp->l_used) != np->l_used
  1173. X    ||
  1174. X    strncmp(rp->l_line, np->l_line, used) != 0
  1175. X    ) {
  1176. X    /*
  1177. X     * The lines are different.
  1178. X     */
  1179. X    np->l_flags |= L_DIRTY;
  1180. X    rp->l_flags |= L_DIRTY;
  1181. X    } else {
  1182. X    rp->l_flags = (np->l_flags &= ~L_DIRTY);
  1183. X    }
  1184. X}
  1185. X
  1186. X/*
  1187. X * Transfer the specified window line into the "new" screen array, at
  1188. X * the given row. Returns the number of screen lines taken up by the
  1189. X * logical buffer line lp, or 0 if the line would not fit; this happens
  1190. X * with longlines at the end of the screen. In this case, the lines
  1191. X * which could not be displayed will have been marked with an '@'.
  1192. X */
  1193. Xstatic int
  1194. Xline_to_new(window, lp, start_row, line)
  1195. XXviwin        *window;
  1196. XLine        *lp;
  1197. Xint        start_row;
  1198. Xlong        line;
  1199. X{
  1200. X    register unsigned    c;    /* next character from file */
  1201. X    register Sline    *curr_line;    /* output line - used for efficiency */
  1202. X    register char    *ltext;        /* pointer to text of line */
  1203. X    register int    curr_index;    /* current index in line */
  1204. X    bool_t        eoln;        /* true when line is done */
  1205. X    char        extra[MAX_TABSTOP];
  1206. X                    /* Stack for extra characters. */
  1207. X    int            nextra = 0;    /* index into stack */
  1208. X    int            srow, scol;    /* current screen row and column */
  1209. X    int            vcol;        /* virtual column */
  1210. X
  1211. X    ltext = lp->l_text;
  1212. X    srow = start_row;
  1213. X    scol = vcol = 0;
  1214. X    curr_line = &new_screen[srow];
  1215. X    curr_index = 0;
  1216. X    eoln = FALSE;
  1217. X
  1218. X    if (Pb(P_number)) {
  1219. X    static Flexbuf    ftmp;
  1220. X
  1221. X    flexclear(&ftmp);
  1222. X    (void) lformat(&ftmp, NUM_FMT, line);
  1223. X    (void) strcpy(curr_line->l_line, flexgetstr(&ftmp));
  1224. X    scol += NUM_SIZE;
  1225. X    }
  1226. X
  1227. X    while (!eoln) {
  1228. X    /*
  1229. X     * Get the next character to put on the screen.
  1230. X     */
  1231. X
  1232. X    /*
  1233. X     * "extra" is a stack containing any extra characters
  1234. X     * we have to put on the screen - this is for chars
  1235. X     * which have a multi-character representation, and
  1236. X     * for the $ at end-of-line in list mode.
  1237. X     */
  1238. X
  1239. X    if (nextra > 0) {
  1240. X        c = extra[--nextra];
  1241. X    } else {
  1242. X        unsigned    n;
  1243. X
  1244. X        c = (unsigned char) (ltext[curr_index++]);
  1245. X
  1246. X        /*
  1247. X         * Deal with situations where it is not
  1248. X         * appropriate just to copy characters
  1249. X         * straight onto the screen.
  1250. X         */
  1251. X        if (c == '\0') {
  1252. X
  1253. X        if (Pb(P_list)) {
  1254. X            /*
  1255. X             * Have to show a '$' sign in list mode.
  1256. X             */
  1257. X            extra[nextra++] = '\0';
  1258. X            c = '$';
  1259. X        }
  1260. X
  1261. X        } else {
  1262. X        char    *p;
  1263. X
  1264. X        n = vischar((int) c, &p, vcol);
  1265. X        /*
  1266. X         * This is a bit paranoid assuming
  1267. X         * that Pn(P_tabstop) can never be
  1268. X         * greater than sizeof (extra), but
  1269. X         * so what.
  1270. X         */
  1271. X        if (nextra + n > sizeof extra)
  1272. X            n = (sizeof extra - nextra);
  1273. X        /*
  1274. X         * Stack the extra characters so that
  1275. X         * they appear in the right order.
  1276. X         */
  1277. X        while (n > 1) {
  1278. X            extra[nextra++] = p[--n];
  1279. X        }
  1280. X        c = p[0];
  1281. X        }
  1282. X    }
  1283. X
  1284. X    if (c == '\0') {
  1285. X        /*
  1286. X         * End of line. Terminate it and finish.
  1287. X         */
  1288. X        eoln = TRUE;
  1289. X        curr_line->l_flags = L_TEXT;
  1290. X        curr_line->l_used = scol;
  1291. X        curr_line->l_line[scol] = '\0';
  1292. X        mark_dirty(srow);
  1293. X        break;
  1294. X    } else {
  1295. X        /*
  1296. X         * Sline folding.
  1297. X         */
  1298. X        if (scol >= window->w_ncols) {
  1299. X        curr_line->l_flags = L_TEXT;
  1300. X        curr_line->l_used = scol;
  1301. X        curr_line->l_line[scol] = '\0';
  1302. X        mark_dirty(srow);
  1303. X        srow += 1;
  1304. X        scol = 0;
  1305. X        curr_line = &new_screen[srow];
  1306. X        }
  1307. X
  1308. X        if (srow >= window->w_cmdline) {
  1309. X        for (srow = start_row; srow < window->w_cmdline; srow++) {
  1310. X            curr_line = &new_screen[srow];
  1311. X
  1312. X            curr_line->l_flags = L_MARKER;
  1313. X            curr_line->l_used = 1;
  1314. X            curr_line->l_line[0] = '@';
  1315. X            curr_line->l_line[1] = '\0';
  1316. X            mark_dirty(srow);
  1317. X        }
  1318. X        return(0);
  1319. X        }
  1320. X
  1321. X        /*
  1322. X         * Store the character in new_screen.
  1323. X         */
  1324. X        curr_line->l_line[scol++] = c;
  1325. X        vcol++;
  1326. X    }
  1327. X    }
  1328. X
  1329. X    return((srow - start_row) + 1);
  1330. X}
  1331. X
  1332. X/*
  1333. X * file_to_new()
  1334. X *
  1335. X * Based on the current value of topline, transfer a screenful
  1336. X * of stuff from file to new_screen, and update botline.
  1337. X */
  1338. Xstatic void
  1339. Xfile_to_new(win)
  1340. Xregister Xviwin    *win;
  1341. X{
  1342. X    register int    row;
  1343. X    register Line    *line;
  1344. X    register Buffer    *buffer;
  1345. X    long        lnum;
  1346. X
  1347. X    buffer = win->w_buffer;
  1348. X    row = win->w_winpos;
  1349. X    line = win->w_topline;
  1350. X    lnum = lineno(buffer, line);
  1351. X
  1352. X    while (row < win->w_cmdline && line != buffer->b_lastline) {
  1353. X    int nlines;
  1354. X
  1355. X    nlines = line_to_new(win, line, row, lnum);
  1356. X    if (nlines == 0) {
  1357. X        /*
  1358. X         * Make it look like we have updated
  1359. X         * all the screen lines, since they
  1360. X         * have '@' signs on them.
  1361. X         */
  1362. X        row = win->w_cmdline;
  1363. X        break;
  1364. X    } else {
  1365. X        row += nlines;
  1366. X        line = line->l_next;
  1367. X        lnum++;
  1368. X    }
  1369. X    }
  1370. X
  1371. X    win->w_botline = line;
  1372. X
  1373. X    /*
  1374. X     * If there are any lines remaining, fill them in
  1375. X     * with '~' characters.
  1376. X     */
  1377. X    for ( ; row < win->w_cmdline; row++) {
  1378. X    register Sline    *curr_line;
  1379. X
  1380. X    curr_line = &new_screen[row];
  1381. X
  1382. X    curr_line->l_flags = L_MARKER;
  1383. X    curr_line->l_used = 1;
  1384. X    curr_line->l_line[0] = '~';
  1385. X    curr_line->l_line[1] = '\0';
  1386. X    mark_dirty(row);
  1387. X    }
  1388. X}
  1389. X
  1390. X/*
  1391. X * new_to_screen
  1392. X *
  1393. X * Transfer the contents of new_screen to the screen,
  1394. X * starting at "start_row", for "nlines" lines,
  1395. X * using real_screen to avoid unnecessary output.
  1396. X */
  1397. Xstatic void
  1398. Xnew_to_screen(vs, start_row, nlines)
  1399. XVirtScr        *vs;
  1400. Xint        start_row;
  1401. Xint        nlines;
  1402. X{
  1403. X    int         row;                    /* current row */
  1404. X    int         end_row;                /* row after last one to be updated */
  1405. X    int         columns;
  1406. X
  1407. X    columns = VScols(vs);
  1408. X
  1409. X    if (!(echo & e_CHARUPDATE)) {
  1410. X    return;
  1411. X    }
  1412. X
  1413. X    end_row = start_row + nlines;
  1414. X
  1415. X    VSset_colour(vs, Pn(P_colour));
  1416. X
  1417. X    for (row = start_row; row < end_row; row++) {
  1418. X    register int            ncol;   /* current column in new_screen */
  1419. X    register Sline          *new,
  1420. X                *real;  /* pointers to current lines */
  1421. X    register unsigned       nflags;
  1422. X    unsigned                rflags; /* flags for current lines */
  1423. X    register char           *ntextp,
  1424. X                *rtextp;
  1425. X                    /* pointers to line text */
  1426. X    register int            nc;     /* current character in new_screen */
  1427. X    int            n_used,
  1428. X                r_used;
  1429. X
  1430. X    nflags = (new = &new_screen[row])->l_flags;
  1431. X    rflags = (real = &real_screen[row])->l_flags;
  1432. X
  1433. X    /*
  1434. X     * If the real and new screens are both "clean",
  1435. X     * don't bother.
  1436. X     */
  1437. X    if (!((nflags & L_DIRTY) || (rflags & L_DIRTY))) {
  1438. X        continue;
  1439. X    }
  1440. X
  1441. X    ntextp = new->l_line;
  1442. X    rtextp = real->l_line;
  1443. X
  1444. X    n_used = new->l_used;
  1445. X    r_used = real->l_used;
  1446. X
  1447. X    if ((nflags & L_MESSAGE) ||
  1448. X                (rflags & L_STATUS) != (nflags & L_STATUS)) {
  1449. X        /*
  1450. X         * If it's a message line, or its status (text line,
  1451. X         * command line or message line) has changed, and either
  1452. X         * the real line or the new line is "dirty", better update
  1453. X         * the whole thing; if any colour changes are required,
  1454. X         * the effects of cursor movements may not be predictable
  1455. X         * on some terminals.
  1456. X         */
  1457. X        VSgoto(vs, row, 0);
  1458. X        if (nflags & L_STATUS) {
  1459. X        VSset_colour(vs, (nflags & L_READONLY) ? Pn(P_roscolour) :
  1460. X                        Pn(P_statuscolour));
  1461. X        }
  1462. X        if ((nc = ntextp[0]) != '\0') {
  1463. X        VSputc(vs, row, 0, nc);
  1464. X        }
  1465. X        /*
  1466. X         * For command lines, only the first character should be
  1467. X         * highlighted.
  1468. X         */
  1469. X        if (nflags & L_COMMAND) {
  1470. X        VSset_colour(vs, Pn(P_colour));
  1471. X        }
  1472. X        if (nc != '\0') {
  1473. X        VSwrite(vs, row, 1, &ntextp[1]);
  1474. X        }
  1475. X
  1476. X        /*
  1477. X         * Clear the rest of the line, if
  1478. X         * there is any left to be cleared.
  1479. X         */
  1480. X        if (n_used < columns) {
  1481. X        VSclear_line(vs, row, n_used);
  1482. X        }
  1483. X
  1484. X        /*
  1485. X         * Change back to text colour if we have to.
  1486. X         */
  1487. X        if ((nflags & L_MESSAGE) != 0) {
  1488. X        VSset_colour(vs, Pn(P_colour));
  1489. X        }
  1490. X
  1491. X        (void) strncpy(rtextp, ntextp, (int) (columns - st_spare_cols));
  1492. X    } else {
  1493. X        /*
  1494. X         * Look at each character in the line, comparing
  1495. X         * the new version with the one on the screen.
  1496. X         * If they differ, put it out.
  1497. X         *
  1498. X         * There is some optimisation here to avoid large
  1499. X         * use of tty_goto.
  1500. X         */
  1501. X        register int        scol;
  1502. X                /* current column on physical screen */
  1503. X        register int        last_ncol;
  1504. X                /* last column to be updated */
  1505. X
  1506. X        for (ncol = scol = last_ncol = 0;
  1507. X                 ncol < n_used && ncol < r_used;
  1508. X                 (ncol++, scol++)) {
  1509. X        if ((nc = ntextp[ncol]) != rtextp[ncol]) {
  1510. X            /*
  1511. X             * They are different. Get to the right
  1512. X             * place before putting out the char.
  1513. X             */
  1514. X            if (ncol != 0) {
  1515. X            VSadvise(vs, row, last_ncol + 1,
  1516. X                        ncol - last_ncol - 1,
  1517. X                        ntextp + last_ncol + 1);
  1518. X            } else {
  1519. X            VSgoto(vs, row, scol);
  1520. X            /*
  1521. X             * A command line should have the first character
  1522. X             * - and only the first character - highlighted.
  1523. X             */
  1524. X            if (ncol == 0 && (nflags & L_STATUS) != 0) {
  1525. X                VSset_colour(vs, (nflags & L_READONLY) ?
  1526. X                    Pn(P_roscolour) : Pn(P_statuscolour));
  1527. X            }
  1528. X            }
  1529. X
  1530. X            VSputc(vs, row, ncol, nc);
  1531. X
  1532. X            if (ncol == 0 && (nflags & L_COMMAND) != 0) {
  1533. X            VSset_colour(vs, Pn(P_colour));
  1534. X            }
  1535. X            last_ncol = ncol;
  1536. X            rtextp[ncol] = nc;
  1537. X        }
  1538. X        if (ncol == 0 && (nflags & L_COMMAND) != 0) {
  1539. X            scol += (colour_cost * 2);
  1540. X        }
  1541. X        }
  1542. X
  1543. X        if (n_used > r_used) {
  1544. X        /*
  1545. X         * We have got to the end of the previous
  1546. X         * screen line; if there is anything left,
  1547. X         * we should just display it.
  1548. X         */
  1549. X        (void) strcpy(&rtextp[ncol], &ntextp[ncol]);
  1550. X        if (ncol == 0 && (nflags & L_COMMAND) != 0) {
  1551. X            /*
  1552. X             * A command line should have the first character
  1553. X             * - and only the first character - highlighted.
  1554. X             */
  1555. X            VSgoto(vs, row, 0);
  1556. X            VSset_colour(vs, Pn(P_statuscolour));
  1557. X            VSputc(vs, row, 0, ntextp[0]);
  1558. X            VSset_colour(vs, Pn(P_colour));
  1559. X            ncol = 1;
  1560. X        } else {
  1561. X            /*
  1562. X             * Skip over initial whitespace.
  1563. X             */
  1564. X            while (ntextp[ncol] == ' ') {
  1565. X            ncol++;
  1566. X            scol++;
  1567. X            }
  1568. X        }
  1569. X        if (ncol < columns)
  1570. X            VSwrite(vs, row, scol, &ntextp[ncol]);
  1571. X        } else if (r_used > n_used) {
  1572. X        /*
  1573. X         * We have got to the end of the new screen
  1574. X         * line, but the old one still has stuff on
  1575. X         * it. We must therefore clear it.
  1576. X         */
  1577. X        VSclear_line(vs, row, scol);
  1578. X        }
  1579. X    }
  1580. X
  1581. X    real->l_line[n_used] = '\0';
  1582. X    real->l_used = n_used;
  1583. X
  1584. X    /*
  1585. X     * The real screen line is a message or command line if the
  1586. X     * newly-updated one was. Otherwise, it isn't.
  1587. X     *
  1588. X     * Both the new and real screens may now be considered
  1589. X     * "clean".
  1590. X     */
  1591. X    real->l_flags = (
  1592. X              /*
  1593. X               * Turn these flags off first ...
  1594. X               */
  1595. X              (rflags & ~(L_STATUS | L_DIRTY))
  1596. X              /*
  1597. X               * ... then set whatever L_STATUS flags are
  1598. X               * set in new_screen.
  1599. X               */
  1600. X              | (nflags & L_STATUS)
  1601. X            );
  1602. X    new->l_flags &= ~L_DIRTY;
  1603. X    }
  1604. X}
  1605. X
  1606. X/*
  1607. X * Update the status line of the given window, and cause the status
  1608. X * line to be written out. Note that we call new_to_screen() to cause
  1609. X * the output to be generated; since there will be no other changes,
  1610. X * only the status line will be changed on the screen.
  1611. X */
  1612. Xvoid
  1613. Xupdate_sline(win)
  1614. XXviwin    *win;
  1615. X{
  1616. X    do_sline(win);
  1617. X    new_to_screen(win->w_vs, (int) win->w_cmdline, 1);
  1618. X    VSflush(win->w_vs);
  1619. X}
  1620. X
  1621. X/*
  1622. X * Update the status line of the given window,
  1623. X * from the one in win->w_statusline.
  1624. X */
  1625. Xstatic void
  1626. Xdo_sline(win)
  1627. XXviwin    *win;
  1628. X{
  1629. X    register char    *from;
  1630. X    register char    *to;
  1631. X    register char    *end;
  1632. X    Sline        *slp;
  1633. X
  1634. X    from = flexgetstr(&win->w_statusline);
  1635. X    slp = &new_screen[win->w_cmdline];
  1636. X    to = slp->l_line;
  1637. X    end = to + win->w_ncols - st_spare_cols;
  1638. X
  1639. X    while (*from != '\0' && to < end) {
  1640. X    *to++ = *from++;
  1641. X    }
  1642. X
  1643. X    /*
  1644. X     * Fill with spaces, and null-terminate.
  1645. X     */
  1646. X    while (to < end) {
  1647. X    *to++ = ' ';
  1648. X    }
  1649. X    *to = '\0';
  1650. X
  1651. X    slp->l_used = win->w_ncols - st_spare_cols;
  1652. X    slp->l_flags = L_MESSAGE;
  1653. X    if (is_readonly(win->w_buffer)) {
  1654. X    slp->l_flags |= L_READONLY;
  1655. X    }
  1656. X    mark_dirty(win->w_cmdline);
  1657. X}
  1658. X
  1659. Xvoid
  1660. Xupdate_cline(win)
  1661. XXviwin    *win;
  1662. X{
  1663. X    Sline    *clp;
  1664. X    unsigned width, maxwidth;
  1665. X
  1666. X    clp = &new_screen[win->w_cmdline];
  1667. X
  1668. X    maxwidth = win->w_ncols - st_spare_cols;
  1669. X    if ((width = flexlen(&win->w_statusline)) > maxwidth) {
  1670. X    width = maxwidth;
  1671. X    }
  1672. X    (void) strncpy(clp->l_line, flexgetstr(&win->w_statusline),
  1673. X                (int) width);
  1674. X    clp->l_used = width;
  1675. X    clp->l_line[width] = '\0';
  1676. X    clp->l_flags = (L_COMMAND | L_DIRTY);
  1677. X    /*
  1678. X     * We don't bother calling mark_dirty() here: it isn't worth
  1679. X     * it because the line's contents have almost certainly
  1680. X     * changed.
  1681. X     */
  1682. X    new_to_screen(win->w_vs, (int) win->w_cmdline, 1);
  1683. X    VSflush(win->w_vs);
  1684. X}
  1685. X
  1686. X/*
  1687. X * updateline() - update the line the cursor is on
  1688. X *
  1689. X * Updateline() is called after changes that only affect the line that
  1690. X * the cursor is on. This improves performance tremendously for normal
  1691. X * insert mode operation. The only thing we have to watch for is when
  1692. X * the cursor line grows or shrinks around a row boundary. This means
  1693. X * we have to repaint other parts of the screen appropriately.
  1694. X */
  1695. Xvoid
  1696. Xupdateline(window)
  1697. XXviwin    *window;
  1698. X{
  1699. X    Line    *currline;
  1700. X    int        nlines;
  1701. X    int        curs_row;
  1702. X
  1703. X    currline = window->w_cursor->p_line;
  1704. X
  1705. X    /*
  1706. X     * Find out which screen line the cursor line starts on.
  1707. X     * This is not necessarily the same as window->w_row,
  1708. X     * because longlines are different.
  1709. X     */
  1710. X    if (plines(window, currline) > 1) {
  1711. X    curs_row = (int) cntplines(window, window->w_topline, currline);
  1712. X    } else {
  1713. X    curs_row = window->w_row;
  1714. X    }
  1715. X
  1716. X    nlines = line_to_new(window, currline,
  1717. X            (int) (curs_row + window->w_winpos),
  1718. X            (long) lineno(window->w_buffer, currline));
  1719. X
  1720. X    if (nlines != window->w_c_line_size) {
  1721. X    update_buffer(window->w_buffer);
  1722. X    } else {
  1723. X    new_to_screen(window->w_vs,
  1724. X            (int) (curs_row + window->w_winpos), nlines);
  1725. X    VSflush(window->w_vs);
  1726. X    }
  1727. X}
  1728. X
  1729. X/*
  1730. X * Completely update the representation of the given window.
  1731. X */
  1732. Xvoid
  1733. Xupdate_window(window)
  1734. XXviwin    *window;
  1735. X{
  1736. X    if (window->w_nrows > 1) {
  1737. X    file_to_new(window);
  1738. X    new_to_screen(window->w_vs,
  1739. X            (int) window->w_winpos, (int) window->w_nrows);
  1740. X    VSflush(window->w_vs);
  1741. X    }
  1742. X}
  1743. X
  1744. X/*
  1745. X * Update all windows.
  1746. X */
  1747. Xvoid
  1748. Xupdate_all()
  1749. X{
  1750. X    Xviwin    *w = curwin;
  1751. X
  1752. X    do {
  1753. X    if (w->w_nrows > 1) {
  1754. X        file_to_new(w);
  1755. X    }
  1756. X    if (w->w_nrows > 0) {
  1757. X        do_sline(w);
  1758. X    }
  1759. X    } while ((w = next_window(w)) != curwin);
  1760. X
  1761. X    new_to_screen(w->w_vs, 0, (int) VSrows(w->w_vs));
  1762. X    VSflush(w->w_vs);
  1763. X}
  1764. X
  1765. X/*
  1766. X * Totally redraw the screen.
  1767. X */
  1768. Xvoid
  1769. Xredraw_screen()
  1770. X{
  1771. X    if (curwin != NULL) {
  1772. X    clear(curwin);
  1773. X    update_all();
  1774. X    }
  1775. X}
  1776. X
  1777. Xvoid
  1778. Xclear(win)
  1779. XXviwin    *win;
  1780. X{
  1781. X    register int    row;
  1782. X    int        nrows;
  1783. X
  1784. X    nrows = VSrows(win->w_vs);
  1785. X
  1786. X    VSset_colour(win->w_vs, Pn(P_colour));
  1787. X    VSclear_all(win->w_vs);
  1788. X
  1789. X    /*
  1790. X     * Clear the real screen lines, and mark them as modified.
  1791. X     */
  1792. X    for (row = 0; row < nrows; row++) {
  1793. X    clrline(row);
  1794. X    }
  1795. X}
  1796. X
  1797. X/*
  1798. X * The rest of the routines in this file perform screen manipulations.
  1799. X * The given operation is performed physically on the screen. The
  1800. X * corresponding change is also made to the internal screen image. In
  1801. X * this way, the editor anticipates the effect of editing changes on
  1802. X * the appearance of the screen. That way, when we call screenupdate a
  1803. X * complete redraw isn't usually necessary. Another advantage is that
  1804. X * we can keep adding code to anticipate screen changes, and in the
  1805. X * meantime, everything still works.
  1806. X */
  1807. X
  1808. X/*
  1809. X * s_ins(win, row, nlines) - insert 'nlines' lines at 'row'
  1810. X */
  1811. Xvoid
  1812. Xs_ins(win, row, nlines)
  1813. XXviwin        *win;
  1814. Xregister int    row;
  1815. Xint        nlines;
  1816. X{
  1817. X    register int    from, to;
  1818. X    int            count;
  1819. X    VirtScr        *vs;
  1820. X
  1821. X    if (!(echo & e_SCROLL))
  1822. X    return;
  1823. X
  1824. X    /*
  1825. X     * There's no point in scrolling more lines than there are
  1826. X     * (below row) in the window, or in scrolling 0 lines.
  1827. X     */
  1828. X    if (nlines == 0 || nlines + row >= win->w_nrows - 1)
  1829. X    return;
  1830. X
  1831. X    /*
  1832. X     * The row specified is relative to the top of the window;
  1833. X     * add the appropriate offset to make it into a screen row.
  1834. X     */
  1835. X    row += win->w_winpos;
  1836. X
  1837. X    /*
  1838. X     * Note that we avoid the use of 1-line scroll regions; these
  1839. X     * only ever occur at the bottom of a window, and it is better
  1840. X     * just to leave the line to be updated in the best way by
  1841. X     * update{line,screen}.
  1842. X     */
  1843. X    if (nlines == 1 && row + 1 == win->w_cmdline) {
  1844. X    return;
  1845. X    }
  1846. X
  1847. X    vs = win->w_vs;
  1848. X
  1849. X    if (vs->v_scroll != NULL) {
  1850. X    if (!VSscroll(vs, row, (int) win->w_cmdline - 1, -nlines)) {
  1851. X        /*
  1852. X         * Can't scroll what we were asked to - try scrolling
  1853. X         * the whole window including the status line.
  1854. X         */
  1855. X        VSclear_line(vs, (int) win->w_cmdline, 0);
  1856. X        clrline(win->w_cmdline);
  1857. X        if (!VSscroll(vs, row, (int) win->w_cmdline, -nlines)) {
  1858. X        /*
  1859. X         * Failed.
  1860. X         */
  1861. X        return;
  1862. X        }
  1863. X    }
  1864. X    } else {
  1865. X    return;
  1866. X    }
  1867. X
  1868. X    /*
  1869. X     * Update the stored screen image so it matches what has
  1870. X     * happened on the screen.
  1871. X     */
  1872. X
  1873. X    /*
  1874. X     * Move section of text down to the bottom.
  1875. X     *
  1876. X     * We do this by rearranging the pointers within the Slines,
  1877. X     * rather than copying the characters.
  1878. X     */
  1879. X    for (to = win->w_cmdline - 1, from = to - nlines; from >= row;
  1880. X                            --from, --to) {
  1881. X    register char    *temp;
  1882. X
  1883. X    temp = real_screen[to].l_line;
  1884. X    real_screen[to].l_line = real_screen[from].l_line;
  1885. X    real_screen[from].l_line = temp;
  1886. X    real_screen[to].l_used = real_screen[from].l_used;
  1887. X    }
  1888. X
  1889. X    /*
  1890. X     * Clear the newly inserted lines.
  1891. X     */
  1892. X    for (count = row; count < row + nlines; count++) {
  1893. X    clrline(count);
  1894. X    }
  1895. X}
  1896. X
  1897. X/*
  1898. X * s_del(win, row, nlines) - delete 'nlines' lines starting at 'row'.
  1899. X */
  1900. Xvoid
  1901. Xs_del(win, row, nlines)
  1902. Xregister Xviwin        *win;
  1903. Xint            row;
  1904. Xint            nlines;
  1905. X{
  1906. X    register int    from, to;
  1907. X    int            count;
  1908. X    VirtScr        *vs;
  1909. X
  1910. X    if (!(echo & e_SCROLL))
  1911. X    return;
  1912. X
  1913. X    /*
  1914. X     * There's no point in scrolling more lines than there are
  1915. X     * (below row) in the window, or in scrolling 0 lines.
  1916. X     */
  1917. X    if (nlines == 0 || nlines + row >= win->w_nrows - 1)
  1918. X    return;
  1919. X
  1920. X    /*
  1921. X     * The row specified is relative to the top of the window;
  1922. X     * add the appropriate offset to make it into a screen row.
  1923. X     */
  1924. X    row += win->w_winpos;
  1925. X
  1926. X    /*
  1927. X     * We avoid the use of 1-line scroll regions, since they don't
  1928. X     * work with many terminals, especially if we are using
  1929. X     * (termcap) DO to scroll the region.
  1930. X     */
  1931. X    if (nlines == 1 && row + 1 == win->w_cmdline) {
  1932. X    return;
  1933. X    }
  1934. X
  1935. X    vs = win->w_vs;
  1936. X
  1937. X    if (vs->v_scroll != NULL) {
  1938. X    if (!VSscroll(vs, row, (int) win->w_cmdline - 1, nlines)) {
  1939. X        /*
  1940. X         * Can't scroll what we were asked to - try scrolling
  1941. X         * the whole window including the status line.
  1942. X         */
  1943. X        VSclear_line(vs, (int) win->w_cmdline, 0);
  1944. X        clrline(win->w_cmdline);
  1945. X        if (!VSscroll(vs, row, (int) win->w_cmdline, nlines)) {
  1946. X        /*
  1947. X         * Failed.
  1948. X         */
  1949. X        return;
  1950. X        }
  1951. X    }
  1952. X    } else {
  1953. X    return;
  1954. X    }
  1955. X
  1956. X    /*
  1957. X     * Update the stored screen image so it matches what has
  1958. X     * happened on the screen.
  1959. X     */
  1960. X
  1961. X    /*
  1962. X     * Move section of text up from the bottom.
  1963. X     *
  1964. X     * We do this by rearranging the pointers within the Slines,
  1965. X     * rather than copying the characters.
  1966. X     */
  1967. X    for (to = row, from = to + nlines;
  1968. X     from < win->w_cmdline;
  1969. X     from++, to++) {
  1970. X    register char    *temp;
  1971. X
  1972. X    temp = real_screen[to].l_line;
  1973. X    real_screen[to].l_line = real_screen[from].l_line;
  1974. X    real_screen[from].l_line = temp;
  1975. X    real_screen[to].l_used = real_screen[from].l_used;
  1976. X    }
  1977. X
  1978. X    /*
  1979. X     * Clear the deleted lines.
  1980. X     */
  1981. X    for (count = win->w_cmdline - nlines; count < win->w_cmdline; count++) {
  1982. X    clrline(count);
  1983. X    }
  1984. X}
  1985. X
  1986. X/*
  1987. X * Insert a character at the cursor position, updating the screen as
  1988. X * necessary. Note that this routine doesn't have to do anything, as
  1989. X * the screen will eventually be correctly updated anyway; it's just
  1990. X * here for speed of screen updating.
  1991. X */
  1992. Xvoid
  1993. Xs_inschar(window, newchar)
  1994. XXviwin            *window;
  1995. Xint            newchar;
  1996. X{
  1997. X    register char    *curp;
  1998. X    register char    *cp;
  1999. X    register char    *sp;
  2000. X    Sline        *rp;
  2001. X    Posn        *pp;
  2002. X    VirtScr        *vs;        /* the VirtScr for this window */
  2003. X    char        *newstr;    /* printable string for newchar */
  2004. X    register unsigned    nchars;        /* number of  chars in newstr */
  2005. X    unsigned        currow;
  2006. X    unsigned        curcol;
  2007. X    unsigned        columns;
  2008. X
  2009. X    vs = window->w_vs;
  2010. X    if (vs->v_insert == NULL)
  2011. X    return;
  2012. X
  2013. X    if (!(echo & e_CHARUPDATE))
  2014. X    return;
  2015. X
  2016. X    pp = window->w_cursor;
  2017. X
  2018. X    /*
  2019. X     * If we are at (or near) the end of the line, it's not worth
  2020. X     * the bother. Define near as 0 or 1 characters to be moved.
  2021. X     */
  2022. X    cp = pp->p_line->l_text + pp->p_index;
  2023. X    if (*cp == '\0' || *(cp+1) == '\0')
  2024. X    return;
  2025. X
  2026. X    curcol = window->w_col;
  2027. X
  2028. X    /*
  2029. X     * If the cursor is on a longline, and not on the last actual
  2030. X     * screen line of that longline, we can't do it.
  2031. X     */
  2032. X    if (window->w_c_line_size > 1 && curcol != window->w_virtcol)
  2033. X    return;
  2034. X
  2035. X    nchars = vischar(newchar, &newstr, curcol);
  2036. X
  2037. X    /*
  2038. X     * And don't bother if we are (or will be) at the last screen column.
  2039. X     */
  2040. X    columns = window->w_ncols;
  2041. X    if (curcol + nchars >= columns)
  2042. X    return;
  2043. X
  2044. X    /*
  2045. X     * Also, trying to push tabs rightwards doesn't work very
  2046. X     * well. It's usually better not to use the insert character
  2047. X     * sequence because in most cases we'll only have to update
  2048. X     * the line as far as the tab anyway.
  2049. X     */
  2050. X    if ((!Pb(P_list) && Pb(P_tabs)) && strchr(cp, '\t') != NULL) {
  2051. X    return;
  2052. X    }
  2053. X
  2054. X    /*
  2055. X     * Okay, we can do it.
  2056. X     */
  2057. X    currow = window->w_row;
  2058. X
  2059. X    VSinsert(vs, window->w_winpos + currow, curcol, newstr);
  2060. X
  2061. X    /*
  2062. X     * Update real_screen.
  2063. X     */
  2064. X    rp = &real_screen[window->w_winpos + currow];
  2065. X    curp = &rp->l_line[curcol];
  2066. X    if ((rp->l_used += nchars) > columns)
  2067. X    rp->l_used = columns;
  2068. X    cp = &rp->l_line[rp->l_used - 1];
  2069. X    cp[1] = '\0';
  2070. X    if (cp - curp >= nchars)
  2071. X    {
  2072. X    sp = cp - nchars;
  2073. X    for (;;) {
  2074. X        *cp-- = *sp;
  2075. X        if (sp-- <= curp)
  2076. X        break;
  2077. X    }
  2078. X    }
  2079. X
  2080. X    /*
  2081. X     * This is the string we've just inserted.
  2082. X     */
  2083. X    sp = newstr;
  2084. X    while (nchars-- > 0) {
  2085. X    *curp++ = *sp++;
  2086. X    }
  2087. X}
  2088. X
  2089. Xvoid
  2090. Xwind_goto(win)
  2091. XXviwin    *win;
  2092. X{
  2093. X    VirtScr    *vs;
  2094. X
  2095. X    if (echo & e_CHARUPDATE) {
  2096. X    vs = win->w_vs;
  2097. X    VSgoto(vs, (int) win->w_winpos + win->w_row, win->w_col);
  2098. X    VSflush(vs);
  2099. X    }
  2100. X}
  2101. X
  2102. Xstatic    char        inbuf[CMDSZ];        /* command input buffer */
  2103. Xstatic    unsigned int    inpos = 0;        /* posn of next input char */
  2104. Xstatic    unsigned char    colposn[CMDSZ];        /* holds n chars per char */
  2105. X
  2106. X/*
  2107. X * cmd_init(window, firstch)
  2108. X *
  2109. X * Initialise command line input.
  2110. X */
  2111. Xvoid
  2112. Xcmd_init(win, firstch)
  2113. XXviwin    *win;
  2114. Xint    firstch;
  2115. X{
  2116. X    if (inpos > 0) {
  2117. X    show_error(win, "Internal error: re-entered command line input mode");
  2118. X    return;
  2119. X    }
  2120. X
  2121. X    State = CMDLINE;
  2122. X
  2123. X    flexclear(&win->w_statusline);
  2124. X    (void) flexaddch(&win->w_statusline, firstch);
  2125. X    inbuf[0] = firstch;
  2126. X    inpos = 1;
  2127. X    update_cline(win);
  2128. X    colposn[0] = 0;
  2129. X}
  2130. X
  2131. X/*
  2132. X * cmd_input(window, character)
  2133. X *
  2134. X * Deal with command line input. Takes an input character and returns
  2135. X * one of cmd_CANCEL (meaning they typed ESC or deleted past the
  2136. X * prompt character), cmd_COMPLETE (indicating that the command has
  2137. X * been completely input), or cmd_INCOMPLETE (indicating that command
  2138. X * line is still the right mode to be in).
  2139. X *
  2140. X * Once cmd_COMPLETE has been returned, it is possible to call
  2141. X * get_cmd(win) to obtain the command line.
  2142. X */
  2143. XCmd_State
  2144. Xcmd_input(win, ch)
  2145. XXviwin    *win;
  2146. Xint    ch;
  2147. X{
  2148. X    static bool_t    literal_next = FALSE;
  2149. X
  2150. X    if (!literal_next) {
  2151. X    switch (ch) {
  2152. X    case CTRL('V'):
  2153. X        literal_next = TRUE;
  2154. X        return(cmd_INCOMPLETE);
  2155. X
  2156. X    case '\n':        /* end of line */
  2157. X    case '\r':
  2158. X        inbuf[inpos] = '\0';    /* terminate input line */
  2159. X        inpos = 0;
  2160. X        State = NORMAL;        /* return state to normal */
  2161. X        do_sline(win);        /* line is now a message line */
  2162. X        return(cmd_COMPLETE);    /* and indicate we are done */
  2163. X
  2164. X    case '\b':        /* backspace or delete */
  2165. X    case DEL:
  2166. X    {
  2167. X        unsigned len;
  2168. X
  2169. X        inbuf[--inpos] = '\0';
  2170. X        len = colposn[inpos - 1] + 1;
  2171. X        while (flexlen(&win->w_statusline) > len)
  2172. X        (void) flexrmchar(&win->w_statusline);
  2173. X        update_cline(win);
  2174. X        if (inpos == 0) {
  2175. X        /*
  2176. X         * Deleted past first char;
  2177. X         * go back to normal mode.
  2178. X         */
  2179. X        State = NORMAL;
  2180. X        return(cmd_CANCEL);
  2181. X        }
  2182. X        return(cmd_INCOMPLETE);
  2183. X    }
  2184. X
  2185. X    case '\033':
  2186. X    case EOF:
  2187. X    case CTRL('U'):        /* line kill */
  2188. X        inpos = 1;
  2189. X        inbuf[1] = '\0';
  2190. X        flexclear(&win->w_statusline);
  2191. X        (void) flexaddch(&win->w_statusline, inbuf[0]);
  2192. X        update_cline(win);
  2193. X        return(cmd_INCOMPLETE);
  2194. X
  2195. X    default:
  2196. X        break;
  2197. X    }
  2198. X    }
  2199. X
  2200. X    literal_next = FALSE;
  2201. X
  2202. X    if (inpos >= sizeof(inbuf) - 1) {
  2203. X    /*
  2204. X     * Must not overflow buffer.
  2205. X     */
  2206. X    beep(win);
  2207. X    } else {
  2208. X    unsigned    curposn;
  2209. X    unsigned    w;
  2210. X    char        *p;
  2211. X
  2212. X    curposn = colposn[inpos - 1];
  2213. X    w = vischar(ch, &p, (int) curposn);
  2214. X    if (curposn + w >= win->w_ncols - 1) {
  2215. X        beep(win);
  2216. X    } else {
  2217. X        colposn[inpos] = curposn + w;
  2218. X        inbuf[inpos++] = ch;
  2219. X        (void) lformat(&win->w_statusline, "%s", p);
  2220. X        update_cline(win);
  2221. X    }
  2222. X    }
  2223. X
  2224. X    return(cmd_INCOMPLETE);
  2225. X}
  2226. X
  2227. X/*ARGSUSED*/
  2228. Xchar *
  2229. Xget_cmd(win)
  2230. XXviwin    *win;
  2231. X{
  2232. X    return(inbuf);
  2233. X}
  2234. X
  2235. X/*ARGSUSED*/
  2236. Xvoid
  2237. Xgotocmd(win, clr)
  2238. XXviwin    *win;
  2239. Xbool_t    clr;
  2240. X{
  2241. X    VirtScr    *vs;
  2242. X
  2243. X    vs = win->w_vs;
  2244. X    if (clr) {
  2245. X    VSclear_line(vs, (int) win->w_cmdline, 0);
  2246. X    }
  2247. X    VSgoto(vs, (int) win->w_cmdline, 0);
  2248. X    VSflush(vs);
  2249. X}
  2250. X
  2251. X/*
  2252. X * Display a prompt on the bottom line of the screen.
  2253. X */
  2254. Xvoid
  2255. Xprompt(message)
  2256. X    char    *message;
  2257. X{
  2258. X    VirtScr    *vs;
  2259. X    int    row;
  2260. X
  2261. X    vs = curwin->w_vs;
  2262. X
  2263. X    row = VSrows(vs) - 1;
  2264. X    VSgoto(vs, row, 0);
  2265. X    VSset_colour(vs, Pn(P_statuscolour));
  2266. X    VSwrite(vs, row, 0, message);
  2267. X    VSset_colour(vs, Pn(P_colour));
  2268. X    VSgoto(vs, row, strlen(message));
  2269. X    VSflush(vs);
  2270. X}
  2271. X
  2272. X/*
  2273. X * Sound the alert.
  2274. X */
  2275. Xvoid
  2276. Xbeep(window)
  2277. Xregister Xviwin *window;
  2278. X{
  2279. X    VSbeep(window->w_vs);
  2280. X}
  2281. X
  2282. Xstatic char    *(*disp_func) P((void));
  2283. Xstatic int    disp_colwidth;
  2284. Xstatic int    disp_maxcol;
  2285. Xstatic bool_t    disp_listmode;
  2286. X
  2287. X/*
  2288. X * Start off "display" mode. The "func" argument is a function pointer
  2289. X * which will be called to obtain each subsequent string to display.
  2290. X * The function returns NULL when no more lines are available.
  2291. X */
  2292. Xvoid
  2293. Xdisp_init(win, func, colwidth, listmode)
  2294. XXviwin        *win;
  2295. Xchar        *(*func) P((void));
  2296. Xint        colwidth;
  2297. Xbool_t        listmode;
  2298. X{
  2299. X    State = DISPLAY;
  2300. X    disp_func = func;
  2301. X    if (colwidth > win->w_ncols)
  2302. X    colwidth = win->w_ncols;
  2303. X    disp_colwidth = colwidth;
  2304. X    disp_maxcol = (win->w_ncols / colwidth) * colwidth;
  2305. X    disp_listmode = listmode;
  2306. X    (void) disp_screen(win);
  2307. X}
  2308. X
  2309. X/*
  2310. X * Display text in glass-teletype mode, in approximately the style of
  2311. X * the more(1) program.
  2312. X *
  2313. X * If the return value from (*disp_func)() is NULL, it means we've got
  2314. X * to the end of the text to be displayed, so we wait for another key
  2315. X * before redisplaying our editing screen.
  2316. X */
  2317. Xbool_t
  2318. Xdisp_screen(win)
  2319. XXviwin    *win;
  2320. X{
  2321. X    int        row;    /* current screen row */
  2322. X    int        col;    /* current screen column */
  2323. X    static bool_t    finished = FALSE;
  2324. X    VirtScr        *vs;
  2325. X
  2326. X    vs = win->w_vs;
  2327. X
  2328. X    if (finished || kbdintr) {
  2329. X    /*
  2330. X     * Clear the screen, and then ensure that the window
  2331. X     * on the current buffer is in the right place and
  2332. X     * updated; finally update the whole screen.
  2333. X     */
  2334. X    clear(win);
  2335. X    move_window_to_cursor(win);
  2336. X    update_all();
  2337. X    State = NORMAL;
  2338. X    finished = FALSE;
  2339. X    if (kbdintr) {
  2340. X        imessage = TRUE;
  2341. X    }
  2342. X    return(TRUE);
  2343. X    }
  2344. X
  2345. X    VSclear_all(vs);
  2346. X
  2347. X    for (col = 0; col < disp_maxcol; col += disp_colwidth) {
  2348. X    for (row = 0; row < VSrows(vs) - 1; row++) {
  2349. X        static char    *line;
  2350. X        int        width;
  2351. X
  2352. X        if (line == NULL && (line = (*disp_func)()) == NULL) {
  2353. X        /*
  2354. X         * We've got to the end.
  2355. X         */
  2356. X        prompt("[Hit return to continue] ");
  2357. X        finished = TRUE;
  2358. X        return(FALSE);
  2359. X        }
  2360. X
  2361. X        for (width = 0; *line != '\0'; line++) {
  2362. X        char        *p;
  2363. X        unsigned    w;
  2364. X
  2365. X        w = vischar(*line, &p, disp_listmode ? -1 : width);
  2366. X
  2367. X        if ((width += w) <= disp_colwidth) {
  2368. X            VSwrite(vs, row, col + width - w, p);
  2369. X        } else {
  2370. X            /*
  2371. X             * The line is too long, so we
  2372. X             * have to wrap around to the
  2373. X             * next screen line.
  2374. X             */
  2375. X            break;
  2376. X        }
  2377. X        }
  2378. X
  2379. X        if (*line == '\0') {
  2380. X        if (disp_listmode) {
  2381. X            /*
  2382. X             * In list mode, we have to
  2383. X             * display a '$' to show the
  2384. X             * end of a line.
  2385. X             */
  2386. X            if (width < disp_colwidth) {
  2387. X            VSputc(vs, row, col + width, '$');
  2388. X            } else {
  2389. X            /*
  2390. X             * We have to wrap it
  2391. X             * to the next screen
  2392. X             * line.
  2393. X             */
  2394. X            continue;
  2395. X            }
  2396. X        }
  2397. X        /*
  2398. X         * If we're not in list mode, or we
  2399. X         * were able to display the '$', we've
  2400. X         * finished with this line.
  2401. X         */
  2402. X        line = NULL;
  2403. X        }
  2404. X    }
  2405. X    }
  2406. X
  2407. X    prompt("[More] ");
  2408. X
  2409. X    return(FALSE);
  2410. X}
  2411. X
  2412. X/*
  2413. X * Clear the given line, marking it as dirty.
  2414. X */
  2415. Xstatic void
  2416. Xclrline(line)
  2417. Xint    line;
  2418. X{
  2419. X    real_screen[line].l_used = 0;
  2420. X    real_screen[line].l_line[0] = '\0';
  2421. X    mark_dirty(line);
  2422. X}
  2423. END_OF_FILE
  2424.   if test 32878 -ne `wc -c <'xvi/src/screen.c'`; then
  2425.     echo shar: \"'xvi/src/screen.c'\" unpacked with wrong size!
  2426.   fi
  2427.   # end of 'xvi/src/screen.c'
  2428. fi
  2429. echo shar: End of archive 6 \(of 18\).
  2430. cp /dev/null ark6isdone
  2431. MISSING=""
  2432. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
  2433.     if test ! -f ark${I}isdone ; then
  2434.     MISSING="${MISSING} ${I}"
  2435.     fi
  2436. done
  2437. if test "${MISSING}" = "" ; then
  2438.     echo You have unpacked all 18 archives.
  2439.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2440. else
  2441.     echo You still must unpack the following archives:
  2442.     echo "        " ${MISSING}
  2443. fi
  2444. exit 0
  2445. exit 0 # Just in case...
  2446.