1 /****************************************************************************
2 * Copyright (c) 1998-2001,2002 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 ****************************************************************************/
35 * captoinfo.c --- conversion between termcap and terminfo formats
37 * The captoinfo() code was swiped from Ross Ridge's mytinfo package,
38 * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
40 * There is just one entry point:
42 * char *_nc_captoinfo(n, s, parametrized)
44 * Convert value s for termcap string capability named n into terminfo
47 * This code recognizes all the standard 4.4BSD %-escapes:
50 * %d output value as in printf %d
51 * %2 output value as in printf %2d
52 * %3 output value as in printf %3d
53 * %. output value as in printf %c
54 * %+x add x to value, then do %.
55 * %>xy if value > x then add y, no output
56 * %r reverse order of two parameters, no output
57 * %i increment by one, no output
58 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
59 * %B BCD (16*(value/10)) + (value%10), no output
60 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
62 * Also, %02 and %03 are accepted as synonyms for %2 and %3.
64 * Besides all the standard termcap escapes, this translator understands
65 * the following extended escapes:
67 * used by GNU Emacs termcap libraries
68 * %a[+*-/=][cp]x GNU arithmetic.
69 * %m xor the first two parameters by 0177
70 * %b backup to previous parameter
71 * %f skip this parameter
73 * used by the University of Waterloo (MFCF) termcap libraries
74 * %-x subtract parameter FROM char x and output it as a char
75 * %ax add the character x to parameter
77 * If #define WATERLOO is on, also enable these translations:
79 * %sx subtract parameter FROM the character x
81 * By default, this Waterloo translations are not compiled in, because
82 * the Waterloo %s conflicts with the way terminfo uses %s in strings for
83 * function programming.
85 * Note the two definitions of %a: the GNU definition is translated if the
86 * characters after the 'a' are valid for it, otherwise the UW definition
90 #include <curses.priv.h>
95 MODULE_ID("$Id: captoinfo.c,v 1.43 2002/09/28 16:38:59 tom Exp $")
97 #define MAX_PUSHED 16 /* max # args we can push onto the stack */
99 static int stack[MAX_PUSHED]; /* the stack */
100 static int stackptr; /* the next empty place on the stack */
101 static int onstack; /* the top of stack */
102 static int seenm; /* seen a %m */
103 static int seenn; /* seen a %n */
104 static int seenr; /* seen a %r */
105 static int param; /* current parameter */
106 static char *dp; /* pointer to end of the converted string */
108 static char *my_string;
109 static size_t my_length;
113 /* initialize 'my_string', 'my_length' */
116 my_string = typeMalloc(char, my_length = 256);
118 _nc_err_abort(MSG_NO_MEMORY);
125 save_string(char *d, const char *const s)
127 size_t have = (d - my_string);
128 size_t need = have + strlen(s) + 2;
129 if (need > my_length) {
130 my_string = (char *) realloc(my_string, my_length = (need + need));
132 _nc_err_abort(MSG_NO_MEMORY);
133 d = my_string + have;
136 return d + strlen(d);
140 save_char(char *s, int c)
144 return save_string(s, temp);
149 /* push onstack on to the stack */
151 if (stackptr > MAX_PUSHED)
152 _nc_warning("string too complex to convert");
154 stack[stackptr++] = onstack;
159 /* pop the top of the stack into onstack */
163 _nc_warning("I'm confused");
167 onstack = stack[--stackptr];
172 cvtchar(register const char *sp)
173 /* convert a character to a terminfo push */
197 while (isdigit(UChar(*sp))) {
198 c = 8 * c + (*sp++ - '0');
216 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
217 dp = save_string(dp, "%\'");
218 dp = save_char(dp, c);
219 dp = save_char(dp, '\'');
221 dp = save_string(dp, "%{");
223 dp = save_char(dp, c / 100 + '0');
225 dp = save_char(dp, ((int) (c / 10)) % 10 + '0');
226 dp = save_char(dp, c % 10 + '0');
227 dp = save_char(dp, '}');
233 getparm(int parm, int n)
234 /* push n copies of param on the terminfo stack if not already there */
242 if (onstack == parm) {
244 _nc_warning("string may not be optimal");
245 dp = save_string(dp, "%Pa");
247 dp = save_string(dp, "%ga");
258 dp = save_string(dp, "%p");
259 dp = save_char(dp, '0' + parm);
262 if (seenn && parm < 3) {
263 dp = save_string(dp, "%{96}%^");
266 if (seenm && parm < 3) {
267 dp = save_string(dp, "%{127}%^");
272 * Convert a termcap string to terminfo format.
273 * 'cap' is the relevant terminfo capability index.
274 * 's' is the string value of the capability.
275 * 'parametrized' tells what type of translations to do:
276 * % translations if 1
277 * pad translations if >=0
280 _nc_captoinfo(const char *cap, const char *s, int const parametrized)
282 const char *capstart;
293 /* skip the initial padding (if we haven't been told not to) */
297 if (parametrized >= 0 && isdigit(UChar(*s)))
298 for (capstart = s;; s++)
299 if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
306 if (parametrized < 1) {
307 dp = save_char(dp, '%');
312 dp = save_char(dp, '%');
316 _nc_warning("saw %%r twice in %s", cap);
321 _nc_warning("saw %%m twice in %s", cap);
326 _nc_warning("saw %%n twice in %s", cap);
330 dp = save_string(dp, "%i");
335 dp = save_string(dp, "%{10}%/%{16}%*");
337 dp = save_string(dp, "%{10}%m%+");
342 dp = save_string(dp, "%{2}%*%-");
346 /* %?%{x}%>%t%{y}%+%; */
347 dp = save_string(dp, "%?");
349 dp = save_string(dp, "%>%t");
351 dp = save_string(dp, "%+%;");
354 if ((*s == '=' || *s == '+' || *s == '-'
355 || *s == '*' || *s == '/')
356 && (s[1] == 'p' || s[1] == 'c')
363 getparm(param + s[2] - '@', 1);
364 if (param != onstack) {
373 dp = save_string(dp, "%+");
376 dp = save_string(dp, "%-");
379 dp = save_string(dp, "%*");
382 dp = save_string(dp, "%/");
401 dp = save_string(dp, "%+");
406 dp = save_string(dp, "%+%c");
413 dp = save_string(dp, "%-");
416 dp = save_string(dp, "%s");
418 #endif /* WATERLOO */
423 dp = save_string(dp, "%-%c");
428 dp = save_string(dp, "%c");
431 case '0': /* not clear any of the historical termcaps did this */
439 dp = save_string(dp, "%2d");
445 dp = save_string(dp, "%3d");
450 dp = save_string(dp, "%d");
460 dp = save_string(dp, "%\\");
464 dp = save_char(dp, '%');
466 _nc_warning("unknown %% code %s (%#x) in %s",
467 unctrl((chtype) *s), UChar(*s), cap);
473 dp = save_char(dp, *s++);
474 dp = save_char(dp, *s++);
477 dp = save_string(dp, "\\n");
481 dp = save_string(dp, "\\t");
485 dp = save_string(dp, "\\r");
489 dp = save_string(dp, "\\0");
493 dp = save_string(dp, "\\f");
497 dp = save_string(dp, "\\b");
501 dp = save_string(dp, "\\s");
505 dp = save_string(dp, "\\^");
509 dp = save_string(dp, "\\:");
513 dp = save_string(dp, "\\,");
518 dp = save_string(dp, "\\E");
520 } else if (*s > 0 && *s < 32) {
521 dp = save_char(dp, '^');
522 dp = save_char(dp, *s + '@');
524 } else if (*s <= 0 || *s >= 127) {
525 dp = save_char(dp, '\\');
526 dp = save_char(dp, ((*s & 0300) >> 6) + '0');
527 dp = save_char(dp, ((*s & 0070) >> 3) + '0');
528 dp = save_char(dp, (*s & 0007) + '0');
531 dp = save_char(dp, *s++);
535 dp = save_char(dp, *s++);
542 * Now, if we stripped off some leading padding, add it at the end
543 * of the string as mandatory padding.
546 dp = save_string(dp, "$<");
547 for (s = capstart;; s++)
548 if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
549 dp = save_char(dp, *s);
552 dp = save_string(dp, "/>");
555 (void) save_char(dp, '\0');
560 * Check for an expression that corresponds to "%B" (BCD):
561 * (parameter / 10) * 16 + (parameter % 10)
564 bcd_expression(const char *str)
566 /* leave this non-const for HPUX */
567 static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
571 if (sscanf(str, fmt, &ch1, &ch2) == 2
572 && isdigit(UChar(ch1))
573 && isdigit(UChar(ch2))
580 sprintf(buffer, fmt, ch1, ch2);
581 tst = strlen(buffer) - 1;
590 save_tc_char(char *bufptr, int c1)
594 if (is7bits(c1) && isprint(c1)) {
595 if (c1 == ':' || c1 == '\\')
596 bufptr = save_char(bufptr, '\\');
597 bufptr = save_char(bufptr, c1);
599 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
600 (void) strcpy(temp, unctrl((chtype) c1));
602 (void) sprintf(temp, "\\%03o", c1);
603 bufptr = save_string(bufptr, temp);
609 save_tc_inequality(char *bufptr, int c1, int c2)
611 bufptr = save_string(bufptr, "%>");
612 bufptr = save_tc_char(bufptr, c1);
613 bufptr = save_tc_char(bufptr, c2);
618 * Here are the capabilities infotocap assumes it can translate to:
621 * %d output value as in printf %d
622 * %2 output value as in printf %2d
623 * %3 output value as in printf %3d
624 * %. output value as in printf %c
625 * %+c add character c to value, then do %.
626 * %>xy if value > x then add y, no output
627 * %r reverse order of two parameters, no output
628 * %i increment by one, no output
629 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
630 * %B BCD (16*(value/10)) + (value%10), no output
631 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
632 * %m exclusive-or all parameters with 0177 (not in 4.4BSD)
636 * Convert a terminfo string to termcap format. Parameters are as in
640 _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parametrized)
642 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
644 const char *trimmed = 0;
645 char ch1 = 0, ch2 = 0;
646 char *bufptr = init_string();
648 bool syntax_error = FALSE;
650 /* we may have to move some trailing mandatory padding up front */
651 padding = str + strlen(str) - 1;
652 if (*padding == '>' && *--padding == '/') {
654 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
656 if (*padding == '<' && *--padding == '$')
660 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
661 bufptr = save_char(bufptr, *padding++);
664 for (; *str && str != trimmed; str++) {
668 if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) {
669 bufptr = save_char(bufptr, *++str);
670 } else if (str[0] == '$' && str[1] == '<') { /* discard padding */
672 while (isdigit(UChar(*str))
679 } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */
680 bufptr = save_string(bufptr, "%%");
681 } else if (*str != '%' || (parametrized < 1)) {
682 bufptr = save_char(bufptr, *str);
683 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
684 str = strchr(str, ';');
685 bufptr = save_tc_inequality(bufptr, c1, c2);
686 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
687 str = strchr(str, ';');
688 bufptr = save_tc_inequality(bufptr, c1, c2);
689 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
690 str = strchr(str, ';');
691 bufptr = save_tc_inequality(bufptr, c1, c2);
692 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
693 str = strchr(str, ';');
694 bufptr = save_tc_inequality(bufptr, c1, c2);
695 } else if ((len = bcd_expression(str)) != 0) {
697 bufptr = save_string(bufptr, "%B");
698 } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
699 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
700 && (cp = strchr(str, '+'))) {
702 bufptr = save_string(bufptr, "%+");
706 bufptr = save_tc_char(bufptr, c1);
708 /* FIXME: this "works" for 'delta' */
709 else if (strncmp(str, "%{2}%*%-", 8) == 0) {
711 bufptr = save_string(bufptr, "%D");
712 } else if (strncmp(str, "%{96}%^", 7) == 0) {
715 bufptr = save_string(bufptr, "%n");
717 } else if (strncmp(str, "%{127}%^", 8) == 0) {
720 bufptr = save_string(bufptr, "%m");
722 } else { /* cm-style format element */
726 bufptr = save_char(bufptr, '%');
739 bufptr = save_char(bufptr, '%');
740 while (isdigit(UChar(*str)))
741 bufptr = save_char(bufptr, *str++);
742 if (strchr("doxX.", *str)) {
743 if (*str != 'd') /* termcap doesn't have octal, hex */
749 bufptr = save_string(bufptr, "%d");
753 bufptr = save_string(bufptr, "%.");
757 * %s isn't in termcap, but it's convenient to pass it through
758 * so we can represent things like terminfo pfkey strings in
762 bufptr = save_string(bufptr, "%s");
769 else if (*str == '2') {
770 if (!seenone && !seentwo) {
771 bufptr = save_string(bufptr, "%r");
774 } else if (*str >= '3')
779 bufptr = save_string(bufptr, "%i");
783 bufptr = save_char(bufptr, *str);
786 } /* endswitch (*str) */
787 } /* endelse (*str == '%') */
792 } /* endwhile (*str) */
794 return (syntax_error ? NULL : my_string);
802 main(int argc, char *argv[])
806 while ((c = getopt(argc, argv, "c")) != EOF)
818 if (fgets(buf, sizeof(buf), stdin) == 0)
820 buf[strlen(buf) - 1] = '\0';
824 char *cp = _nc_infotocap("to termcap", buf, 1);
827 (void) fputs(cp, stdout);
829 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
830 (void) putchar('\n');
836 /* captoinfo.c ends here */