home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / zle_refresh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  16.6 KB  |  770 lines

  1. /*
  2.  *
  3.  * zle_refresh.c - screen update
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #define ZLE
  22. #include "zsh.h"
  23.  
  24. char **obuf = NULL, **nbuf = NULL;
  25. static int olnct, vcs, vln, vmaxln, winw, winh, winpos, ovln;
  26.  
  27. void resetvideo()
  28. {                /**/
  29.     int ln;
  30.     static int lwinw = -1, lwinh = -1;
  31.  
  32.     winw = columns;
  33.     if (isset(SINGLELINEZLE) || !termok)
  34.     winh = 1;
  35.     else
  36.     winh = (lines < 2) ? 24 : lines;
  37.     winpos = vln = vmaxln = 0;
  38.     if (lwinw != winw || lwinh != winh) {
  39.     if (nbuf) {
  40.         for (ln = 0; ln != lwinh; ln++) {
  41.         zfree(nbuf[ln], winw + 1);
  42.         zfree(obuf[ln], winw + 1);
  43.         }
  44.         free(nbuf);
  45.         free(obuf);
  46.     }
  47.     nbuf = (char **)zcalloc((winh + 1) * sizeof(char *));
  48.     obuf = (char **)zcalloc((winh + 1) * sizeof(char *));
  49.  
  50.     nbuf[0] = (char *)zalloc(winw + 1);
  51.     obuf[0] = (char *)zalloc(winw + 1);
  52.  
  53.     lwinw = winw;
  54.     lwinh = winh;
  55.     }
  56.     for (ln = 0; ln != winh + 1; ln++) {
  57.     if (nbuf[ln])
  58.         *nbuf[ln] = '\0';
  59.     if (obuf[ln])
  60.         *obuf[ln] = '\0';
  61.     }
  62.  
  63.     if (pptlen) {
  64.     for (ln = 0; ln != pptlen; ln++)
  65.         nbuf[0][ln] = obuf[0][ln] = ' ';
  66.     nbuf[0][pptlen] = obuf[0][pptlen] = '\0';
  67.     }
  68.     vcs = pptlen;
  69.     olnct = nlnct = 1;
  70. }
  71.  
  72. int scrollwindow()
  73. {                /**/
  74.     int t0, hwinh = winh / 2;
  75.  
  76.     for (t0 = 0; t0 != winh - hwinh; t0++) {
  77.     char *s;
  78.  
  79.     s = nbuf[t0];
  80.     nbuf[t0] = nbuf[t0 + hwinh];
  81.     nbuf[t0 + hwinh] = s;
  82.     }
  83.     for (t0 = 0; t0 < pptlen - 1; t0++)
  84.     nbuf[0][t0] = ' ';
  85.     strcpy(nbuf[0] + t0, "> ...");
  86.     return winh - hwinh;
  87. }
  88.  
  89. /* this is the messy part. */
  90. /* this define belongs where it's used!!! */
  91.  
  92. #define nextline { *s = (unsigned char)'\0'; \
  93.     if (winh == ln+1) if (nvln != -1) break; else ln = scrollwindow()-1; \
  94.     if (!nbuf[++ln]) nbuf[ln] = (char *)zalloc(winw + 1); \
  95.     s = (unsigned char *)nbuf[ln]; sen = s+winw; \
  96.     }
  97.  
  98. #ifdef TIOCGWINSZ
  99. int winchanged;
  100. #endif
  101.  
  102. int hasam;
  103. static oput_rprompt;
  104. extern int clearflag;
  105.  
  106. void refresh()
  107. {                /**/
  108.     unsigned char *s, *t, *sen, *scs = line + cs;
  109.     char **qbuf;
  110.     int ln = 0, nvcs = 0, nvln = -1, t0 = -1, put_rprompt, res = 0;
  111.  
  112. #ifdef HAS_SELECT
  113.     cost = 0;
  114. #endif
  115.     if (resetneeded) {
  116.     setterm();
  117. #ifdef TIOCGWINSZ
  118.     if (winchanged) {
  119.         moveto(0, 0);
  120.         t0 = olnct;        /* this is to clear extra lines even when */
  121.         winchanged = 0;    /* the terminal cannot TCCLEAREOD */
  122.     }
  123. #endif
  124.     resetvideo();
  125.     resetneeded = 0;
  126.     oput_rprompt = 0;
  127.     if (tccan(TCCLEAREOD))
  128.         tcout(TCCLEAREOD);
  129.     else
  130.         res = 1;
  131.     if (t0 > -1)
  132.         olnct = t0;
  133.     if (isset(SINGLELINEZLE) || !termok)
  134.         vcs = 0;
  135.     else if (pmpt && !clearflag)
  136.         fputs(pmpt, stdout), fflush(stdout);
  137.     if (clearflag)
  138.         putchar('\r'), vcs = 0, moveto(0, pptlen);
  139.     }
  140.     if (isset(SINGLELINEZLE) || !termok) {
  141.     singlerefresh();
  142.     return;
  143.     }
  144. /* first, we generate the video line buffers so we know what to
  145.     put on the screen.
  146.  
  147.     s = ptr into the video buffer.
  148.     t = ptr into the real buffer.
  149.     sen = end of the video buffer (eol)
  150. */
  151.  
  152.     s = (unsigned char *)(nbuf[ln = 0] + pptlen);
  153.     t = line;
  154.     sen = (unsigned char *)(*nbuf + winw);
  155.     for (; *t; t++) {
  156.     if (icntrl(*t))
  157.         if (*t == '\n') {
  158.         if (t == scs) {
  159.             if ((nvcs = (char *)s - nbuf[nvln = ln]) == columns)
  160.             nvcs = 0, nvln++;
  161.             scs = NULL;
  162.         }
  163.         if (s == sen)
  164.             nextline;
  165.         nextline;
  166.         } else if ((char)*t == '\t') {
  167.         t0 = (char *)s - nbuf[ln];
  168.         if (t == scs) {
  169.             nvln = ln; scs = NULL;
  170.             if ((nvcs = t0) == columns)
  171.             nvcs = 0, nvln++;
  172.         }
  173.         if ((t0 | 7) + 1 >= winw) {
  174.             nextline;
  175.             if (t0 == columns)
  176.             for (t0 = 8; t0; t0--)
  177.                 *s++ = ' ';    /* make tab in first column visible */
  178.         } else {
  179.             if (t0 == winw) {
  180.             t0 = 0; nextline;
  181.             }
  182.             do
  183.             *s++ = ' ';
  184.             while ((++t0) & 7);
  185.         }
  186.         } else {
  187.         if (s == sen)
  188.             nextline;
  189.         *s++ = '^';
  190.         if (t == scs)
  191.             nvcs = s - (unsigned char *)(nbuf[nvln = ln]) - 1,
  192.             scs = NULL;
  193.         if (s == sen)
  194.             nextline;
  195.         *s++ = (*t == 127) ? '?' : (*t | '@');
  196.     } else {
  197.         if (s == sen)
  198.         nextline;
  199.         *s++ = *t;
  200.     }
  201.     /* if the cursor is here, remember it */
  202.  
  203.     if (t == scs)
  204.         nvcs = s - (unsigned char *)(nbuf[nvln = ln]) - 1;
  205.     }
  206.     if (scs == t && (nvcs = s - (unsigned char *)(nbuf[nvln = ln])) == columns)
  207.     nvcs = 0, nvln++;
  208.     *s = '\0';
  209.     nlnct = ln + 1;
  210.  
  211.     if (statusline) {
  212.     if (!nbuf[(nlnct == winh) ? winh - 1 : nlnct++])
  213.         nbuf[nlnct -1] = (char*)zalloc(winw + 1);
  214.     s = (unsigned char *)nbuf[nlnct - 1];
  215.     t = (unsigned char *)statusline;
  216.     sen = (unsigned char *)(*nbuf + winw);
  217.     for (; *t; t++) {
  218.         if (icntrl(*t)) {    /* simplified processing in the status line */
  219.         if (s == sen)
  220.             nextline;
  221.         *s++ = '^';
  222.         if (s == sen)
  223.             nextline;
  224.         *s++ = (*t == 127) ? '?' : (*t | '@');
  225.         } else {
  226.         if (s == sen)
  227.             nextline;
  228.         *s++ = *t;
  229.         }
  230.     }
  231.     *s = '\0';
  232.     }
  233.  
  234.     for (ln = nlnct; ln < winh; ln++)
  235.     zfree(nbuf[ln], winw + 1), nbuf[ln] = NULL;
  236.  
  237. /* do RPROMPT */
  238.  
  239.     put_rprompt = pmpt2 && (int)strlen(nbuf[0]) + ppt2len < winw - 1;
  240.     if (put_rprompt) {
  241.     for (t0 = strlen(nbuf[0]); t0 != winw - 1 - ppt2len; t0++)
  242.         nbuf[0][t0] = ' ';
  243.     nbuf[0][t0] = '\0';
  244.     }
  245.  
  246.     for (ln = 0; ln < nlnct; ln++) {
  247.  
  248.     /* if old line and new line are different,
  249.        see if we can insert/delete a line */
  250.  
  251.     if (ln < olnct - 1 && !(hasam && vcs == columns) &&
  252.         nbuf[ln] && obuf[ln] &&
  253.         strncmp(nbuf[ln], obuf[ln], 16)) {
  254.         if (tccan(TCDELLINE) && obuf[ln + 1] && obuf[ln + 1][0] && 
  255.         nbuf[ln] && !strncmp(nbuf[ln], obuf[ln + 1], 16)) {
  256.         moveto(ln, 0);
  257.         tcout(TCDELLINE);
  258.         zfree(obuf[ln], winw + 1);
  259.         for (t0 = ln; t0 != olnct; t0++)
  260.             obuf[t0] = obuf[t0 + 1];
  261.         obuf[--olnct] = NULL;
  262.         }
  263.     /* don't try to insert a line if olnct = vmaxln (vmaxln is the number
  264.        of lines that have been displayed by this routine) so that we don't
  265.        go off the end of the screen. */
  266.  
  267.         else if (tccan(TCINSLINE) && olnct < vmaxln && nbuf[ln + 1] &&
  268.              obuf[ln] && !strncmp(nbuf[ln + 1], obuf[ln], 16)) {
  269.         moveto(ln, 0);
  270.         tcout(TCINSLINE);
  271.         for (t0 = olnct; t0 != ln; t0--)
  272.             obuf[t0] = obuf[t0 - 1];
  273.         obuf[ln] = NULL;
  274.         olnct++;
  275.         }
  276.     }
  277.     if (res && tccan(TCCLEAREOL)) {
  278.         moveto(ln, 0);
  279.         tcout(TCCLEAREOL);
  280.         refreshline(ln, put_rprompt, 0);
  281.     }
  282.     else
  283.         refreshline(ln, put_rprompt, res);
  284.     if (!ln && put_rprompt && !oput_rprompt) {
  285.         moveto(0, winw - 1 - ppt2len);
  286.         fputs(pmpt2, stdout);
  287.         vcs = winw - 1;
  288.     }
  289.     }
  290.  
  291. /* if old buffer had extra lines, do a clear-end-of-display if we can,
  292.    otherwise, just fill new buffer with blank lines and refresh them */
  293.  
  294.     if (olnct > nlnct)
  295.     if (tccan(TCCLEAREOD)) {
  296.         moveto(nlnct, 0);
  297.         tcout(TCCLEAREOD);
  298.     } else
  299.         for (ln = nlnct; ln < olnct; ln++)
  300.         if (res && tccan(TCCLEAREOL)) {
  301.             moveto(ln, 0);
  302.             tcout(TCCLEAREOL);
  303.             refreshline(ln, put_rprompt, 0);
  304.         }
  305.         else
  306.             refreshline(ln, put_rprompt, res);
  307.  
  308. /* move to the new cursor position */
  309.  
  310.     moveto(nvln, nvcs);
  311.  
  312.     if (isset(ALWAYSLASTPROMPT) &&
  313.     (!nvcs || (nvln == ovln + 1)) && 
  314.     cs == ll &&
  315.     tccan(TCCLEAREOL))
  316.     tcout(TCCLEAREOL);
  317.  
  318.     ovln = nvln;
  319.     qbuf = nbuf;
  320.     nbuf = obuf;
  321.     obuf = qbuf;
  322.     olnct = nlnct;
  323.     oput_rprompt = put_rprompt;
  324.     if (nlnct > vmaxln)
  325.     vmaxln = nlnct;
  326.     fflush(stdout);
  327. }
  328.  
  329. #define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
  330. #define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
  331. #define tc_delchars(X) tcmultout(TCDEL,TCMULTDEL,(X))
  332. #define tc_inschars(X) tcmultout(TCINS,TCMULTINS,(X))
  333. #define tc_upcurs(X) tcmultout(TCUP,TCMULTUP,(X))
  334. #define tc_leftcurs(X) tcmultout(TCLEFT,TCMULTLEFT,(X))
  335.  
  336. void refreshline(ln, put_rprompt, res)        /**/
  337. int ln;
  338. int put_rprompt;
  339. int res;
  340. {
  341. /* the test in nl below is to prevent a segv if the terminal cannot clear
  342.    either to end of line or display, and nlnct < olnct :-( */
  343.  
  344.     char *nl = nbuf[ln] ? nbuf[ln] : obuf[0], *ol = obuf[ln] ? obuf[ln] : "", *p1;
  345.     int ccs = 0;
  346.  
  347.     if (res) {
  348.     char *p = hcalloc(winw + 1);
  349.  
  350.     memset(p, ' ', winw);
  351.     strcpy(p, nl);
  352.     p[strlen(p)] = ' ';
  353.     nl = p;
  354.     }
  355.  
  356.     if (hasam && vcs == columns) {    /* must always write another char */
  357.     if (*nl) {            /* after writing in last column */ 
  358.         putchar(*nl);
  359.         nl++, vcs = ccs = 1;
  360.         if (*ol)
  361.         ol++;
  362.     } else
  363.         putchar('\r'), putchar('\n'), vcs = 0;
  364.     vln++;
  365.     }
  366.     for (;;) {
  367.     while (*nl && *nl == *ol) {
  368.         nl++, ol++, ccs++;
  369.     }
  370.     if (!*nl && !*ol)
  371.         if (!ln && !put_rprompt && oput_rprompt)
  372.         if (tccan(TCCLEAREOL)) {
  373.             moveto(0, ccs);
  374.             tcout(TCCLEAREOL);
  375.             return;
  376.         } else {
  377.             int x = winw - 1 - ccs;
  378.  
  379.             p1 = nl;
  380.             while (x--)
  381.             *p1++ = ' ';
  382.             *p1 = '\0';
  383.         }
  384.         else {
  385.         if (hasam && ccs == columns && ln < nlnct - 1 &&
  386.             ln < olnct - 1 && *nbuf[ln + 1] &&
  387.             !*obuf[ln + 1]) {        /* force join of lines */
  388.             moveto(ln, ccs - 1);
  389.             putchar(nl[-1]);
  390. #ifdef HAS_SELECT
  391.             cost++;
  392. #endif
  393.             vcs++;
  394.         }
  395.         return;
  396.         }
  397.  
  398.     /* if this is the end of the new buffer but the old buffer has stuff
  399.        here, clear to end of line if we can, otherwise fill the new buffer
  400.        with blanks and continue. */
  401.  
  402.     if (!*nl) {
  403.         int x = strlen(ol);
  404.  
  405.         if (tccan(TCCLEAREOL) &&
  406.         (x > tclen[TCCLEAREOL] || (hasam && ccs + x == columns))) {
  407.         moveto(ln, ccs);
  408.         tcout(TCCLEAREOL);
  409.         *ol = '\0';
  410.         return;
  411.         } else {
  412.         p1 = nl;
  413.         while (x--)
  414.             *p1++ = ' ';
  415.         *p1 = '\0';
  416.         continue;
  417.         }
  418.     }
  419.     /* if this is the end of the old buffer, just dump the rest of the
  420.        new buffer. */
  421.  
  422.     if (!*ol) {
  423.         while (!res && *nl == ' ')
  424.         nl++, ccs++;
  425.         if (*nl) {
  426.         moveto(ln, ccs);
  427.         fwrite(nl, strlen(nl), 1, stdout);
  428. #ifdef HAS_SELECT
  429.         cost += strlen(nl);
  430. #endif
  431.         vcs += strlen(nl);
  432.  
  433.         if (oput_rprompt && !put_rprompt) {
  434.             ccs += strlen(nl);
  435.             *nl = '\0';
  436.             continue;
  437.         }
  438.         } else if (hasam && ccs == columns) { /* must always write */
  439.         moveto(ln, ccs - 1);          /* last column */
  440.         putchar(' '), vcs++;
  441. #ifdef HAS_SELECT
  442.         cost ++;
  443. #endif
  444.         }
  445.         return;
  446.     }
  447.  
  448.     /* try to insert/delete characters unless there is an rprompt and the old
  449.        line also had it; in this case the length is not changed so that we
  450.        don't have to redraw the rprompt */
  451.  
  452.     moveto(ln, ccs);
  453.     if (!ln && put_rprompt && oput_rprompt)
  454.         goto jump;
  455.  
  456.     if (ol[1] != nl[1] && tccan(TCDEL)) {
  457.         int ct = 0;
  458.  
  459.         for (p1 = ol; *p1; p1++, ct++)
  460.         if (tcdelcost(ct) < pfxlen(p1, nl)) {
  461.             tc_delchars(ct);
  462.             ol = p1;
  463.             break;
  464.         }
  465.         if (*p1)
  466.         continue;
  467.     }
  468.     if (ol[1] != nl[1] && tccan(TCINS)) {
  469.         int ct = 0;
  470.  
  471.         for (p1 = nl; *p1; p1++, ct++)
  472.         if (tcinscost(ct) < pfxlen(p1, ol) + ct) {
  473.         /* make sure we aren't inserting characters off the end of the
  474.            screen */
  475. #if 0
  476.         /* if we are, jump to the end and truncate the line, if we can
  477.            do it quickly (gee, clever idea, Paul!) */
  478.             if (ct + ccs + strlen(ol) >= winw - 1) {
  479.             if (!tccan(TCMULTRIGHT) || ccs > winw - tclen[TCMULTRIGHT])
  480.                 continue;
  481.             moveto(ln, winw - 1 - ct);
  482.             if (!tccan(TCCLEAREOL) || ct < tclen[TCCLEAREOL]) {
  483.                 int x = ct;
  484.  
  485.                 while (vcs++, x--)
  486.                 putchar(' ');
  487.             } else
  488.                 tcout(TCCLEAREOL);
  489.             moveto(ln, ccs);
  490.             }
  491. #endif
  492.             if (ct + ccs + (int) strlen(ol) < winw - 1) {
  493.             tc_inschars(ct = p1 - nl);
  494.             ccs = (vcs += ct);
  495. #ifdef HAS_SELECT
  496.             cost += ct;
  497. #endif
  498.             fwrite(nl, ct, 1, stdout);
  499.             nl += ct;
  500.             break;
  501.             }
  502.         }
  503.         if (*p1)
  504.         continue;
  505.     }
  506.     /* if we can't do anything fancy, just write the new character and
  507.        keep going. */
  508.  
  509.       jump:
  510.     putchar(*nl);
  511. #ifdef HAS_SELECT
  512.     cost++;
  513. #endif
  514.     nl++, ol++, ccs = ++vcs;
  515.     }
  516. }
  517.  
  518. void moveto(ln, cl)        /**/
  519. int ln;
  520. int cl;
  521. {
  522.     if (ln == vln && cl == vcs)
  523.     return;
  524.  
  525.     if (hasam && vcs == columns && vln != lines - 1) {
  526.     putchar(' '), tcout(TCLEFT);
  527.     vln++, vcs = 0;
  528. #ifdef HAS_SELECT
  529.     cost ++;
  530. #endif
  531.     }
  532.  
  533. /* move up */
  534.  
  535.     if (ln < vln) {
  536.     tc_upcurs(vln - ln);
  537.     vln = ln;
  538.     }
  539. /* move down; if we might go off the end of the screen, use newlines
  540.     instead of TCDOWN */
  541.  
  542.     while (ln > vln) {
  543.         if (vln < vmaxln - 1)
  544.             if (ln > vmaxln - 1) {
  545.         if (tc_downcurs(vmaxln - 1 - vln))
  546.             vcs = 0;
  547.                 vln = vmaxln - 1;
  548.             } else {
  549.                 if (tc_downcurs(ln - vln))
  550.             vcs = 0;
  551.                 vln = ln;
  552.                 continue;
  553.             }
  554.     putchar('\r'), vcs = 0;    /* safety precaution */
  555. #ifdef HAS_SELECT
  556.     cost ++;
  557. #endif
  558.         while (ln > vln) {
  559.             putchar('\n');
  560. #ifdef HAS_SELECT
  561.             cost ++;
  562. #endif
  563.             vln++;
  564.         }
  565.     }
  566.     if (cl < vcs / 2) {
  567.     putchar('\r');
  568. #ifdef HAS_SELECT
  569.     cost++;
  570. #endif
  571.     vcs = 0;
  572.     }
  573.     if (vcs < cl)
  574.     tc_rightcurs(cl);
  575.     else if (vcs > cl)
  576.     tc_leftcurs(vcs - cl);
  577.     vcs = cl;
  578. }
  579.  
  580. void tcmultout(cap, multcap, ct)/**/
  581. int cap;
  582. int multcap;
  583. int ct;
  584. {
  585.     if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap] * ct))
  586.     tcoutarg(multcap, ct);
  587.     else
  588.     while (ct--)
  589.         tcout(cap);
  590. }
  591.  
  592. void tc_rightcurs(cl)        /**/
  593. int cl;
  594. {
  595.     int ct = cl - vcs;
  596.  
  597. /* do a multright if it's cheaper or if we're walking over the prompt.  */
  598.  
  599.     if (tccan(TCMULTRIGHT) &&
  600.     (ct > tclen[TCMULTRIGHT] || (vln == 0 && vcs < pptlen))) {
  601.     tcoutarg(TCMULTRIGHT, ct);
  602.     return;
  603.     }
  604.  
  605. /* try to go with tabs if a multright is not feasible/convenient;
  606.    tabs are assumed to be 8 spaces */
  607.  
  608.     if (tccan(TCNEXTTAB)) {
  609.     if ((vcs | 7) + 1 <= cl) {
  610.         tcout(TCNEXTTAB);
  611.         vcs = (vcs | 7) + 1;
  612.     }
  613.     for (; vcs + 8 <= cl; vcs += 8)
  614.         tcout(TCNEXTTAB);
  615.     if (vcs == cl)
  616.         return;
  617.     }
  618.  
  619. /* if we're walking over the prompt and we can do a bunch of cursor rights,
  620.    do them, even though they're more expensive.  (We can't redraw the
  621.    prompt very easily in general.)  */
  622.  
  623.     if (vln == 0 && tccan(TCRIGHT))
  624.     for (; vcs < pptlen; vcs++)
  625.         tcout(TCRIGHT);
  626.  
  627. /* otherwise write the contents of the video buffer. */
  628.  
  629.     if ((ct = cl - vcs)) {
  630.     fwrite(nbuf[vln] + vcs, ct, 1, stdout);
  631. #ifdef HAS_SELECT
  632.     cost += ct;
  633. #endif
  634.     }
  635. }
  636.  
  637. int tc_downcurs(ct)        /**/
  638. int ct;
  639. {
  640.     int ret = 0;
  641.     if (ct) {
  642.     if (tccan(TCMULTDOWN) &&
  643.         (!tccan(TCDOWN) || tclen[TCMULTDOWN] < tclen[TCDOWN] * ct))
  644.         tcoutarg(TCMULTDOWN, ct);
  645.     else if (tccan(TCDOWN)) {
  646.         while (ct--)
  647.         tcout(TCDOWN);
  648.     } else {
  649.         while (ct--)
  650.         putchar('\n');
  651.         putchar('\r'), ret = -1;
  652.     }
  653.     }
  654.     return ret;
  655. }
  656.  
  657. /* I'm NOT going to worry about padding unless anyone complains. */
  658.  
  659. void tcout(cap)            /**/
  660. int cap;
  661. {
  662.     tputs(tcstr[cap], 1, putraw);
  663. }
  664.  
  665. void tcoutarg(cap, arg)        /**/
  666. int cap;
  667. int arg;
  668. {
  669.     tputs(tgoto(tcstr[cap], arg, arg), 1, putraw);
  670. }
  671.  
  672. void clearscreen()
  673. {                /**/
  674.     tcout(TCCLEARSCREEN);
  675.     resetneeded = 1;
  676.     clearflag = 0;
  677. }
  678.  
  679. void redisplay()
  680. {                /**/
  681.     moveto(0, pptlen);
  682.     if (tccan(TCCLEAREOD))
  683.     tcout(TCCLEAREOD);
  684.     resetneeded = clearflag = 1;
  685. }
  686.  
  687. void singlerefresh()
  688. {                /**/
  689.     char *vbuf, *vp, **qbuf, *refreshop;
  690.     int t0, vsiz, nvcs = 0;
  691.  
  692.     for (vsiz = 1 + pptlen, t0 = 0; t0 != ll; t0++, vsiz++)
  693.     if (line[t0] == '\t')
  694.         vsiz += 7;
  695.     else if (icntrl(line[t0]))
  696.         vsiz++;
  697.     vbuf = (char *)zalloc(vsiz);
  698.     strcpy(vbuf, pmpt);
  699.     vp = vbuf + pptlen;
  700.     for (t0 = 0; t0 != ll; t0++) {
  701.     if (line[t0] == '\t')
  702.         do
  703.         *vp++ = ' ';
  704.         while ((vp - vbuf) & 7);
  705.     else if (line[t0] == '\n') {
  706.         *vp++ = '\\';
  707.         *vp++ = 'n';
  708.     } else if (line[t0] == 0x7f) {
  709.         *vp++ = '^';
  710.         *vp++ = '?';
  711.     } else if (icntrl(line[t0])) {
  712.         *vp++ = '^';
  713.         *vp++ = line[t0] | '@';
  714.     } else
  715.         *vp++ = line[t0];
  716.     if (t0 == cs)
  717.         nvcs = vp - vbuf - 1;
  718.     }
  719.     if (t0 == cs)
  720.     nvcs = vp - vbuf;
  721.     *vp = '\0';
  722.     if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 1)) {
  723.     if ((winpos = nvcs - (winw / 2)) < 0)
  724.         winpos = 0;
  725.     }
  726.     if (winpos)
  727.     vbuf[winpos] = '<';
  728.     if ((int) strlen(vbuf + winpos) > winw) {
  729.     vbuf[winpos + winw - 1] = '>';
  730.     vbuf[winpos + winw] = '\0';
  731.     }
  732.     strcpy(nbuf[0], vbuf + winpos);
  733.     zfree(vbuf, vsiz);
  734.     nvcs -= winpos;
  735.     for (t0 = 0, vp = *nbuf, refreshop = *obuf; *vp; t0++, vp++) {
  736.     if (*vp != *refreshop && !(*vp == ' ' && !*refreshop)) {
  737.         singmoveto(t0);
  738.         putchar(*vp);
  739.         vcs++;
  740.     }
  741.     if (*refreshop)
  742.         refreshop++;
  743.     }
  744.     if (*refreshop) {
  745.     singmoveto(t0);
  746.     for (; *refreshop; refreshop++) {
  747.         putchar(' ');
  748.         vcs++;
  749.     }
  750.     }
  751.     singmoveto(nvcs);
  752.     qbuf = nbuf;
  753.     nbuf = obuf;
  754.     obuf = qbuf;
  755.     fflush(stdout);
  756. }
  757.  
  758. void singmoveto(pos)        /**/
  759. int pos;
  760. {
  761.     while (pos < vcs) {
  762.     vcs--;
  763.     putchar('\b');
  764.     }
  765.     while (pos > vcs) {
  766.     putchar(nbuf[0][vcs]);
  767.     vcs++;
  768.     }
  769. }
  770.