term.cxx

Go to the documentation of this file.
00001 // @(#)root/editline:$Id: term.cxx 36313 2010-10-12 12:40:20Z 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: term.c,v 1.32 2001/01/23 15:55:31 jdolecek 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  * term.c: Editor/termcap-curses interface
00050  *         We have to declare a static variable here, since the
00051  *         termcap putchar routine does not take an argument!
00052  */
00053 #include "sys.h"
00054 #include <stdio.h>
00055 #include <signal.h>
00056 #include <string.h>
00057 #include <stdlib.h>
00058 #include <unistd.h>
00059 #include <sys/types.h>
00060 #include <sys/ioctl.h>
00061 #include <string>
00062 
00063 #include "el.h"
00064 #include "TTermManip.h"
00065 
00066 // termcap.h an be extremely "dirty", polluting with CPP macros,
00067 // so #include last!
00068 #include "rlcurses.h"
00069 
00070 /*
00071  * IMPORTANT NOTE: these routines are allowed to look at the current screen
00072  * and the current possition assuming that it is correct.  If this is not
00073  * true, then the update will be WRONG!  This is (should be) a valid
00074  * assumption...
00075  */
00076 
00077 #define TC_BUFSIZE 2048
00078 
00079 #define GoodStr(a) (el->fTerm.fStr[a] != NULL && \
00080                     el->fTerm.fStr[a][0] != '\0')
00081 #define Str(a) el->fTerm.fStr[a]
00082 #define Val(a) el->fTerm.fVal[a]
00083 
00084 #ifdef notdef
00085 el_private const struct {
00086    const char* b_name;
00087    int b_rate;
00088 } baud_rate[] = {
00089 # ifdef B0
00090    { "0", B0 },
00091 # endif
00092 # ifdef B50
00093    { "50", B50 },
00094 # endif
00095 # ifdef B75
00096    { "75", B75 },
00097 # endif
00098 # ifdef B110
00099    { "110", B110 },
00100 # endif
00101 # ifdef B134
00102    { "134", B134 },
00103 # endif
00104 # ifdef B150
00105    { "150", B150 },
00106 # endif
00107 # ifdef B200
00108    { "200", B200 },
00109 # endif
00110 # ifdef B300
00111    { "300", B300 },
00112 # endif
00113 # ifdef B600
00114    { "600", B600 },
00115 # endif
00116 # ifdef B900
00117    { "900", B900 },
00118 # endif
00119 # ifdef B1200
00120    { "1200", B1200 },
00121 # endif
00122 # ifdef B1800
00123    { "1800", B1800 },
00124 # endif
00125 # ifdef B2400
00126    { "2400", B2400 },
00127 # endif
00128 # ifdef B3600
00129    { "3600", B3600 },
00130 # endif
00131 # ifdef B4800
00132    { "4800", B4800 },
00133 # endif
00134 # ifdef B7200
00135    { "7200", B7200 },
00136 # endif
00137 # ifdef B9600
00138    { "9600", B9600 },
00139 # endif
00140 # ifdef EXTA
00141    { "19200", EXTA },
00142 # endif
00143 # ifdef B19200
00144    { "19200", B19200 },
00145 # endif
00146 # ifdef EXTB
00147    { "38400", EXTB },
00148 # endif
00149 # ifdef B38400
00150    { "38400", B38400 },
00151 # endif
00152    { NULL, 0 }
00153 };
00154 #endif
00155 
00156 el_private const struct TermCapStr_t {
00157    const char* fName;
00158    const char* fLongName;
00159 } tstr[] = {
00160 #define T_al 0
00161    { "al", "add new blank line" },
00162 #define T_bl 1
00163    { "bl", "audible bell" },
00164 #define T_cd 2
00165    { "cd", "clear to bottom" },
00166 #define T_ce 3
00167    { "ce", "clear to end of line" },
00168 #define T_ch 4
00169    { "ch", "cursor to horiz pos" },
00170 #define T_cl 5
00171    { "cl", "clear screen" },
00172 #define T_dc 6
00173    { "dc", "delete a character" },
00174 #define T_dl 7
00175    { "dl", "delete a line" },
00176 #define T_dm 8
00177    { "dm", "start delete mode" },
00178 #define T_ed 9
00179    { "ed", "end delete mode" },
00180 #define T_ei 10
00181    { "ei", "end insert mode" },
00182 #define T_fs 11
00183    { "fs", "cursor from status line" },
00184 #define T_ho 12
00185    { "ho", "home cursor" },
00186 #define T_ic 13
00187    { "ic", "insert character" },
00188 #define T_im 14
00189    { "im", "start insert mode" },
00190 #define T_ip 15
00191    { "ip", "insert padding" },
00192 #define T_kd 16
00193    { "kd", "sends cursor down" },
00194 #define T_kl 17
00195    { "kl", "sends cursor left" },
00196 #define T_kr 18
00197    { "kr", "sends cursor right" },
00198 #define T_ku 19
00199    { "ku", "sends cursor up" },
00200 #define T_md 20
00201    { "md", "begin bold" },
00202 #define T_me 21
00203    { "me", "end attributes" },
00204 #define T_nd 22
00205    { "nd", "non destructive space" },
00206 #define T_se 23
00207    { "se", "end standout" },
00208 #define T_so 24
00209    { "so", "begin standout" },
00210 #define T_ts 25
00211    { "ts", "cursor to status line" },
00212 #define T_up 26
00213    { "up", "cursor up one" },
00214 #define T_us 27
00215    { "us", "begin underline" },
00216 #define T_ue 28
00217    { "ue", "end underline" },
00218 #define T_vb 29
00219    { "vb", "visible bell" },
00220 #define T_DC 30
00221    { "DC", "delete multiple chars" },
00222 #define T_DO 31
00223    { "DO", "cursor down multiple" },
00224 #define T_IC 32
00225    { "IC", "insert multiple chars" },
00226 #define T_LE 33
00227    { "LE", "cursor left multiple" },
00228 #define T_RI 34
00229    { "RI", "cursor right multiple" },
00230 #define T_UP 35
00231    { "UP", "cursor up multiple" },
00232 #define T_kh 36
00233    { "kh", "send cursor home" },
00234 #define T_at7 37
00235    { "@7", "send cursor end" },
00236 #define T_kD 38
00237    { "kD", "delete a character" },
00238 #define T_str 39
00239    { NULL, NULL }
00240 };
00241 
00242 el_private const struct TermCapVal_t {
00243    const char* fName;
00244    const char* fLongName;
00245 } tval[] = {
00246 #define T_am 0
00247    { "am", "has automatic margins" },
00248 #define T_pt 1
00249    { "pt", "has physical tabs" },
00250 #define T_li 2
00251    { "li", "Number of lines" },
00252 #define T_co 3
00253    { "co", "Number of columns" },
00254 #define T_km 4
00255    { "km", "Has meta key" },
00256 #define T_xt 5
00257    { "xt", "Tab chars destructive" },
00258 #define T_xn 6
00259    { "xn", "newline ignored at right margin" },
00260 #define T_MT 7
00261    { "MT", "Has meta key" },                            /* XXX? */
00262 #define T_val 8
00263    { NULL, NULL, }
00264 };
00265 /* do two or more of the attributes use me */
00266 
00267 el_private void term_setflags(EditLine_t*);
00268 el_private int term_rebuffer_display(EditLine_t*);
00269 el_private void term_free_display(EditLine_t*);
00270 el_private int term_alloc_display(EditLine_t*);
00271 el_private void term_alloc(EditLine_t*, const struct TermCapStr_t*, const char*);
00272 el_private void term_init_arrow(EditLine_t*);
00273 el_private void term_reset_arrow(EditLine_t*);
00274 el_private void term_init_color(EditLine_t*);
00275 
00276 
00277 el_private FILE* term_outfile = NULL;   /* XXX: How do we fix that? */
00278 
00279 
00280 /* term_setflags():
00281  *      Set the terminal capability flags
00282  */
00283 el_private void
00284 term_setflags(EditLine_t* el) {
00285    EL_FLAGS = 0;
00286 
00287    if (el->fTTY.t_tabs) {
00288       EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0;
00289    }
00290 
00291    EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0;
00292    EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0;
00293    EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0;
00294    EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ?
00295                TERM_CAN_INSERT : 0;
00296    EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0;
00297    EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0;
00298    EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0;
00299 
00300    if (GoodStr(T_me) && GoodStr(T_ue)) {
00301       EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ?
00302                   TERM_CAN_ME : 0;
00303    } else {
00304       EL_FLAGS &= ~TERM_CAN_ME;
00305    }
00306 
00307    if (GoodStr(T_me) && GoodStr(T_se)) {
00308       EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ?
00309                   TERM_CAN_ME : 0;
00310    }
00311 
00312 
00313 #ifdef DEBUG_SCREEN
00314 
00315    if (!EL_CAN_UP) {
00316       (void) fprintf(el->fErrFile,
00317                      "WARNING: Your terminal cannot move up.\n");
00318       (void) fprintf(el->fErrFile,
00319                      "Editing may be odd for long lines.\n");
00320    }
00321 
00322    if (!EL_CAN_CEOL) {
00323       (void) fprintf(el->fErrFile, "no clear EOL capability.\n");
00324    }
00325 
00326    if (!EL_CAN_DELETE) {
00327       (void) fprintf(el->fErrFile, "no delete char capability.\n");
00328    }
00329 
00330    if (!EL_CAN_INSERT) {
00331       (void) fprintf(el->fErrFile, "no insert char capability.\n");
00332    }
00333 #endif /* DEBUG_SCREEN */
00334 } // term_setflags
00335 
00336 
00337 /* term_init():
00338  *      Initialize the terminal stuff
00339  */
00340 el_protected int
00341 term_init(EditLine_t* el) {
00342    el->fTerm.fBuf = (char*) el_malloc(TC_BUFSIZE);
00343 
00344    if (el->fTerm.fBuf == NULL) {
00345       return -1;
00346    }
00347    el->fTerm.fCap = (char*) el_malloc(TC_BUFSIZE);
00348 
00349    if (el->fTerm.fCap == NULL) {
00350       return -1;
00351    }
00352    el->fTerm.fFKey = (FKey_t*) el_malloc(A_K_NKEYS * sizeof(FKey_t));
00353 
00354    if (el->fTerm.fFKey == NULL) {
00355       return -1;
00356    }
00357    el->fTerm.fLoc = 0;
00358    el->fTerm.fStr = (char**) el_malloc(T_str * sizeof(char*));
00359 
00360    if (el->fTerm.fStr == NULL) {
00361       return -1;
00362    }
00363    (void) memset(el->fTerm.fStr, 0, T_str * sizeof(char*));
00364    el->fTerm.fVal = (int*) el_malloc(T_val * sizeof(int));
00365 
00366    if (el->fTerm.fVal == NULL) {
00367       return -1;
00368    }
00369    (void) memset(el->fTerm.fVal, 0, T_val * sizeof(int));
00370    term_outfile = el->fOutFile;
00371 
00372    if (term_set(el, NULL) == -1) {
00373       return -1;
00374    }
00375    term_init_arrow(el);
00376 
00377    term_init_color(el);
00378 
00379    return 0;
00380 } // term_init
00381 
00382 
00383 /* term_end():
00384  *      Clean up the terminal stuff
00385  */
00386 el_protected void
00387 term_end(EditLine_t* el) {
00388    el_free((ptr_t) el->fTerm.fBuf);
00389    el->fTerm.fBuf = NULL;
00390    el_free((ptr_t) el->fTerm.fCap);
00391    el->fTerm.fCap = NULL;
00392    el->fTerm.fLoc = 0;
00393    el_free((ptr_t) el->fTerm.fStr);
00394    el->fTerm.fStr = NULL;
00395    el_free((ptr_t) el->fTerm.fVal);
00396    el->fTerm.fVal = NULL;
00397    term_free_display(el);
00398 }
00399 
00400 
00401 /* term_alloc():
00402  *      Maintain a string pool for termcap strings
00403  */
00404 el_private void
00405 term_alloc(EditLine_t* el, const struct TermCapStr_t* t, const char* cap) {
00406    char termbuf[TC_BUFSIZE];
00407    int tlen, clen;
00408    char** tlist = el->fTerm.fStr;
00409    char** tmp, ** str = &tlist[t - tstr];
00410 
00411    if (cap == NULL || *cap == '\0') {
00412       *str = NULL;
00413       return;
00414    } else {
00415       clen = strlen(cap);
00416    }
00417 
00418    tlen = *str == NULL ? 0 : strlen(*str);
00419 
00420    /*
00421     * New string is shorter; no need to allocate space
00422     */
00423    if (clen <= tlen) {
00424       // coverity[secure_coding]
00425       (void) strcpy(*str, cap);                 /* XXX strcpy is safe */
00426       return;
00427    }
00428 
00429    /*
00430     * New string is longer; see if we have enough space to append
00431     */
00432    if (el->fTerm.fLoc + 3 < TC_BUFSIZE) {
00433       /* XXX strcpy is safe */
00434       // coverity[secure_coding]
00435       (void) strcpy(*str = &el->fTerm.fBuf[el->fTerm.fLoc],
00436                     cap);
00437       el->fTerm.fLoc += clen + 1;            /* one for \0 */
00438       return;
00439    }
00440 
00441    /*
00442     * Compact our buffer; no need to check compaction, cause we know it
00443     * fits...
00444     */
00445    tlen = 0;
00446 
00447    for (tmp = tlist; tmp < &tlist[T_str]; tmp++) {
00448       if (*tmp != NULL && *tmp != '\0' && *tmp != *str) {
00449          char* ptr;
00450 
00451          for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) {
00452             continue;
00453          }
00454          termbuf[tlen++] = '\0';
00455       }
00456    }
00457    memcpy(el->fTerm.fBuf, termbuf, TC_BUFSIZE);
00458    el->fTerm.fLoc = tlen;
00459 
00460    if (el->fTerm.fLoc + 3 >= TC_BUFSIZE) {
00461       (void) fprintf(el->fErrFile,
00462                      "Out of termcap string space.\n");
00463       return;
00464    }
00465    /* XXX strcpy is safe */
00466    // coverity[secure_coding]
00467    (void) strcpy(*str = &el->fTerm.fBuf[el->fTerm.fLoc], cap);
00468    el->fTerm.fLoc += clen + 1;       /* one for \0 */
00469    return;
00470 } // term_alloc
00471 
00472 
00473 /* term_rebuffer_display():
00474  *      Rebuffer the display after the screen changed size
00475  */
00476 el_private int
00477 term_rebuffer_display(EditLine_t* el) {
00478    ElCoord_t* c = &el->fTerm.fSize;
00479 
00480    term_free_display(el);
00481 
00482    c->fH = Val(T_co);
00483    c->fV = Val(T_li);
00484 
00485    if (term_alloc_display(el) == -1) {
00486       return -1;
00487    }
00488    return 0;
00489 }
00490 
00491 
00492 /* term_alloc_display():
00493  *      Allocate a new display.
00494  */
00495 el_private int
00496 term_alloc_display(EditLine_t* el) {                      // LOUISE COLOUR : duplicated all display functionality for colour
00497    int i;
00498    char** b;
00499    ElColor_t** col;
00500    ElCoord_t* c = &el->fTerm.fSize;
00501 
00502    // original display
00503    b = (char**) el_malloc((size_t) (sizeof(char*) * (c->fV + 1)));
00504 
00505    if (b == NULL) {
00506       return -1;
00507    }
00508 
00509    for (i = 0; i < c->fV; i++) {
00510       b[i] = (char*) el_malloc((size_t) (sizeof(char) * (c->fH + 1)));
00511 
00512       if (b[i] == NULL) {
00513          el_free((ptr_t) b);
00514          return -1;
00515       }
00516    }
00517    b[c->fV] = NULL;
00518    el->fDisplay = b;
00519 
00520    // duplicate el_display for el_dispcolor
00521    col = (ElColor_t**) el_malloc((size_t) (sizeof(ElColor_t*) * (c->fV + 1)));
00522 
00523    if (col == NULL) {
00524       return -1;
00525    }
00526 
00527    for (i = 0; i < c->fV; i++) {
00528       col[i] = (ElColor_t*) el_malloc((size_t) (sizeof(ElColor_t) * (c->fH + 1)));
00529 
00530       if (col[i] == NULL) {
00531          el_free((ptr_t) col);
00532          return -1;
00533       }
00534    }
00535    col[c->fV] = NULL;
00536    el->fDispColor = col;
00537 
00538    // original el_vdisplay code
00539    b = (char**) el_malloc((size_t) (sizeof(char*) * (c->fV + 1)));
00540 
00541    if (b == NULL) {
00542       return -1;
00543    }
00544 
00545    for (i = 0; i < c->fV; i++) {
00546       b[i] = (char*) el_malloc((size_t) (sizeof(char) * (c->fH + 1)));
00547 
00548       if (b[i] == NULL) {
00549          for (int ii = 0; ii < i; ++ii) {
00550             el_free((ptr_t) b[ii]);
00551          }
00552          el_free((ptr_t) b);
00553          return -1;
00554       }
00555    }
00556    b[c->fV] = NULL;
00557    el->fVDisplay = b;
00558 
00559    // duplicate el_vdisplay functionality for el_vdispcolor
00560    col = (ElColor_t**) el_malloc((size_t) (sizeof(ElColor_t*) * (c->fV + 1)));
00561 
00562    if (col == NULL) {
00563       return -1;
00564    }
00565 
00566    for (i = 0; i < c->fV; i++) {
00567       col[i] = (ElColor_t*) el_malloc((size_t) (sizeof(ElColor_t) * (c->fH + 1)));
00568 
00569       if (col[i] == NULL) {
00570          for (int ii = 0; ii < i; ++ii) {
00571             el_free((ptr_t) col[ii]);
00572          }
00573          el_free((ptr_t) col);
00574          return -1;
00575       }
00576    }
00577    col[c->fV] = NULL;
00578    el->fVDispColor = col;
00579 
00580    return 0;
00581 } // term_alloc_display
00582 
00583 
00584 /* term_free_display():
00585  *      Free the display buffers
00586  */
00587 el_private void
00588 term_free_display(EditLine_t* el) {               // LOUISE COLOUR : duplicated all display functionality for colour
00589    char** b;
00590    char** bufp;
00591    ElColor_t** c;
00592    ElColor_t** bufc;
00593 
00594    // free display (original)
00595    b = el->fDisplay;
00596    el->fDisplay = NULL;
00597 
00598    if (b != NULL) {
00599       for (bufp = b; *bufp != NULL; bufp++) {
00600          el_free((ptr_t) *bufp);
00601       }
00602       el_free((ptr_t) b);
00603    }
00604 
00605    // free display colour info
00606    c = el->fDispColor;
00607    el->fDispColor = NULL;
00608 
00609    if (c != NULL) {
00610       for (bufc = c; *bufc != NULL; bufc++) {
00611          el_free((ptr_t) *bufc);
00612       }
00613       el_free((ptr_t) c);
00614    }
00615 
00616    // free vdisplay (original)
00617    b = el->fVDisplay;
00618    el->fVDisplay = NULL;
00619 
00620    if (b != NULL) {
00621       for (bufp = b; *bufp != NULL; bufp++) {
00622          el_free((ptr_t) *bufp);
00623       }
00624       el_free((ptr_t) b);
00625    }
00626 
00627    // free vdisplay colour info
00628    c = el->fVDispColor;
00629    el->fVDispColor = NULL;
00630 
00631    if (c != NULL) {
00632       for (bufc = c; *bufc != NULL; bufc++) {
00633          el_free((ptr_t) *bufc);
00634       }
00635       el_free((ptr_t) c);
00636    }
00637 } // term_free_display
00638 
00639 
00640 /* term_move_to_line():
00641  *      move to line <where> (first line == 0)
00642  *      as efficiently as possible
00643  */
00644 el_protected void
00645 term_move_to_line(EditLine_t* el, int where) {
00646    int del;
00647 
00648    if (where == el->fCursor.fV) {
00649       return;
00650    }
00651 
00652    if (where > el->fTerm.fSize.fV) {
00653 #ifdef DEBUG_SCREEN
00654          (void) fprintf(el->fErrFile,
00655                         "term_move_to_line: where is ridiculous: %d\r\n", where);
00656 #endif /* DEBUG_SCREEN */
00657       return;
00658    }
00659 
00660    if ((del = where - el->fCursor.fV) > 0) {
00661       while (del > 0) {
00662          if (EL_HAS_AUTO_MARGINS &&
00663              el->fDisplay[el->fCursor.fV][0] != '\0') {
00664             /* move without newline */
00665             term_move_to_char(el, el->fTerm.fSize.fH - 1);
00666             term_overwrite(el,
00667                            &el->fDisplay[el->fCursor.fV][el->fCursor.fH],
00668                            &el->fDispColor[el->fCursor.fV][el->fCursor.fH],
00669                            1);
00670             /* updates Cursor */
00671             del--;
00672          } else {
00673             if ((del > 1) && GoodStr(T_DO)) {
00674                (void) tputs(tgoto(Str(T_DO), del, del), del, term__putc);
00675                del = 0;
00676             } else {
00677                for ( ; del > 0; del--) {
00678                   term__putcolorch('\n', NULL);
00679                }
00680                /* because the \n will become \r\n */
00681                el->fCursor.fH = 0;
00682             }
00683          }
00684       }
00685    } else {                     /* del < 0 */
00686       if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) {
00687          (void) tputs(tgoto(Str(T_UP), -del, -del), -del, term__putc);
00688       } else {
00689          if (GoodStr(T_up)) {
00690             for ( ; del < 0; del++) {
00691                (void) tputs(Str(T_up), 1, term__putc);
00692             }
00693          }
00694       }
00695    }
00696    el->fCursor.fV = where;     /* now where is here */
00697 } // term_move_to_line
00698 
00699 
00700 /* term_move_to_char():
00701  *      Move to the character position specified
00702  */
00703 el_protected void
00704 term_move_to_char(EditLine_t* el, int where) {
00705    int del, i;
00706 
00707 mc_again:
00708 
00709    if (where == el->fCursor.fH) {
00710       return;
00711    }
00712 
00713    if (where > el->fTerm.fSize.fH) {
00714 #ifdef DEBUG_SCREEN
00715          (void) fprintf(el->fErrFile,
00716                         "term_move_to_char: where is riduculous: %d\r\n", where);
00717 #endif /* DEBUG_SCREEN */
00718       return;
00719    }
00720 
00721    if (!where) {                /* if where is first column */
00722       term__putcolorch('\r', NULL);             /* do a CR */
00723       el->fCursor.fH = 0;
00724       return;
00725    }
00726    del = where - el->fCursor.fH;
00727 
00728    if ((del < -4 || del > 4) && GoodStr(T_ch)) {
00729       /* go there directly */
00730       (void) tputs(tgoto(Str(T_ch), where, where), where, term__putc);
00731    } else {
00732       if (del > 0) {            /* moving forward */
00733          if ((del > 4) && GoodStr(T_RI)) {
00734             (void) tputs(tgoto(Str(T_RI), del, del), del, term__putc);
00735          } else {
00736             /* if I can do tabs, use them */
00737             if (EL_CAN_TAB) {
00738                if ((el->fCursor.fH & 0370) !=
00739                    (where & 0370)) {
00740                   /* if not within tab stop */
00741                   for (i =
00742                           (el->fCursor.fH & 0370);
00743                        i < (where & 0370);
00744                        i += 8) {
00745                      term__putcolorch('\t', NULL);
00746                   }
00747                   /* then tab over */
00748                   el->fCursor.fH = where & 0370;
00749                }
00750             }
00751 
00752             /*
00753              * it's usually cheaper to just write the
00754              * chars, so we do.
00755              */
00756 
00757             /*
00758              * NOTE THAT term_overwrite() WILL CHANGE
00759              * el->fCursor.fH!!!
00760              */
00761             term_overwrite(el,
00762                            &el->fDisplay[el->fCursor.fV][el->fCursor.fH],
00763                            &el->fDispColor[el->fCursor.fV][el->fCursor.fH],
00764                            where - el->fCursor.fH);
00765 
00766          }
00767       } else {                  /* del < 0 := moving backward */
00768          if ((-del > 4) && GoodStr(T_LE)) {
00769             (void) tputs(tgoto(Str(T_LE), -del, -del), -del, term__putc);
00770          } else {               /* can't go directly there */
00771                                 /*
00772                                  * if the "cost" is greater than the "cost"
00773                                  * from col 0
00774                                  */
00775             if (EL_CAN_TAB ?
00776                 (-del > ((where >> 3) +
00777                          (where & 07)))
00778                 : (-del > where)) {
00779                term__putcolorch('\r', NULL);                            /* do a CR */
00780                el->fCursor.fH = 0;
00781                goto mc_again;                           /* and try again */
00782             }
00783 
00784             for (i = 0; i < -del; i++) {
00785                term__putcolorch('\b', &el->fDispColor[el->fCursor.fV][el->fCursor.fH]);
00786             }
00787          }
00788       }
00789    }
00790    el->fCursor.fH = where;                     /* now where is here */
00791 } // term_move_to_char
00792 
00793 
00794 /* term_overwrite():
00795  *      Overstrike num characters
00796  */
00797 el_protected void
00798 term_overwrite(EditLine_t* el, const char* cp, ElColor_t* color, int n) {
00799    if (n <= 0) {
00800       return;                   /* catch bugs */
00801 
00802    }
00803 
00804    if (n > el->fTerm.fSize.fH) {
00805 #ifdef DEBUG_SCREEN
00806          (void) fprintf(el->fErrFile,
00807                         "term_overwrite: n is riduculous: %d\r\n", n);
00808 #endif /* DEBUG_SCREEN */
00809       return;
00810    }
00811 
00812    do {
00813       if (color) {
00814          el->fDispColor[el->fCursor.fV][el->fCursor.fH] = *color;
00815       }
00816       term__putcolorch(*cp++, /*&(el->fLine.fBufColor[cp - el->fLine.fBuffer])*/ color ? color++ : 0);
00817       el->fCursor.fH++;
00818    }
00819    while (--n);
00820 
00821    if (el->fCursor.fH >= el->fTerm.fSize.fH) {       /* wrap? */
00822       if (EL_HAS_AUTO_MARGINS) {                /* yes */
00823          el->fCursor.fH = 0;
00824          el->fCursor.fV++;
00825 
00826          if (EL_HAS_MAGIC_MARGINS) {
00827             /* force the wrap to avoid the "magic"
00828              * situation */
00829             char c;
00830 
00831             if ((c = el->fDisplay[el->fCursor.fV][el->fCursor.fH]) != '\0') {
00832                term_overwrite(el, &c, &el->fDispColor[el->fCursor.fV][el->fCursor.fH], 1);
00833             } else {
00834                term__putcolorch(' ', NULL);
00835             }
00836             el->fCursor.fH = 1;
00837          }
00838       } else {                  /* no wrap, but cursor stays on screen */
00839          el->fCursor.fH = el->fTerm.fSize.fH;
00840       }
00841    }
00842 } // term_overwrite
00843 
00844 
00845 /* term_deletechars():
00846  *      Delete num characters
00847  */
00848 el_protected void
00849 term_deletechars(EditLine_t* el, int num) {
00850    if (num <= 0) {
00851       return;
00852    }
00853 
00854    if (!EL_CAN_DELETE) {
00855 #ifdef DEBUG_EDIT
00856          (void) fprintf(el->fErrFile, "   ERROR: cannot delete   \n");
00857 #endif /* DEBUG_EDIT */
00858       return;
00859    }
00860 
00861    if (num > el->fTerm.fSize.fH) {
00862 #ifdef DEBUG_SCREEN
00863          (void) fprintf(el->fErrFile,
00864                         "term_deletechars: num is riduculous: %d\r\n", num);
00865 #endif /* DEBUG_SCREEN */
00866       return;
00867    }
00868 
00869    if (GoodStr(T_DC)) {         /* if I have multiple delete */
00870       if ((num > 1) || !GoodStr(T_dc)) {                /* if dc would be more
00871                                                          * expen. */
00872          (void) tputs(tgoto(Str(T_DC), num, num), num, term__putc);
00873          return;
00874       }
00875    }
00876 
00877    if (GoodStr(T_dm)) {         /* if I have delete mode */
00878       (void) tputs(Str(T_dm), 1, term__putc);
00879    }
00880 
00881    if (GoodStr(T_dc)) {         /* else do one at a time */
00882       while (num--)
00883          (void) tputs(Str(T_dc), 1, term__putc);
00884    }
00885 
00886    if (GoodStr(T_ed)) {         /* if I have delete mode */
00887       (void) tputs(Str(T_ed), 1, term__putc);
00888    }
00889 } // term_deletechars
00890 
00891 
00892 /* term_insertwrite():
00893  *      Puts terminal in insert character mode or inserts num
00894  *      characters in the line
00895  */
00896 el_protected void
00897 term_insertwrite(EditLine_t* el, const char* cp, ElColor_t* color, int num) {
00898    if (num <= 0) {
00899       return;
00900    }
00901 
00902    if (!EL_CAN_INSERT) {
00903 #ifdef DEBUG_EDIT
00904          (void) fprintf(el->fErrFile, "   ERROR: cannot insert   \n");
00905 #endif /* DEBUG_EDIT */
00906       return;
00907    }
00908 
00909    if (num > el->fTerm.fSize.fH) {
00910 #ifdef DEBUG_SCREEN
00911          (void) fprintf(el->fErrFile,
00912                         "StartInsert: num is riduculous: %d\r\n", num);
00913 #endif /* DEBUG_SCREEN */
00914       return;
00915    }
00916 
00917    if (GoodStr(T_IC)) {         /* if I have multiple insert */
00918       if ((num > 1) || !GoodStr(T_ic)) {
00919          /* if ic would be more expensive */
00920 
00921          (void) tputs(tgoto(Str(T_IC), num, num), num, term__putc);
00922          term_overwrite(el, cp, color, num);
00923 
00924          /* this updates el_cursor.fH */
00925          return;
00926       }
00927    }
00928 
00929    if (GoodStr(T_im) && GoodStr(T_ei)) {        /* if I have insert mode */
00930       (void) tputs(Str(T_im), 1, term__putc);
00931 
00932       el->fCursor.fH += num;
00933 
00934       do {
00935          // need to get color info about cp
00936          term__putcolorch(*cp++, /*&(el->fLine.fBufColor[cp - el->fLine.fBuffer])*/ color ? color++ : 0);
00937       }
00938       while (--num);
00939 
00940       if (GoodStr(T_ip)) {              /* have to make num chars insert */
00941          (void) tputs(Str(T_ip), 1, term__putc);
00942       }
00943 
00944       (void) tputs(Str(T_ei), 1, term__putc);
00945       return;
00946    }
00947 
00948    do {
00949       if (GoodStr(T_ic)) {              /* have to make num chars insert */
00950          (void) tputs(Str(T_ic), 1, term__putc);
00951       }
00952       /* insert a char */
00953       term__putcolorch(*cp++, /*&(el->fLine.fBufColor[cp - el->fLine.fBuffer])*/ color ? color++ : 0);
00954 
00955       el->fCursor.fH++;
00956 
00957       if (GoodStr(T_ip)) {              /* have to make num chars insert */
00958          (void) tputs(Str(T_ip), 1, term__putc);
00959       }
00960       /* pad the inserted char */
00961 
00962    }
00963    while (--num);
00964 } // term_insertwrite
00965 
00966 
00967 /* term_clear_EOL():
00968  *      clear to end of line.  There are num characters to clear
00969  */
00970 el_protected void
00971 term_clear_EOL(EditLine_t* el, int num) {
00972    int i;
00973 
00974    if (EL_CAN_CEOL && GoodStr(T_ce)) {
00975       (void) tputs(Str(T_ce), 1, term__putc);
00976    } else {
00977       for (i = 0; i < num; i++) {
00978          term__putcolorch(' ', NULL);
00979       }
00980       el->fCursor.fH += num;           /* have written num spaces */
00981    }
00982 }
00983 
00984 
00985 /* term_clear_screen():
00986  *      Clear the screen
00987  */
00988 el_protected void
00989 term_clear_screen(EditLine_t* el) { /* clear the whole screen and home */
00990    if (GoodStr(T_cl)) {
00991       /* send the clear screen code */
00992       (void) tputs(Str(T_cl), Val(T_li), term__putc);
00993    } else if (GoodStr(T_ho) && GoodStr(T_cd)) {
00994       (void) tputs(Str(T_ho), Val(T_li), term__putc);           /* home */
00995       /* clear to bottom of screen */
00996       (void) tputs(Str(T_cd), Val(T_li), term__putc);
00997    } else {
00998       term__putcolorch('\r', NULL);
00999       term__putcolorch('\n', NULL);
01000    }
01001 }
01002 
01003 
01004 /* term_beep():
01005  *      Beep the way the terminal wants us
01006  */
01007 el_protected void
01008 term_beep(EditLine_t* el) {
01009    if (GoodStr(T_bl)) {
01010       /* what termcap says we should use */
01011       (void) tputs(Str(T_bl), 1, term__putc);
01012    } else {
01013       term__putcolorch('\007', NULL);           /* an ASCII bell; ^G */
01014    }
01015 }
01016 
01017 
01018 #ifdef notdef
01019 
01020 /* term_clear_to_bottom():
01021  *      Clear to the bottom of the screen
01022  */
01023 el_protected void
01024 term_clear_to_bottom(EditLine_t* el) {
01025    if (GoodStr(T_cd)) {
01026       (void) tputs(Str(T_cd), Val(T_li), term__putc);
01027    } else if (GoodStr(T_ce)) {
01028       (void) tputs(Str(T_ce), Val(T_li), term__putc);
01029    }
01030 }
01031 
01032 
01033 #endif
01034 
01035 
01036 /* term_set():
01037  *      Read in the terminal capabilities from the requested terminal
01038  */
01039 el_protected int
01040 term_set(EditLine_t* el, const char* term) {
01041    int i;
01042    char buf[TC_BUFSIZE];
01043    char* area;
01044    const struct TermCapStr_t* t;
01045    sigset_t oset, nset;
01046    int lins, cols;
01047 
01048    (void) sigemptyset(&nset);
01049    (void) sigaddset(&nset, SIGWINCH);
01050    (void) sigprocmask(SIG_BLOCK, &nset, &oset);
01051 
01052    area = buf;
01053 
01054    if (term == NULL) {
01055       term = getenv("TERM");
01056    }
01057 
01058    if (!term || !term[0]
01059        || !isatty(0)
01060        || !isatty(1)) {
01061       term = "dumb";
01062    }
01063 
01064    if (strcmp(term, "emacs") == 0
01065        || !isatty(0)) {
01066       el->fFlags |= EDIT_DISABLED;
01067    }
01068 
01069    memset(el->fTerm.fCap, 0, TC_BUFSIZE);
01070 
01071    i = tgetent(el->fTerm.fCap, term);
01072 
01073    if (i <= 0) {
01074       if (i == -1) {
01075          (void) fprintf(el->fErrFile,
01076                         "Cannot read termcap database;\n");
01077       } else if (i == 0) {
01078          (void) fprintf(el->fErrFile,
01079                         "No entry for terminal type \"%s\";\n", term);
01080       }
01081       (void) fprintf(el->fErrFile,
01082                      "using dumb terminal settings.\n");
01083       Val(T_co) = 80;           /* do a dumb terminal */
01084       Val(T_pt) = Val(T_km) = Val(T_li) = 0;
01085       Val(T_xt) = Val(T_MT);
01086 
01087       for (t = tstr; t->fName != NULL; t++) {
01088          term_alloc(el, t, NULL);
01089       }
01090    } else {
01091       /* auto/magic margins */
01092       Val(T_am) = tgetflag((char*)"am");
01093       Val(T_xn) = tgetflag((char*)"xn");
01094       /* Can we tab */
01095       Val(T_pt) = tgetflag((char*)"pt");
01096       Val(T_xt) = tgetflag((char*)"xt");
01097       /* do we have a meta? */
01098       Val(T_km) = tgetflag((char*)"km");
01099       Val(T_MT) = tgetflag((char*)"MT");
01100       /* Get the size */
01101       Val(T_co) = tgetnum((char*)"co");
01102       Val(T_li) = tgetnum((char*)"li");
01103 
01104       for (t = tstr; t->fName != NULL; t++) {
01105          term_alloc(el, t, tgetstr((char*)t->fName, &area));
01106       }
01107    }
01108 
01109    if (Val(T_co) < 2) {
01110       Val(T_co) = 80;           /* just in case */
01111    }
01112 
01113    if (Val(T_li) < 1) {
01114       Val(T_li) = 24;
01115    }
01116 
01117    el->fTerm.fSize.fV = Val(T_co);
01118    el->fTerm.fSize.fH = Val(T_li);
01119 
01120    term_setflags(el);
01121 
01122    /* get the correct window size */
01123    (void) term_get_size(el, &lins, &cols);
01124 
01125    if (term_change_size(el, lins, cols) == -1) {
01126       return -1;
01127    }
01128    (void) sigprocmask(SIG_SETMASK, &oset, NULL);
01129    term_bind_arrow(el);
01130    return i <= 0 ? -1 : 0;
01131 } // term_set
01132 
01133 
01134 /* term_get_size():
01135  *      Return the new window size in lines and cols, and
01136  *      true if the size was changed.
01137  */
01138 el_protected int
01139 term_get_size(EditLine_t* el, int* lins, int* cols) {
01140    *cols = Val(T_co);
01141    *lins = Val(T_li);
01142 
01143 #ifdef TIOCGWINSZ
01144    {
01145       struct winsize ws;
01146 
01147       if (ioctl(el->fInFD, TIOCGWINSZ, (ioctl_t) &ws) != -1) {
01148          if (ws.ws_col) {
01149             *cols = ws.ws_col;
01150          }
01151 
01152          if (ws.ws_row) {
01153             *lins = ws.ws_row;
01154          }
01155       }
01156    }
01157 #endif
01158 #ifdef TIOCGSIZE
01159    {
01160       struct ttysize ts;
01161 
01162       if (ioctl(el->fInFD, TIOCGSIZE, (ioctl_t) &ts) != -1) {
01163          if (ts.ts_cols) {
01164             *cols = ts.ts_cols;
01165          }
01166 
01167          if (ts.ts_lines) {
01168             *lins = ts.ts_lines;
01169          }
01170       }
01171    }
01172 #endif
01173    return Val(T_co) != *cols || Val(T_li) != *lins;
01174 } // term_get_size
01175 
01176 
01177 /* term_change_size():
01178  *      Change the size of the terminal
01179  */
01180 el_protected int
01181 term_change_size(EditLine_t* el, int lins, int cols) {
01182    /*
01183     * Just in case
01184     */
01185    Val(T_co) = (cols < 2) ? 80 : cols;
01186    Val(T_li) = (lins < 1) ? 24 : lins;
01187 
01188    /* re-make display buffers */
01189    if (term_rebuffer_display(el) == -1) {
01190       return -1;
01191    }
01192    re_clear_display(el);
01193    return 0;
01194 }
01195 
01196 
01197 /* term_init_arrow():
01198  *      Initialize the arrow key bindings from termcap
01199  */
01200 el_private void
01201 term_init_arrow(EditLine_t* el) {
01202    FKey_t* arrow = el->fTerm.fFKey;
01203 
01204    arrow[A_K_DN].fName = "down";
01205    arrow[A_K_DN].fKey = T_kd;
01206    arrow[A_K_DN].fFun.fCmd = ED_NEXT_HISTORY;
01207    arrow[A_K_DN].fType = XK_CMD;
01208 
01209    arrow[A_K_UP].fName = "up";
01210    arrow[A_K_UP].fKey = T_ku;
01211    arrow[A_K_UP].fFun.fCmd = ED_PREV_HISTORY;
01212    arrow[A_K_UP].fType = XK_CMD;
01213 
01214    arrow[A_K_LT].fName = "left";
01215    arrow[A_K_LT].fKey = T_kl;
01216    arrow[A_K_LT].fFun.fCmd = ED_PREV_CHAR;
01217    arrow[A_K_LT].fType = XK_CMD;
01218 
01219    arrow[A_K_RT].fName = "right";
01220    arrow[A_K_RT].fKey = T_kr;
01221    arrow[A_K_RT].fFun.fCmd = ED_NEXT_CHAR;
01222    arrow[A_K_RT].fType = XK_CMD;
01223 
01224    arrow[A_K_HO].fName = "home";
01225    arrow[A_K_HO].fKey = T_kh;
01226    arrow[A_K_HO].fFun.fCmd = ED_MOVE_TO_BEG;
01227    arrow[A_K_HO].fType = XK_CMD;
01228 
01229    arrow[A_K_EN].fName = "end";
01230    arrow[A_K_EN].fKey = T_at7;
01231    arrow[A_K_EN].fFun.fCmd = ED_MOVE_TO_END;
01232    arrow[A_K_EN].fType = XK_CMD;
01233 
01234    arrow[A_K_DE].fName = "del";
01235    arrow[A_K_DE].fKey = T_kD;
01236    arrow[A_K_DE].fFun.fCmd = ED_DELETE_NEXT_CHAR;      //EM_DELETE_OR_LIST;
01237    arrow[A_K_DE].fType = XK_CMD;
01238 } // term_init_arrow
01239 
01240 
01241 /* term_reset_arrow():
01242  *      Reset arrow key bindings
01243  */
01244 el_private void
01245 term_reset_arrow(EditLine_t* el) {
01246    FKey_t* arrow = el->fTerm.fFKey;
01247    static const char strA[] = { 033, '[', 'A', '\0' };
01248    static const char strB[] = { 033, '[', 'B', '\0' };
01249    static const char strC[] = { 033, '[', 'C', '\0' };
01250    static const char strD[] = { 033, '[', 'D', '\0' };
01251    static const char strH[] = { 033, '[', 'H', '\0' };
01252    static const char strF[] = { 033, '[', 'F', '\0' };
01253    static const char stOA[] = { 033, 'O', 'A', '\0' };
01254    static const char stOB[] = { 033, 'O', 'B', '\0' };
01255    static const char stOC[] = { 033, 'O', 'C', '\0' };
01256    static const char stOD[] = { 033, 'O', 'D', '\0' };
01257    static const char stOH[] = { 033, 'O', 'H', '\0' };
01258    static const char stOF[] = { 033, 'O', 'F', '\0' };
01259 
01260    key_add(el, strA, &arrow[A_K_UP].fFun, arrow[A_K_UP].fType);
01261    key_add(el, strB, &arrow[A_K_DN].fFun, arrow[A_K_DN].fType);
01262    key_add(el, strC, &arrow[A_K_RT].fFun, arrow[A_K_RT].fType);
01263    key_add(el, strD, &arrow[A_K_LT].fFun, arrow[A_K_LT].fType);
01264    key_add(el, strH, &arrow[A_K_HO].fFun, arrow[A_K_HO].fType);
01265    key_add(el, strF, &arrow[A_K_EN].fFun, arrow[A_K_EN].fType);
01266    key_add(el, stOA, &arrow[A_K_UP].fFun, arrow[A_K_UP].fType);
01267    key_add(el, stOB, &arrow[A_K_DN].fFun, arrow[A_K_DN].fType);
01268    key_add(el, stOC, &arrow[A_K_RT].fFun, arrow[A_K_RT].fType);
01269    key_add(el, stOD, &arrow[A_K_LT].fFun, arrow[A_K_LT].fType);
01270    key_add(el, stOH, &arrow[A_K_HO].fFun, arrow[A_K_HO].fType);
01271    key_add(el, stOF, &arrow[A_K_EN].fFun, arrow[A_K_EN].fType);
01272    key_add(el, stOF, &arrow[A_K_EN].fFun, arrow[A_K_EN].fType);
01273 
01274    if (el->fMap.fType == MAP_VI) {
01275       key_add(el, &strA[1], &arrow[A_K_UP].fFun, arrow[A_K_UP].fType);
01276       key_add(el, &strB[1], &arrow[A_K_DN].fFun, arrow[A_K_DN].fType);
01277       key_add(el, &strC[1], &arrow[A_K_RT].fFun, arrow[A_K_RT].fType);
01278       key_add(el, &strD[1], &arrow[A_K_LT].fFun, arrow[A_K_LT].fType);
01279       key_add(el, &strH[1], &arrow[A_K_HO].fFun, arrow[A_K_HO].fType);
01280       key_add(el, &strF[1], &arrow[A_K_EN].fFun, arrow[A_K_EN].fType);
01281       key_add(el, &stOA[1], &arrow[A_K_UP].fFun, arrow[A_K_UP].fType);
01282       key_add(el, &stOB[1], &arrow[A_K_DN].fFun, arrow[A_K_DN].fType);
01283       key_add(el, &stOC[1], &arrow[A_K_RT].fFun, arrow[A_K_RT].fType);
01284       key_add(el, &stOD[1], &arrow[A_K_LT].fFun, arrow[A_K_LT].fType);
01285       key_add(el, &stOH[1], &arrow[A_K_HO].fFun, arrow[A_K_HO].fType);
01286       key_add(el, &stOF[1], &arrow[A_K_EN].fFun, arrow[A_K_EN].fType);
01287    }
01288 } // term_reset_arrow
01289 
01290 
01291 /* term_set_arrow():
01292  *      Set an arrow key binding
01293  */
01294 el_protected int
01295 term_set_arrow(EditLine_t* el, char* name, KeyValue_t* fun, int type) {
01296    FKey_t* arrow = el->fTerm.fFKey;
01297    int i;
01298 
01299    for (i = 0; i < A_K_NKEYS; i++) {
01300       if (strcmp(name, arrow[i].fName) == 0) {
01301          arrow[i].fFun = *fun;
01302          arrow[i].fType = type;
01303          return 0;
01304       }
01305    }
01306    return -1;
01307 }
01308 
01309 
01310 /* term_clear_arrow():
01311  *      Clear an arrow key binding
01312  */
01313 el_protected int
01314 term_clear_arrow(EditLine_t* el, char* name) {
01315    FKey_t* arrow = el->fTerm.fFKey;
01316    int i;
01317 
01318    for (i = 0; i < A_K_NKEYS; i++) {
01319       if (strcmp(name, arrow[i].fName) == 0) {
01320          arrow[i].fType = XK_NOD;
01321          return 0;
01322       }
01323    }
01324    return -1;
01325 }
01326 
01327 
01328 /* term_print_arrow():
01329  *      Print the arrow key bindings
01330  */
01331 el_protected void
01332 term_print_arrow(EditLine_t* el, const char* name) {
01333    int i;
01334    FKey_t* arrow = el->fTerm.fFKey;
01335 
01336    for (i = 0; i < A_K_NKEYS; i++) {
01337       if (*name == '\0' || strcmp(name, arrow[i].fName) == 0) {
01338          if (arrow[i].fType != XK_NOD) {
01339             key_kprint(el, arrow[i].fName, &arrow[i].fFun,
01340                        arrow[i].fType);
01341          }
01342       }
01343    }
01344 }
01345 
01346 
01347 /* term_bind_arrow():
01348  *      Bind the arrow keys
01349  */
01350 el_protected void
01351 term_bind_arrow(EditLine_t* el) {
01352    ElAction_t* map;
01353    const ElAction_t* dmap;
01354    int i, j;
01355    char* p;
01356    FKey_t* arrow = el->fTerm.fFKey;
01357 
01358    /* Check if the components needed are initialized */
01359    if (el->fTerm.fBuf == NULL || el->fMap.fKey == NULL) {
01360       return;
01361    }
01362 
01363    map = el->fMap.fType == MAP_VI ? el->fMap.fAlt : el->fMap.fKey;
01364    dmap = el->fMap.fType == MAP_VI ? el->fMap.fVic : el->fMap.fEmacs;
01365 
01366    term_reset_arrow(el);
01367 
01368    for (i = 0; i < A_K_NKEYS; i++) {
01369       p = el->fTerm.fStr[arrow[i].fKey];
01370 
01371       if (p && *p) {
01372          j = (unsigned char) *p;
01373 
01374          /*
01375           * Assign the arrow keys only if:
01376           *
01377           * 1. They are multi-character arrow keys and the user
01378           *    has not re-assigned the leading character, or
01379           *    has re-assigned the leading character to be
01380           *       ED_SEQUENCE_LEAD_IN
01381           * 2. They are single arrow keys pointing to an
01382           *    unassigned key.
01383           */
01384          if (arrow[i].fType == XK_NOD) {
01385             key_clear(el, map, p);
01386          } else {
01387             if (p[1] && (dmap[j] == map[j] ||
01388                          map[j] == ED_SEQUENCE_LEAD_IN)) {
01389                key_add(el, p, &arrow[i].fFun,
01390                        arrow[i].fType);
01391                map[j] = ED_SEQUENCE_LEAD_IN;
01392             } else if (map[j] == ED_UNASSIGNED) {
01393                key_clear(el, map, p);
01394 
01395                if (arrow[i].fType == XK_CMD) {
01396                   map[j] = arrow[i].fFun.fCmd;
01397                } else {
01398                   key_add(el, p, &arrow[i].fFun,
01399                           arrow[i].fType);
01400                }
01401             }
01402          }
01403       }
01404    }
01405 } // term_bind_arrow
01406 
01407 
01408 /* term_init_color():
01409  *      Initialize the color handling
01410  */
01411 el_private void
01412 term_init_color(EditLine_t* el) {
01413    int errcode;
01414 
01415    if ((el->fFlags & NO_TTY) || !isatty(1)) {
01416       // no TTY, no color.
01417       return;
01418    }
01419 
01420    if (ERR == setupterm(0, 1, &errcode)) {
01421       char* eldebug = getenv("EDITLINEDEBUG");
01422       if (eldebug != 0 && eldebug[0]) {
01423          fprintf(stderr, "ERROR initializing the terminal [TERM=%s]:\n", getenv("TERM"));
01424          switch (errcode) {
01425          case 1:
01426             fprintf(stderr,
01427                     "  Your terminal cannot be used for curses applications [code 1].\n"
01428                     "  Please reconfigure ROOT with --disable-editline, or get a better terminal.\n\n");
01429             break;
01430          case 0:
01431             fprintf(stderr,
01432                     "  the terminal could not be found, or it is a generic type [code 0].\n"
01433                     "  Please reconfigure ROOT with --disable-editline, or get a better terminal.\n\n");
01434             break;
01435          case -1:
01436             fprintf(stderr,
01437                     "  the terminfo database could not be found [code -1].\n"
01438                     "  Please make sure that it is accessible.\n\n");
01439             break;
01440          default:
01441             fprintf(stderr,
01442                     "  unknown curses error while setting up the terminal [code %d].\n\n",
01443                     errcode);
01444          }
01445       }
01446    }
01447 }
01448 
01449 
01450 /* term__gettermmanip():
01451  *      Retrieve the static terminal manipulation object
01452  */
01453 el_private TTermManip&
01454 term__gettermmanip() {
01455    static TTermManip tm; /* Terminal color manipulation */
01456    return tm;
01457 }
01458 
01459 
01460 /* term__resetcolor():
01461  *      Reset the color to its default value
01462  */
01463 el_protected void
01464 term__resetcolor() {
01465    TTermManip& tm = term__gettermmanip();
01466    tm.ResetTerm();
01467    term__flush();
01468 }
01469 
01470 
01471 /* term__putc():
01472  *      Add a character
01473  */
01474 el_protected int
01475 term__putc(int c) {
01476    return term__putcolorch(c, NULL);
01477 }
01478 
01479 /* term__atocolor():
01480  *      Get the color index for a color name.
01481  *      Name can be black, gray, blue,...
01482  *      or #rrbbgg or #rgb
01483  */
01484 el_public int
01485 term__atocolor(const char* name) {
01486    int attr = 0;
01487    std::string lowname(name);
01488    size_t lenname = strlen(name);
01489    for (size_t i = 0; i < lenname; ++i)
01490       lowname[i] = tolower(lowname[i]);
01491 
01492    if (lowname.find("bold") != std::string::npos
01493        || lowname.find("light") != std::string::npos)
01494       attr |= 0x2000;
01495    if (lowname.find("under") != std::string::npos)
01496       attr |= 0x4000;
01497 
01498    TTermManip& tm = term__gettermmanip();
01499    size_t poshash = lowname.find('#');
01500    size_t lenrgb = 0;
01501    if (poshash != std::string::npos) {
01502       int endrgb = poshash + 1;
01503       while ((lowname[endrgb] >= '0' && lowname[endrgb] <= '9')
01504               || (lowname[endrgb] >= 'a' && lowname[endrgb] <= 'f')) {
01505          ++endrgb;
01506       }
01507       lenrgb = endrgb - poshash - 1;
01508    }
01509 
01510    if (lenrgb == 3) {
01511       int rgb[3] = {0};
01512       for (int i = 0; i < 3; ++i) {
01513          rgb[i] = lowname[poshash + 1 + i] - '0';
01514          if (rgb[i] > 9) {
01515             rgb[i] = rgb[i] + '0' - 'a' + 10;
01516          }
01517          rgb[i] *= 16; // only upper 4 bits are set.
01518       }
01519       return attr | tm.GetColorIndex(rgb[0], rgb[1], rgb[2]);
01520    } else if (lenrgb == 6) {
01521       int rgb[3] = {0};
01522       for (int i = 0; i < 6; ++i) {
01523          int v = lowname[poshash + 1 + i] - '0';
01524          if (v > 9) {
01525             v = v + '0' - 'a' + 10;
01526          }
01527          if (i % 2 == 0) {
01528             v *= 16;
01529          }
01530          rgb[i / 2] += v;
01531       }
01532       return attr | tm.GetColorIndex(rgb[0], rgb[1], rgb[2]);
01533    } else {
01534       if (lowname.find("default") != std::string::npos) {
01535          return attr | 0xff;
01536       }
01537 
01538       static const char* colornames[] = {
01539          "black", "red", "green", "yellow",
01540          "blue", "magenta", "cyan", "white", 0
01541       };
01542       static const unsigned char colorrgb[][3] = {
01543          {0,0,0}, {127,0,0}, {0,127,0}, {127,127,0},
01544          {0,0,127}, {127,0,127}, {0,127,127}, {127,127,127},
01545          {0}
01546       };
01547 
01548       for (int i = 0; colornames[i]; ++i) {
01549          if (lowname.find(colornames[i]) != std::string::npos) {
01550             int boldify = 0;
01551             if (attr & 0x2000)
01552                boldify = 64;
01553             return attr | tm.GetColorIndex(colorrgb[i][0] + boldify,
01554                                            colorrgb[i][1] + boldify,
01555                                            colorrgb[i][2] + boldify);
01556          }
01557       }
01558    }
01559    fprintf(stderr, "editline / term__atocolor: cannot parse color %s!\n", name);
01560    return -1;
01561 }
01562 
01563 
01564 /* term__setcolor():
01565  *      Set terminal to a given foreground colour
01566  */
01567 el_protected void
01568 term__setcolor(int fgcol) {
01569    TTermManip& tm = term__gettermmanip();
01570 
01571    int idx = (fgcol & 0xff);
01572    if (idx == 0xff) {
01573       tm.SetDefaultColor();
01574    } else {
01575       tm.SetColor(idx);
01576    }
01577 
01578    if (fgcol != -1) {
01579       if (fgcol & 0x2000) {
01580          tm.StartBold();
01581       } else {
01582          tm.StopBold();
01583       }
01584       if (fgcol & 0x4000) {
01585          tm.StartUnderline();
01586       } else {
01587          tm.StopUnderline();
01588       }
01589    }
01590 
01591 } // term__setcolor
01592 
01593 
01594 /* term__putcolorch():
01595  *      Add a character with colour information
01596  */
01597 el_protected int
01598 term__putcolorch(int c, ElColor_t* color) {
01599    if (color != NULL && c != ' ') {
01600       term__setcolor(color->fForeColor);
01601    }
01602 
01603    int res = fputc(c, term_outfile);
01604    return res;
01605 
01606 }
01607 
01608 
01609 /* term__repaint():
01610  *      Repaint existing character at index (in order to display new colour attribute)
01611  */
01612 el_protected void
01613 term__repaint(EditLine_t* el, int index) {
01614    // store where cursor is currently (involves el)
01615    char* cursor = el->fLine.fCursor;
01616 
01617    int promptSize = el->fPrompt.fPos.fH;
01618    int oriCursor = el->fCursor.fH;
01619    int oriLine = el->fCursor.fV;
01620 
01621    // move to index of char to change
01622    el->fLine.fCursor = el->fLine.fBuffer + index;
01623 
01624    int line = (promptSize + index) / el->fTerm.fSize.fH;
01625    int hpos = (promptSize + index) % el->fTerm.fSize.fH;
01626    term_move_to_line(el, line);
01627    term_move_to_char(el, hpos);
01628 
01629    // rewrite char
01630    term_overwrite(el, el->fLine.fCursor,
01631                   el->fLine.fBufColor + index,
01632                   1);
01633 
01634    // move cursor back
01635    el->fLine.fCursor = cursor;
01636    term_move_to_line(el, oriLine);
01637    term_move_to_char(el, oriCursor);
01638 
01639    term__flush();
01640 } // term__repaint
01641 
01642 
01643 /* term__flush():
01644  *      Flush output
01645  */
01646 el_protected void
01647 term__flush(void) {
01648    (void) fflush(term_outfile);
01649 }
01650 
01651 
01652 /* term_telltc():
01653  *      Print the current termcap characteristics
01654  */
01655 el_protected int
01656 /*ARGSUSED*/
01657 term_telltc(EditLine_t* el, int /*argc*/, const char** /*argv*/) {
01658    const struct TermCapStr_t* t;
01659    char** ts;
01660    char upbuf[EL_BUFSIZ];
01661 
01662    (void) fprintf(el->fOutFile, "\n\tYour terminal has the\n");
01663    (void) fprintf(el->fOutFile, "\tfollowing characteristics:\n\n");
01664    (void) fprintf(el->fOutFile, "\tIt has %d columns and %d lines\n",
01665                   Val(T_co), Val(T_li));
01666    (void) fprintf(el->fOutFile,
01667                   "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no");
01668    (void) fprintf(el->fOutFile,
01669                   "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not ");
01670    (void) fprintf(el->fOutFile, "\tIt %s automatic margins\n",
01671                   EL_HAS_AUTO_MARGINS ? "has" : "does not have");
01672 
01673    if (EL_HAS_AUTO_MARGINS) {
01674       (void) fprintf(el->fOutFile, "\tIt %s magic margins\n",
01675                      EL_HAS_MAGIC_MARGINS ? "has" : "does not have");
01676    }
01677 
01678    for (t = tstr, ts = el->fTerm.fStr; t->fName != NULL; t++, ts++) {
01679       (void) fprintf(el->fOutFile, "\t%25s (%s) == %s\n",
01680                      t->fLongName,
01681                      t->fName, *ts && **ts ?
01682                      key__decode_str(*ts, upbuf, "") : "(empty)");
01683    }
01684    (void) fputc('\n', el->fOutFile);
01685    return 0;
01686 } // term_telltc
01687 
01688 
01689 /* term_settc():
01690  *      Change the current terminal characteristics
01691  */
01692 el_protected int
01693 /*ARGSUSED*/
01694 term_settc(EditLine_t* el, int /*argc*/, const char** argv) {
01695    const struct TermCapStr_t* ts;
01696    const struct TermCapVal_t* tv;
01697    const char* what, * how;
01698 
01699    if (argv == NULL || argv[1] == NULL || argv[2] == NULL) {
01700       return -1;
01701    }
01702 
01703    // gcc bug? it sees these access as non-const:
01704    what = argv[1];
01705    how = argv[2];
01706 
01707    /*
01708     * Do the strings first
01709     */
01710    for (ts = tstr; ts->fName != NULL; ts++) {
01711       if (strcmp(ts->fName, what) == 0) {
01712          break;
01713       }
01714    }
01715 
01716    if (ts->fName != NULL) {
01717       term_alloc(el, ts, how);
01718       term_setflags(el);
01719       return 0;
01720    }
01721 
01722    /*
01723     * Do the numeric ones second
01724     */
01725    for (tv = tval; tv->fName != NULL; tv++) {
01726       if (strcmp(tv->fName, what) == 0) {
01727          break;
01728       }
01729    }
01730 
01731    if (tv->fName != NULL) {
01732       if (tv == &tval[T_pt] || tv == &tval[T_km] ||
01733           tv == &tval[T_am] || tv == &tval[T_xn]) {
01734          if (strcmp(how, "yes") == 0) {
01735             el->fTerm.fVal[tv - tval] = 1;
01736          } else if (strcmp(how, "no") == 0) {
01737             el->fTerm.fVal[tv - tval] = 0;
01738          } else {
01739             (void) fprintf(el->fErrFile,
01740                            "settc: Bad value `%s'.\n", how);
01741             return -1;
01742          }
01743          term_setflags(el);
01744 
01745          if (term_change_size(el, Val(T_li), Val(T_co)) == -1) {
01746             return -1;
01747          }
01748          return 0;
01749       } else {
01750          long i;
01751          char* ep;
01752 
01753          i = strtol(how, &ep, 10);
01754 
01755          if (*ep != '\0') {
01756             (void) fprintf(el->fErrFile,
01757                            "settc: Bad value `%s'.\n", how);
01758             return -1;
01759          }
01760          el->fTerm.fVal[tv - tval] = (int) i;
01761          el->fTerm.fSize.fV = Val(T_co);
01762          el->fTerm.fSize.fH = Val(T_li);
01763 
01764          if (tv == &tval[T_co] || tv == &tval[T_li]) {
01765             if (term_change_size(el, Val(T_li), Val(T_co))
01766                 == -1) {
01767                return -1;
01768             }
01769          }
01770          return 0;
01771       }
01772    }
01773    return -1;
01774 } // term_settc
01775 
01776 
01777 /* term_echotc():
01778  *      Print the termcap string out with variable substitution
01779  */
01780 el_protected int
01781 /*ARGSUSED*/
01782 term_echotc(EditLine_t* el, int /*argc*/, const char** argv) {
01783    char* cap, * scap, * ep;
01784    int arg_need, arg_cols, arg_rows;
01785    int verbose = 0, silent = 0;
01786    char* area;
01787    static const char fmts[] = "%s\n", fmtd[] = "%d\n";
01788    const struct TermCapStr_t* t;
01789    char buf[TC_BUFSIZE];
01790    long i;
01791 
01792    area = buf;
01793 
01794    if (argv == NULL || argv[1] == NULL) {
01795       return -1;
01796    }
01797    argv++;
01798 
01799    if (argv[0][0] == '-') {
01800       switch (argv[0][1]) {
01801       case 'v':
01802          verbose = 1;
01803          break;
01804       case 's':
01805          silent = 1;
01806          break;
01807       default:
01808          /* stderror(ERR_NAME | ERR_TCUSAGE); */
01809          break;
01810       }
01811       argv++;
01812    }
01813 
01814    if (!*argv || *argv[0] == '\0') {
01815       return 0;
01816    }
01817 
01818    if (strcmp(*argv, "tabs") == 0) {
01819       (void) fprintf(el->fOutFile, fmts, EL_CAN_TAB ? "yes" : "no");
01820       return 0;
01821    } else if (strcmp(*argv, "meta") == 0) {
01822       (void) fprintf(el->fOutFile, fmts, Val(T_km) ? "yes" : "no");
01823       return 0;
01824    } else if (strcmp(*argv, "xn") == 0) {
01825       (void) fprintf(el->fOutFile, fmts, EL_HAS_MAGIC_MARGINS ?
01826                      "yes" : "no");
01827       return 0;
01828    } else if (strcmp(*argv, "am") == 0) {
01829       (void) fprintf(el->fOutFile, fmts, EL_HAS_AUTO_MARGINS ?
01830                      "yes" : "no");
01831       return 0;
01832    } else if (strcmp(*argv, "baud") == 0) {
01833 #ifdef notdef
01834       int i;
01835 
01836       for (i = 0; baud_rate[i].b_name != NULL; i++) {
01837          if (el->fTTY.t_speed == baud_rate[i].b_rate) {
01838             (void) fprintf(el->fOutFile, fmts,
01839                            baud_rate[i].b_name);
01840             return 0;
01841          }
01842       }
01843       (void) fprintf(el->fOutFile, fmtd, 0);
01844 #else
01845       (void) fprintf(el->fOutFile, fmtd, (int)el->fTTY.t_speed);
01846 #endif
01847       return 0;
01848    } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) {
01849       (void) fprintf(el->fOutFile, fmtd, Val(T_li));
01850       return 0;
01851    } else if (strcmp(*argv, "cols") == 0) {
01852       (void) fprintf(el->fOutFile, fmtd, Val(T_co));
01853       return 0;
01854    }
01855 
01856    /*
01857     * Try to use our local definition first
01858     */
01859    scap = NULL;
01860 
01861    for (t = tstr; t->fName != NULL; t++) {
01862       if (strcmp(t->fName, *argv) == 0) {
01863          scap = el->fTerm.fStr[t - tstr];
01864          break;
01865       }
01866    }
01867 
01868    if (t->fName == NULL) {
01869       scap = tgetstr((char*)*argv, &area);
01870    }
01871 
01872    if (!scap || scap[0] == '\0') {
01873       if (!silent) {
01874          (void) fprintf(el->fErrFile,
01875                         "echotc: Termcap parameter `%s' not found.\n",
01876                         *argv);
01877       }
01878       return -1;
01879    }
01880 
01881    /*
01882     * Count home many values we need for this capability.
01883     */
01884    for (cap = scap, arg_need = 0; *cap; cap++) {
01885       if (*cap == '%') {
01886          switch (*++cap) {
01887          case 'd':
01888          case '2':
01889          case '3':
01890          case '.':
01891          case '+':
01892             arg_need++;
01893             break;
01894          case '%':
01895          case '>':
01896          case 'i':
01897          case 'r':
01898          case 'n':
01899          case 'B':
01900          case 'D':
01901             break;
01902          default:
01903 
01904             /*
01905              * hpux has lot's of them...
01906              */
01907             if (verbose) {
01908                (void) fprintf(el->fErrFile,
01909                               "echotc: Warning: unknown termcap %% `%c'.\n",
01910                               *cap);
01911             }
01912             /* This is bad, but I won't complain */
01913             break;
01914          } // switch
01915       }
01916    }
01917 
01918    switch (arg_need) {
01919    case 0:
01920       argv++;
01921 
01922       if (*argv && *argv[0]) {
01923          if (!silent) {
01924             (void) fprintf(el->fErrFile,
01925                            "echotc: Warning: Extra argument `%s'.\n",
01926                            *argv);
01927          }
01928          return -1;
01929       }
01930       (void) tputs(scap, 1, term__putc);
01931       break;
01932    case 1:
01933       argv++;
01934 
01935       if (!*argv || *argv[0] == '\0') {
01936          if (!silent) {
01937             (void) fprintf(el->fErrFile,
01938                            "echotc: Warning: Missing argument.\n");
01939          }
01940          return -1;
01941       }
01942       arg_cols = 0;
01943       i = strtol(*argv, &ep, 10);
01944 
01945       if (*ep != '\0' || i < 0) {
01946          if (!silent) {
01947             (void) fprintf(el->fErrFile,
01948                            "echotc: Bad value `%s' for rows.\n",
01949                            *argv);
01950          }
01951          return -1;
01952       }
01953       arg_rows = (int) i;
01954       argv++;
01955 
01956       if (*argv && *argv[0]) {
01957          if (!silent) {
01958             (void) fprintf(el->fErrFile,
01959                            "echotc: Warning: Extra argument `%s'.\n",
01960                            *argv);
01961          }
01962          return -1;
01963       }
01964       (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc);
01965       break;
01966    default:
01967 
01968       /* This is wrong, but I will ignore it... */
01969       if (verbose) {
01970          (void) fprintf(el->fErrFile,
01971                         "echotc: Warning: Too many required arguments (%d).\n",
01972                         arg_need);
01973       }
01974    /* FALLTHROUGH */
01975    case 2:
01976       argv++;
01977 
01978       if (!*argv || *argv[0] == '\0') {
01979          if (!silent) {
01980             (void) fprintf(el->fErrFile,
01981                            "echotc: Warning: Missing argument.\n");
01982          }
01983          return -1;
01984       }
01985       i = strtol(*argv, &ep, 10);
01986 
01987       if (*ep != '\0' || i < 0) {
01988          if (!silent) {
01989             (void) fprintf(el->fErrFile,
01990                            "echotc: Bad value `%s' for cols.\n",
01991                            *argv);
01992          }
01993          return -1;
01994       }
01995       arg_cols = (int) i;
01996       argv++;
01997 
01998       if (!*argv || *argv[0] == '\0') {
01999          if (!silent) {
02000             (void) fprintf(el->fErrFile,
02001                            "echotc: Warning: Missing argument.\n");
02002          }
02003          return -1;
02004       }
02005       i = strtol(*argv, &ep, 10);
02006 
02007       if (*ep != '\0' || i < 0) {
02008          if (!silent) {
02009             (void) fprintf(el->fErrFile,
02010                            "echotc: Bad value `%s' for rows.\n",
02011                            *argv);
02012          }
02013          return -1;
02014       }
02015       arg_rows = (int) i;
02016 
02017       if (*ep != '\0') {
02018          if (!silent) {
02019             (void) fprintf(el->fErrFile,
02020                            "echotc: Bad value `%s'.\n", *argv);
02021          }
02022          return -1;
02023       }
02024       argv++;
02025 
02026       if (*argv && *argv[0]) {
02027          if (!silent) {
02028             (void) fprintf(el->fErrFile,
02029                            "echotc: Warning: Extra argument `%s'.\n",
02030                            *argv);
02031          }
02032          return -1;
02033       }
02034       (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, term__putc);
02035       break;
02036    } // switch
02037    return 0;
02038 } // term_echotc

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