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