display.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:20k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* ANSI display emulation
  2.  *
  3.  * This file emulates the IBM ANSI terminal display. It maintains a
  4.  * display buffer and descriptor for each virtual display, of which there
  5.  * can be many. All writes occur first into this display buffer, and then
  6.  * any particular display buffer can be copied onto the real screen.
  7.  * This allows many background tasks to run without blocking even though
  8.  * only one task's display is actually being shown.
  9.  *
  10.  * This display driver is substantially faster than even the NANSI.SYS
  11.  * loadable screen driver, particularly when large blocks are written.
  12.  *
  13.  * Extensions to handle displaying multiple small virtual windows should
  14.  * be pretty straightforward.
  15.  *
  16.  * Copyright 1992 Phil Karn, KA9Q
  17.  * 
  18.  */
  19. #include <conio.h>
  20. #include <string.h>
  21. #include <sys/stat.h>
  22. #include "global.h"
  23. #include "display.h"
  24. #include "proc.h"
  25. #define DCOL 67
  26. #define DSIZ (81-DCOL)
  27. uint8 fgattr[] = { 0, 4, 2, 14, 1, 5, 3, 7 }; /* Foreground attribs */
  28. uint8 bgattr[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* Background attribs */
  29. static void dclrscr(struct display *dp);
  30. static void desc(struct display *dp,uint8 c);
  31. static void darg(struct display *dp,uint8 c);
  32. static void dchar(struct display *dp,uint8 c);
  33. static void dclreol(struct display *dp,int row,int col);
  34. static void dattrib(struct display *dp,int val);
  35. static uint8 *bufloc(struct display *dp,int row,int col);
  36. static void dinsline(struct display *dp);
  37. static void ddelline(struct display *dp);
  38. static void ddelchar(struct display *dp);
  39. static void dinsert(struct display *dp);
  40. static void dclreod(struct display *dp,int row,int col);
  41. extern struct proc *Display;
  42. /* Create a new virtual display.
  43.  * The "noscrol" flag, if set, causes lines to "wrap around" from the bottom
  44.  * to the top of the screen instead of scrolling the entire screen upwards
  45.  * with each new line. This can be handy for packet trace screens.
  46.  */
  47. struct display *
  48. newdisplay(rows,cols,noscrol,sflimit)
  49. int rows,cols; /* Size of new screen. 0,0 defaults to whole screen */
  50. int noscrol; /* 1: old IBM-style wrapping instead of scrolling */
  51. int sflimit; /* Scrollback file size, lines */
  52. {
  53. struct display *dp;
  54. struct text_info text_info;
  55. int i;
  56. gettextinfo(&text_info);
  57. if(rows == 0)
  58. rows = text_info.screenheight;
  59. if(cols == 0)
  60. cols = text_info.screenwidth;
  61. dp = (struct display *)calloc(1,sizeof(struct display) +
  62.  2*rows*cols + rows*sizeof(struct dirty) + cols);
  63. dp->cookie = D_COOKIE;
  64. dp->buf = (uint8 *)(dp + 1);
  65. dp->dirty = (struct dirty *)(dp->buf + 2*rows*cols);
  66. dp->tabstops = (uint8 *)(dp->dirty + rows);
  67. dp->rows = rows;
  68. dp->cols = cols;
  69. /* Set default tabs every 8 columns */
  70. for(i=0;i<cols;i+= 8)
  71. dp->tabstops[i] = 1;
  72. /* Default scrolling region is all but last line of display,
  73.  * which is reserved for a status display
  74.  */
  75. dp->slast = rows - 2;
  76. dp->attrib = 0x7; /* White on black, no blink or intensity */
  77. dclrscr(dp); /* Start with a clean slate */
  78. dclreol(dp,rows-1,0); /* Clear status line too */
  79. dp->flags.dirty_cursor = 1;
  80. dp->flags.no_scroll = noscrol;
  81. if(sflimit != 0 && (dp->sfile = tmpfile()) == NULL)
  82. sflimit = 0; /* Out of handles? */
  83. dp->sflimit = sflimit;
  84. return dp;
  85. }
  86. /* Close a display - simply get rid of the memory */
  87. void
  88. closedisplay(dp)
  89. struct display *dp;
  90. {
  91. if(dp == NULL || dp->cookie != D_COOKIE)
  92. return;
  93. if(dp->sfile != NULL)
  94. fclose(dp->sfile);
  95. free(dp);
  96. }
  97. /* Write buffer to status line. Works independently of the ANSI
  98.  * machinery so as to not upset a possible escape sequence in
  99.  * progress. Maximum of one line allowed, no control sequences
  100.  */
  101. void
  102. statwrite(dp,col,buf,cnt,attrib)
  103. struct display *dp; /* Virtual screen pointer */
  104. int col; /* Starting column of write */
  105. void *buf; /* Data to be written */
  106. int cnt; /* Count */
  107. int attrib; /* Screen attribute to be used */
  108. {
  109. uint8 *buf1 = buf;
  110. uint8 *sp = bufloc(dp,dp->slast+1,col);
  111. struct dirty *dirtp = &dp->dirty[dp->slast+1];
  112. /* Clip debug area if activated */
  113. if(Kdebug && cnt > DCOL - col - 1)
  114. cnt = DCOL - col - 1;
  115. else if(cnt > dp->cols-col)
  116. cnt = dp->cols - col; /* Limit write to line length */
  117. while(cnt-- != 0){
  118. if(sp[0] != *buf1 || sp[1] != attrib){
  119. if(col < dirtp->lcol)
  120. dirtp->lcol = col; 
  121. if(col > dirtp->rcol)
  122. dirtp->rcol = col;
  123. sp[0] = *buf1;
  124. sp[1] = attrib;
  125. }
  126. buf1++;
  127. sp += 2;
  128. col++;
  129. }
  130. }
  131. /* Write data to the virtual display. Does NOT affect the real screen -
  132.  * dupdate(dp) must be called to copy the virtual screen to the real
  133.  * screen.
  134.  */
  135. void
  136. displaywrite(dp,buf,cnt)
  137. struct display *dp; /* Virtual screen pointer */
  138. void *buf; /* Data to be written */
  139. int cnt; /* Count */
  140. {
  141. uint8 c;
  142. char *bufp = buf;
  143. if(dp == NULL || dp->cookie != D_COOKIE)
  144. return;
  145. while(cnt-- != 0){
  146. c = *bufp++;
  147. switch(dp->state){
  148. case DISP_ESCAPE:
  149. desc(dp,c);
  150. break;
  151. case DISP_ARG:
  152. darg(dp,c);
  153. break;
  154. case DISP_NORMAL:
  155. dchar(dp,c);
  156. break;
  157. }
  158. }
  159. ksignal(dp,1);
  160. }
  161. /* Make the real screen look like the virtual one. It attempts to do as
  162.  * little work as possible unless the "dirty screen" flag is set -- then
  163.  * the entire screen is updated. (This is useful when switching between
  164.  * virtual display screens.)
  165.  *
  166.  * Note the different row and column numbering conventions -- I start
  167.  * at zero, the puttext() and gotoxy() library functions start at 1.
  168.  */
  169. void
  170. dupdate(dp)
  171. struct display *dp; /* Virtual screen pointer */
  172. {
  173. int row,rows;
  174. long sp;
  175. uint8 *lbuf;
  176. struct dirty *dirtp;
  177. long offset;
  178. if(dp == NULL || dp->cookie != D_COOKIE)
  179. return;
  180. offset = dp->flags.scrollbk ? dp->sfoffs : 0;
  181. if(offset > 0 && dp->flags.dirty_screen){
  182. /* Display from scrollback file */
  183. sp = dp->sfseek - 2*offset*dp->cols;
  184. if(sp < 0)
  185. sp += 2*dp->sfsize*dp->cols; /* Wrap back */
  186. rows = min(offset,dp->slast+1); /* # rows to read */
  187. lbuf = malloc(2*dp->cols*rows);
  188. fseek(dp->sfile,sp,SEEK_SET);
  189. /* row = actual # rows read */
  190. row = fread(lbuf,2*dp->cols,rows,dp->sfile);
  191. if(row != 0)
  192. puttext(1,1,dp->cols,row,lbuf);
  193. if(row != rows){
  194. /* Hit end of file; rewind and read the rest */
  195. fseek(dp->sfile,0L,SEEK_SET);
  196. fread(lbuf,2*dp->cols,rows-row,dp->sfile);
  197. puttext(1,row+1,dp->cols,rows,lbuf);
  198. }
  199. free(lbuf);
  200. }
  201. /* Display from memory image of current screen (if visible) */
  202. for(row = offset,dirtp = &dp->dirty[row];
  203.  row<=dp->slast;row++,dirtp++){
  204. if(dp->flags.dirty_screen){
  205. /* Force display of all columns */
  206. dirtp->lcol = 0;
  207. dirtp->rcol = dp->cols-1;
  208. }
  209. if(dirtp->lcol <= dirtp->rcol){
  210. puttext(dirtp->lcol+1,row+1,dirtp->rcol+1,row+1,
  211.  bufloc(dp,row-offset,dirtp->lcol));
  212. dirtp->lcol = dp->cols-1;
  213. dirtp->rcol = 0;
  214. }
  215. }
  216. /* Display unscrolled status region */
  217. for(row=dp->slast+1,dirtp = &dp->dirty[row];row<dp->rows;row++,dirtp++){
  218. if(dp->flags.dirty_screen){
  219. dirtp->lcol = 0;
  220. dirtp->rcol = dp->cols-1;
  221. }
  222. if(dirtp->lcol <= dirtp->rcol){
  223. puttext(dirtp->lcol+1,row+1,dirtp->rcol+1,row+1,
  224.  bufloc(dp,row,dirtp->lcol));
  225. dirtp->lcol = dp->cols-1;
  226. dirtp->rcol = 0;
  227. }
  228. }
  229. if(dp->flags.dirty_screen || (dp->flags.dirty_cursor)){
  230. /* Update cursor */
  231. if(dp->row+offset <= dp->slast){
  232. gotoxy(dp->col+1,dp->row+1+offset);
  233. _setcursortype(_NORMALCURSOR);
  234. } else {
  235. /* Turn off cursor entirely */
  236. _setcursortype(_NOCURSOR);
  237. }
  238. }
  239. dp->flags.dirty_cursor = 0;
  240. dp->flags.dirty_screen = 0;
  241. }
  242. void
  243. dscrollmode(dp,flag)
  244. struct display *dp;
  245. int flag;
  246. {
  247. if(dp == NULL || dp->cookie != D_COOKIE)
  248. return;
  249. if(flag != dp->flags.scrollbk){
  250. dp->flags.scrollbk = flag;
  251. if(dp->sfoffs != 0)
  252. dp->flags.dirty_screen = 1;
  253. alert(Display,1);
  254. }
  255. }
  256. void
  257. dhome(dp)
  258. struct display *dp;
  259. {
  260. if(dp == NULL || dp->cookie != D_COOKIE)
  261. return;
  262. if(dp->sfoffs != dp->sfsize){
  263. dp->sfoffs = dp->sfsize;
  264. dp->flags.dirty_screen = 1;
  265. alert(Display,1);
  266. }
  267. }
  268. void
  269. dend(dp)
  270. struct display *dp;
  271. {
  272. if(dp == NULL || dp->cookie != D_COOKIE)
  273. return;
  274. if(dp->sfoffs != 0){
  275. dp->sfoffs = 0;
  276. dp->flags.dirty_screen = 1;
  277. alert(Display,1);
  278. }
  279. }
  280. void
  281. dpgup(dp)
  282. struct display *dp;
  283. {
  284. long newoffs;
  285. if(dp == NULL || dp->cookie != D_COOKIE)
  286. return;
  287. newoffs = dp->sfoffs + dp->slast + 1;
  288. newoffs = min(newoffs,dp->sfsize);
  289. if(newoffs != dp->sfoffs){
  290. dp->sfoffs = newoffs;
  291. dp->flags.dirty_screen = 1;
  292. alert(Display,1);
  293. }
  294. }
  295. void
  296. dpgdown(dp)
  297. struct display *dp;
  298. {
  299. long newoffs;
  300. if(dp == NULL || dp->cookie != D_COOKIE)
  301. return;
  302. newoffs = dp->sfoffs - (dp->slast + 1);
  303. newoffs = max(0,newoffs);
  304. if(newoffs != dp->sfoffs){
  305. dp->sfoffs = newoffs;
  306. dp->flags.dirty_screen = 1; 
  307. alert(Display,1);
  308. }
  309. }
  310. void
  311. dcursup(dp)
  312. struct display *dp;
  313. {
  314. if(dp == NULL || dp->cookie != D_COOKIE)
  315. return;
  316. if(dp->sfoffs < dp->sfsize){
  317. dp->sfoffs++;
  318. dp->flags.dirty_screen = 1; 
  319. alert(Display,1);
  320. }
  321. }
  322. void
  323. dcursdown(dp)
  324. struct display *dp;
  325. {
  326. if(dp == NULL || dp->cookie != D_COOKIE)
  327. return;
  328. if(dp->sfoffs != 0){
  329. dp->sfoffs--;
  330. dp->flags.dirty_screen = 1; 
  331. alert(Display,1);
  332. }
  333. }
  334. /* Process incoming character while in ESCAPE state */
  335. static void
  336. desc(dp,c)
  337. struct display *dp;
  338. uint8 c;
  339. {
  340. int i;
  341. switch(c){
  342. case 'O':
  343. case '[': /* Always second char of ANSI escape sequence */
  344. /* Get ready for argument list */
  345. dp->state = DISP_ARG;
  346. dp->argi = 0;
  347. for(i=0;i<MAXARGS;i++)
  348. dp->arg[i] = 0;
  349. break;
  350. case '7': /* Save cursor location (VT-100) */
  351. dp->savcol = dp->col;
  352. dp->savrow = dp->row;
  353. dp->state = DISP_NORMAL;
  354. break;
  355. case '8': /* Restore cursor location (VT-100) */
  356. dp->col = dp->savcol;
  357. dp->row = dp->savrow;
  358. dp->flags.dirty_cursor = 1;
  359. dp->state = DISP_NORMAL;
  360. break;
  361. case ESC:
  362. break; /* Remain in ESCAPE state */
  363. case 'H': /* Set tab stop at current position (VT-100) */
  364. dp->tabstops[dp->col] = 1;
  365. break;
  366. default:
  367. dp->state = DISP_NORMAL;
  368. dchar(dp,c);
  369. }
  370. }
  371. /* Process characters after a ESC[ sequence */
  372. static void
  373. darg(dp,c)
  374. struct display *dp;
  375. uint8 c;
  376. {
  377. int i;
  378. switch(c){
  379. case ESC:
  380. dp->state = DISP_ESCAPE;
  381. return;
  382. case '?': /* Ignored */
  383. case '=':
  384. return;
  385. case '0':
  386. case '1':
  387. case '2':
  388. case '3':
  389. case '4':
  390. case '5':
  391. case '6':
  392. case '7':
  393. case '8':
  394. case '9':
  395. /* Collect decimal number */
  396. dp->arg[dp->argi] = 10*dp->arg[dp->argi] + (c - '0');
  397. return;
  398. case ';': /* Next argument is beginning */
  399. if(dp->argi <= MAXARGS - 1)
  400. dp->argi++;
  401. dp->arg[dp->argi] = 0;
  402. return;
  403. case '@': /* Open up space for character */
  404. dinsert(dp);
  405. break;
  406. case 'A': /* Cursor up */
  407. if(dp->arg[0] == 0)
  408. dp->arg[0] = 1; /* Default is one line */
  409. if(dp->arg[0] <= dp->row)
  410. dp->row -= dp->arg[0];
  411. else
  412. dp->row = 0;
  413. dp->flags.dirty_cursor = 1;
  414. break;
  415. case 'B': /* Cursor down */
  416. if(dp->arg[0] == 0)
  417. dp->arg[0] = 1; /* Default is one line */
  418. dp->row += dp->arg[0];
  419. if(dp->row > dp->slast)
  420. dp->row = dp->slast;
  421. dp->flags.dirty_cursor = 1; 
  422. break;
  423. case 'C': /* Cursor right */
  424. if(dp->arg[0] == 0)
  425. dp->arg[0] = 1; /* Default is one column */
  426. dp->col += dp->arg[0];
  427. if(dp->col >= dp->cols)
  428. dp->col = dp->cols - 1;
  429. dp->flags.dirty_cursor = 1;
  430. break;
  431. case 'D': /* Cursor left */
  432. if(dp->arg[0] == 0)
  433. dp->arg[0] = 1; /* Default is one column */
  434. if(dp->arg[0] <= dp->col)
  435. dp->col -= dp->arg[0];
  436. else
  437. dp->col = 0;
  438. dp->flags.dirty_cursor = 1;
  439. break;
  440. case 'f':
  441. case 'H': /* Cursor motion - limit to scrolled region */
  442. i = (dp->arg[0] == 0) ? 0 : dp->arg[0] - 1;
  443. if(i > dp->slast)
  444. i = dp->slast;
  445. dp->row = i;
  446. i = (dp->arg[1] == 0) ? 0 : dp->arg[1] - 1;
  447. if(i >= dp->cols)
  448. i = dp->cols - 1;
  449. dp->col = i;
  450. dp->state = DISP_NORMAL;
  451. dp->flags.dirty_cursor = 1;
  452. break;
  453. case 'h': /* Set mode */
  454. switch(dp->arg[0]){
  455. case 7: /* Turn on wrap mode */
  456. dp->flags.no_line_wrap = 0;
  457. break;
  458. }
  459. break;
  460. case 'J': /* Clear screen */
  461. switch(dp->arg[0]){
  462. case 2:
  463. dclrscr(dp); /* Clear entire screen, home cursor */
  464. break;
  465. case 0:
  466. dclreod(dp,dp->row,dp->col); /* Clear to end of screen (VT-100) */
  467. break;
  468. }
  469. break;
  470. case 'K': /* Erase to end of current line */
  471. dclreol(dp,dp->row,dp->col);
  472. break;
  473. case 'L': /* Add blank line */
  474. dinsline(dp);
  475. break;
  476. case 'l': /* Clear mode */
  477. switch(dp->arg[0]){
  478. case 7: /* Turn off wrap mode */
  479. dp->flags.no_line_wrap = 1;
  480. break;
  481. }
  482. break;
  483. case 'M': /* Delete line */
  484. ddelline(dp);
  485. break;
  486. case 'm': /* Set screen attributes */
  487. for(i=0;i<=dp->argi;i++){
  488. dattrib(dp,dp->arg[i]);
  489. }
  490. break;
  491. case 'P': /* Delete character */
  492. ddelchar(dp);
  493. break;
  494. case 's': /* Save cursor position */
  495. dp->savcol = dp->col;
  496. dp->savrow = dp->row;
  497. break;
  498. case 'u': /* Restore cursor position */
  499. dp->col = dp->savcol;
  500. dp->row = dp->savrow;
  501. dp->flags.dirty_cursor = 1;
  502. break;
  503. case 'g':
  504. switch(dp->arg[0]){
  505. case 0:
  506. dp->tabstops[dp->col] = 0;
  507. break;
  508. case 3:
  509. memset(dp->tabstops,0,dp->cols);
  510. break;
  511. }
  512. break;
  513. }
  514. dp->state = DISP_NORMAL;
  515. }
  516. /* Clear from specified location to end of screen, leaving cursor as is */
  517. static void
  518. dclreod(dp,row,col)
  519. struct display *dp;
  520. int row,col;
  521. {
  522. dclreol(dp,row,col); /* Clear current line */
  523. for(row = row + 1;row <= dp->slast;row++)
  524. dclreol(dp,row,0); /* Clear all lines below */
  525. }
  526. /* Insert space at cursor, moving all chars on right to right one position */
  527. static void
  528. dinsert(dp)
  529. struct display *dp;
  530. {
  531. int i = 2*(dp->cols - dp->col - 1);
  532. uint8 *cp = bufloc(dp,dp->row,dp->col);
  533. struct dirty *dirtp = &dp->dirty[dp->row];
  534. if(i != 0)
  535. memmove(cp+2,cp,i); /* handles overlapping blocks */
  536. *cp++ = ' ';
  537. *cp = dp->attrib;
  538. /* Dirty everything from the cursor to the right edge */
  539. if(dp->col < dirtp->lcol)
  540. dirtp->lcol = dp->col;
  541. dirtp->rcol = dp->cols-1;
  542. }
  543. /* Delete character at cursor, moving chars to right left one position */
  544. static void
  545. ddelchar(dp)
  546. struct display *dp;
  547. {
  548. uint8 *cp = bufloc(dp,dp->row,dp->col);
  549. int i = 2*(dp->cols-dp->col-1);
  550. struct dirty *dirtp = &dp->dirty[dp->row];
  551. /* Copy characters to right one space left */
  552. if(i != 0)
  553. memmove(cp,cp+2,i); /* memmove handles overlapping blocks */
  554. /* Clear right most character on line */
  555. cp[i] = ' ';
  556. cp[i+1] = dp->attrib;
  557. /* Dirty everything from the cursor to the right edge */
  558. if(dp->col < dirtp->lcol)
  559. dirtp->lcol = dp->col;
  560. dirtp->rcol = dp->cols-1;
  561. }
  562. /* Delete line containing cursor, moving lines below up one line */
  563. static void
  564. ddelline(dp)
  565. struct display *dp;
  566. {
  567. uint8 *cp1,*cp2;
  568. int row;
  569. struct dirty *dirtp;
  570. for(row=dp->row,dirtp = &dp->dirty[row];row < dp->slast;row++,dirtp++){
  571. cp1 = bufloc(dp,row,0);
  572. cp2 = bufloc(dp,row+1,0);
  573. memcpy(cp1,cp2,dp->cols*2);
  574. /* Dirty entire line */
  575. dirtp->lcol = 0;
  576. dirtp->rcol = dp->cols-1;
  577. }
  578. /* Clear bottom line */
  579. dclreol(dp,dp->slast,0);
  580. }
  581. /* Insert blank line where cursor is. Push existing lines down one */
  582. static void
  583. dinsline(dp)
  584. struct display *dp;
  585. {
  586. uint8 *cp1,*cp2;
  587. int row;
  588. struct dirty *dirtp;
  589. /* Copy lines down */
  590. for(row = dp->slast,dirtp = &dp->dirty[row];row > dp->row;row--){
  591. cp1 = bufloc(dp,row-1,0);
  592. cp2 = bufloc(dp,row,0);
  593. memcpy(cp2,cp1,2*dp->cols);
  594. /* Dirty entire line */
  595. dirtp->lcol = 0;
  596. dirtp->rcol = dp->cols-1;
  597. }
  598. /* Clear current line */
  599. dclreol(dp,dp->row,0);
  600. }
  601. /* Process an argument to an attribute set command */
  602. static void
  603. dattrib(dp,val)
  604. struct display *dp;
  605. int val;
  606. {
  607. switch(val){
  608. case 0: /* Normal white on black */
  609. dp->attrib = 0x7;
  610. break;
  611. case 1: /* High intensity */
  612. dp->attrib |= 0x8;
  613. break;
  614. case 5: /* Blink on */
  615. dp->attrib |= 0x80;
  616. break;
  617. case 7: /* Reverse video (black on white) */
  618. dp->attrib = 0x70;
  619. break;
  620. default:
  621. if(val >= 30 && val < 38){
  622. /* Set foreground color */
  623. dp->attrib = (dp->attrib & ~0x7) | fgattr[val - 30];
  624. } else if(val >= 40 && val < 48){
  625. /* Set background color */
  626. dp->attrib = (dp->attrib & ~0x70) | ((bgattr[val - 40]) << 4);
  627. }
  628. break;
  629. }
  630.  }
  631. /* Display character */
  632. static void
  633. dchar(dp,c)
  634. struct display *dp;
  635. uint8 c;
  636. {
  637. uint8 *cp;
  638. int row,rowchange;
  639. struct dirty *dirtp;
  640. rowchange = 0;
  641. switch(c){
  642. case ESC:
  643. dp->state = DISP_ESCAPE;
  644. return;
  645. case CTLQ: /*****/
  646. case '': /* Ignore nulls and bells */
  647. case BELL:
  648. break;
  649. case 'b': /* Backspace */
  650. if(dp->col > 0){
  651. dp->col--;
  652. dp->flags.dirty_cursor = 1;
  653. }
  654. break;
  655. case FF: /* Page feed */
  656. dclrscr(dp);
  657. break;
  658. case 't': /* Tab */
  659. while(dp->col < dp->cols-1){
  660. if(dp->tabstops[++dp->col])
  661. break;
  662. }
  663. dp->flags.dirty_cursor = 1;
  664. break;
  665. case 'n': /* Move cursor down one row */
  666. dp->row++;
  667. rowchange = 1;
  668. dp->flags.dirty_cursor = 1;
  669. break;
  670. case 'r': /* Move cursor to beginning of current row */
  671. dp->col = 0;
  672. dp->flags.dirty_cursor = 1;
  673. break;
  674. default: /* Display character on screen */
  675. /* Compute location in screen buffer memory */
  676. cp = bufloc(dp,dp->row,dp->col);
  677. /* Normal display */
  678. if(c != *cp || cp[1] != dp->attrib){
  679. dirtp = &dp->dirty[dp->row];
  680. if(dp->col < dirtp->lcol)
  681. dirtp->lcol = dp->col;
  682. if(dp->col > dirtp->rcol)
  683. dirtp->rcol = dp->col;
  684. }
  685. *cp++ = c;
  686. *cp = dp->attrib;
  687. dp->flags.dirty_cursor = 1;
  688. /* Update cursor position, wrapping if necessary */
  689. if(++dp->col == dp->cols){
  690. if(dp->flags.no_line_wrap){
  691. dp->col--;
  692. } else {
  693. dp->col = 0;
  694. dp->row++;
  695. rowchange = 1;
  696. }
  697. }
  698. }
  699. /* Scroll screen if necessary */
  700. if(rowchange && dp->row > dp->slast){
  701. dp->row--;
  702. /* Scroll screen up */
  703. dp->scroll = (dp->scroll + 1) % (dp->slast + 1);
  704. if(!dp->flags.no_scroll){
  705. for(row=0,dirtp=&dp->dirty[row];row <=dp->slast;row++,dirtp++){
  706. dirtp->lcol = 0;
  707. dirtp->rcol = dp->cols-1;
  708. }
  709. }
  710. if(dp->sfile != NULL){
  711. uint8 *cp;
  712. /* When scrolled back, leave screen stationary */
  713. if(dp->flags.scrollbk && dp->sfoffs != dp->sflimit)
  714. dp->sfoffs++;
  715. /* Copy scrolled line to scrollback file */
  716. cp = bufloc(dp,dp->row,0);
  717. fseek(dp->sfile,dp->sfseek,SEEK_SET);
  718. fwrite(cp,2,dp->cols,dp->sfile);
  719. dp->sfseek += 2*dp->cols;
  720. if(dp->sfseek >= 2*dp->cols*dp->sflimit)
  721. dp->sfseek = 0;
  722. if(dp->sfsize < dp->sflimit)
  723. dp->sfsize++;
  724. }
  725. dclreol(dp,dp->row,0);
  726. }
  727. }
  728. /* Clear from specified location to end of line. Cursor is not moved */
  729. static void
  730. dclreol(dp,row,col)
  731. struct display *dp;
  732. int row,col;
  733. {
  734. uint8 *cp = bufloc(dp,row,col);
  735. struct dirty *dirtp = &dp->dirty[row];
  736. int i;
  737. for(i=dp->cols - col;i!=0;i--){
  738. *cp++ = ' ';
  739. *cp++ = dp->attrib;
  740. }
  741. /* Dirty from current column to right edge */
  742. if(col < dirtp->lcol)
  743. dirtp->lcol = col;
  744. dirtp->rcol = dp->cols-1;
  745. }
  746. /* Move cursor to top left corner, clear screen */
  747. static void
  748. dclrscr(dp)
  749. struct display *dp;
  750. {
  751. dclreod(dp,0,0);
  752. dp->row = dp->col = 0;
  753. dp->scroll = 0;
  754. dp->flags.dirty_cursor = 1;
  755. }
  756. /* Return pointer into screen buffer for specified cursor location.
  757.  * Not guaranteed to be valid past the end of the current line due to
  758.  * scrolling
  759.  */
  760. static uint8 *
  761. bufloc(dp,row,col)
  762. struct display *dp;
  763. int row,col;
  764. {
  765. #ifndef notdef
  766. if(row < 0 || row >= dp->rows || col < 0 || col >= dp->cols){
  767. stktrace();
  768. cprintf("panic: bufloc(%p,%d,%d)n",dp,row,col);
  769. exit(1);
  770. }
  771. #endif
  772. if(row <= dp->slast)
  773. row = (row + dp->scroll) % (dp->slast + 1);
  774. return dp->buf + 2*(col + dp->cols*row);
  775. }
  776. /* Immediately display short debug string on lower right corner of display */
  777. void
  778. debug(s)
  779. char *s;
  780. {
  781. int i;
  782. static uint8 msg[2*DSIZ];
  783. if(msg[1] != 0x7){
  784. /* One time initialization to blanks with white-on-black */
  785. for(i=0;i<DSIZ;i++){
  786. msg[2*i] = ' ';
  787. msg[2*i+1] = 0x7;
  788. }
  789. }
  790. if(s == NULL)
  791. return;
  792. for(i=0;i<DSIZ && *s != '';i++)
  793. msg[2*i] = (uint8) *s++;
  794. for(;i<DSIZ;i++)
  795. msg[2*i] = ' ';
  796. puttext(DCOL,25,80,25,msg);
  797. }