1 /****************************************************************************
2 * Copyright (c) 1998,1999,2000 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 *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.37 2000/04/01 20:07:34 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("Out of 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("Out of memory");
133 d = my_string + have;
136 return d + strlen(d);
140 save_char(char *s, char 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(*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}%^");
273 /* convert a termcap string to terminfo format */
274 register const char *cap, /* relevant terminfo capability index */
275 register const char *s, /* string value of the capability */
276 int const parametrized /* do % translations if 1, pad translations if >=0 */
279 const char *capstart;
290 /* skip the initial padding (if we haven't been told not to) */
294 if (parametrized >= 0 && isdigit(*s))
295 for (capstart = s;; s++)
296 if (!(isdigit(*s) || *s == '*' || *s == '.'))
303 if (parametrized < 1) {
304 dp = save_char(dp, '%');
309 dp = save_char(dp, '%');
313 _nc_warning("saw %%r twice in %s", cap);
318 _nc_warning("saw %%m twice in %s", cap);
323 _nc_warning("saw %%n twice in %s", cap);
327 dp = save_string(dp, "%i");
332 dp = save_string(dp, "%{10}%/%{16}%*");
334 dp = save_string(dp, "%{10}%m%+");
339 dp = save_string(dp, "%{2}%*%-");
343 /* %?%{x}%>%t%{y}%+%; */
344 dp = save_string(dp, "%?");
346 dp = save_string(dp, "%>%t");
348 dp = save_string(dp, "%+%;");
351 if ((*s == '=' || *s == '+' || *s == '-'
352 || *s == '*' || *s == '/')
353 && (s[1] == 'p' || s[1] == 'c')
360 getparm(param + s[2] - '@', 1);
361 if (param != onstack) {
370 dp = save_string(dp, "%+");
373 dp = save_string(dp, "%-");
376 dp = save_string(dp, "%*");
379 dp = save_string(dp, "%/");
398 dp = save_string(dp, "%+");
403 dp = save_string(dp, "%+%c");
410 dp = save_string(dp, "%-");
413 dp = save_string(dp, "%s");
415 #endif /* WATERLOO */
420 dp = save_string(dp, "%-%c");
425 dp = save_string(dp, "%c");
428 case '0': /* not clear any of the historical termcaps did this */
436 dp = save_string(dp, "%2d");
442 dp = save_string(dp, "%3d");
447 dp = save_string(dp, "%d");
457 dp = save_string(dp, "%\\");
461 dp = save_char(dp, '%');
463 _nc_warning("unknown %% code %s (%#x) in %s",
464 unctrl(*s), (*s) & 0xff, cap);
470 dp = save_char(dp, *s++);
471 dp = save_char(dp, *s++);
474 dp = save_string(dp, "\\n");
478 dp = save_string(dp, "\\t");
482 dp = save_string(dp, "\\r");
486 dp = save_string(dp, "\\0");
490 dp = save_string(dp, "\\f");
494 dp = save_string(dp, "\\b");
498 dp = save_string(dp, "\\s");
502 dp = save_string(dp, "\\^");
506 dp = save_string(dp, "\\:");
510 dp = save_string(dp, "\\,");
515 dp = save_string(dp, "\\E");
517 } else if (*s > 0 && *s < 32) {
518 dp = save_char(dp, '^');
519 dp = save_char(dp, *s + '@');
521 } else if (*s <= 0 || *s >= 127) {
522 dp = save_char(dp, '\\');
523 dp = save_char(dp, ((*s & 0300) >> 6) + '0');
524 dp = save_char(dp, ((*s & 0070) >> 3) + '0');
525 dp = save_char(dp, (*s & 0007) + '0');
528 dp = save_char(dp, *s++);
532 dp = save_char(dp, *s++);
539 * Now, if we stripped off some leading padding, add it at the end
540 * of the string as mandatory padding.
543 dp = save_string(dp, "$<");
544 for (s = capstart;; s++)
545 if (isdigit(*s) || *s == '*' || *s == '.')
546 dp = save_char(dp, *s);
549 dp = save_string(dp, "/>");
552 (void) save_char(dp, '\0');
557 * Check for an expression that corresponds to "%B" (BCD):
558 * (parameter / 10) * 16 + (parameter % 10)
561 bcd_expression(const char *str)
563 /* leave this non-const for HPUX */
564 static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
568 if (sscanf(str, fmt, &ch1, &ch2) == 2
577 sprintf(buffer, fmt, ch1, ch2);
578 tst = strlen(buffer) - 1;
587 save_tc_char(char *bufptr, int c1)
591 if (is7bits(c1) && isprint(c1)) {
592 if (c1 == ':' || c1 == '\\')
593 bufptr = save_char(bufptr, '\\');
594 bufptr = save_char(bufptr, c1);
596 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
597 (void) strcpy(temp, unctrl(c1));
599 (void) sprintf(temp, "\\%03o", c1);
600 bufptr = save_string(bufptr, temp);
606 save_tc_inequality(char *bufptr, int c1, int c2)
608 bufptr = save_string(bufptr, "%>");
609 bufptr = save_tc_char(bufptr, c1);
610 bufptr = save_tc_char(bufptr, c2);
615 * Here are the capabilities infotocap assumes it can translate to:
618 * %d output value as in printf %d
619 * %2 output value as in printf %2d
620 * %3 output value as in printf %3d
621 * %. output value as in printf %c
622 * %+c add character c to value, then do %.
623 * %>xy if value > x then add y, no output
624 * %r reverse order of two parameters, no output
625 * %i increment by one, no output
626 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
627 * %B BCD (16*(value/10)) + (value%10), no output
628 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
629 * %m exclusive-or all parameters with 0177 (not in 4.4BSD)
634 /* convert a terminfo string to termcap format */
635 register const char *cap GCC_UNUSED, /* relevant termcap capability index */
636 register const char *str, /* string value of the capability */
637 int const parametrized /* do % translations if 1, pad translations if >=0 */
640 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
642 const char *trimmed = 0;
643 char ch1 = 0, ch2 = 0;
644 char *bufptr = init_string();
646 bool syntax_error = FALSE;
648 /* we may have to move some trailing mandatory padding up front */
649 padding = str + strlen(str) - 1;
650 if (*padding == '>' && *--padding == '/') {
652 while (isdigit(*padding) || *padding == '.' || *padding == '*')
654 if (*padding == '<' && *--padding == '$')
658 while (isdigit(*padding) || *padding == '.' || *padding == '*')
659 bufptr = save_char(bufptr, *padding++);
662 for (; *str && str != trimmed; str++) {
666 if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) {
667 bufptr = save_char(bufptr, *++str);
668 } else if (str[0] == '$' && str[1] == '<') { /* discard padding */
670 while (isdigit(*str) || *str == '.' || *str == '*' || *str ==
674 } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */
675 bufptr = save_string(bufptr, "%%");
676 } else if (*str != '%' || (parametrized < 1)) {
677 bufptr = save_char(bufptr, *str);
678 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
679 str = strchr(str, ';');
680 bufptr = save_tc_inequality(bufptr, c1, c2);
681 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
682 str = strchr(str, ';');
683 bufptr = save_tc_inequality(bufptr, c1, c2);
684 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
685 str = strchr(str, ';');
686 bufptr = save_tc_inequality(bufptr, c1, c2);
687 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
688 str = strchr(str, ';');
689 bufptr = save_tc_inequality(bufptr, c1, c2);
690 } else if ((len = bcd_expression(str)) != 0) {
692 bufptr = save_string(bufptr, "%B");
693 } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
694 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
695 && (cp = strchr(str, '+'))) {
697 bufptr = save_string(bufptr, "%+");
701 bufptr = save_tc_char(bufptr, c1);
703 /* FIXME: this "works" for 'delta' */
704 else if (strncmp(str, "%{2}%*%-", 8) == 0) {
706 bufptr = save_string(bufptr, "%D");
707 } else if (strncmp(str, "%{96}%^", 7) == 0) {
710 bufptr = save_string(bufptr, "%n");
712 } else if (strncmp(str, "%{127}%^", 8) == 0) {
715 bufptr = save_string(bufptr, "%m");
717 } else { /* cm-style format element */
721 bufptr = save_char(bufptr, '%');
734 bufptr = save_char(bufptr, '%');
735 while (isdigit(*str))
736 bufptr = save_char(bufptr, *str++);
737 if (strchr("doxX.", *str)) {
738 if (*str != 'd') /* termcap doesn't have octal, hex */
744 bufptr = save_string(bufptr, "%d");
748 bufptr = save_string(bufptr, "%.");
752 * %s isn't in termcap, but it's convenient to pass it through
753 * so we can represent things like terminfo pfkey strings in
757 bufptr = save_string(bufptr, "%s");
764 else if (*str == '2') {
765 if (!seenone && !seentwo) {
766 bufptr = save_string(bufptr, "%r");
769 } else if (*str >= '3')
774 bufptr = save_string(bufptr, "%i");
778 bufptr = save_char(bufptr, *str);
781 } /* endswitch (*str) */
782 } /* endelse (*str == '%') */
787 } /* endwhile (*str) */
789 return (syntax_error ? NULL : my_string);
797 main(int argc, char *argv[])
801 while ((c = getopt(argc, argv, "c")) != EOF)
813 if (fgets(buf, sizeof(buf), stdin) == 0)
815 buf[strlen(buf) - 1] = '\0';
819 char *cp = _nc_infotocap("to termcap", buf, 1);
822 (void) fputs(cp, stdout);
824 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
825 (void) putchar('\n');
831 /* captoinfo.c ends here */