refresh.cxx

Go to the documentation of this file.
00001 // @(#)root/editline:$Id: refresh.cxx 30214 2009-09-17 09:32:03Z axel $
00002 // Author: Mary-Louise Gill, 2009
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /*      $NetBSD: refresh.c,v 1.17 2001/04/13 00:53:11 lukem Exp $       */
00013 
00014 /*-
00015  * Copyright (c) 1992, 1993
00016  *      The Regents of the University of California.  All rights reserved.
00017  *
00018  * This code is derived from software contributed to Berkeley by
00019  * Christos Zoulas of Cornell University.
00020  *
00021  * Redistribution and use in source and binary forms, with or without
00022  * modification, are permitted provided that the following conditions
00023  * are met:
00024  * 1. Redistributions of source code must retain the above copyright
00025  *    notice, this list of conditions and the following disclaimer.
00026  * 2. Redistributions in binary form must reproduce the above copyright
00027  *    notice, this list of conditions and the following disclaimer in the
00028  *    documentation and/or other materials provided with the distribution.
00029  * 3. Neither the name of the University nor the names of its contributors
00030  *    may be used to endorse or promote products derived from this software
00031  *    without specific prior written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00034  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00035  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00037  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00039  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00041  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00042  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00043  * SUCH DAMAGE.
00044  */
00045 
00046 #include "compat.h"
00047 
00048 /*
00049  * refresh.c: Lower level screen refreshing functions
00050  */
00051 #include "sys.h"
00052 #include <stdio.h>
00053 #include <ctype.h>
00054 #include <unistd.h>
00055 #include <string.h>
00056 
00057 #include "el.h"
00058 
00059 el_private void re_addc(EditLine_t*, int, ElColor_t* color);
00060 el_private void re_update_line(EditLine_t*, char*, char*, ElColor_t*, int);
00061 el_private void re_insert(EditLine_t*, char*, int, int, char*, int);
00062 el_private void re_delete(EditLine_t*, char*, int, int, int);
00063 el_private void re_fastputc(EditLine_t*, int);
00064 el_private void re__strncopy(char*, char*, size_t);
00065 el_private void re__copy_and_pad(char*, const char*, size_t);
00066 
00067 /* re__copy_and_pad():
00068  *      Copy string and pad with spaces
00069  */
00070 
00071 el_private void
00072 re__copy_and_pad(char* dst, const char* src, size_t width) {
00073    size_t i;
00074 
00075    for (i = 0; i < width; i++) {
00076       if (*src == 0) {
00077          break;
00078       }
00079       *dst++ = *src++;
00080    }
00081 
00082    for ( ; i < width; i++) {
00083       *dst++ = ' ';
00084    }
00085 
00086    *dst = 0;
00087 }
00088 
00089 
00090 el_private void
00091 re__copy_and_pad(ElColor_t* dst, const ElColor_t* src, size_t width) {
00092    size_t i;
00093 
00094    for (i = 0; i < width; i++) {
00095       *dst++ = *src++;
00096    }
00097 
00098    for ( ; i < width; i++) {
00099       *dst++ = -1;
00100    }
00101 
00102    *dst = -1;
00103 }
00104 
00105 
00106 #ifdef DEBUG_REFRESH
00107 el_private void re_printstr(EditLine_t*, char*, char*, char*);
00108 # define __F el->fErrFile
00109 # define ELRE_ASSERT(a, b, c) do { \
00110       if (a) { \
00111          (void) fprintf b; \
00112          c; \
00113       } } \
00114    while (0)
00115 # define ELRE_DEBUG(a, b) ELRE_ASSERT(a, b,;)
00116 
00117 /* re_printstr():
00118  *      Print a string on the debugging pty
00119  */
00120 el_private void
00121 re_printstr(EditLine_t* el, char* str, char* f, char* t) {
00122    ELRE_DEBUG(1, (__F, "%s:\"", str));
00123 
00124    while (f < t)
00125       ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
00126    ELRE_DEBUG(1, (__F, "\"\r\n"));
00127 }
00128 
00129 
00130 #else
00131 # define ELRE_ASSERT(a, b, c)
00132 # define ELRE_DEBUG(a, b)
00133 #endif
00134 
00135 
00136 /* re_addc():
00137  *      Draw c, expanding tabs, control chars etc.
00138  */
00139 el_private void
00140 re_addc(EditLine_t* el, int c, ElColor_t* color) {
00141    if (isprint(c)) {
00142       re_putc(el, c, 1, color);
00143       return;
00144    }
00145 
00146    if (c == '\n') {                                     /* expand the newline */
00147       int oldv = el->fRefresh.r_cursor.fV;
00148       re_putc(el, '\0', 0, 0);                                  /* assure end of line */
00149 
00150       if (oldv == el->fRefresh.r_cursor.fV) {           /* XXX */
00151          el->fRefresh.r_cursor.fH = 0;                 /* reset cursor pos */
00152          el->fRefresh.r_cursor.fV++;
00153       }
00154       return;
00155    }
00156 
00157    if (c == '\t') {                                     /* expand the tab */
00158       for ( ; ;) {
00159          re_putc(el, ' ', 1, 0);
00160 
00161          if ((el->fRefresh.r_cursor.fH & 07) == 0) {
00162             break;                                      /* go until tab stop */
00163          }
00164       }
00165    } else if (iscntrl(c)) {
00166       re_putc(el, '^', 1, 0);
00167 
00168       if (c == '\177') {
00169          re_putc(el, '?', 1, 0);
00170       } else {
00171          /* uncontrolify it; works only for iso8859-1 like sets */
00172          re_putc(el, (c | 0100), 1, 0);
00173       }
00174    } else {
00175       re_putc(el, '\\', 1, 0);
00176       re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1, 0);
00177       re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1, 0);
00178       re_putc(el, (c & 07) + '0', 1, 0);
00179    }
00180 } // re_addc
00181 
00182 
00183 /* re_putc():
00184  *      Draw the character given
00185  */
00186 el_protected void
00187 re_putc(EditLine_t* el, int c, int shift, ElColor_t* color) {
00188    ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
00189 
00190    el->fVDisplay[el->fRefresh.r_cursor.fV][el->fRefresh.r_cursor.fH] = c;
00191 
00192    if (color) {
00193       el->fVDispColor[el->fRefresh.r_cursor.fV][el->fRefresh.r_cursor.fH] = *color;
00194    } else {
00195       el->fVDispColor[el->fRefresh.r_cursor.fV][el->fRefresh.r_cursor.fH] = -1;
00196    }
00197 
00198    if (!shift) {
00199       return;
00200    }
00201 
00202    el->fRefresh.r_cursor.fH++;         /* advance to next place */
00203 
00204    if (el->fRefresh.r_cursor.fH >= el->fTerm.fSize.fH) {
00205       el->fVDisplay[el->fRefresh.r_cursor.fV][el->fTerm.fSize.fH] = '\0';
00206       el->fVDispColor[el->fRefresh.r_cursor.fV][el->fTerm.fSize.fH] = -1;
00207 
00208       /* assure end of line */
00209       el->fRefresh.r_cursor.fH = 0;            /* reset it. */
00210 
00211       /*
00212        * If we would overflow (input is longer than terminal size),
00213        * emulate scroll by dropping first line and shuffling the rest.
00214        * We do this via pointer shuffling - it's safe in this case
00215        * and we avoid memcpy().
00216        */
00217       if (el->fRefresh.r_cursor.fV + 1 >= el->fTerm.fSize.fV) {
00218          int i, lins = el->fTerm.fSize.fV;
00219          char* firstline = el->fVDisplay[0];
00220          ElColor_t* firstcolor = el->fVDispColor[0];
00221 
00222          for (i = 1; i < lins; i++) {
00223             el->fVDisplay[i - 1] = el->fVDisplay[i];
00224             el->fVDispColor[i - 1] = el->fVDispColor[i];
00225          }
00226 
00227          firstline[0] = '\0';                           /* empty the string */
00228          firstcolor[0] = -1;
00229 
00230          el->fVDisplay[i - 1] = firstline;
00231          el->fVDispColor[i - 1] = firstcolor;
00232       } else {
00233          el->fRefresh.r_cursor.fV++;
00234       }
00235 
00236       ELRE_ASSERT(el->fRefresh.r_cursor.fV >= el->fTerm.fSize.fV,
00237                   (__F, "\r\nre_putc: overflow! r_cursor.fV == %d > %d\r\n",
00238                    el->fRefresh.r_cursor.fV, el->fTerm.fSize.fV),
00239                   abort());
00240    }
00241 } // re_putc
00242 
00243 
00244 /* re_refresh():
00245  *      draws the new virtual screen image from the current input
00246  *      line, then goes line-by-line changing the real image to the new
00247  *      virtual image. The routine to re-draw a line can be replaced
00248  *      easily in hopes of a smarter one being placed there.
00249  */
00250 el_protected void
00251 re_refresh(EditLine_t* el) {
00252    int i, rhdiff;
00253    char* cp, * st;
00254    ElCoord_t cur;
00255 #ifdef notyet
00256    size_t termsz;
00257 #endif
00258 
00259    ELRE_DEBUG(1, (__F, "el->fLine.fBuffer = :%s:\r\n",
00260                   el->fLine.fBuffer));
00261 
00262    /* reset the Drawing cursor */
00263    el->fRefresh.r_cursor.fH = 0;
00264    el->fRefresh.r_cursor.fV = 0;
00265 
00266    /* temporarily draw rprompt to calculate its size */
00267    prompt_print(el, EL_RPROMPT);
00268 
00269    /* reset the Drawing cursor */
00270    el->fRefresh.r_cursor.fH = 0;
00271    el->fRefresh.r_cursor.fV = 0;
00272 
00273    cur.fH = -1;                  /* set flag in case I'm not set */
00274    cur.fV = 0;
00275 
00276    prompt_print(el, EL_PROMPT);
00277 
00278    /* draw the current input buffer */
00279 #if notyet
00280    termsz = el->fTerm.fSize.fH * el->fTerm.fSize.fV;
00281 
00282    if (el->fLine.fLastChar - el->fLine.fBuffer > termsz) {
00283       /*
00284        * If line is longer than terminal, process only part
00285        * of line which would influence display.
00286        */
00287       size_t rem = (el->fLine.fLastChar - el->fLine.fBuffer) % termsz;
00288 
00289       st = el->fLine.fLastChar - rem
00290            - (termsz - (((rem / el->fTerm.fSize.fV) - 1)
00291                         * el->fTerm.fSize.fV));
00292    } else
00293 #endif
00294    st = el->fLine.fBuffer;
00295 
00296    for (cp = st; cp < el->fLine.fLastChar; cp++) {
00297       if (cp == el->fLine.fCursor) {
00298          /* save for later */
00299          cur.fH = el->fRefresh.r_cursor.fH;
00300          cur.fV = el->fRefresh.r_cursor.fV;
00301       }
00302       re_addc(el, (unsigned char) *cp, &el->fLine.fBufColor[cp - el->fLine.fBuffer]);
00303    }
00304 
00305    if (cur.fH == -1) {           /* if I haven't been set yet, I'm at the end */
00306       cur.fH = el->fRefresh.r_cursor.fH;
00307       cur.fV = el->fRefresh.r_cursor.fV;
00308    }
00309    rhdiff = el->fTerm.fSize.fH - el->fRefresh.r_cursor.fH - el->fRPrompt.fPos.fH;
00310 
00311    if (el->fRPrompt.fPos.fH && !el->fRPrompt.fPos.fV &&
00312        !el->fRefresh.r_cursor.fV && rhdiff > 1) {
00313       /*
00314        * have a right-hand side prompt that will fit
00315        * on the end of the first line with at least
00316        * one character gap to the input buffer.
00317        */
00318       while (--rhdiff > 0)              /* pad out with spaces */
00319          re_putc(el, ' ', 1, 0);
00320       prompt_print(el, EL_RPROMPT);
00321    } else {
00322       el->fRPrompt.fPos.fH = 0;               /* flag "not using rprompt" */
00323       el->fRPrompt.fPos.fV = 0;
00324    }
00325 
00326    re_putc(el, '\0', 0, 0);             /* make line ended with NUL, no cursor shift */
00327 
00328    el->fRefresh.r_newcv = el->fRefresh.r_cursor.fV;
00329 
00330    ELRE_DEBUG(1, (__F,
00331                   "term.fH=%d vcur.fH=%d vcur.fV=%d vdisplay[0]=\r\n:%80.80s:\r\n",
00332                   el->fTerm.fSize.fH, el->fRefresh.r_cursor.fH,
00333                   el->fRefresh.r_cursor.fV, el->fVDisplay[0]));
00334 
00335    ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->fRefresh.r_newcv));
00336 
00337    //int curHPos = el->fCursor.fH;
00338    //int curVPos = el->fCursor.fV;
00339 
00340    for (i = 0; i <= el->fRefresh.r_newcv; i++) {
00341       /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
00342       term_move_to_line(el, i);
00343       term_move_to_char(el, 0);
00344       term__flush();
00345       re_update_line(el, el->fDisplay[i], el->fVDisplay[i],
00346                      el->fVDispColor[i],
00347                      i);
00348 
00349       /*
00350        * Copy the new line to be the current one, and pad out with
00351        * spaces to the full width of the terminal so that if we try
00352        * moving the cursor by writing the character that is at the
00353        * end of the screen line, it won't be a NUL or some old
00354        * leftover stuff.
00355        */
00356       re__copy_and_pad(el->fDisplay[i], el->fVDisplay[i],
00357                        (size_t) el->fTerm.fSize.fH);
00358       re__copy_and_pad(el->fDispColor[i], el->fVDispColor[i],
00359                        (size_t) el->fTerm.fSize.fH);
00360    }
00361    //term_move_to_line(el, curVPos);
00362    //term_move_to_char(el, curHPos);
00363 
00364    ELRE_DEBUG(1, (__F,
00365                   "\r\nel->fRefresh.r_cursor.fV=%d,el->fRefresh.r_oldcv=%d i=%d\r\n",
00366                   el->fRefresh.r_cursor.fV, el->fRefresh.r_oldcv, i));
00367 
00368    if (el->fRefresh.r_oldcv > el->fRefresh.r_newcv) {
00369       for ( ; i <= el->fRefresh.r_oldcv; i++) {
00370          term_move_to_line(el, i);
00371          term_move_to_char(el, 0);
00372          term_clear_EOL(el, (int) strlen(el->fDisplay[i]));
00373 #ifdef DEBUG_REFRESH
00374          term_overwrite(el, "C\b", 0, 2);
00375 #endif /* DEBUG_REFRESH */
00376          el->fDisplay[i][0] = '\0';
00377          el->fDispColor[i][0] = -1;
00378       }
00379    }
00380 
00381    term__setcolor(-1);      // prompt / keyword, whatever: back to normal
00382    el->fRefresh.r_oldcv = el->fRefresh.r_newcv;      /* set for next time */
00383    ELRE_DEBUG(1, (__F,
00384                   "\r\ncursor.fH = %d, cursor.fV = %d, cur.fH = %d, cur.fV = %d\r\n",
00385                   el->fRefresh.r_cursor.fH, el->fRefresh.r_cursor.fV,
00386                   cur.fH, cur.fV));
00387    term_move_to_line(el, cur.fV);        /* go to where the cursor is */
00388    term_move_to_char(el, cur.fH);
00389 } // re_refresh
00390 
00391 
00392 /* re_goto_bottom():
00393  *       used to go to last used screen line
00394  */
00395 el_protected void
00396 re_goto_bottom(EditLine_t* el) {
00397    term_move_to_line(el, el->fRefresh.r_oldcv);
00398 
00399    term__putcolorch('\r', NULL);                                        // LOUISE COLOUR
00400    term__putcolorch('\n', NULL);                                        // LOUISE COLOUR
00401    re_clear_display(el);
00402    term__flush();
00403 }
00404 
00405 
00406 /* re_insert():
00407  *      insert num characters of s into d (in front of the character)
00408  *      at dat, maximum length of d is dlen
00409  */
00410 el_private void
00411 /*ARGSUSED*/
00412 re_insert(EditLine_t* /*el*/, char* d, int dat, int dlen, char* s, int num) {
00413    char* a, * b;
00414 
00415    if (num <= 0) {
00416       return;
00417    }
00418 
00419    if (num > dlen - dat) {
00420       num = dlen - dat;
00421    }
00422 
00423    ELRE_DEBUG(1,
00424               (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
00425                num, dat, dlen, d));
00426    ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
00427 
00428    /* open up the space for num chars */
00429    if (num > 0) {
00430       b = d + dlen - 1;
00431       a = b - num;
00432 
00433       while (a >= &d[dat])
00434          *b-- = *a--;
00435       d[dlen] = '\0';           /* just in case */
00436    }
00437    ELRE_DEBUG(1, (__F,
00438                   "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
00439                   num, dat, dlen, d));
00440    ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
00441 
00442    /* copy the characters */
00443    for (a = d + dat; (a < d + dlen) && (num > 0); num--) {
00444       *a++ = *s++;
00445    }
00446 
00447    ELRE_DEBUG(1,
00448               (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
00449                num, dat, dlen, d, s));
00450    ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
00451 } // re_insert
00452 
00453 
00454 /* re_delete():
00455  *      delete num characters d at dat, maximum length of d is dlen
00456  */
00457 el_private void
00458 /*ARGSUSED*/
00459 re_delete(EditLine_t* /*el*/, char* d, int dat, int dlen, int num) {
00460    char* a, * b;
00461 
00462    if (num <= 0) {
00463       return;
00464    }
00465 
00466    if (dat + num >= dlen) {
00467       d[dat] = '\0';
00468       return;
00469    }
00470    ELRE_DEBUG(1,
00471               (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
00472                num, dat, dlen, d));
00473 
00474    /* open up the space for num chars */
00475    if (num > 0) {
00476       b = d + dat;
00477       a = b + num;
00478 
00479       while (a < &d[dlen])
00480          *b++ = *a++;
00481       d[dlen] = '\0';           /* just in case */
00482    }
00483    ELRE_DEBUG(1,
00484               (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
00485                num, dat, dlen, d));
00486 } // re_delete
00487 
00488 
00489 /* re__strncopy():
00490  *      Like strncpy without padding.
00491  */
00492 el_private void
00493 re__strncopy(char* a, char* b, size_t n) {
00494    while (n-- && *b)
00495       *a++ = *b++;
00496 }
00497 
00498 
00499 /*****************************************************************
00500     re_update_line() is based on finding the middle difference of each line
00501     on the screen; vis:
00502 
00503                              /old first difference
00504         /beginning of line   |              /old last same       /old EOL
00505         v                    v              v                    v
00506    old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
00507    new: eddie> Oh, my little buggy says to me, as lurgid as
00508         ^                    ^        ^                    ^
00509         \beginning of line   |        \new last same       \new end of line
00510                              \new first difference
00511 
00512     all are character pointers for the sake of speed.  Special cases for
00513     no differences, as well as for end of line additions must be handled.
00514  **************************************************************** */
00515 
00516 /* Minimum at which doing an insert it "worth it".  This should be about
00517  * half the "cost" of going into insert mode, inserting a character, and
00518  * going back out.  This should really be calculated from the termcap
00519  * data...  For the moment, a good number for ANSI terminals.
00520  */
00521 #define MIN_END_KEEP 4
00522 
00523 el_private void
00524 re_update_line(EditLine_t* el, char* old, char* newp, ElColor_t* color, int i) {
00525    char* o, * n, * p, c;
00526    char* ofd, * ols, * oe, * nfd, * nls, * ne;
00527    char* osb, * ose, * nsb, * nse;
00528    ElColor_t* nfd_col, * nse_col;
00529    int fx, sx;
00530 
00531    /*
00532     * find first diff
00533     */
00534    for (o = old, n = newp; *o && (*o == *n); o++, n++) {
00535       continue;
00536    }
00537    ofd = o;
00538    nfd = n;
00539    nfd_col = color ? color + (nfd - newp) : 0;
00540 
00541    /*
00542     * Find the end of both old and newp
00543     */
00544    while (*o)
00545       o++;
00546 
00547    /*
00548     * Remove any trailing blanks off of the end, being careful not to
00549     * back up past the beginning.
00550     */
00551    while (ofd < o) {
00552       if (o[-1] != ' ') {
00553          break;
00554       }
00555       o--;
00556    }
00557    oe = o;
00558    *oe = '\0';
00559 
00560    while (*n)
00561       n++;
00562 
00563    /* remove blanks from end of newp */
00564    while (nfd < n) {
00565       if (n[-1] != ' ') {
00566          break;
00567       }
00568       n--;
00569    }
00570    ne = n;
00571    *ne = '\0';
00572 
00573    /*
00574     * if no diff, continue to next line of redraw
00575     */
00576    if (*ofd == '\0' && *nfd == '\0') {
00577       ELRE_DEBUG(1, (__F, "no difference.\r\n"));
00578       return;
00579    }
00580 
00581    /*
00582     * find last same pointer
00583     */
00584    while ((o > ofd) && (n > nfd) && (*--o == *--n))
00585       continue;
00586    ols = ++o;
00587    nls = ++n;
00588 
00589    /*
00590     * find same begining and same end
00591     */
00592    osb = ols;
00593    nsb = nls;
00594    ose = ols;
00595    nse = nls;
00596    nse_col = color ? color + (nse - newp) : 0;
00597 
00598    /*
00599     * case 1: insert: scan from nfd to nls looking for *ofd
00600     */
00601    if (*ofd) {
00602       for (c = *ofd, n = nfd; n < nls; n++) {
00603          if (c == *n) {
00604             for (o = ofd, p = n;
00605                  p < nls && o < ols && *o == *p;
00606                  o++, p++) {
00607                continue;
00608             }
00609 
00610             /*
00611              * if the new match is longer and it's worth
00612              * keeping, then we take it
00613              */
00614             if (((nse - nsb) < (p - n)) &&
00615                 (2 * (p - n) > n - nfd)) {
00616                nsb = n;
00617                nse = p;
00618                nse_col = color ? color + (nse - newp) : 0;
00619                osb = ofd;
00620                ose = o;
00621             }
00622          }
00623       }
00624    }
00625 
00626    /*
00627     * case 2: delete: scan from ofd to ols looking for *nfd
00628     */
00629    if (*nfd) {
00630       for (c = *nfd, o = ofd; o < ols; o++) {
00631          if (c == *o) {
00632             for (n = nfd, p = o;
00633                  p < ols && n < nls && *p == *n;
00634                  p++, n++) {
00635                continue;
00636             }
00637 
00638             /*
00639              * if the new match is longer and it's worth
00640              * keeping, then we take it
00641              */
00642             if (((ose - osb) < (p - o)) &&
00643                 (2 * (p - o) > o - ofd)) {
00644                nsb = nfd;
00645                nse = n;
00646                nse_col = color ? color + (nse - newp) : 0;
00647                osb = o;
00648                ose = p;
00649             }
00650          }
00651       }
00652    }
00653 
00654    /*
00655     * Pragmatics I: If old trailing whitespace or not enough characters to
00656     * save to be worth it, then don't save the last same info.
00657     */
00658    if ((oe - ols) < MIN_END_KEEP) {
00659       ols = oe;
00660       nls = ne;
00661    }
00662 
00663    /*
00664     * Pragmatics II: if the terminal isn't smart enough, make the data
00665     * dumber so the smart update doesn't try anything fancy
00666     */
00667 
00668    /*
00669     * fx is the number of characters we need to insert/delete: in the
00670     * beginning to bring the two same begins together
00671     */
00672    fx = (nsb - nfd) - (osb - ofd);
00673 
00674    /*
00675     * sx is the number of characters we need to insert/delete: in the
00676     * end to bring the two same last parts together
00677     */
00678    sx = (nls - nse) - (ols - ose);
00679 
00680    if (!EL_CAN_INSERT) {
00681       if (fx > 0) {
00682          osb = ols;
00683          ose = ols;
00684          nsb = nls;
00685          nse = nls;
00686          nse_col = color ? color + (nse - newp) : 0;
00687       }
00688 
00689       if (sx > 0) {
00690          ols = oe;
00691          nls = ne;
00692       }
00693 
00694       if ((ols - ofd) < (nls - nfd)) {
00695          ols = oe;
00696          nls = ne;
00697       }
00698    }
00699 
00700    if (!EL_CAN_DELETE) {
00701       if (fx < 0) {
00702          osb = ols;
00703          ose = ols;
00704          nsb = nls;
00705          nse = nls;
00706          nse_col = color ? color + (nse - newp) : 0;
00707       }
00708 
00709       if (sx < 0) {
00710          ols = oe;
00711          nls = ne;
00712       }
00713 
00714       if ((ols - ofd) > (nls - nfd)) {
00715          ols = oe;
00716          nls = ne;
00717       }
00718    }
00719 
00720    /*
00721     * Pragmatics III: make sure the middle shifted pointers are correct if
00722     * they don't point to anything (we may have moved ols or nls).
00723     */
00724    /* if the change isn't worth it, don't bother */
00725    /* was: if (osb == ose) */
00726    if ((ose - osb) < MIN_END_KEEP) {
00727       osb = ols;
00728       ose = ols;
00729       nsb = nls;
00730       nse = nls;
00731       nse_col = color ? color + (nse - newp) : 0;
00732    }
00733 
00734    /*
00735     * Now that we are done with pragmatics we recompute fx, sx
00736     */
00737    fx = (nsb - nfd) - (osb - ofd);
00738    sx = (nls - nse) - (ols - ose);
00739 
00740    ELRE_DEBUG(1, (__F, "\n"));
00741    ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
00742                   ofd - old, osb - old, ose - old, ols - old, oe - old));
00743    ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
00744                   nfd - newp, nsb - newp, nse - newp, nls - newp, ne - newp));
00745    ELRE_DEBUG(1, (__F,
00746                   "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
00747    ELRE_DEBUG(1, (__F,
00748                   "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
00749 #ifdef DEBUG_REFRESH
00750    re_printstr(el, "old- oe", old, oe);
00751    re_printstr(el, "new- ne", newp, ne);
00752    re_printstr(el, "old-ofd", old, ofd);
00753    re_printstr(el, "new-nfd", newp, nfd);
00754    re_printstr(el, "ofd-osb", ofd, osb);
00755    re_printstr(el, "nfd-nsb", nfd, nsb);
00756    re_printstr(el, "osb-ose", osb, ose);
00757    re_printstr(el, "nsb-nse", nsb, nse);
00758    re_printstr(el, "ose-ols", ose, ols);
00759    re_printstr(el, "nse-nls", nse, nls);
00760    re_printstr(el, "ols- oe", ols, oe);
00761    re_printstr(el, "nls- ne", nls, ne);
00762 #endif /* DEBUG_REFRESH */
00763 
00764    /*
00765     * el_cursor.fV to this line i MUST be in this routine so that if we
00766     * don't have to change the line, we don't move to it. el_cursor.fH to
00767     * first diff char
00768     */
00769    term_move_to_line(el, i);
00770 
00771    /*
00772     * at this point we have something like this:
00773     *
00774     * /old                  /ofd    /osb               /ose    /ols     /oe
00775     * v.....................fV       v..................fV       v........fV
00776     * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
00777     * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
00778     * ^.....................^     ^..................^       ^........^
00779     * \newp                  \nfd  \nsb               \nse     \nls    \ne
00780     *
00781     * fx is the difference in length between the chars between nfd and
00782     * nsb, and the chars between ofd and osb, and is thus the number of
00783     * characters to delete if < 0 (newp is shorter than old, as above),
00784     * or insert (newp is longer than short).
00785     *
00786     * sx is the same for the second differences.
00787     */
00788 
00789    /*
00790     * if we have a net insert on the first difference, AND inserting the
00791     * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
00792     * character (which is ne if nls != ne, otherwise is nse) off the edge
00793     * of the screen (el->fTerm.fSize.fH) else we do the deletes first
00794     * so that we keep everything we need to.
00795     */
00796 
00797    /*
00798     * if the last same is the same like the end, there is no last same
00799     * part, otherwise we want to keep the last same part set p to the
00800     * last useful old character
00801     */
00802    p = (ols != oe) ? oe : ose;
00803 
00804    /*
00805     * if (There is a diffence in the beginning) && (we need to insert
00806     *   characters) && (the number of characters to insert is less than
00807     *   the term width)
00808     *   We need to do an insert!
00809     * else if (we need to delete characters)
00810     *   We need to delete characters!
00811     * else
00812     *   No insert or delete
00813     */
00814    if ((nsb != nfd) && fx > 0 &&
00815        ((p - old) + fx <= el->fTerm.fSize.fH)) {
00816       ELRE_DEBUG(1,
00817                  (__F, "first diff insert at %d...\r\n", nfd - newp));
00818 
00819       /*
00820        * Move to the first char to insert, where the first diff is.
00821        */
00822       term_move_to_char(el, nfd - newp);
00823 
00824       /*
00825        * Check if we have stuff to keep at end
00826        */
00827       if (nsb != ne) {
00828          ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
00829 
00830          /*
00831           * insert fx chars of newp starting at nfd
00832           */
00833          if (fx > 0) {
00834             ELRE_DEBUG(!EL_CAN_INSERT, (__F,
00835                                         "ERROR: cannot insert in early first diff\n"));
00836             term_insertwrite(el, nfd, nfd_col, fx);
00837             re_insert(el, old, ofd - old,
00838                       el->fTerm.fSize.fH, nfd, fx);
00839          }
00840 
00841          /*
00842           * write (nsb-nfd) - fx chars of newp starting at
00843           * (nfd + fx)
00844           */
00845          term_overwrite(el, nfd + fx, nfd_col ? nfd_col + fx : 0, (nsb - nfd) - fx);
00846          re__strncopy(ofd + fx, nfd + fx,
00847                       (size_t) ((nsb - nfd) - fx));
00848       } else {
00849          ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
00850          term_overwrite(el, nfd, nfd_col, (nsb - nfd));
00851          re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
00852 
00853          /*
00854           * Done
00855           */
00856          return;
00857       }
00858    } else if (fx < 0) {
00859       ELRE_DEBUG(1,
00860                  (__F, "first diff delete at %d...\r\n", ofd - old));
00861 
00862       /*
00863        * move to the first char to delete where the first diff is
00864        */
00865       term_move_to_char(el, ofd - old);
00866 
00867       /*
00868        * Check if we have stuff to save
00869        */
00870       if (osb != oe) {
00871          ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
00872 
00873          /*
00874           * fx is less than zero *always* here but we check
00875           * for code symmetry
00876           */
00877          if (fx < 0) {
00878             ELRE_DEBUG(!EL_CAN_DELETE, (__F,
00879                                         "ERROR: cannot delete in first diff\n"));
00880             term_deletechars(el, -fx);
00881             re_delete(el, old, ofd - old,
00882                       el->fTerm.fSize.fH, -fx);
00883          }
00884 
00885          /*
00886           * write (nsb-nfd) chars of newp starting at nfd
00887           */
00888          term_overwrite(el, nfd, nfd_col, (nsb - nfd));
00889          re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
00890 
00891       } else {
00892          ELRE_DEBUG(1, (__F,
00893                         "but with nothing left to save\r\n"));
00894 
00895          /*
00896           * write (nsb-nfd) chars of newp starting at nfd
00897           */
00898          term_overwrite(el, nfd, nfd_col, (nsb - nfd));
00899          ELRE_DEBUG(1, (__F,
00900                         "cleareol %d\n", (oe - old) - (ne - newp)));
00901          term_clear_EOL(el, (oe - old) - (ne - newp));
00902 
00903          /*
00904           * Done
00905           */
00906          return;
00907       }
00908    } else {
00909       fx = 0;
00910    }
00911 
00912    if (sx < 0 && (ose - old) + fx < el->fTerm.fSize.fH) {
00913       ELRE_DEBUG(1, (__F,
00914                      "second diff delete at %d...\r\n", (ose - old) + fx));
00915 
00916       /*
00917        * Check if we have stuff to delete
00918        */
00919 
00920       /*
00921        * fx is the number of characters inserted (+) or deleted (-)
00922        */
00923 
00924       term_move_to_char(el, (ose - old) + fx);
00925 
00926       /*
00927        * Check if we have stuff to save
00928        */
00929       if (ols != oe) {
00930          ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
00931 
00932          /*
00933           * Again a duplicate test.
00934           */
00935          if (sx < 0) {
00936             ELRE_DEBUG(!EL_CAN_DELETE, (__F,
00937                                         "ERROR: cannot delete in second diff\n"));
00938             term_deletechars(el, -sx);
00939          }
00940 
00941          /*
00942           * write (nls-nse) chars of newp starting at nse
00943           */
00944          term_overwrite(el, nse, nse_col, (nls - nse));
00945       } else {
00946          ELRE_DEBUG(1, (__F,
00947                         "but with nothing left to save\r\n"));
00948          term_overwrite(el, nse, nse_col, (nls - nse));
00949          ELRE_DEBUG(1, (__F,
00950                         "cleareol %d\n", (oe - old) - (ne - newp)));
00951 
00952          if ((oe - old) - (ne - newp) != 0) {
00953             term_clear_EOL(el, (oe - old) - (ne - newp));
00954          }
00955       }
00956    }
00957 
00958    /*
00959     * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
00960     */
00961    if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
00962       ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
00963                      nfd - newp));
00964 
00965       term_move_to_char(el, nfd - newp);
00966 
00967       /*
00968        * Check if we have stuff to keep at the end
00969        */
00970       if (nsb != ne) {
00971          ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
00972 
00973          /*
00974           * We have to recalculate fx here because we set it
00975           * to zero above as a flag saying that we hadn't done
00976           * an early first insert.
00977           */
00978          fx = (nsb - nfd) - (osb - ofd);
00979 
00980          if (fx > 0) {
00981             /*
00982              * insert fx chars of newp starting at nfd
00983              */
00984             ELRE_DEBUG(!EL_CAN_INSERT, (__F,
00985                                         "ERROR: cannot insert in late first diff\n"));
00986             term_insertwrite(el, nfd, nfd_col, fx);
00987             re_insert(el, old, ofd - old,
00988                       el->fTerm.fSize.fH, nfd, fx);
00989          }
00990 
00991          /*
00992           * write (nsb-nfd) - fx chars of newp starting at
00993           * (nfd + fx)
00994           */
00995          term_overwrite(el, nfd + fx, nfd_col ? nfd_col + fx : 0, (nsb - nfd) - fx);
00996          re__strncopy(ofd + fx, nfd + fx,
00997                       (size_t) ((nsb - nfd) - fx));
00998       } else {
00999          ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
01000          term_overwrite(el, nfd, nfd_col, (nsb - nfd));
01001          re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
01002       }
01003    }
01004 
01005    /*
01006     * line is now NEW up to nse
01007     */
01008    if (sx >= 0) {
01009       ELRE_DEBUG(1, (__F,
01010                      "second diff insert at %d...\r\n", nse - newp));
01011       term_move_to_char(el, nse - newp);
01012 
01013       if (ols != oe) {
01014          ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
01015 
01016          if (sx > 0) {
01017             /* insert sx chars of newp starting at nse */
01018             ELRE_DEBUG(!EL_CAN_INSERT, (__F,
01019                                         "ERROR: cannot insert in second diff\n"));
01020             term_insertwrite(el, nse, nse_col, sx);
01021          }
01022 
01023          /*
01024           * write (nls-nse) - sx chars of newp starting at
01025           * (nse + sx)
01026           */
01027          term_overwrite(el, nse + sx, nse_col ? nse_col + sx : 0, (nls - nse) - sx);
01028       } else {
01029          ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
01030          term_overwrite(el, nse, nse_col, (nls - nse));
01031 
01032          /*
01033           * No need to do a clear-to-end here because we were
01034           * doing a second insert, so we will have over
01035           * written all of the old string.
01036           */
01037       }
01038    }
01039    ELRE_DEBUG(1, (__F, "done.\r\n"));
01040 } // re_update_line
01041 
01042 
01043 /* re_refresh_cursor():
01044  *      Move to the new cursor position
01045  */
01046 el_protected void
01047 re_refresh_cursor(EditLine_t* el) {
01048    char* cp, c;
01049    int h, v, th;
01050 
01051    /* first we must find where the cursor is... */
01052    h = el->fPrompt.fPos.fH;
01053    v = el->fPrompt.fPos.fV;
01054    th = el->fTerm.fSize.fH;           /* optimize for speed */
01055 
01056    /* do input buffer to el->fLine.fCursor */
01057    for (cp = el->fLine.fBuffer; cp < el->fLine.fCursor; cp++) {
01058       c = *cp;
01059       h++;                      /* all chars at least this long */
01060 
01061       if (c == '\n') {          /* handle newline in data part too */
01062          h = 0;
01063          v++;
01064       } else {
01065          if (c == '\t') {                       /* if a tab, to next tab stop */
01066             while (h & 07) {
01067                h++;
01068             }
01069          } else if (iscntrl((unsigned char) c)) {
01070             /* if control char */
01071             h++;
01072 
01073             if (h > th) {                       /* if overflow, compensate */
01074                h = 1;
01075                v++;
01076             }
01077          } else if (!isprint((unsigned char) c)) {
01078             h += 3;
01079 
01080             if (h > th) {                       /* if overflow, compensate */
01081                h = h - th;
01082                v++;
01083             }
01084          }
01085       }
01086 
01087       if (h >= th) {            /* check, extra long tabs picked up here also */
01088          h = 0;
01089          v++;
01090       }
01091    }
01092 
01093    /* now go there */
01094    term_move_to_line(el, v);
01095    term_move_to_char(el, h);
01096    term__flush();
01097 } // re_refresh_cursor
01098 
01099 
01100 /* re_fastputc():
01101  *      Add a character fast.
01102  */
01103 el_private void
01104 re_fastputc(EditLine_t* el, int c) {
01105    // color = get color info from el, pass to term__putc
01106    int curCharIndex = (el->fLine.fCursor - 1) - el->fLine.fBuffer;
01107    term__putcolorch(c, &el->fLine.fBufColor[curCharIndex]);
01108    el->fDisplay[el->fCursor.fV][el->fCursor.fH++] = c;
01109    (el->fDispColor[el->fCursor.fV][el->fCursor.fH]) = -1;
01110 
01111    if (el->fCursor.fH >= el->fTerm.fSize.fH) {
01112       /* if we must overflow */
01113       el->fCursor.fH = 0;
01114 
01115       /*
01116        * If we would overflow (input is longer than terminal size),
01117        * emulate scroll by dropping first line and shuffling the rest.
01118        * We do this via pointer shuffling - it's safe in this case
01119        * and we avoid memcpy().
01120        */
01121       if (el->fCursor.fV + 1 >= el->fTerm.fSize.fV) {
01122          int i, lins = el->fTerm.fSize.fV;
01123          char* firstline = el->fDisplay[0];
01124          ElColor_t* firstcolor = el->fDispColor[0];
01125 
01126          for (i = 1; i < lins; i++) {
01127             el->fDisplay[i - 1] = el->fDisplay[i];
01128             el->fDispColor[i - 1] = el->fDispColor[i];
01129          }
01130 
01131          re__copy_and_pad(firstline, "", 0);
01132          el->fDisplay[i - 1] = firstline;
01133          el->fDispColor[i - 1] = firstcolor;
01134       } else {
01135          el->fCursor.fV++;
01136          el->fRefresh.r_oldcv++;
01137       }
01138 
01139       if (EL_HAS_AUTO_MARGINS) {
01140          if (EL_HAS_MAGIC_MARGINS) {
01141             term__putcolorch(' ', NULL);
01142             term__putcolorch('\b', NULL);
01143          }
01144       } else {
01145          term__putcolorch('\r', NULL);
01146          term__putcolorch('\n', NULL);
01147       }
01148    }
01149 } // re_fastputc
01150 
01151 
01152 /* re_fastaddc():
01153  *      we added just one char, handle it fast.
01154  *      Assumes that screen cursor == real cursor
01155  */
01156 el_protected void
01157 re_fastaddc(EditLine_t* el) {
01158    char c;
01159    int rhdiff;
01160 
01161    c = el->fLine.fCursor[-1];
01162 
01163    if (c == '\t' || el->fLine.fCursor != el->fLine.fLastChar) {
01164       re_refresh(el);           /* too hard to handle */
01165       return;
01166    }
01167    rhdiff = el->fTerm.fSize.fH - el->fCursor.fH -
01168             el->fRPrompt.fPos.fH;
01169 
01170    if (el->fRPrompt.fPos.fH && rhdiff < 3) {
01171       re_refresh(el);           /* clear out rprompt if less than 1 char gap */
01172       return;
01173    }                            /* else (only do at end of line, no TAB) */
01174 
01175    if (iscntrl((unsigned char) c)) {            /* if control char, do caret */
01176       char mc = (c == '\177') ? '?' : (c | 0100);
01177       re_fastputc(el, '^');
01178       re_fastputc(el, mc);
01179    } else if (isprint((unsigned char) c)) {             /* normal char */
01180       re_fastputc(el, c);
01181    } else {
01182       re_fastputc(el, '\\');
01183       re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0'));
01184       re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0'));
01185       re_fastputc(el, (c & 7) + '0');
01186    }
01187    term__flush();
01188 } // re_fastaddc
01189 
01190 
01191 /* re_clear_display():
01192  *      clear the screen buffers so that new new prompt starts fresh.
01193  */
01194 el_protected void
01195 re_clear_display(EditLine_t* el) {
01196    int i;
01197 
01198    el->fCursor.fV = 0;
01199    el->fCursor.fH = 0;
01200 
01201    for (i = 0; i < el->fTerm.fSize.fV; i++) {
01202       el->fDisplay[i][0] = '\0';
01203       el->fDispColor[i][0] = -1;
01204    }
01205    el->fRefresh.r_oldcv = 0;
01206 }
01207 
01208 
01209 /* re_clear_lines():
01210  *      Make sure all lines are *really* blank
01211  */
01212 el_protected void
01213 re_clear_lines(EditLine_t* el) {
01214    if (EL_CAN_CEOL) {
01215       int i;
01216       term_move_to_char(el, 0);
01217 
01218       for (i = 0; i <= el->fRefresh.r_oldcv; i++) {
01219          /* for each line on the screen */
01220          term_move_to_line(el, i);
01221          term_clear_EOL(el, el->fTerm.fSize.fH);
01222       }
01223       term_move_to_line(el, 0);
01224    } else {
01225       term_move_to_line(el, el->fRefresh.r_oldcv);
01226       /* go to last line */
01227       term__putcolorch('\r', NULL);             /* go to BOL */
01228       term__putcolorch('\n', NULL);             /* go to new line */
01229    }
01230 } // re_clear_lines

Generated on Tue Jul 5 14:11:38 2011 for ROOT_528-00b_version by  doxygen 1.5.1