ncurses 5.7 - patch 20100123
[ncurses.git] / ncurses / tinfo / parse_entry.c
1 /****************************************************************************
2  * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  *     and: Thomas E. Dickey                        1996-on                 *
33  ****************************************************************************/
34
35 /*
36  *      parse_entry.c -- compile one terminfo or termcap entry
37  *
38  *      Get an exact in-core representation of an entry.  Don't
39  *      try to resolve use or tc capabilities, that is someone
40  *      else's job.  Depends on the lexical analyzer to get tokens
41  *      from the input stream.
42  */
43
44 #define __INTERNAL_CAPS_VISIBLE
45 #include <curses.priv.h>
46
47 #include <ctype.h>
48 #include <tic.h>
49
50 MODULE_ID("$Id: parse_entry.c,v 1.72 2010/01/23 17:57:43 tom Exp $")
51
52 #ifdef LINT
53 static short const parametrized[] =
54 {0};
55 #else
56 #include <parametrized.h>
57 #endif
58
59 static void postprocess_termcap(TERMTYPE *, bool);
60 static void postprocess_terminfo(TERMTYPE *);
61 static struct name_table_entry const *lookup_fullname(const char *name);
62
63 #if NCURSES_XNAMES
64
65 static struct name_table_entry const *
66 _nc_extend_names(ENTRY * entryp, char *name, int token_type)
67 {
68     static struct name_table_entry temp;
69     TERMTYPE *tp = &(entryp->tterm);
70     unsigned offset = 0;
71     unsigned actual;
72     unsigned tindex;
73     unsigned first, last, n;
74     bool found;
75
76     switch (token_type) {
77     case BOOLEAN:
78         first = 0;
79         last = tp->ext_Booleans;
80         offset = tp->ext_Booleans;
81         tindex = tp->num_Booleans;
82         break;
83     case NUMBER:
84         first = tp->ext_Booleans;
85         last = tp->ext_Numbers + first;
86         offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers);
87         tindex = tp->num_Numbers;
88         break;
89     case STRING:
90         first = (unsigned) (tp->ext_Booleans + tp->ext_Numbers);
91         last = tp->ext_Strings + first;
92         offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings);
93         tindex = tp->num_Strings;
94         break;
95     case CANCEL:
96         actual = NUM_EXT_NAMES(tp);
97         for (n = 0; n < actual; n++) {
98             if (!strcmp(name, tp->ext_Names[n])) {
99                 if (n > (unsigned) (tp->ext_Booleans + tp->ext_Numbers)) {
100                     token_type = STRING;
101                 } else if (n > tp->ext_Booleans) {
102                     token_type = NUMBER;
103                 } else {
104                     token_type = BOOLEAN;
105                 }
106                 return _nc_extend_names(entryp, name, token_type);
107             }
108         }
109         /* Well, we are given a cancel for a name that we don't recognize */
110         return _nc_extend_names(entryp, name, STRING);
111     default:
112         return 0;
113     }
114
115     /* Adjust the 'offset' (insertion-point) to keep the lists of extended
116      * names sorted.
117      */
118     for (n = first, found = FALSE; n < last; n++) {
119         int cmp = strcmp(tp->ext_Names[n], name);
120         if (cmp == 0)
121             found = TRUE;
122         if (cmp >= 0) {
123             offset = n;
124             tindex = n - first;
125             switch (token_type) {
126             case BOOLEAN:
127                 tindex += BOOLCOUNT;
128                 break;
129             case NUMBER:
130                 tindex += NUMCOUNT;
131                 break;
132             case STRING:
133                 tindex += STRCOUNT;
134                 break;
135             }
136             break;
137         }
138     }
139
140 #define for_each_value(max) \
141         for (last = (unsigned) (max - 1); last > tindex; last--)
142
143     if (!found) {
144         switch (token_type) {
145         case BOOLEAN:
146             tp->ext_Booleans++;
147             tp->num_Booleans++;
148             tp->Booleans = typeRealloc(NCURSES_SBOOL, tp->num_Booleans, tp->Booleans);
149             for_each_value(tp->num_Booleans)
150                 tp->Booleans[last] = tp->Booleans[last - 1];
151             break;
152         case NUMBER:
153             tp->ext_Numbers++;
154             tp->num_Numbers++;
155             tp->Numbers = typeRealloc(short, tp->num_Numbers, tp->Numbers);
156             for_each_value(tp->num_Numbers)
157                 tp->Numbers[last] = tp->Numbers[last - 1];
158             break;
159         case STRING:
160             tp->ext_Strings++;
161             tp->num_Strings++;
162             tp->Strings = typeRealloc(char *, tp->num_Strings, tp->Strings);
163             for_each_value(tp->num_Strings)
164                 tp->Strings[last] = tp->Strings[last - 1];
165             break;
166         }
167         actual = NUM_EXT_NAMES(tp);
168         tp->ext_Names = typeRealloc(char *, actual, tp->ext_Names);
169         while (--actual > offset)
170             tp->ext_Names[actual] = tp->ext_Names[actual - 1];
171         tp->ext_Names[offset] = _nc_save_str(name);
172     }
173
174     temp.nte_name = tp->ext_Names[offset];
175     temp.nte_type = token_type;
176     temp.nte_index = (short) tindex;
177     temp.nte_link = -1;
178
179     return &temp;
180 }
181 #endif /* NCURSES_XNAMES */
182
183 /*
184  *      int
185  *      _nc_parse_entry(entry, literal, silent)
186  *
187  *      Compile one entry.  Doesn't try to resolve use or tc capabilities.
188  *
189  *      found-forward-use = FALSE
190  *      re-initialise internal arrays
191  *      get_token();
192  *      if the token was not a name in column 1, complain and die
193  *      save names in entry's string table
194  *      while (get_token() is not EOF and not NAMES)
195  *              check for existence and type-correctness
196  *              enter cap into structure
197  *              if STRING
198  *                  save string in entry's string table
199  *      push back token
200  */
201
202 #define BAD_TC_USAGE if (!bad_tc_usage) \
203         { bad_tc_usage = TRUE; \
204          _nc_warning("Legacy termcap allows only a trailing tc= clause"); }
205
206 NCURSES_EXPORT(int)
207 _nc_parse_entry(struct entry *entryp, int literal, bool silent)
208 {
209     int token_type;
210     struct name_table_entry const *entry_ptr;
211     char *ptr, *base;
212     bool bad_tc_usage = FALSE;
213
214     token_type = _nc_get_token(silent);
215
216     if (token_type == EOF)
217         return (EOF);
218     if (token_type != NAMES)
219         _nc_err_abort("Entry does not start with terminal names in column one");
220
221     _nc_init_entry(&entryp->tterm);
222
223     entryp->cstart = _nc_comment_start;
224     entryp->cend = _nc_comment_end;
225     entryp->startline = _nc_start_line;
226     DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend));
227
228     /*
229      * Strip off the 2-character termcap name, if present.  Originally termcap
230      * used that as an indexing aid.  We can retain 2-character terminfo names,
231      * but note that they would be lost if we translate to/from termcap.  This
232      * feature is supposedly obsolete since "newer" BSD implementations do not
233      * use it; however our reference for this feature is SunOS 4.x, which
234      * implemented it.  Note that the resulting terminal type was never the
235      * 2-character name, but was instead the first alias after that.
236      */
237     ptr = _nc_curr_token.tk_name;
238     if (_nc_syntax == SYN_TERMCAP
239 #if NCURSES_XNAMES
240         && !_nc_user_definable
241 #endif
242         ) {
243         if (ptr[2] == '|') {
244             ptr += 3;
245             _nc_curr_token.tk_name[2] = '\0';
246         }
247     }
248
249     entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr);
250
251     if (entryp->tterm.str_table == 0)
252         return (ERR);
253
254     DEBUG(1, ("Starting '%s'", ptr));
255
256     /*
257      * We do this because the one-token lookahead in the parse loop
258      * results in the terminal type getting prematurely set to correspond
259      * to that of the next entry.
260      */
261     _nc_set_type(_nc_first_name(entryp->tterm.term_names));
262
263     /* check for overly-long names and aliases */
264     for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
265          base = ptr + 1) {
266         if (ptr - base > MAX_ALIAS) {
267             _nc_warning("%s `%.*s' may be too long",
268                         (base == entryp->tterm.term_names)
269                         ? "primary name"
270                         : "alias",
271                         (int) (ptr - base), base);
272         }
273     }
274
275     entryp->nuses = 0;
276
277     for (token_type = _nc_get_token(silent);
278          token_type != EOF && token_type != NAMES;
279          token_type = _nc_get_token(silent)) {
280         bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0);
281         bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0);
282         if (is_use || is_tc) {
283             entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
284             entryp->uses[entryp->nuses].line = _nc_curr_line;
285             entryp->nuses++;
286             if (entryp->nuses > 1 && is_tc) {
287                 BAD_TC_USAGE
288             }
289         } else {
290             /* normal token lookup */
291             entry_ptr = _nc_find_entry(_nc_curr_token.tk_name,
292                                        _nc_get_hash_table(_nc_syntax));
293
294             /*
295              * Our kluge to handle aliasing.  The reason it's done
296              * this ugly way, with a linear search, is so the hashing
297              * machinery doesn't have to be made really complicated
298              * (also we get better warnings this way).  No point in
299              * making this case fast, aliased caps aren't common now
300              * and will get rarer.
301              */
302             if (entry_ptr == NOTFOUND) {
303                 const struct alias *ap;
304
305                 if (_nc_syntax == SYN_TERMCAP) {
306                     if (entryp->nuses != 0) {
307                         BAD_TC_USAGE
308                     }
309                     for (ap = _nc_get_alias_table(TRUE); ap->from; ap++)
310                         if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
311                             if (ap->to == (char *) 0) {
312                                 _nc_warning("%s (%s termcap extension) ignored",
313                                             ap->from, ap->source);
314                                 goto nexttok;
315                             }
316
317                             entry_ptr = _nc_find_entry(ap->to,
318                                                        _nc_get_hash_table(TRUE));
319                             if (entry_ptr && !silent)
320                                 _nc_warning("%s (%s termcap extension) aliased to %s",
321                                             ap->from, ap->source, ap->to);
322                             break;
323                         }
324                 } else {        /* if (_nc_syntax == SYN_TERMINFO) */
325                     for (ap = _nc_get_alias_table(FALSE); ap->from; ap++)
326                         if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
327                             if (ap->to == (char *) 0) {
328                                 _nc_warning("%s (%s terminfo extension) ignored",
329                                             ap->from, ap->source);
330                                 goto nexttok;
331                             }
332
333                             entry_ptr = _nc_find_entry(ap->to,
334                                                        _nc_get_hash_table(FALSE));
335                             if (entry_ptr && !silent)
336                                 _nc_warning("%s (%s terminfo extension) aliased to %s",
337                                             ap->from, ap->source, ap->to);
338                             break;
339                         }
340
341                     if (entry_ptr == NOTFOUND) {
342                         entry_ptr = lookup_fullname(_nc_curr_token.tk_name);
343                     }
344                 }
345             }
346 #if NCURSES_XNAMES
347             /*
348              * If we have extended-names active, we will automatically
349              * define a name based on its context.
350              */
351             if (entry_ptr == NOTFOUND
352                 && _nc_user_definable
353                 && (entry_ptr = _nc_extend_names(entryp,
354                                                  _nc_curr_token.tk_name,
355                                                  token_type)) != 0) {
356                 if (_nc_tracing >= DEBUG_LEVEL(1))
357                     _nc_warning("extended capability '%s'", _nc_curr_token.tk_name);
358             }
359 #endif /* NCURSES_XNAMES */
360
361             /* can't find this cap name, not even as an alias */
362             if (entry_ptr == NOTFOUND) {
363                 if (!silent)
364                     _nc_warning("unknown capability '%s'",
365                                 _nc_curr_token.tk_name);
366                 continue;
367             }
368
369             /* deal with bad type/value combinations. */
370             if (token_type != CANCEL && entry_ptr->nte_type != token_type) {
371                 /*
372                  * Nasty special cases here handle situations in which type
373                  * information can resolve name clashes.  Normal lookup
374                  * finds the last instance in the capability table of a
375                  * given name, regardless of type.  find_type_entry looks
376                  * for a first matching instance with given type.  So as
377                  * long as all ambiguous names occur in pairs of distinct
378                  * type, this will do the job.
379                  */
380
381                 if (token_type == NUMBER
382                     && !strcmp("ma", _nc_curr_token.tk_name)) {
383                     /* tell max_attributes from arrow_key_map */
384                     entry_ptr = _nc_find_type_entry("ma", NUMBER,
385                                                     _nc_syntax != 0);
386                     assert(entry_ptr != 0);
387
388                 } else if (token_type == STRING
389                            && !strcmp("MT", _nc_curr_token.tk_name)) {
390                     /* map terminfo's string MT to MT */
391                     entry_ptr = _nc_find_type_entry("MT", STRING,
392                                                     _nc_syntax != 0);
393                     assert(entry_ptr != 0);
394
395                 } else if (token_type == BOOLEAN
396                            && entry_ptr->nte_type == STRING) {
397                     /* treat strings without following "=" as empty strings */
398                     token_type = STRING;
399                 } else {
400                     /* we couldn't recover; skip this token */
401                     if (!silent) {
402                         const char *type_name;
403                         switch (entry_ptr->nte_type) {
404                         case BOOLEAN:
405                             type_name = "boolean";
406                             break;
407                         case STRING:
408                             type_name = "string";
409                             break;
410                         case NUMBER:
411                             type_name = "numeric";
412                             break;
413                         default:
414                             type_name = "unknown";
415                             break;
416                         }
417                         _nc_warning("wrong type used for %s capability '%s'",
418                                     type_name, _nc_curr_token.tk_name);
419                     }
420                     continue;
421                 }
422             }
423
424             /* now we know that the type/value combination is OK */
425             switch (token_type) {
426             case CANCEL:
427                 switch (entry_ptr->nte_type) {
428                 case BOOLEAN:
429                     entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN;
430                     break;
431
432                 case NUMBER:
433                     entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC;
434                     break;
435
436                 case STRING:
437                     entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING;
438                     break;
439                 }
440                 break;
441
442             case BOOLEAN:
443                 entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE;
444                 break;
445
446             case NUMBER:
447                 entryp->tterm.Numbers[entry_ptr->nte_index] =
448                     (short) _nc_curr_token.tk_valnumber;
449                 break;
450
451             case STRING:
452                 ptr = _nc_curr_token.tk_valstring;
453                 if (_nc_syntax == SYN_TERMCAP)
454                     ptr = _nc_captoinfo(_nc_curr_token.tk_name,
455                                         ptr,
456                                         parametrized[entry_ptr->nte_index]);
457                 entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr);
458                 break;
459
460             default:
461                 if (!silent)
462                     _nc_warning("unknown token type");
463                 _nc_panic_mode((char) ((_nc_syntax == SYN_TERMCAP) ? ':' : ','));
464                 continue;
465             }
466         }                       /* end else cur_token.name != "use" */
467       nexttok:
468         continue;               /* cannot have a label w/o statement */
469     }                           /* endwhile (not EOF and not NAMES) */
470
471     _nc_push_token(token_type);
472     _nc_set_type(_nc_first_name(entryp->tterm.term_names));
473
474     /*
475      * Try to deduce as much as possible from extension capabilities
476      * (this includes obsolete BSD capabilities).  Sigh...it would be more
477      * space-efficient to call this after use resolution, but it has
478      * to be done before entry allocation is wrapped up.
479      */
480     if (!literal) {
481         if (_nc_syntax == SYN_TERMCAP) {
482             bool has_base_entry = FALSE;
483             unsigned i;
484
485             /*
486              * Don't insert defaults if this is a `+' entry meant only
487              * for inclusion in other entries (not sure termcap ever
488              * had these, actually).
489              */
490             if (strchr(entryp->tterm.term_names, '+'))
491                 has_base_entry = TRUE;
492             else
493                 /*
494                  * Otherwise, look for a base entry that will already
495                  * have picked up defaults via translation.
496                  */
497                 for (i = 0; i < entryp->nuses; i++)
498                     if (!strchr((char *) entryp->uses[i].name, '+'))
499                         has_base_entry = TRUE;
500
501             postprocess_termcap(&entryp->tterm, has_base_entry);
502         } else
503             postprocess_terminfo(&entryp->tterm);
504     }
505     _nc_wrap_entry(entryp, FALSE);
506
507     return (OK);
508 }
509
510 NCURSES_EXPORT(int)
511 _nc_capcmp(const char *s, const char *t)
512 /* compare two string capabilities, stripping out padding */
513 {
514     if (!s && !t)
515         return (0);
516     else if (!s || !t)
517         return (1);
518
519     for (;;) {
520         if (s[0] == '$' && s[1] == '<') {
521             for (s += 2;; s++)
522                 if (!(isdigit(UChar(*s))
523                       || *s == '.'
524                       || *s == '*'
525                       || *s == '/'
526                       || *s == '>'))
527                     break;
528         }
529
530         if (t[0] == '$' && t[1] == '<') {
531             for (t += 2;; t++)
532                 if (!(isdigit(UChar(*t))
533                       || *t == '.'
534                       || *t == '*'
535                       || *t == '/'
536                       || *t == '>'))
537                     break;
538         }
539
540         /* we've now pushed s and t past any padding they were pointing at */
541
542         if (*s == '\0' && *t == '\0')
543             return (0);
544
545         if (*s != *t)
546             return (*t - *s);
547
548         /* else *s == *t but one is not NUL, so continue */
549         s++, t++;
550     }
551 }
552
553 static void
554 append_acs0(string_desc * dst, int code, int src)
555 {
556     if (src != 0) {
557         char temp[3];
558         temp[0] = (char) code;
559         temp[1] = (char) src;
560         temp[2] = 0;
561         _nc_safe_strcat(dst, temp);
562     }
563 }
564
565 static void
566 append_acs(string_desc * dst, int code, char *src)
567 {
568     if (src != 0 && strlen(src) == 1) {
569         append_acs0(dst, code, *src);
570     }
571 }
572
573 /*
574  * The ko capability, if present, consists of a comma-separated capability
575  * list.  For each capability, we may assume there is a keycap that sends the
576  * string which is the value of that capability.
577  */
578 typedef struct {
579     const char *from;
580     const char *to;
581 } assoc;
582 static assoc const ko_xlate[] =
583 {
584     {"al", "kil1"},             /* insert line key  -> KEY_IL    */
585     {"bt", "kcbt"},             /* back tab         -> KEY_BTAB  */
586     {"cd", "ked"},              /* clear-to-eos key -> KEY_EOL   */
587     {"ce", "kel"},              /* clear-to-eol key -> KEY_EOS   */
588     {"cl", "kclr"},             /* clear key        -> KEY_CLEAR */
589     {"ct", "tbc"},              /* clear all tabs   -> KEY_CATAB */
590     {"dc", "kdch1"},            /* delete char      -> KEY_DC    */
591     {"dl", "kdl1"},             /* delete line      -> KEY_DL    */
592     {"do", "kcud1"},            /* down key         -> KEY_DOWN  */
593     {"ei", "krmir"},            /* exit insert key  -> KEY_EIC   */
594     {"ho", "khome"},            /* home key         -> KEY_HOME  */
595     {"ic", "kich1"},            /* insert char key  -> KEY_IC    */
596     {"im", "kIC"},              /* insert-mode key  -> KEY_SIC   */
597     {"le", "kcub1"},            /* le key           -> KEY_LEFT  */
598     {"nd", "kcuf1"},            /* nd key           -> KEY_RIGHT */
599     {"nl", "kent"},             /* new line key     -> KEY_ENTER */
600     {"st", "khts"},             /* set-tab key      -> KEY_STAB  */
601     {"ta", CANCELLED_STRING},
602     {"up", "kcuu1"},            /* up-arrow key     -> KEY_UP    */
603     {(char *) 0, (char *) 0},
604 };
605
606 /*
607  * This routine fills in string caps that either had defaults under
608  * termcap or can be manufactured from obsolete termcap capabilities.
609  * It was lifted from Ross Ridge's mytinfo package.
610  */
611
612 static const char C_CR[] = "\r";
613 static const char C_LF[] = "\n";
614 static const char C_BS[] = "\b";
615 static const char C_HT[] = "\t";
616
617 /*
618  * Note that WANTED and PRESENT are not simple inverses!  If a capability
619  * has been explicitly cancelled, it's not considered WANTED.
620  */
621 #define WANTED(s)       ((s) == ABSENT_STRING)
622 #define PRESENT(s)      (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
623
624 /*
625  * This bit of legerdemain turns all the terminfo variable names into
626  * references to locations in the arrays Booleans, Numbers, and Strings ---
627  * precisely what's needed.
628  */
629
630 #undef CUR
631 #define CUR tp->
632
633 static void
634 postprocess_termcap(TERMTYPE *tp, bool has_base)
635 {
636     char buf[MAX_LINE * 2 + 2];
637     string_desc result;
638
639     /*
640      * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS
641      *
642      * This first part of the code is the functional inverse of the
643      * fragment in capdefaults.c.
644      * ----------------------------------------------------------------------
645      */
646
647     /* if there was a tc entry, assume we picked up defaults via that */
648     if (!has_base) {
649         if (WANTED(init_3string) && termcap_init2)
650             init_3string = _nc_save_str(termcap_init2);
651
652         if (WANTED(reset_2string) && termcap_reset)
653             reset_2string = _nc_save_str(termcap_reset);
654
655         if (WANTED(carriage_return)) {
656             if (carriage_return_delay > 0) {
657                 sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay);
658                 carriage_return = _nc_save_str(buf);
659             } else
660                 carriage_return = _nc_save_str(C_CR);
661         }
662         if (WANTED(cursor_left)) {
663             if (backspace_delay > 0) {
664                 sprintf(buf, "%s$<%d>", C_BS, backspace_delay);
665                 cursor_left = _nc_save_str(buf);
666             } else if (backspaces_with_bs == 1)
667                 cursor_left = _nc_save_str(C_BS);
668             else if (PRESENT(backspace_if_not_bs))
669                 cursor_left = backspace_if_not_bs;
670         }
671         /* vi doesn't use "do", but it does seems to use nl (or '\n') instead */
672         if (WANTED(cursor_down)) {
673             if (PRESENT(linefeed_if_not_lf))
674                 cursor_down = linefeed_if_not_lf;
675             else if (linefeed_is_newline != 1) {
676                 if (new_line_delay > 0) {
677                     sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
678                     cursor_down = _nc_save_str(buf);
679                 } else
680                     cursor_down = _nc_save_str(C_LF);
681             }
682         }
683         if (WANTED(scroll_forward) && crt_no_scrolling != 1) {
684             if (PRESENT(linefeed_if_not_lf))
685                 cursor_down = linefeed_if_not_lf;
686             else if (linefeed_is_newline != 1) {
687                 if (new_line_delay > 0) {
688                     sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
689                     scroll_forward = _nc_save_str(buf);
690                 } else
691                     scroll_forward = _nc_save_str(C_LF);
692             }
693         }
694         if (WANTED(newline)) {
695             if (linefeed_is_newline == 1) {
696                 if (new_line_delay > 0) {
697                     sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
698                     newline = _nc_save_str(buf);
699                 } else
700                     newline = _nc_save_str(C_LF);
701             } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) {
702                 _nc_str_init(&result, buf, sizeof(buf));
703                 if (_nc_safe_strcat(&result, carriage_return)
704                     && _nc_safe_strcat(&result, scroll_forward))
705                     newline = _nc_save_str(buf);
706             } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) {
707                 _nc_str_init(&result, buf, sizeof(buf));
708                 if (_nc_safe_strcat(&result, carriage_return)
709                     && _nc_safe_strcat(&result, cursor_down))
710                     newline = _nc_save_str(buf);
711             }
712         }
713     }
714
715     /*
716      * Inverse of capdefaults.c code ends here.
717      * ----------------------------------------------------------------------
718      *
719      * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION
720      *
721      * These translations will *not* be inverted by tgetent().
722      */
723
724     if (!has_base) {
725         /*
726          * We wait until now to decide if we've got a working cr because even
727          * one that doesn't work can be used for newline. Unfortunately the
728          * space allocated for it is wasted.
729          */
730         if (return_does_clr_eol == 1 || no_correctly_working_cr == 1)
731             carriage_return = ABSENT_STRING;
732
733         /*
734          * Supposedly most termcap entries have ta now and '\t' is no longer a
735          * default, but it doesn't seem to be true...
736          */
737         if (WANTED(tab)) {
738             if (horizontal_tab_delay > 0) {
739                 sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay);
740                 tab = _nc_save_str(buf);
741             } else
742                 tab = _nc_save_str(C_HT);
743         }
744         if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE)
745             init_tabs = 8;
746
747         /*
748          * Assume we can beep with ^G unless we're given bl@.
749          */
750         if (WANTED(bell))
751             bell = _nc_save_str("\007");
752     }
753
754     /*
755      * Translate the old termcap :pt: capability to it#8 + ht=\t
756      */
757     if (has_hardware_tabs == TRUE) {
758         if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
759             _nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
760         else {
761             if (tab && _nc_capcmp(tab, C_HT))
762                 _nc_warning("hardware tabs with a non-^I tab string %s",
763                             _nc_visbuf(tab));
764             else {
765                 if (WANTED(tab))
766                     tab = _nc_save_str(C_HT);
767                 init_tabs = 8;
768             }
769         }
770     }
771     /*
772      * Now translate the ko capability, if there is one.  This
773      * isn't from mytinfo...
774      */
775     if (PRESENT(other_non_function_keys)) {
776         char *base = other_non_function_keys;
777         char *bp, *cp, *dp;
778         struct name_table_entry const *from_ptr;
779         struct name_table_entry const *to_ptr;
780         assoc const *ap;
781         char buf2[MAX_TERMINFO_LENGTH];
782         bool foundim;
783
784         /* we're going to use this for a special case later */
785         dp = strchr(other_non_function_keys, 'i');
786         foundim = (dp != 0) && (dp[1] == 'm');
787
788         /* look at each comma-separated capability in the ko string... */
789         for (base = other_non_function_keys;
790              (cp = strchr(base, ',')) != 0;
791              base = cp + 1) {
792             size_t len = (unsigned) (cp - base);
793
794             for (ap = ko_xlate; ap->from; ap++) {
795                 if (len == strlen(ap->from)
796                     && strncmp(ap->from, base, len) == 0)
797                     break;
798             }
799             if (!(ap->from && ap->to)) {
800                 _nc_warning("unknown capability `%.*s' in ko string",
801                             (int) len, base);
802                 continue;
803             } else if (ap->to == CANCELLED_STRING)      /* ignore it */
804                 continue;
805
806             /* now we know we found a match in ko_table, so... */
807
808             from_ptr = _nc_find_entry(ap->from, _nc_get_hash_table(TRUE));
809             to_ptr = _nc_find_entry(ap->to, _nc_get_hash_table(FALSE));
810
811             if (!from_ptr || !to_ptr)   /* should never happen! */
812                 _nc_err_abort("ko translation table is invalid, I give up");
813
814             if (WANTED(tp->Strings[from_ptr->nte_index])) {
815                 _nc_warning("no value for ko capability %s", ap->from);
816                 continue;
817             }
818
819             if (tp->Strings[to_ptr->nte_index]) {
820                 /* There's no point in warning about it if it's the same
821                  * string; that's just an inefficiency.
822                  */
823                 if (strcmp(
824                               tp->Strings[from_ptr->nte_index],
825                               tp->Strings[to_ptr->nte_index]) != 0)
826                     _nc_warning("%s (%s) already has an explicit value %s, ignoring ko",
827                                 ap->to, ap->from,
828                                 _nc_visbuf(tp->Strings[to_ptr->nte_index]));
829                 continue;
830             }
831
832             /*
833              * The magic moment -- copy the mapped key string over,
834              * stripping out padding.
835              */
836             for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
837                 if (bp[0] == '$' && bp[1] == '<') {
838                     while (*bp && *bp != '>') {
839                         ++bp;
840                     }
841                 } else
842                     *dp++ = *bp;
843             }
844             *dp++ = '\0';
845
846             tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
847         }
848
849         /*
850          * Note: ko=im and ko=ic both want to grab the `Insert'
851          * keycap.  There's a kich1 but no ksmir, so the ic capability
852          * got mapped to kich1 and im to kIC to avoid a collision.
853          * If the description has im but not ic, hack kIC back to kich1.
854          */
855         if (foundim && WANTED(key_ic) && key_sic) {
856             key_ic = key_sic;
857             key_sic = ABSENT_STRING;
858         }
859     }
860
861     if (!has_base) {
862         if (!hard_copy) {
863             if (WANTED(key_backspace))
864                 key_backspace = _nc_save_str(C_BS);
865             if (WANTED(key_left))
866                 key_left = _nc_save_str(C_BS);
867             if (WANTED(key_down))
868                 key_down = _nc_save_str(C_LF);
869         }
870     }
871
872     /*
873      * Translate XENIX forms characters.
874      */
875     if (PRESENT(acs_ulcorner) ||
876         PRESENT(acs_llcorner) ||
877         PRESENT(acs_urcorner) ||
878         PRESENT(acs_lrcorner) ||
879         PRESENT(acs_ltee) ||
880         PRESENT(acs_rtee) ||
881         PRESENT(acs_btee) ||
882         PRESENT(acs_ttee) ||
883         PRESENT(acs_hline) ||
884         PRESENT(acs_vline) ||
885         PRESENT(acs_plus)) {
886         char buf2[MAX_TERMCAP_LENGTH];
887
888         _nc_str_init(&result, buf2, sizeof(buf2));
889         _nc_safe_strcat(&result, acs_chars);
890
891         append_acs(&result, 'j', acs_lrcorner);
892         append_acs(&result, 'k', acs_urcorner);
893         append_acs(&result, 'l', acs_ulcorner);
894         append_acs(&result, 'm', acs_llcorner);
895         append_acs(&result, 'n', acs_plus);
896         append_acs(&result, 'q', acs_hline);
897         append_acs(&result, 't', acs_ltee);
898         append_acs(&result, 'u', acs_rtee);
899         append_acs(&result, 'v', acs_btee);
900         append_acs(&result, 'w', acs_ttee);
901         append_acs(&result, 'x', acs_vline);
902
903         if (buf2[0]) {
904             acs_chars = _nc_save_str(buf2);
905             _nc_warning("acsc string synthesized from XENIX capabilities");
906         }
907     } else if (acs_chars == 0
908                && enter_alt_charset_mode != 0
909                && exit_alt_charset_mode != 0) {
910         acs_chars = _nc_save_str(VT_ACSC);
911     }
912 }
913
914 static void
915 postprocess_terminfo(TERMTYPE *tp)
916 {
917     /*
918      * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION
919      * ----------------------------------------------------------------------
920      */
921
922     /*
923      * Translate AIX forms characters.
924      */
925     if (PRESENT(box_chars_1)) {
926         char buf2[MAX_TERMCAP_LENGTH];
927         string_desc result;
928
929         _nc_str_init(&result, buf2, sizeof(buf2));
930         _nc_safe_strcat(&result, acs_chars);
931
932         append_acs0(&result, 'l', box_chars_1[0]);      /* ACS_ULCORNER */
933         append_acs0(&result, 'q', box_chars_1[1]);      /* ACS_HLINE */
934         append_acs0(&result, 'k', box_chars_1[2]);      /* ACS_URCORNER */
935         append_acs0(&result, 'x', box_chars_1[3]);      /* ACS_VLINE */
936         append_acs0(&result, 'j', box_chars_1[4]);      /* ACS_LRCORNER */
937         append_acs0(&result, 'm', box_chars_1[5]);      /* ACS_LLCORNER */
938         append_acs0(&result, 'w', box_chars_1[6]);      /* ACS_TTEE */
939         append_acs0(&result, 'u', box_chars_1[7]);      /* ACS_RTEE */
940         append_acs0(&result, 'v', box_chars_1[8]);      /* ACS_BTEE */
941         append_acs0(&result, 't', box_chars_1[9]);      /* ACS_LTEE */
942         append_acs0(&result, 'n', box_chars_1[10]);     /* ACS_PLUS */
943
944         if (buf2[0]) {
945             acs_chars = _nc_save_str(buf2);
946             _nc_warning("acsc string synthesized from AIX capabilities");
947             box_chars_1 = ABSENT_STRING;
948         }
949     }
950     /*
951      * ----------------------------------------------------------------------
952      */
953 }
954
955 /*
956  * Do a linear search through the terminfo tables to find a given full-name.
957  * We don't expect to do this often, so there's no hashing function.
958  *
959  * In effect, this scans through the 3 lists of full-names, and looks them
960  * up in _nc_info_table, which is organized so that the nte_index fields are
961  * sorted, but the nte_type fields are not necessarily grouped together.
962  */
963 static struct name_table_entry const *
964 lookup_fullname(const char *find)
965 {
966     int state = -1;
967
968     for (;;) {
969         int count = 0;
970         NCURSES_CONST char *const *names;
971
972         switch (++state) {
973         case BOOLEAN:
974             names = boolfnames;
975             break;
976         case STRING:
977             names = strfnames;
978             break;
979         case NUMBER:
980             names = numfnames;
981             break;
982         default:
983             return NOTFOUND;
984         }
985
986         for (count = 0; names[count] != 0; count++) {
987             if (!strcmp(names[count], find)) {
988                 struct name_table_entry const *entry_ptr = _nc_get_table(FALSE);
989                 while (entry_ptr->nte_type != state
990                        || entry_ptr->nte_index != count)
991                     entry_ptr++;
992                 return entry_ptr;
993             }
994         }
995     }
996 }
997
998 /* parse_entry.c ends here */