1 /****************************************************************************
2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
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 ****************************************************************************/
36 * parse_entry.c -- compile one terminfo or termcap entry
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.
44 #define __INTERNAL_CAPS_VISIBLE
45 #include <curses.priv.h>
50 MODULE_ID("$Id: parse_entry.c,v 1.75 2010/05/01 19:35:09 tom Exp $")
53 static short const parametrized
[] =
56 #include <parametrized.h>
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
);
65 static struct name_table_entry
const *
66 _nc_extend_names(ENTRY
* entryp
, char *name
, int token_type
)
68 static struct name_table_entry temp
;
69 TERMTYPE
*tp
= &(entryp
->tterm
);
73 unsigned first
, last
, n
;
79 last
= tp
->ext_Booleans
;
80 offset
= tp
->ext_Booleans
;
81 tindex
= tp
->num_Booleans
;
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
;
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
;
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
)) {
101 } else if (n
> tp
->ext_Booleans
) {
104 token_type
= BOOLEAN
;
106 return _nc_extend_names(entryp
, name
, token_type
);
109 /* Well, we are given a cancel for a name that we don't recognize */
110 return _nc_extend_names(entryp
, name
, STRING
);
115 /* Adjust the 'offset' (insertion-point) to keep the lists of extended
118 for (n
= first
, found
= FALSE
; n
< last
; n
++) {
119 int cmp
= strcmp(tp
->ext_Names
[n
], name
);
125 switch (token_type
) {
140 #define for_each_value(max) \
141 for (last = (unsigned) (max - 1); last > tindex; last--)
144 switch (token_type
) {
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];
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];
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];
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
);
174 temp
.nte_name
= tp
->ext_Names
[offset
];
175 temp
.nte_type
= token_type
;
176 temp
.nte_index
= (short) tindex
;
181 #endif /* NCURSES_XNAMES */
185 * _nc_parse_entry(entry, literal, silent)
187 * Compile one entry. Doesn't try to resolve use or tc capabilities.
189 * found-forward-use = FALSE
190 * re-initialise internal arrays
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
198 * save string in entry's string table
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"); }
207 _nc_parse_entry(struct entry
*entryp
, int literal
, bool silent
)
210 struct name_table_entry
const *entry_ptr
;
212 bool bad_tc_usage
= FALSE
;
214 token_type
= _nc_get_token(silent
);
216 if (token_type
== EOF
)
218 if (token_type
!= NAMES
)
219 _nc_err_abort("Entry does not start with terminal names in column one");
221 _nc_init_entry(&entryp
->tterm
);
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
));
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.
237 ptr
= _nc_curr_token
.tk_name
;
238 if (_nc_syntax
== SYN_TERMCAP
240 && !_nc_user_definable
245 _nc_curr_token
.tk_name
[2] = '\0';
249 entryp
->tterm
.str_table
= entryp
->tterm
.term_names
= _nc_save_str(ptr
);
251 if (entryp
->tterm
.str_table
== 0)
254 DEBUG(1, ("Starting '%s'", ptr
));
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.
261 _nc_set_type(_nc_first_name(entryp
->tterm
.term_names
));
263 /* check for overly-long names and aliases */
264 for (base
= entryp
->tterm
.term_names
; (ptr
= strchr(base
, '|')) != 0;
266 if (ptr
- base
> MAX_ALIAS
) {
267 _nc_warning("%s `%.*s' may be too long",
268 (base
== entryp
->tterm
.term_names
)
271 (int) (ptr
- base
), base
);
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
;
286 if (entryp
->nuses
> 1 && is_tc
) {
290 /* normal token lookup */
291 entry_ptr
= _nc_find_entry(_nc_curr_token
.tk_name
,
292 _nc_get_hash_table(_nc_syntax
));
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.
302 if (entry_ptr
== NOTFOUND
) {
303 const struct alias
*ap
;
305 if (_nc_syntax
== SYN_TERMCAP
) {
306 if (entryp
->nuses
!= 0) {
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
);
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
);
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
);
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
);
341 if (entry_ptr
== NOTFOUND
) {
342 entry_ptr
= lookup_fullname(_nc_curr_token
.tk_name
);
348 * If we have extended-names active, we will automatically
349 * define a name based on its context.
351 if (entry_ptr
== NOTFOUND
352 && _nc_user_definable
353 && (entry_ptr
= _nc_extend_names(entryp
,
354 _nc_curr_token
.tk_name
,
356 if (_nc_tracing
>= DEBUG_LEVEL(1))
357 _nc_warning("extended capability '%s'", _nc_curr_token
.tk_name
);
359 #endif /* NCURSES_XNAMES */
361 /* can't find this cap name, not even as an alias */
362 if (entry_ptr
== NOTFOUND
) {
364 _nc_warning("unknown capability '%s'",
365 _nc_curr_token
.tk_name
);
369 /* deal with bad type/value combinations. */
370 if (token_type
!= CANCEL
&& entry_ptr
->nte_type
!= token_type
) {
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.
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
,
386 assert(entry_ptr
!= 0);
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
,
393 assert(entry_ptr
!= 0);
395 } else if (token_type
== BOOLEAN
396 && entry_ptr
->nte_type
== STRING
) {
397 /* treat strings without following "=" as empty strings */
400 /* we couldn't recover; skip this token */
402 const char *type_name
;
403 switch (entry_ptr
->nte_type
) {
405 type_name
= "boolean";
408 type_name
= "string";
411 type_name
= "numeric";
414 type_name
= "unknown";
417 _nc_warning("wrong type used for %s capability '%s'",
418 type_name
, _nc_curr_token
.tk_name
);
424 /* now we know that the type/value combination is OK */
425 switch (token_type
) {
427 switch (entry_ptr
->nte_type
) {
429 entryp
->tterm
.Booleans
[entry_ptr
->nte_index
] = CANCELLED_BOOLEAN
;
433 entryp
->tterm
.Numbers
[entry_ptr
->nte_index
] = CANCELLED_NUMERIC
;
437 entryp
->tterm
.Strings
[entry_ptr
->nte_index
] = CANCELLED_STRING
;
443 entryp
->tterm
.Booleans
[entry_ptr
->nte_index
] = TRUE
;
447 entryp
->tterm
.Numbers
[entry_ptr
->nte_index
] =
448 (short) _nc_curr_token
.tk_valnumber
;
452 ptr
= _nc_curr_token
.tk_valstring
;
453 if (_nc_syntax
== SYN_TERMCAP
)
454 ptr
= _nc_captoinfo(_nc_curr_token
.tk_name
,
456 parametrized
[entry_ptr
->nte_index
]);
457 entryp
->tterm
.Strings
[entry_ptr
->nte_index
] = _nc_save_str(ptr
);
462 _nc_warning("unknown token type");
463 _nc_panic_mode((char) ((_nc_syntax
== SYN_TERMCAP
) ? ':' : ','));
466 } /* end else cur_token.name != "use" */
468 continue; /* cannot have a label w/o statement */
469 } /* endwhile (not EOF and not NAMES) */
471 _nc_push_token(token_type
);
472 _nc_set_type(_nc_first_name(entryp
->tterm
.term_names
));
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.
481 if (_nc_syntax
== SYN_TERMCAP
) {
482 bool has_base_entry
= FALSE
;
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).
490 if (strchr(entryp
->tterm
.term_names
, '+'))
491 has_base_entry
= TRUE
;
494 * Otherwise, look for a base entry that will already
495 * have picked up defaults via translation.
497 for (i
= 0; i
< entryp
->nuses
; i
++)
498 if (!strchr((char *) entryp
->uses
[i
].name
, '+'))
499 has_base_entry
= TRUE
;
501 postprocess_termcap(&entryp
->tterm
, has_base_entry
);
503 postprocess_terminfo(&entryp
->tterm
);
505 _nc_wrap_entry(entryp
, FALSE
);
511 _nc_capcmp(const char *s
, const char *t
)
512 /* compare two string capabilities, stripping out padding */
514 if (!VALID_STRING(s
) && !VALID_STRING(t
))
516 else if (!VALID_STRING(s
) || !VALID_STRING(t
))
520 if (s
[0] == '$' && s
[1] == '<') {
522 if (!(isdigit(UChar(*s
))
530 if (t
[0] == '$' && t
[1] == '<') {
532 if (!(isdigit(UChar(*t
))
540 /* we've now pushed s and t past any padding they were pointing at */
542 if (*s
== '\0' && *t
== '\0')
548 /* else *s == *t but one is not NUL, so continue */
554 append_acs0(string_desc
* dst
, int code
, int src
)
558 temp
[0] = (char) code
;
559 temp
[1] = (char) src
;
561 _nc_safe_strcat(dst
, temp
);
566 append_acs(string_desc
* dst
, int code
, char *src
)
568 if (src
!= 0 && strlen(src
) == 1) {
569 append_acs0(dst
, code
, *src
);
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.
582 static assoc
const ko_xlate
[] =
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},
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.
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";
618 * Note that WANTED and PRESENT are not simple inverses! If a capability
619 * has been explicitly cancelled, it's not considered WANTED.
621 #define WANTED(s) ((s) == ABSENT_STRING)
622 #define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
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.
634 postprocess_termcap(TERMTYPE
*tp
, bool has_base
)
636 char buf
[MAX_LINE
* 2 + 2];
640 * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS
642 * This first part of the code is the functional inverse of the
643 * fragment in capdefaults.c.
644 * ----------------------------------------------------------------------
647 /* if there was a tc entry, assume we picked up defaults via that */
649 if (WANTED(init_3string
) && termcap_init2
)
650 init_3string
= _nc_save_str(termcap_init2
);
652 if (WANTED(reset_2string
) && termcap_reset
)
653 reset_2string
= _nc_save_str(termcap_reset
);
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
);
660 carriage_return
= _nc_save_str(C_CR
);
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
;
671 /* vi doesn't use "do", but it does seem 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
);
680 cursor_down
= _nc_save_str(C_LF
);
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
);
691 scroll_forward
= _nc_save_str(C_LF
);
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
);
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
);
716 * Inverse of capdefaults.c code ends here.
717 * ----------------------------------------------------------------------
719 * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION
721 * These translations will *not* be inverted by tgetent().
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.
730 if (return_does_clr_eol
== 1 || no_correctly_working_cr
== 1)
731 carriage_return
= ABSENT_STRING
;
734 * Supposedly most termcap entries have ta now and '\t' is no longer a
735 * default, but it doesn't seem to be true...
738 if (horizontal_tab_delay
> 0) {
739 sprintf(buf
, "%s$<%d>", C_HT
, horizontal_tab_delay
);
740 tab
= _nc_save_str(buf
);
742 tab
= _nc_save_str(C_HT
);
744 if (init_tabs
== ABSENT_NUMERIC
&& has_hardware_tabs
== TRUE
)
748 * Assume we can beep with ^G unless we're given bl@.
751 bell
= _nc_save_str("\007");
755 * Translate the old termcap :pt: capability to it#8 + ht=\t
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
);
761 if (tab
&& _nc_capcmp(tab
, C_HT
))
762 _nc_warning("hardware tabs with a non-^I tab string %s",
766 tab
= _nc_save_str(C_HT
);
772 * Now translate the ko capability, if there is one. This
773 * isn't from mytinfo...
775 if (PRESENT(other_non_function_keys
)) {
778 struct name_table_entry
const *from_ptr
;
779 struct name_table_entry
const *to_ptr
;
781 char buf2
[MAX_TERMINFO_LENGTH
];
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');
788 /* look at each comma-separated capability in the ko string... */
789 for (base
= other_non_function_keys
;
790 (cp
= strchr(base
, ',')) != 0;
792 size_t len
= (unsigned) (cp
- base
);
794 for (ap
= ko_xlate
; ap
->from
; ap
++) {
795 if (len
== strlen(ap
->from
)
796 && strncmp(ap
->from
, base
, len
) == 0)
799 if (!(ap
->from
&& ap
->to
)) {
800 _nc_warning("unknown capability `%.*s' in ko string",
803 } else if (ap
->to
== CANCELLED_STRING
) /* ignore it */
806 /* now we know we found a match in ko_table, so... */
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
));
811 if (!from_ptr
|| !to_ptr
) /* should never happen! */
812 _nc_err_abort("ko translation table is invalid, I give up");
814 if (WANTED(tp
->Strings
[from_ptr
->nte_index
])) {
815 _nc_warning("no value for ko capability %s", ap
->from
);
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.
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",
828 _nc_visbuf(tp
->Strings
[to_ptr
->nte_index
]));
833 * The magic moment -- copy the mapped key string over,
834 * stripping out padding.
836 for (dp
= buf2
, bp
= tp
->Strings
[from_ptr
->nte_index
]; *bp
; bp
++) {
837 if (bp
[0] == '$' && bp
[1] == '<') {
838 while (*bp
&& *bp
!= '>') {
846 tp
->Strings
[to_ptr
->nte_index
] = _nc_save_str(buf2
);
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.
855 if (foundim
&& WANTED(key_ic
) && key_sic
) {
857 key_sic
= ABSENT_STRING
;
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
);
873 * Translate XENIX forms characters.
875 if (PRESENT(acs_ulcorner
) ||
876 PRESENT(acs_llcorner
) ||
877 PRESENT(acs_urcorner
) ||
878 PRESENT(acs_lrcorner
) ||
883 PRESENT(acs_hline
) ||
884 PRESENT(acs_vline
) ||
886 char buf2
[MAX_TERMCAP_LENGTH
];
888 _nc_str_init(&result
, buf2
, sizeof(buf2
));
889 _nc_safe_strcat(&result
, acs_chars
);
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
);
904 acs_chars
= _nc_save_str(buf2
);
905 _nc_warning("acsc string synthesized from XENIX capabilities");
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
);
915 postprocess_terminfo(TERMTYPE
*tp
)
918 * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION
919 * ----------------------------------------------------------------------
923 * Translate AIX forms characters.
925 if (PRESENT(box_chars_1
)) {
926 char buf2
[MAX_TERMCAP_LENGTH
];
929 _nc_str_init(&result
, buf2
, sizeof(buf2
));
930 _nc_safe_strcat(&result
, acs_chars
);
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 */
945 acs_chars
= _nc_save_str(buf2
);
946 _nc_warning("acsc string synthesized from AIX capabilities");
947 box_chars_1
= ABSENT_STRING
;
951 * ----------------------------------------------------------------------
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.
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.
963 static struct name_table_entry
const *
964 lookup_fullname(const char *find
)
970 NCURSES_CONST
char *const *names
;
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
)
998 /* parse_entry.c ends here */