|
|
1.1 ! root 1: /* ! 2: * The functions in this file handle redisplay. ! 3: * There are two halves, the ones that update the virtual display screen, ! 4: * and the ones that make the physical display screen the same as the virtual ! 5: * display screen. These functions use hints that are left in the windows by ! 6: * the commands. ! 7: */ ! 8: #include <stdio.h> ! 9: #include "ed.h" ! 10: ! 11: #define WFDEBUG 0 /* Window flag debug. */ ! 12: #define FASTHACK 1 /* Slightly faster update code */ ! 13: ! 14: typedef struct VIDEO { ! 15: short v_flag; /* Flags */ ! 16: uchar v_text[]; /* Screen data. */ ! 17: } VIDEO; ! 18: ! 19: #define VFCHG 0x0001 /* Changed. */ ! 20: #define VFSTD 0x0002 /* Standout. */ ! 21: ! 22: int sgarbf = TRUE; /* TRUE if screen is garbage */ ! 23: int mpresf = FALSE; /* TRUE if message in last line */ ! 24: int vtrow = 0; /* Row location of SW cursor */ ! 25: int vtcol = 0; /* Column location of SW cursor */ ! 26: int ttrow = HUGE; /* Row location of HW cursor */ ! 27: int ttcol = HUGE; /* Column location of HW cursor */ ! 28: VIDEO **vscreen; /* Virtual screen. */ ! 29: VIDEO **pscreen; /* Physical screen. */ ! 30: ! 31: /* ! 32: * Initialize the data structures used by the display code. ! 33: * The edge vectors used to access the screens are set up. ! 34: * The operating system's terminal I/O channel is set up. ! 35: * All the other things get initialized at compile time. ! 36: * The original window has "WFCHG" set, so that it will get ! 37: * completely redrawn on the first call to "update". ! 38: */ ! 39: vtinit() ! 40: { ! 41: register int i; ! 42: register VIDEO *vp; ! 43: ! 44: vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); ! 45: if (vscreen == NULL) ! 46: abort(); ! 47: pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); ! 48: if (pscreen == NULL) ! 49: abort(); ! 50: for (i=0; i<term.t_nrow; ++i) { ! 51: vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol); ! 52: if (vp == NULL) ! 53: abort(); ! 54: vscreen[i] = vp; ! 55: vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol); ! 56: if (vp == NULL) ! 57: abort(); ! 58: pscreen[i] = vp; ! 59: } ! 60: } ! 61: ! 62: /* ! 63: * Clean up the virtual terminal system, in anticipation for a return to the ! 64: * operating system. Move down to the last line and clear it out (the next ! 65: * system prompt will be written in the line). Shut down the channel to the ! 66: * terminal. ! 67: */ ! 68: vttidy() ! 69: { ! 70: movecursor(term.t_nrow, 0); ! 71: teeol(); ! 72: tstand(0); ! 73: tclose(); ! 74: } ! 75: ! 76: /* ! 77: * Set the virtual cursor to the specified row and column on the ! 78: * virtual screen. There is no checking for nonsense values; this might ! 79: * be a good idea during the early stages. ! 80: */ ! 81: vtmove(row, col) ! 82: { ! 83: vtrow = row; ! 84: vtcol = col; ! 85: } ! 86: ! 87: /* ! 88: * If bind.dispmode == 1 chars < ' ' are displayed directly ! 89: * else they are displayed whit preceeding ^ and ^= '@' ! 90: */ ! 91: displaymod() ! 92: { ! 93: bind.dispmode ^= 1; ! 94: } ! 95: ! 96: /* ! 97: * Return 2 if char is tab 1 if it needs ^ for ansi emulation. ! 98: */ ! 99: dblchr(c) ! 100: register unsigned c; ! 101: { ! 102: if (bind.dispmode) { ! 103: switch(c) { ! 104: case '\n': ! 105: case '\f': ! 106: case '\r': ! 107: case 0x1b: ! 108: return (1); ! 109: case '\t': ! 110: return (2); ! 111: } ! 112: return (0); ! 113: } ! 114: return (((c < ' ') || (c == 0x7f)) ? ((c == '\t') ? 2 : 1) : 0); ! 115: } ! 116: ! 117: /* ! 118: * Write a character to the virtual screen. The virtual row and ! 119: * column are updated. If the line is too long put a "$" in the last column. ! 120: * This routine only puts printing characters into the virtual terminal buffers. ! 121: * Only column overflow is checked. ! 122: */ ! 123: vtputc(c) ! 124: unsigned c; ! 125: { ! 126: register VIDEO *vp; ! 127: ! 128: vp = vscreen[vtrow]; ! 129: switch (dblchr(c)) { ! 130: case 0: /* normal character */ ! 131: if (vtcol >= term.t_ncol) ! 132: vp->v_text[term.t_ncol - 1] = '$'; ! 133: else ! 134: vp->v_text[vtcol++] = c; ! 135: break; ! 136: case 2: /* tab */ ! 137: do { ! 138: if (vtcol >= term.t_ncol) { ! 139: vp->v_text[term.t_ncol - 1] = '$'; ! 140: break; ! 141: } else ! 142: vp->v_text[vtcol++] = ' '; ! 143: } while (vtcol % bind.tabsiz); ! 144: break; ! 145: case 1: /* needs ^ */ ! 146: vtputc('^'); ! 147: vtputc(c ^ 0x40); ! 148: break; ! 149: } ! 150: } ! 151: ! 152: /* ! 153: * Erase from the end of the software cursor to the end of the line on which ! 154: * the software cursor is located. ! 155: */ ! 156: vteeol() ! 157: { ! 158: register VIDEO *vp; ! 159: ! 160: vp = vscreen[vtrow]; ! 161: while (vtcol < term.t_ncol) ! 162: vp->v_text[vtcol++] = ' '; ! 163: } ! 164: ! 165: /* ! 166: * Make sure that the display is right. This is a three part process. ! 167: * First, scan through all of the windows looking for dirty ones. ! 168: * Check the framing, and refresh the screen. ! 169: * Second, make sure that "currow" and "curcol" are correct for the current ! 170: * window. ! 171: * Third, make the virtual and physical screens the same. ! 172: */ ! 173: update() ! 174: { ! 175: register LINE *lp; ! 176: LINE *xlp; ! 177: register WINDOW *wp; ! 178: register VIDEO *vp1; ! 179: register VIDEO *vp2; ! 180: register int i; ! 181: register int j; ! 182: ! 183: wp = wheadp; ! 184: while (wp != NULL) { ! 185: /* Look at any window with update flags set on. */ ! 186: if (wp->w_flag != 0) { ! 187: /* If not force reframe, check the framing. */ ! 188: if ((wp->w_flag&WFFORCE) == 0) { ! 189: lp = wp->w_linep; ! 190: for (i=0; i<wp->w_ntrows; ++i) { ! 191: if (lp == wp->w_dotp) ! 192: goto out; ! 193: if (lp == wp->w_bufp->b_linep) ! 194: break; ! 195: lp = lforw(lp); ! 196: } ! 197: } ! 198: /* Not acceptable, better compute a new value */ ! 199: /* for the line at the top of the window. Then */ ! 200: /* set the "WFHARD" flag to force full redraw. */ ! 201: i = wp->w_force; ! 202: if (i > 0) { ! 203: --i; ! 204: if (i >= wp->w_ntrows) ! 205: i = wp->w_ntrows-1; ! 206: } else if (i < 0) { ! 207: i += wp->w_ntrows; ! 208: if (i < 0) ! 209: i = 0; ! 210: } else ! 211: i = wp->w_ntrows/2; ! 212: lp = wp->w_dotp; ! 213: while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) { ! 214: --i; ! 215: lp = lback(lp); ! 216: } ! 217: wp->w_linep = lp; ! 218: wp->w_flag |= WFHARD; /* Force full. */ ! 219: out: ! 220: /* Try to use reduced update. Mode line update */ ! 221: /* has its own special flag. The fast update is */ ! 222: /* used if the only thing to do is within the */ ! 223: /* line editing. */ ! 224: lp = wp->w_linep; ! 225: i = wp->w_toprow; ! 226: if ((wp->w_flag&~WFMODE) == WFEDIT) { ! 227: while (lp != wp->w_dotp) { ! 228: ++i; ! 229: lp = lforw(lp); ! 230: } ! 231: #ifdef FASTHACK ! 232: vscreen[i]->v_flag = VFCHG; ! 233: #else ! 234: vscreen[i]->v_flag |= VFCHG; ! 235: vscreen[i]->v_flag &= ~VFSTD; ! 236: #endif ! 237: vtmove(i, 0); ! 238: for (j=0; j<llength(lp); ++j) ! 239: vtputc(lgetc(lp, j)); ! 240: vteeol(); ! 241: } else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) { ! 242: while (i < wp->w_toprow+wp->w_ntrows) { ! 243: #ifdef FASTHACK ! 244: vscreen[i]->v_flag = VFCHG; ! 245: #else ! 246: vscreen[i]->v_flag |= VFCHG; ! 247: vscreen[i]->v_flag &= ~VFSTD; ! 248: #endif ! 249: vtmove(i, 0); ! 250: if (lp != wp->w_bufp->b_linep) { ! 251: for (j=0; j<llength(lp); ++j) ! 252: vtputc(lgetc(lp, j)); ! 253: lp = lforw(lp); ! 254: } ! 255: vteeol(); ! 256: ++i; ! 257: } ! 258: } ! 259: #if !WFDEBUG ! 260: if ((wp->w_flag&WFMODE) != 0) ! 261: modeline(wp); ! 262: wp->w_flag = 0; ! 263: wp->w_force = 0; ! 264: #endif ! 265: } ! 266: #if WFDEBUG ! 267: modeline(wp); ! 268: wp->w_flag = 0; ! 269: wp->w_force = 0; ! 270: #endif ! 271: /* Set standout mode on status line... */ ! 272: vscreen[wp->w_toprow+wp->w_ntrows]->v_flag |= VFSTD; ! 273: wp = wp->w_wndp; ! 274: } ! 275: /* Always recompute the row and column number of the hardware */ ! 276: /* cursor. This is the only update for simple moves. */ ! 277: xlp = lp = curwp->w_linep; ! 278: currow = curwp->w_toprow; ! 279: while (lp != curwp->w_dotp) { ! 280: ++currow; ! 281: if (xlp == (lp = lforw(lp))) { /* Fix infinite loop problem */ ! 282: currow = curwp->w_toprow; ! 283: curwp->w_dotp = lp = xlp; ! 284: curwp->w_doto = 0; ! 285: break; ! 286: } ! 287: } ! 288: curcol = truecol(lp, curwp->w_doto); ! 289: ! 290: #if GEM && NATIVE ! 291: /* Special preparation for screen update on ATARI ST native screen */ ! 292: /* We shut off the cursor -- This speeds up the writing of text */ ! 293: /* quite a bit. */ ! 294: ! 295: astcursor(0); /* Turn cursor off for update */ ! 296: #endif ! 297: ! 298: /* Special hacking if the screen is garbage. Clear the hardware */ ! 299: /* screen, and update your copy to agree with it. Set all the */ ! 300: /* virtual screen change bits, to force a full update. */ ! 301: ! 302: if (sgarbf != FALSE) { ! 303: for (i=0; i<term.t_nrow; ++i) { ! 304: vscreen[i]->v_flag |= VFCHG; ! 305: vp1 = pscreen[i]; ! 306: for (j=0; j<term.t_ncol; ++j) ! 307: vp1->v_text[j] = ' '; ! 308: } ! 309: teeop(); /* Erase the screen. */ ! 310: sgarbf = FALSE; /* Erase-page clears */ ! 311: mpresf = FALSE; /* the message area. */ ! 312: } ! 313: ! 314: /* Make sure that the physical and virtual displays agree. */ ! 315: /* Unlike before, the "updateline" code is only called with a */ ! 316: /* line that has been updated for sure. */ ! 317: ! 318: for (i=0; i<term.t_nrow; ++i) { ! 319: vp1 = vscreen[i]; ! 320: if ((vp1->v_flag&VFCHG) != 0) { ! 321: vp2 = pscreen[i]; ! 322: if ((vp1->v_flag&VFSTD) != 0) { /* Standout mode */ ! 323: #ifndef FASTHACK ! 324: vp1->v_flag &= ~VFSTD; ! 325: #endif ! 326: tstand(1); ! 327: updateline(i, &vp1->v_text[0], &vp2->v_text[0]); ! 328: tstand(0); ! 329: } else ! 330: updateline(i, &vp1->v_text[0], &vp2->v_text[0]); ! 331: #ifdef FASTHACK ! 332: vp1->v_flag = 0; ! 333: #else ! 334: vp1->v_flag &= ~VFCHG; ! 335: #endif ! 336: } ! 337: } ! 338: /* Finally, update the hardware cursor and flush out buffers. */ ! 339: bracketmode(currow, curcol); ! 340: #if GEM && NATIVE ! 341: astcursor(1); /* Turn cursor back on... */ ! 342: #endif ! 343: tflush(); ! 344: } ! 345: ! 346: /* ! 347: * Update a single line. This does not know how to use insert or delete ! 348: * character sequences; we are using VT52 functionality. Update the physical ! 349: * row and column variables. It does try and exploit erase to end of line. ! 350: * The RAINBOW version of this routine uses fast video. ! 351: */ ! 352: updateline(row, vline, pline) ! 353: uchar vline[]; ! 354: uchar pline[]; ! 355: { ! 356: #if RAINBOW|IBM ! 357: register uchar *cp1; ! 358: register uchar *cp2; ! 359: register int nch; ! 360: ! 361: cp1 = &vline[0]; /* Use fast video. */ ! 362: cp2 = &pline[0]; ! 363: putline(row+1, 1, cp1); ! 364: nch = term.t_ncol; ! 365: do { ! 366: *cp2 = *cp1; ! 367: ++cp2; ! 368: ++cp1; ! 369: } while (--nch); ! 370: #else ! 371: register uchar *cp1; ! 372: register uchar *cp2; ! 373: register uchar *cp3; ! 374: register uchar *cp4; ! 375: register uchar *cp5; ! 376: register int nbflag; ! 377: ! 378: cp1 = &vline[0]; /* Compute left match. */ ! 379: cp2 = &pline[0]; ! 380: while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) { ! 381: ++cp1; ! 382: ++cp2; ! 383: } ! 384: /* This can still happen, even though we only call this routine */ ! 385: /* on changed lines. A hard update is always done when a line */ ! 386: /* splits, a massive change is done, or a buffer is displayed */ ! 387: /* twice. This optimizes out most of the excess updating. A lot */ ! 388: /* of computes are used, but these tend to be hard operations */ ! 389: /* that do a lot of update, so I don't really care. */ ! 390: if (cp1 == &vline[term.t_ncol]) /* All equal. */ ! 391: return; ! 392: nbflag = FALSE; ! 393: cp3 = &vline[term.t_ncol]; /* Compute right match. */ ! 394: cp4 = &pline[term.t_ncol]; ! 395: while (cp3[-1] == cp4[-1]) { ! 396: --cp3; ! 397: --cp4; ! 398: if (cp3[0] != ' ') /* Note if any nonblank */ ! 399: nbflag = TRUE; /* in right match. */ ! 400: } ! 401: cp5 = cp3; ! 402: if (nbflag == FALSE) { /* Erase to EOL ? */ ! 403: while (cp5!=cp1 && cp5[-1]==' ') ! 404: --cp5; ! 405: if (cp3-cp5 <= 3) /* Use only if erase is */ ! 406: cp5 = cp3; /* fewer characters. */ ! 407: } ! 408: movecursor(row, (int)(cp1-&vline[0])); /* Go to start of line. */ ! 409: while (cp1 != cp5) { /* Ordinary. */ ! 410: tputc(*cp1); ! 411: ++ttcol; ! 412: *cp2++ = *cp1++; ! 413: } ! 414: if (cp5 != cp3) { /* Erase. */ ! 415: teeol(); ! 416: while (cp1 != cp3) ! 417: *cp2++ = *cp1++; ! 418: } ! 419: #endif ! 420: } ! 421: ! 422: /* ! 423: * Redisplay the mode line for the window pointed to by the "wp". ! 424: * This is the only routine that has any idea of how the modeline is formatted. ! 425: * You can change the modeline format by hacking at this routine. ! 426: * Called by "update" any time there is a dirty window. ! 427: */ ! 428: modeline(wp) ! 429: register WINDOW *wp; ! 430: { ! 431: register uchar *cp; ! 432: register int c; ! 433: register int n; ! 434: register BUFFER *bp; ! 435: ! 436: n = wp->w_toprow+wp->w_ntrows; /* Location. */ ! 437: vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */ ! 438: vtmove(n, 0); /* Seek to right line. */ ! 439: vtputc('-'); ! 440: bp = wp->w_bufp; ! 441: if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */ ! 442: vtputc('*'); ! 443: else ! 444: vtputc('-'); ! 445: n = 2; ! 446: cp = PROMPT; /* Buffer name. */ ! 447: while ((c = *cp++) != 0) { ! 448: vtputc(c); ! 449: ++n; ! 450: } ! 451: cp = &bp->b_bname[0]; ! 452: while ((c = *cp++) != 0) { ! 453: vtputc(c); ! 454: ++n; ! 455: } ! 456: vtputc(' '); ! 457: ++n; ! 458: if (bp->b_fname[0] != 0) { /* File name. */ ! 459: #if LIBHELP ! 460: if (bp->b_flag & BFHELP) ! 461: cp = "- Subject: "; ! 462: else ! 463: #endif ! 464: cp = "-- File: "; ! 465: while ((c = *cp++) != 0) { ! 466: vtputc(c); ! 467: ++n; ! 468: } ! 469: cp = &bp->b_fname[0]; ! 470: while ((c = *cp++) != 0) { ! 471: vtputc(c); ! 472: ++n; ! 473: } ! 474: vtputc(' '); ! 475: ++n; ! 476: } ! 477: #if WFDEBUG ! 478: vtputc('-'); ! 479: vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : '-'); ! 480: vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : '-'); ! 481: vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : '-'); ! 482: vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : '-'); ! 483: vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-'); ! 484: n += 6; ! 485: #endif ! 486: while (n < term.t_ncol) { /* Pad to full width. */ ! 487: vtputc('-'); ! 488: ++n; ! 489: } ! 490: } ! 491: ! 492: /* ! 493: * Send a command to the terminal to move the hardware cursor to row "row" ! 494: * and column "col". The row and column arguments are origin 0. ! 495: * Optimize out random calls. Update "ttrow" and "ttcol". ! 496: */ ! 497: movecursor(row, col) ! 498: { ! 499: if (row!=ttrow || col!=ttcol) { ! 500: ttrow = row; ! 501: ttcol = col; ! 502: tmove(row, col); ! 503: } ! 504: } ! 505: ! 506: /* ! 507: * Erase the message line. ! 508: * This is a special routine because the message line is not considered to be ! 509: * part of the virtual screen. It always works immediately; the terminal ! 510: * buffer is flushed via a call to the flusher. ! 511: */ ! 512: mlerase() ! 513: { ! 514: movecursor(term.t_nrow, 0); ! 515: teeol(); ! 516: tflush(); ! 517: mpresf = FALSE; ! 518: } ! 519: ! 520: /* ! 521: * Ask a yes or no question in the message line. ! 522: * Return either TRUE, FALSE, or ABORT. The ABORT status is returned ! 523: * if the user bumps out of the question with a ^G. ! 524: * Used any time a confirmation is required. ! 525: */ ! 526: mlyesno(prompt) ! 527: uchar *prompt; ! 528: { ! 529: register int s; ! 530: uchar buf[64]; ! 531: ! 532: for (;;) { ! 533: strcpy(buf, prompt); ! 534: strcat(buf, " [y/n]? "); ! 535: s = mlreply(buf, buf, sizeof(buf)); ! 536: if (s == ABORT) ! 537: return (ABORT); ! 538: if (s != FALSE) { ! 539: if (buf[0]=='y' || buf[0]=='Y') ! 540: return (TRUE); ! 541: if (buf[0]=='n' || buf[0]=='N') ! 542: return (FALSE); ! 543: } ! 544: } ! 545: } ! 546: ! 547: /* ! 548: * Write a prompt into the message line, then read back a response. ! 549: * Keep track of the physical position of the cursor. ! 550: * If we are in a keyboard macro throw the prompt away, and return ! 551: * the remembered response. This lets macros run at full speed. ! 552: * The reply is always terminated by a carriage return. ! 553: * Handle erase, kill, and abort keys. ! 554: */ ! 555: mlreply(prompt, buf, nbuf) ! 556: uchar *prompt; ! 557: uchar *buf; ! 558: { ! 559: register int cpos; ! 560: register int i; ! 561: register int c; ! 562: ! 563: cpos = 0; ! 564: if (kbdmop != NULL) { ! 565: while ((c = *kbdmop++) != '\0') ! 566: buf[cpos++] = c; ! 567: buf[cpos] = 0; ! 568: if (buf[0] == 0) ! 569: return (FALSE); ! 570: return (TRUE); ! 571: } ! 572: mlwrite(prompt); ! 573: for (;;) { ! 574: c = tgetc(); ! 575: switch (c) { ! 576: case 0x0D: /* Return, end of line */ ! 577: buf[cpos++] = 0; ! 578: if (kbdmip != NULL) { ! 579: if ((kbdmip+cpos) > (kbdm + ((NKBDM - 3)/2))) { ! 580: ctrlg(FALSE, 0); ! 581: tflush(); ! 582: return (ABORT); ! 583: } ! 584: for (i=0; i<cpos; ++i) ! 585: *kbdmip++ = buf[i]; ! 586: } ! 587: tputc('\r'); ! 588: ttcol = 0; ! 589: tflush(); ! 590: if (buf[0] == 0) ! 591: return (FALSE); ! 592: return (TRUE); ! 593: ! 594: case 0x07: /* Bell, abort */ ! 595: tputc('^'); ! 596: tputc('G'); ! 597: ttcol += 2; ! 598: ctrlg(FALSE, 0); ! 599: tflush(); ! 600: return (ABORT); ! 601: ! 602: case 0x7f: /* Rubout, erase */ ! 603: case 0x08: /* Backspace, erase */ ! 604: if (cpos != 0) { ! 605: tputc('\b'); ! 606: tputc(' '); ! 607: tputc('\b'); ! 608: --ttcol; ! 609: if (buf[--cpos] < 0x20) { ! 610: tputc('\b'); ! 611: tputc(' '); ! 612: tputc('\b'); ! 613: --ttcol; ! 614: } ! 615: tflush(); ! 616: } ! 617: break; ! 618: ! 619: case 0x15: /* C-U, kill */ ! 620: while (cpos != 0) { ! 621: tputc('\b'); ! 622: tputc(' '); ! 623: tputc('\b'); ! 624: --ttcol; ! 625: if (buf[--cpos] < 0x20) { ! 626: tputc('\b'); ! 627: tputc(' '); ! 628: tputc('\b'); ! 629: --ttcol; ! 630: } ! 631: } ! 632: tflush(); ! 633: break; ! 634: ! 635: default: ! 636: if (cpos < nbuf-1) { ! 637: buf[cpos++] = c; ! 638: if (c < ' ') { ! 639: tputc('^'); ! 640: ++ttcol; ! 641: c ^= 0x40; ! 642: } ! 643: tputc(c); ! 644: ++ttcol; ! 645: tflush(); ! 646: } ! 647: } ! 648: } ! 649: } ! 650: ! 651: /* ! 652: * Write a message into the message line. ! 653: * Keep track of the physical cursor position. ! 654: * A small class of printf like format items is handled. ! 655: * Assumes the stack grows down; this assumption is made by the "++" ! 656: * in the argument scan loop. Set the "message line" flag TRUE. ! 657: */ ! 658: mlwrite(fmt) ! 659: uchar *fmt; ! 660: { ! 661: register int c; ! 662: ! 663: uchar buf[NPAT * 2]; ! 664: ! 665: movecursor(term.t_nrow, 0); ! 666: sprintf(buf, "%r", &fmt); ! 667: if (strlen(buf) > (term.t_ncol - 1)) ! 668: buf[term.t_ncol - 1] = 0; ! 669: for (fmt = buf; c = *fmt; fmt++) { ! 670: tputc(c); ! 671: ++ttcol; ! 672: } ! 673: teeol(); ! 674: tflush(); ! 675: mpresf = TRUE; ! 676: } ! 677: ! 678: /* ! 679: * Write out a string. ! 680: * Update the physical cursor position. This assumes that the characters in the ! 681: * string all have width "1"; if this is not the case things will get screwed up ! 682: * a little. ! 683: */ ! 684: mlputs(s) ! 685: register uchar *s; ! 686: { ! 687: register int c; ! 688: ! 689: while ((c = *s++) != 0) { ! 690: tputc(c); ! 691: ++ttcol; ! 692: } ! 693: } ! 694: ! 695: /* ! 696: * find the logical cursor. Return line from top of ! 697: * window. ! 698: */ ! 699: locatecursor(what) ! 700: LINE *what; ! 701: { ! 702: int row; ! 703: LINE *clp; ! 704: ! 705: row = 0; ! 706: for (clp = curwp->w_linep; clp != what; clp = lforw(clp)) { ! 707: if ((clp == curbp->b_linep) || (row > curwp->w_ntrows)) ! 708: return (-1); ! 709: row++; ! 710: } ! 711: return (row + curwp->w_toprow); ! 712: } ! 713: ! 714: /* ! 715: * turn LINE and char pointer into display col. ! 716: */ ! 717: truecol(clp, col) ! 718: LINE *clp; ! 719: { ! 720: register int i, tcol; ! 721: unsigned c; ! 722: ! 723: for (i = tcol = 0; i < col; i++) { ! 724: c = lgetc(clp, i); ! 725: switch (dblchr(c)) { ! 726: case 2: ! 727: taber(tcol); ! 728: break; ! 729: case 1: ! 730: tcol++; ! 731: } ! 732: tcol++; ! 733: } ! 734: if (tcol >= term.t_ncol) /* too far out */ ! 735: tcol = term.t_ncol - 1; ! 736: return (tcol); ! 737: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.