Back to index

tetex-bin  3.0
parse_entry.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
00031  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
00032  *     and: Thomas E. Dickey                        1996-2004               *
00033  ****************************************************************************/
00034 
00035 /*
00036  *     parse_entry.c -- compile one terminfo or termcap entry
00037  *
00038  *     Get an exact in-core representation of an entry.  Don't
00039  *     try to resolve use or tc capabilities, that is someone
00040  *     else's job.  Depends on the lexical analyzer to get tokens
00041  *     from the input stream.
00042  */
00043 
00044 #define __INTERNAL_CAPS_VISIBLE
00045 #include <curses.priv.h>
00046 
00047 #include <ctype.h>
00048 #include <tic.h>
00049 #include <term_entry.h>
00050 
00051 MODULE_ID("$Id: parse_entry.c,v 1.61 2004/05/01 21:33:25 tom Exp $")
00052 
00053 #ifdef LINT
00054 static short const parametrized[] =
00055 {0};
00056 #else
00057 #include <parametrized.h>
00058 #endif
00059 
00060 static void postprocess_termcap(TERMTYPE *, bool);
00061 static void postprocess_terminfo(TERMTYPE *);
00062 static struct name_table_entry const *lookup_fullname(const char *name);
00063 
00064 #if NCURSES_XNAMES
00065 
00066 static struct name_table_entry const *
00067 _nc_extend_names(ENTRY * entryp, char *name, int token_type)
00068 {
00069     static struct name_table_entry temp;
00070     TERMTYPE *tp = &(entryp->tterm);
00071     unsigned offset = 0;
00072     unsigned actual;
00073     unsigned tindex;
00074     unsigned first, last, n;
00075     bool found;
00076 
00077     switch (token_type) {
00078     case BOOLEAN:
00079        first = 0;
00080        last = tp->ext_Booleans;
00081        offset = tp->ext_Booleans;
00082        tindex = tp->num_Booleans;
00083        break;
00084     case NUMBER:
00085        first = tp->ext_Booleans;
00086        last = tp->ext_Numbers + first;
00087        offset = tp->ext_Booleans + tp->ext_Numbers;
00088        tindex = tp->num_Numbers;
00089        break;
00090     case STRING:
00091        first = tp->ext_Booleans + tp->ext_Numbers;
00092        last = tp->ext_Strings + first;
00093        offset = tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings;
00094        tindex = tp->num_Strings;
00095        break;
00096     case CANCEL:
00097        actual = NUM_EXT_NAMES(tp);
00098        for (n = 0; n < actual; n++) {
00099            if (!strcmp(name, tp->ext_Names[n])) {
00100               if (n > (unsigned) (tp->ext_Booleans + tp->ext_Numbers)) {
00101                   token_type = STRING;
00102               } else if (n > tp->ext_Booleans) {
00103                   token_type = NUMBER;
00104               } else {
00105                   token_type = BOOLEAN;
00106               }
00107               return _nc_extend_names(entryp, name, token_type);
00108            }
00109        }
00110        /* Well, we are given a cancel for a name that we don't recognize */
00111        return _nc_extend_names(entryp, name, STRING);
00112     default:
00113        return 0;
00114     }
00115 
00116     /* Adjust the 'offset' (insertion-point) to keep the lists of extended
00117      * names sorted.
00118      */
00119     for (n = first, found = FALSE; n < last; n++) {
00120        int cmp = strcmp(tp->ext_Names[n], name);
00121        if (cmp == 0)
00122            found = TRUE;
00123        if (cmp >= 0) {
00124            offset = n;
00125            tindex = n - first;
00126            switch (token_type) {
00127            case BOOLEAN:
00128               tindex += BOOLCOUNT;
00129               break;
00130            case NUMBER:
00131               tindex += NUMCOUNT;
00132               break;
00133            case STRING:
00134               tindex += STRCOUNT;
00135               break;
00136            }
00137            break;
00138        }
00139     }
00140     if (!found) {
00141        switch (token_type) {
00142        case BOOLEAN:
00143            tp->ext_Booleans += 1;
00144            tp->num_Booleans += 1;
00145            tp->Booleans = typeRealloc(char, tp->num_Booleans, tp->Booleans);
00146            for (last = tp->num_Booleans - 1; last > tindex; last--)
00147               tp->Booleans[last] = tp->Booleans[last - 1];
00148            break;
00149        case NUMBER:
00150            tp->ext_Numbers += 1;
00151            tp->num_Numbers += 1;
00152            tp->Numbers = typeRealloc(short, tp->num_Numbers, tp->Numbers);
00153            for (last = tp->num_Numbers - 1; last > tindex; last--)
00154               tp->Numbers[last] = tp->Numbers[last - 1];
00155            break;
00156        case STRING:
00157            tp->ext_Strings += 1;
00158            tp->num_Strings += 1;
00159            tp->Strings = typeRealloc(char *, tp->num_Strings, tp->Strings);
00160            for (last = tp->num_Strings - 1; last > tindex; last--)
00161               tp->Strings[last] = tp->Strings[last - 1];
00162            break;
00163        }
00164        actual = NUM_EXT_NAMES(tp);
00165        tp->ext_Names = typeRealloc(char *, actual, tp->ext_Names);
00166        while (--actual > offset)
00167            tp->ext_Names[actual] = tp->ext_Names[actual - 1];
00168        tp->ext_Names[offset] = _nc_save_str(name);
00169     }
00170 
00171     temp.nte_name = tp->ext_Names[offset];
00172     temp.nte_type = token_type;
00173     temp.nte_index = tindex;
00174     temp.nte_link = -1;
00175 
00176     return &temp;
00177 }
00178 #endif /* NCURSES_XNAMES */
00179 
00180 /*
00181  *     int
00182  *     _nc_parse_entry(entry, literal, silent)
00183  *
00184  *     Compile one entry.  Doesn't try to resolve use or tc capabilities.
00185  *
00186  *     found-forward-use = FALSE
00187  *     re-initialise internal arrays
00188  *     get_token();
00189  *     if the token was not a name in column 1, complain and die
00190  *     save names in entry's string table
00191  *     while (get_token() is not EOF and not NAMES)
00192  *             check for existence and type-correctness
00193  *             enter cap into structure
00194  *             if STRING
00195  *                 save string in entry's string table
00196  *     push back token
00197  */
00198 
00199 #define BAD_TC_USAGE if (!bad_tc_usage) \
00200        { bad_tc_usage = TRUE; \
00201         _nc_warning("Legacy termcap allows only a trailing tc= clause"); }
00202 
00203 NCURSES_EXPORT(int)
00204 _nc_parse_entry(struct entry *entryp, int literal, bool silent)
00205 {
00206     int token_type;
00207     struct name_table_entry const *entry_ptr;
00208     char *ptr, *base;
00209     bool bad_tc_usage = FALSE;
00210 
00211     token_type = _nc_get_token(silent);
00212 
00213     if (token_type == EOF)
00214        return (EOF);
00215     if (token_type != NAMES)
00216        _nc_err_abort("Entry does not start with terminal names in column one");
00217 
00218     _nc_init_entry(&entryp->tterm);
00219 
00220     entryp->cstart = _nc_comment_start;
00221     entryp->cend = _nc_comment_end;
00222     entryp->startline = _nc_start_line;
00223     DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend));
00224 
00225     /*
00226      * Strip off the 2-character termcap name, if present.  Originally termcap
00227      * used that as an indexing aid.  We can retain 2-character terminfo names,
00228      * but note that they would be lost if we translate to/from termcap.  This
00229      * feature is supposedly obsolete since "newer" BSD implementations do not
00230      * use it; however our reference for this feature is SunOS 4.x, which
00231      * implemented it.  Note that the resulting terminal type was never the
00232      * 2-character name, but was instead the first alias after that.
00233      */
00234     ptr = _nc_curr_token.tk_name;
00235     if (_nc_syntax == SYN_TERMCAP
00236 #if NCURSES_XNAMES
00237        && !_nc_user_definable
00238 #endif
00239        ) {
00240        if (ptr[2] == '|') {
00241            ptr += 3;
00242            _nc_curr_token.tk_name[2] = '\0';
00243        }
00244     }
00245 
00246     entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr);
00247 
00248     DEBUG(1, ("Starting '%s'", ptr));
00249 
00250     /*
00251      * We do this because the one-token lookahead in the parse loop
00252      * results in the terminal type getting prematurely set to correspond
00253      * to that of the next entry.
00254      */
00255     _nc_set_type(_nc_first_name(entryp->tterm.term_names));
00256 
00257     /* check for overly-long names and aliases */
00258     for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
00259         base = ptr + 1) {
00260        if (ptr - base > MAX_ALIAS) {
00261            _nc_warning("%s `%.*s' may be too long",
00262                      (base == entryp->tterm.term_names)
00263                      ? "primary name"
00264                      : "alias",
00265                      (int) (ptr - base), base);
00266        }
00267     }
00268 
00269     entryp->nuses = 0;
00270 
00271     for (token_type = _nc_get_token(silent);
00272         token_type != EOF && token_type != NAMES;
00273         token_type = _nc_get_token(silent)) {
00274        bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0);
00275        bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0);
00276        if (is_use || is_tc) {
00277            entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
00278            entryp->uses[entryp->nuses].line = _nc_curr_line;
00279            entryp->nuses++;
00280            if (entryp->nuses > 1 && is_tc) {
00281               BAD_TC_USAGE
00282            }
00283        } else {
00284            /* normal token lookup */
00285            entry_ptr = _nc_find_entry(_nc_curr_token.tk_name,
00286                                    _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table);
00287 
00288            /*
00289             * Our kluge to handle aliasing.  The reason it's done
00290             * this ugly way, with a linear search, is so the hashing
00291             * machinery doesn't have to be made really complicated
00292             * (also we get better warnings this way).  No point in
00293             * making this case fast, aliased caps aren't common now
00294             * and will get rarer.
00295             */
00296            if (entry_ptr == NOTFOUND) {
00297               const struct alias *ap;
00298 
00299               if (_nc_syntax == SYN_TERMCAP) {
00300                   if (entryp->nuses != 0) {
00301                      BAD_TC_USAGE
00302                   }
00303                   for (ap = _nc_capalias_table; ap->from; ap++)
00304                      if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
00305                          if (ap->to == (char *) 0) {
00306                             _nc_warning("%s (%s termcap extension) ignored",
00307                                        ap->from, ap->source);
00308                             goto nexttok;
00309                          }
00310 
00311                          entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table);
00312                          if (entry_ptr && !silent)
00313                             _nc_warning("%s (%s termcap extension) aliased to %s",
00314                                        ap->from, ap->source, ap->to);
00315                          break;
00316                      }
00317               } else {      /* if (_nc_syntax == SYN_TERMINFO) */
00318                   for (ap = _nc_infoalias_table; ap->from; ap++)
00319                      if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
00320                          if (ap->to == (char *) 0) {
00321                             _nc_warning("%s (%s terminfo extension) ignored",
00322                                        ap->from, ap->source);
00323                             goto nexttok;
00324                          }
00325 
00326                          entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table);
00327                          if (entry_ptr && !silent)
00328                             _nc_warning("%s (%s terminfo extension) aliased to %s",
00329                                        ap->from, ap->source, ap->to);
00330                          break;
00331                      }
00332 
00333                   if (entry_ptr == NOTFOUND) {
00334                      entry_ptr = lookup_fullname(_nc_curr_token.tk_name);
00335                   }
00336               }
00337            }
00338 #if NCURSES_XNAMES
00339            /*
00340             * If we have extended-names active, we will automatically
00341             * define a name based on its context.
00342             */
00343            if (entry_ptr == NOTFOUND
00344               && _nc_user_definable
00345               && (entry_ptr = _nc_extend_names(entryp,
00346                                            _nc_curr_token.tk_name,
00347                                            token_type)) != 0) {
00348               if (_nc_tracing >= DEBUG_LEVEL(1))
00349                   _nc_warning("extended capability '%s'", _nc_curr_token.tk_name);
00350            }
00351 #endif /* NCURSES_XNAMES */
00352 
00353            /* can't find this cap name, not even as an alias */
00354            if (entry_ptr == NOTFOUND) {
00355               if (!silent)
00356                   _nc_warning("unknown capability '%s'",
00357                             _nc_curr_token.tk_name);
00358               continue;
00359            }
00360 
00361            /* deal with bad type/value combinations. */
00362            if (token_type != CANCEL && entry_ptr->nte_type != token_type) {
00363               /*
00364                * Nasty special cases here handle situations in which type
00365                * information can resolve name clashes.  Normal lookup
00366                * finds the last instance in the capability table of a
00367                * given name, regardless of type.  find_type_entry looks
00368                * for a first matching instance with given type.  So as
00369                * long as all ambiguous names occur in pairs of distinct
00370                * type, this will do the job.
00371                */
00372 
00373               /* tell max_attributes from arrow_key_map */
00374               if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name))
00375                   entry_ptr = _nc_find_type_entry("ma", NUMBER,
00376                                               _nc_get_table(_nc_syntax
00377                                                           != 0));
00378 
00379               /* map terminfo's string MT to MT */
00380               else if (token_type == STRING && !strcmp("MT", _nc_curr_token.tk_name))
00381                   entry_ptr = _nc_find_type_entry("MT", STRING,
00382                                               _nc_get_table(_nc_syntax
00383                                                           != 0));
00384 
00385               /* treat strings without following "=" as empty strings */
00386               else if (token_type == BOOLEAN && entry_ptr->nte_type == STRING)
00387                   token_type = STRING;
00388               /* we couldn't recover; skip this token */
00389               else {
00390                   if (!silent) {
00391                      const char *type_name;
00392                      switch (entry_ptr->nte_type) {
00393                      case BOOLEAN:
00394                          type_name = "boolean";
00395                          break;
00396                      case STRING:
00397                          type_name = "string";
00398                          break;
00399                      case NUMBER:
00400                          type_name = "numeric";
00401                          break;
00402                      default:
00403                          type_name = "unknown";
00404                          break;
00405                      }
00406                      _nc_warning("wrong type used for %s capability '%s'",
00407                                 type_name, _nc_curr_token.tk_name);
00408                   }
00409                   continue;
00410               }
00411            }
00412 
00413            /* now we know that the type/value combination is OK */
00414            switch (token_type) {
00415            case CANCEL:
00416               switch (entry_ptr->nte_type) {
00417               case BOOLEAN:
00418                   entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN;
00419                   break;
00420 
00421               case NUMBER:
00422                   entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC;
00423                   break;
00424 
00425               case STRING:
00426                   entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING;
00427                   break;
00428               }
00429               break;
00430 
00431            case BOOLEAN:
00432               entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE;
00433               break;
00434 
00435            case NUMBER:
00436               entryp->tterm.Numbers[entry_ptr->nte_index] =
00437                   _nc_curr_token.tk_valnumber;
00438               break;
00439 
00440            case STRING:
00441               ptr = _nc_curr_token.tk_valstring;
00442               if (_nc_syntax == SYN_TERMCAP)
00443                   ptr = _nc_captoinfo(_nc_curr_token.tk_name,
00444                                    ptr,
00445                                    parametrized[entry_ptr->nte_index]);
00446               entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr);
00447               break;
00448 
00449            default:
00450               if (!silent)
00451                   _nc_warning("unknown token type");
00452               _nc_panic_mode((_nc_syntax == SYN_TERMCAP) ? ':' : ',');
00453               continue;
00454            }
00455        }                    /* end else cur_token.name != "use" */
00456       nexttok:
00457        continue;            /* cannot have a label w/o statement */
00458     }                       /* endwhile (not EOF and not NAMES) */
00459 
00460     _nc_push_token(token_type);
00461     _nc_set_type(_nc_first_name(entryp->tterm.term_names));
00462 
00463     /*
00464      * Try to deduce as much as possible from extension capabilities
00465      * (this includes obsolete BSD capabilities).  Sigh...it would be more
00466      * space-efficient to call this after use resolution, but it has
00467      * to be done before entry allocation is wrapped up.
00468      */
00469     if (!literal) {
00470        if (_nc_syntax == SYN_TERMCAP) {
00471            bool has_base_entry = FALSE;
00472            int i;
00473 
00474            /*
00475             * Don't insert defaults if this is a `+' entry meant only
00476             * for inclusion in other entries (not sure termcap ever
00477             * had these, actually).
00478             */
00479            if (strchr(entryp->tterm.term_names, '+'))
00480               has_base_entry = TRUE;
00481            else
00482               /*
00483                * Otherwise, look for a base entry that will already
00484                * have picked up defaults via translation.
00485                */
00486               for (i = 0; i < entryp->nuses; i++)
00487                   if (!strchr((char *) entryp->uses[i].name, '+'))
00488                      has_base_entry = TRUE;
00489 
00490            postprocess_termcap(&entryp->tterm, has_base_entry);
00491        } else
00492            postprocess_terminfo(&entryp->tterm);
00493     }
00494     _nc_wrap_entry(entryp, FALSE);
00495 
00496     return (OK);
00497 }
00498 
00499 NCURSES_EXPORT(int)
00500 _nc_capcmp(const char *s, const char *t)
00501 /* compare two string capabilities, stripping out padding */
00502 {
00503     if (!s && !t)
00504        return (0);
00505     else if (!s || !t)
00506        return (1);
00507 
00508     for (;;) {
00509        if (s[0] == '$' && s[1] == '<') {
00510            for (s += 2;; s++)
00511               if (!(isdigit(UChar(*s))
00512                     || *s == '.'
00513                     || *s == '*'
00514                     || *s == '/'
00515                     || *s == '>'))
00516                   break;
00517        }
00518 
00519        if (t[0] == '$' && t[1] == '<') {
00520            for (t += 2;; t++)
00521               if (!(isdigit(UChar(*t))
00522                     || *t == '.'
00523                     || *t == '*'
00524                     || *t == '/'
00525                     || *t == '>'))
00526                   break;
00527        }
00528 
00529        /* we've now pushed s and t past any padding they were pointing at */
00530 
00531        if (*s == '\0' && *t == '\0')
00532            return (0);
00533 
00534        if (*s != *t)
00535            return (*t - *s);
00536 
00537        /* else *s == *t but one is not NUL, so continue */
00538        s++, t++;
00539     }
00540 }
00541 
00542 static void
00543 append_acs0(string_desc * dst, int code, int src)
00544 {
00545     if (src != 0) {
00546        char temp[3];
00547        temp[0] = code;
00548        temp[1] = src;
00549        temp[2] = 0;
00550        _nc_safe_strcat(dst, temp);
00551     }
00552 }
00553 
00554 static void
00555 append_acs(string_desc * dst, int code, char *src)
00556 {
00557     if (src != 0 && strlen(src) == 1) {
00558        append_acs0(dst, code, *src);
00559     }
00560 }
00561 
00562 /*
00563  * The ko capability, if present, consists of a comma-separated capability
00564  * list.  For each capability, we may assume there is a keycap that sends the
00565  * string which is the value of that capability.
00566  */
00567 typedef struct {
00568     const char *from;
00569     const char *to;
00570 } assoc;
00571 static assoc const ko_xlate[] =
00572 {
00573     {"al", "kil1"},         /* insert line key  -> KEY_IL    */
00574     {"bt", "kcbt"},         /* back tab         -> KEY_BTAB  */
00575     {"cd", "ked"},          /* clear-to-eos key -> KEY_EOL   */
00576     {"ce", "kel"},          /* clear-to-eol key -> KEY_EOS   */
00577     {"cl", "kclr"},         /* clear key        -> KEY_CLEAR */
00578     {"ct", "tbc"},          /* clear all tabs   -> KEY_CATAB */
00579     {"dc", "kdch1"},        /* delete char      -> KEY_DC    */
00580     {"dl", "kdl1"},         /* delete line      -> KEY_DL    */
00581     {"do", "kcud1"},        /* down key         -> KEY_DOWN  */
00582     {"ei", "krmir"},        /* exit insert key  -> KEY_EIC   */
00583     {"ho", "khome"},        /* home key         -> KEY_HOME  */
00584     {"ic", "kich1"},        /* insert char key  -> KEY_IC    */
00585     {"im", "kIC"},          /* insert-mode key  -> KEY_SIC   */
00586     {"le", "kcub1"},        /* le key           -> KEY_LEFT  */
00587     {"nd", "kcuf1"},        /* nd key           -> KEY_RIGHT */
00588     {"nl", "kent"},         /* new line key     -> KEY_ENTER */
00589     {"st", "khts"},         /* set-tab key      -> KEY_STAB  */
00590     {"ta", CANCELLED_STRING},
00591     {"up", "kcuu1"},        /* up-arrow key     -> KEY_UP    */
00592     {(char *) 0, (char *) 0},
00593 };
00594 
00595 /*
00596  * This routine fills in string caps that either had defaults under
00597  * termcap or can be manufactured from obsolete termcap capabilities.
00598  * It was lifted from Ross Ridge's mytinfo package.
00599  */
00600 
00601 static const char C_CR[] = "\r";
00602 static const char C_LF[] = "\n";
00603 static const char C_BS[] = "\b";
00604 static const char C_HT[] = "\t";
00605 
00606 /*
00607  * Note that WANTED and PRESENT are not simple inverses!  If a capability
00608  * has been explicitly cancelled, it's not considered WANTED.
00609  */
00610 #define WANTED(s)    ((s) == ABSENT_STRING)
00611 #define PRESENT(s)   (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
00612 
00613 /*
00614  * This bit of legerdemain turns all the terminfo variable names into
00615  * references to locations in the arrays Booleans, Numbers, and Strings ---
00616  * precisely what's needed.
00617  */
00618 
00619 #undef CUR
00620 #define CUR tp->
00621 
00622 static void
00623 postprocess_termcap(TERMTYPE * tp, bool has_base)
00624 {
00625     char buf[MAX_LINE * 2 + 2];
00626     string_desc result;
00627 
00628     /*
00629      * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS
00630      *
00631      * This first part of the code is the functional inverse of the
00632      * fragment in capdefaults.c.
00633      * ----------------------------------------------------------------------
00634      */
00635 
00636     /* if there was a tc entry, assume we picked up defaults via that */
00637     if (!has_base) {
00638        if (WANTED(init_3string) && termcap_init2)
00639            init_3string = _nc_save_str(termcap_init2);
00640 
00641        if (WANTED(reset_2string) && termcap_reset)
00642            reset_2string = _nc_save_str(termcap_reset);
00643 
00644        if (WANTED(carriage_return)) {
00645            if (carriage_return_delay > 0) {
00646               sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay);
00647               carriage_return = _nc_save_str(buf);
00648            } else
00649               carriage_return = _nc_save_str(C_CR);
00650        }
00651        if (WANTED(cursor_left)) {
00652            if (backspace_delay > 0) {
00653               sprintf(buf, "%s$<%d>", C_BS, backspace_delay);
00654               cursor_left = _nc_save_str(buf);
00655            } else if (backspaces_with_bs == 1)
00656               cursor_left = _nc_save_str(C_BS);
00657            else if (PRESENT(backspace_if_not_bs))
00658               cursor_left = backspace_if_not_bs;
00659        }
00660        /* vi doesn't use "do", but it does seems to use nl (or '\n') instead */
00661        if (WANTED(cursor_down)) {
00662            if (PRESENT(linefeed_if_not_lf))
00663               cursor_down = linefeed_if_not_lf;
00664            else if (linefeed_is_newline != 1) {
00665               if (new_line_delay > 0) {
00666                   sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
00667                   cursor_down = _nc_save_str(buf);
00668               } else
00669                   cursor_down = _nc_save_str(C_LF);
00670            }
00671        }
00672        if (WANTED(scroll_forward) && crt_no_scrolling != 1) {
00673            if (PRESENT(linefeed_if_not_lf))
00674               cursor_down = linefeed_if_not_lf;
00675            else if (linefeed_is_newline != 1) {
00676               if (new_line_delay > 0) {
00677                   sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
00678                   scroll_forward = _nc_save_str(buf);
00679               } else
00680                   scroll_forward = _nc_save_str(C_LF);
00681            }
00682        }
00683        if (WANTED(newline)) {
00684            if (linefeed_is_newline == 1) {
00685               if (new_line_delay > 0) {
00686                   sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
00687                   newline = _nc_save_str(buf);
00688               } else
00689                   newline = _nc_save_str(C_LF);
00690            } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) {
00691               _nc_str_init(&result, buf, sizeof(buf));
00692               if (_nc_safe_strcat(&result, carriage_return)
00693                   && _nc_safe_strcat(&result, scroll_forward))
00694                   newline = _nc_save_str(buf);
00695            } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) {
00696               _nc_str_init(&result, buf, sizeof(buf));
00697               if (_nc_safe_strcat(&result, carriage_return)
00698                   && _nc_safe_strcat(&result, cursor_down))
00699                   newline = _nc_save_str(buf);
00700            }
00701        }
00702     }
00703 
00704     /*
00705      * Inverse of capdefaults.c code ends here.
00706      * ----------------------------------------------------------------------
00707      *
00708      * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION
00709      *
00710      * These translations will *not* be inverted by tgetent().
00711      */
00712 
00713     if (!has_base) {
00714        /*
00715         * We wait until now to decide if we've got a working cr because even
00716         * one that doesn't work can be used for newline. Unfortunately the
00717         * space allocated for it is wasted.
00718         */
00719        if (return_does_clr_eol == 1 || no_correctly_working_cr == 1)
00720            carriage_return = ABSENT_STRING;
00721 
00722        /*
00723         * Supposedly most termcap entries have ta now and '\t' is no longer a
00724         * default, but it doesn't seem to be true...
00725         */
00726        if (WANTED(tab)) {
00727            if (horizontal_tab_delay > 0) {
00728               sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay);
00729               tab = _nc_save_str(buf);
00730            } else
00731               tab = _nc_save_str(C_HT);
00732        }
00733        if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE)
00734            init_tabs = 8;
00735 
00736        /*
00737         * Assume we can beep with ^G unless we're given bl@.
00738         */
00739        if (WANTED(bell))
00740            bell = _nc_save_str("\007");
00741     }
00742 
00743     /*
00744      * Translate the old termcap :pt: capability to it#8 + ht=\t
00745      */
00746     if (has_hardware_tabs == TRUE) {
00747        if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
00748            _nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
00749        else {
00750            if (tab && _nc_capcmp(tab, C_HT))
00751               _nc_warning("hardware tabs with a non-^I tab string %s",
00752                          _nc_visbuf(tab));
00753            else {
00754               if (WANTED(tab))
00755                   tab = _nc_save_str(C_HT);
00756               init_tabs = 8;
00757            }
00758        }
00759     }
00760     /*
00761      * Now translate the ko capability, if there is one.  This
00762      * isn't from mytinfo...
00763      */
00764     if (PRESENT(other_non_function_keys)) {
00765        char *base = other_non_function_keys;
00766        char *bp, *cp, *dp;
00767        struct name_table_entry const *from_ptr;
00768        struct name_table_entry const *to_ptr;
00769        assoc const *ap;
00770        char buf2[MAX_TERMINFO_LENGTH];
00771        bool foundim;
00772 
00773        /* we're going to use this for a special case later */
00774        dp = strchr(other_non_function_keys, 'i');
00775        foundim = (dp != 0) && (dp[1] == 'm');
00776 
00777        /* look at each comma-separated capability in the ko string... */
00778        for (base = other_non_function_keys;
00779             (cp = strchr(base, ',')) != 0;
00780             base = cp + 1) {
00781            size_t len = cp - base;
00782 
00783            for (ap = ko_xlate; ap->from; ap++)
00784               if (len == strlen(ap->from)
00785                   && strncmp(ap->from, base, len) == 0)
00786                   break;
00787            if (!ap->to) {
00788               _nc_warning("unknown capability `%.*s' in ko string",
00789                          (int) len, base);
00790               continue;
00791            } else if (ap->to == CANCELLED_STRING)       /* ignore it */
00792               continue;
00793 
00794            /* now we know we found a match in ko_table, so... */
00795 
00796            from_ptr = _nc_find_entry(ap->from, _nc_cap_hash_table);
00797            to_ptr = _nc_find_entry(ap->to, _nc_info_hash_table);
00798 
00799            if (!from_ptr || !to_ptr)      /* should never happen! */
00800               _nc_err_abort("ko translation table is invalid, I give up");
00801 
00802            if (WANTED(tp->Strings[from_ptr->nte_index])) {
00803               _nc_warning("no value for ko capability %s", ap->from);
00804               continue;
00805            }
00806 
00807            if (tp->Strings[to_ptr->nte_index]) {
00808               /* There's no point in warning about it if it's the same
00809                * string; that's just an inefficiency.
00810                */
00811               if (strcmp(
00812                            tp->Strings[from_ptr->nte_index],
00813                            tp->Strings[to_ptr->nte_index]) != 0)
00814                   _nc_warning("%s (%s) already has an explicit value %s, ignoring ko",
00815                             ap->to, ap->from,
00816                             _nc_visbuf(tp->Strings[to_ptr->nte_index]));
00817               continue;
00818            }
00819 
00820            /*
00821             * The magic moment -- copy the mapped key string over,
00822             * stripping out padding.
00823             */
00824            for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
00825               if (bp[0] == '$' && bp[1] == '<') {
00826                   while (*bp && *bp != '>') {
00827                      ++bp;
00828                   }
00829               } else
00830                   *dp++ = *bp;
00831            }
00832            *dp++ = '\0';
00833 
00834            tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
00835        }
00836 
00837        /*
00838         * Note: ko=im and ko=ic both want to grab the `Insert'
00839         * keycap.  There's a kich1 but no ksmir, so the ic capability
00840         * got mapped to kich1 and im to kIC to avoid a collision.
00841         * If the description has im but not ic, hack kIC back to kich1.
00842         */
00843        if (foundim && WANTED(key_ic) && key_sic) {
00844            key_ic = key_sic;
00845            key_sic = ABSENT_STRING;
00846        }
00847     }
00848 
00849     if (!has_base) {
00850        if (!hard_copy) {
00851            if (WANTED(key_backspace))
00852               key_backspace = _nc_save_str(C_BS);
00853            if (WANTED(key_left))
00854               key_left = _nc_save_str(C_BS);
00855            if (WANTED(key_down))
00856               key_down = _nc_save_str(C_LF);
00857        }
00858     }
00859 
00860     /*
00861      * Translate XENIX forms characters.
00862      */
00863     if (PRESENT(acs_ulcorner) ||
00864        PRESENT(acs_llcorner) ||
00865        PRESENT(acs_urcorner) ||
00866        PRESENT(acs_lrcorner) ||
00867        PRESENT(acs_ltee) ||
00868        PRESENT(acs_rtee) ||
00869        PRESENT(acs_btee) ||
00870        PRESENT(acs_ttee) ||
00871        PRESENT(acs_hline) ||
00872        PRESENT(acs_vline) ||
00873        PRESENT(acs_plus)) {
00874        char buf2[MAX_TERMCAP_LENGTH];
00875 
00876        _nc_str_init(&result, buf2, sizeof(buf2));
00877        _nc_safe_strcat(&result, acs_chars);
00878 
00879        append_acs(&result, 'j', acs_lrcorner);
00880        append_acs(&result, 'k', acs_urcorner);
00881        append_acs(&result, 'l', acs_ulcorner);
00882        append_acs(&result, 'm', acs_llcorner);
00883        append_acs(&result, 'n', acs_plus);
00884        append_acs(&result, 'q', acs_hline);
00885        append_acs(&result, 't', acs_ltee);
00886        append_acs(&result, 'u', acs_rtee);
00887        append_acs(&result, 'v', acs_btee);
00888        append_acs(&result, 'w', acs_ttee);
00889        append_acs(&result, 'x', acs_vline);
00890 
00891        if (buf2[0]) {
00892            acs_chars = _nc_save_str(buf2);
00893            _nc_warning("acsc string synthesized from XENIX capabilities");
00894        }
00895     } else if (acs_chars == 0
00896               && enter_alt_charset_mode != 0
00897               && exit_alt_charset_mode != 0) {
00898        acs_chars = _nc_save_str(VT_ACSC);
00899     }
00900 }
00901 
00902 static void
00903 postprocess_terminfo(TERMTYPE * tp)
00904 {
00905     /*
00906      * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION
00907      * ----------------------------------------------------------------------
00908      */
00909 
00910     /*
00911      * Translate AIX forms characters.
00912      */
00913     if (PRESENT(box_chars_1)) {
00914        char buf2[MAX_TERMCAP_LENGTH];
00915        string_desc result;
00916 
00917        _nc_str_init(&result, buf2, sizeof(buf2));
00918        _nc_safe_strcat(&result, acs_chars);
00919 
00920        append_acs0(&result, 'l', box_chars_1[0]);       /* ACS_ULCORNER */
00921        append_acs0(&result, 'q', box_chars_1[1]);       /* ACS_HLINE */
00922        append_acs0(&result, 'k', box_chars_1[2]);       /* ACS_URCORNER */
00923        append_acs0(&result, 'x', box_chars_1[3]);       /* ACS_VLINE */
00924        append_acs0(&result, 'j', box_chars_1[4]);       /* ACS_LRCORNER */
00925        append_acs0(&result, 'm', box_chars_1[5]);       /* ACS_LLCORNER */
00926        append_acs0(&result, 'w', box_chars_1[6]);       /* ACS_TTEE */
00927        append_acs0(&result, 'u', box_chars_1[7]);       /* ACS_RTEE */
00928        append_acs0(&result, 'v', box_chars_1[8]);       /* ACS_BTEE */
00929        append_acs0(&result, 't', box_chars_1[9]);       /* ACS_LTEE */
00930        append_acs0(&result, 'n', box_chars_1[10]);      /* ACS_PLUS */
00931 
00932        if (buf2[0]) {
00933            acs_chars = _nc_save_str(buf2);
00934            _nc_warning("acsc string synthesized from AIX capabilities");
00935            box_chars_1 = ABSENT_STRING;
00936        }
00937     }
00938     /*
00939      * ----------------------------------------------------------------------
00940      */
00941 }
00942 
00943 /*
00944  * Do a linear search through the terminfo tables to find a given full-name.
00945  * We don't expect to do this often, so there's no hashing function.
00946  *
00947  * In effect, this scans through the 3 lists of full-names, and looks them
00948  * up in _nc_info_table, which is organized so that the nte_index fields are
00949  * sorted, but the nte_type fields are not necessarily grouped together.
00950  */
00951 static struct name_table_entry const *
00952 lookup_fullname(const char *find)
00953 {
00954     int state = -1;
00955 
00956     for (;;) {
00957        int count = 0;
00958        NCURSES_CONST char *const *names;
00959 
00960        switch (++state) {
00961        case BOOLEAN:
00962            names = boolfnames;
00963            break;
00964        case STRING:
00965            names = strfnames;
00966            break;
00967        case NUMBER:
00968            names = numfnames;
00969            break;
00970        default:
00971            return NOTFOUND;
00972        }
00973 
00974        for (count = 0; names[count] != 0; count++) {
00975            if (!strcmp(names[count], find)) {
00976               struct name_table_entry const *entry_ptr = _nc_get_table(FALSE);
00977               while (entry_ptr->nte_type != state
00978                      || entry_ptr->nte_index != count)
00979                   entry_ptr++;
00980               return entry_ptr;
00981            }
00982        }
00983     }
00984 }
00985 
00986 /* parse_entry.c ends here */