1 /****************************************************************************
2 * Copyright (c) 1998 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 ****************************************************************************/
37 * captoinfo.c --- conversion between termcap and terminfo formats
39 * The captoinfo() code was swiped from Ross Ridge's mytinfo package,
40 * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
42 * There is just one entry point:
44 * char *captoinfo(n, s, parametrized)
46 * Convert value s for termcap string capability named n into terminfo
49 * This code recognizes all the standard 4.4BSD %-escapes:
52 * %d output value as in printf %d
53 * %2 output value as in printf %2d
54 * %3 output value as in printf %3d
55 * %. output value as in printf %c
56 * %+x add x to value, then do %.
57 * %>xy if value > x then add y, no output
58 * %r reverse order of two parameters, no output
59 * %i increment by one, no output
60 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
61 * %B BCD (16*(value/10)) + (value%10), no output
62 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
64 * Also, %02 and %03 are accepted as synonyms for %2 and %3.
66 * Besides all the standard termcap escapes, this translator understands
67 * the following extended escapes:
69 * used by GNU Emacs termcap libraries
70 * %a[+*-/=][cp]x GNU arithmetic.
71 * %m xor the first two parameters by 0177
72 * %b backup to previous parameter
73 * %f skip this parameter
75 * used by the University of Waterloo (MFCF) termcap libraries
76 * %-x subtract parameter FROM char x and output it as a char
77 * %ax add the character x to parameter
79 * If #define WATERLOO is on, also enable these translations:
81 * %sx subtract parameter FROM the character x
83 * By default, this Waterloo translations are not compiled in, because
84 * the Waterloo %s conflicts with the way terminfo uses %s in strings for
85 * function programming.
87 * Note the two definitions of %a: the GNU definition is translated if the
88 * characters after the 'a' are valid for it, otherwise the UW definition
92 #include <curses.priv.h>
97 MODULE_ID("$Id: captoinfo.c,v 1.24 1999/07/24 20:06:13 tom Exp $")
99 #define MAX_PUSHED 16 /* max # args we can push onto the stack */
100 #define MAX_ENTRY 2048 /* maximum chars in a translated capability */
102 static int stack[MAX_PUSHED]; /* the stack */
103 static int stackptr; /* the next empty place on the stack */
104 static int onstack; /* the top of stack */
105 static int seenm; /* seen a %m */
106 static int seenn; /* seen a %n */
107 static int seenr; /* seen a %r */
108 static int param; /* current parameter */
109 static char *dp; /* pointer to end of the converted string */
111 static char *my_string;
112 static size_t my_length;
114 static char *init_string(void)
115 /* initialize 'my_string', 'my_length' */
118 my_string = typeMalloc(char, my_length = 256);
120 _nc_err_abort("Out of memory");
126 static char *save_string(char *d, const char *const s)
128 size_t have = (d - my_string);
129 size_t need = have + strlen(s) + 2;
130 if (need > my_length) {
131 my_string = (char *)realloc(my_string, my_length = (need + need));
133 _nc_err_abort("Out of memory");
134 d = my_string + have;
137 return d + strlen(d);
140 static inline char *save_char(char *s, char c)
144 return save_string(s, temp);
147 static void push(void)
148 /* push onstack on to the stack */
150 if (stackptr > MAX_PUSHED)
151 _nc_warning("string too complex to convert");
153 stack[stackptr++] = onstack;
156 static void pop(void)
157 /* pop the top of the stack into onstack */
161 _nc_warning("I'm confused");
166 onstack = stack[--stackptr];
170 static int cvtchar(register const char *sp)
171 /* convert a character to a terminfo push */
197 c = 8 * c + (*sp++ - '0');
215 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
216 *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
218 *dp++ = '%'; *dp++ = '{';
220 *dp++ = c / 100 + '0';
222 *dp++ = ((int)(c / 10)) % 10 + '0';
223 *dp++ = c % 10 + '0';
229 static void getparm(int parm, int n)
230 /* push n copies of param on the terminfo stack if not already there */
238 if (onstack == parm) {
240 _nc_warning("string may not be optimal");
241 *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
243 *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
253 while(n--) { /* %p0 */
254 *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
257 if (seenn && parm < 3) { /* %{96}%^ */
258 *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
259 *dp++ = '%'; *dp++ = '^';
262 if (seenm && parm < 3) { /* %{127}%^ */
263 *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
264 *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
269 /* convert a termcap string to terminfo format */
270 register const char *cap, /* relevant terminfo capability index */
271 register const char *s, /* string value of the capability */
272 int const parametrized) /* do % translations if 1, pad translations if >=0 */
274 static char line[MAX_ENTRY];
275 const char *capstart;
286 /* skip the initial padding (if we haven't been told not to) */
290 if (parametrized >= 0 && isdigit(*s))
291 for (capstart = s; ; s++)
292 if (!(isdigit(*s) || *s == '*' || *s == '.'))
299 if (parametrized < 1) {
304 case '%': *dp++ = '%'; break;
307 _nc_warning("saw %%r twice in %s", cap);
312 _nc_warning("saw %%m twice in %s", cap);
317 _nc_warning("saw %%n twice in %s", cap);
320 case 'i': *dp++ = '%'; *dp++ = 'i'; break;
325 *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
326 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
327 *dp++ = '%'; *dp++ = '+';
333 *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
334 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
335 *dp++ = '%'; *dp++ = '-';
339 /* %?%{x}%>%t%{y}%+%; */
340 *dp++ = '%'; *dp++ = '?';
342 *dp++ = '%'; *dp++ = '>';
343 *dp++ = '%'; *dp++ = 't';
345 *dp++ = '%'; *dp++ = '+';
346 *dp++ = '%'; *dp++ = ';';
349 if ((*s == '=' || *s == '+' || *s == '-'
350 || *s == '*' || *s == '/')
351 && (s[1] == 'p' || s[1] == 'c')
358 getparm(param + s[2] - '@', 1);
359 if (param != onstack) {
368 *dp++ = '%'; *dp++ = '+';
371 *dp++ = '%'; *dp++ = '-';
374 *dp++ = '%'; *dp++ = '*';
377 *dp++ = '%'; *dp++ = '/';
397 *dp++ = '%'; *dp++ = '+';
402 *dp++ = '%'; *dp++ = '+';
403 *dp++ = '%'; *dp++ = 'c';
410 *dp++ = '%'; *dp++ = '-';
413 *dp++ = '%'; *dp++ = 's';
415 #endif /* WATERLOO */
420 *dp++ = '%'; *dp++ = '-';
421 *dp++ = '%'; *dp++ = 'c';
426 *dp++ = '%'; *dp++ = 'c';
429 case '0': /* not clear any of the historical termcaps did this */
437 *dp++ = '%'; /* *dp++ = '0'; */
438 *dp++ = '2'; *dp++ = 'd';
443 *dp++ = '%'; /* *dp++ = '0'; */
444 *dp++ = '3'; *dp++ = 'd';
449 *dp++ = '%'; *dp++ = 'd';
465 _nc_warning("unknown %% code %s in %s",
466 _tracechar(*s), cap);
472 *dp++ = *s++; *dp++ = *s++; break;
474 *dp++ = '\\'; *dp++ = 'n'; s++; break;
476 *dp++ = '\\'; *dp++ = 't'; s++; break;
478 *dp++ = '\\'; *dp++ = 'r'; s++; break;
480 *dp++ = '\\'; *dp++ = '0'; s++; break;
482 *dp++ = '\\'; *dp++ = 'f'; s++; break;
484 *dp++ = '\\'; *dp++ = 'b'; s++; break;
486 *dp++ = '\\'; *dp++ = 's'; s++; break;
488 *dp++ = '\\'; *dp++ = '^'; s++; break;
490 *dp++ = '\\'; *dp++ = ':'; s++; break;
492 *dp++ = '\\'; *dp++ = ','; s++; break;
498 } else if (*s > 0 && *s < 32) {
502 } else if (*s <= 0 || *s >= 127) {
504 *dp++ = ((*s & 0300) >> 6) + '0';
505 *dp++ = ((*s & 0070) >> 3) + '0';
506 *dp++ = (*s & 0007) + '0';
520 * Now, if we stripped off some leading padding, add it at the end
521 * of the string as mandatory padding.
527 for (s = capstart; ; s++)
528 if (isdigit(*s) || *s == '*' || *s == '.')
541 * Here are the capabilities infotocap assumes it can translate to:
544 * %d output value as in printf %d
545 * %2 output value as in printf %2d
546 * %3 output value as in printf %3d
547 * %. output value as in printf %c
548 * %+c add character c to value, then do %.
549 * %>xy if value > x then add y, no output
550 * %r reverse order of two parameters, no output
551 * %i increment by one, no output
552 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
553 * %B BCD (16*(value/10)) + (value%10), no output
554 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
555 * %m exclusive-or all parameters with 0177 (not in 4.4BSD)
559 /* convert a terminfo string to termcap format */
560 register const char *cap GCC_UNUSED, /* relevant termcap capability index */
561 register const char *str, /* string value of the capability */
562 int const parametrized) /* do % translations if 1, pad translations if >=0 */
564 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
566 const char *trimmed = 0;
567 char ch1 = 0, ch2 = 0;
568 char *bufptr = init_string();
571 /* we may have to move some trailing mandatory padding up front */
572 padding = str + strlen(str) - 1;
573 if (*padding == '>' && *--padding == '/')
576 while (isdigit(*padding) || *padding == '.' || *padding == '*')
578 if (*padding == '<' && *--padding == '$')
582 while (isdigit(*padding) || *padding == '.' || *padding == '*')
583 bufptr = save_char(bufptr, *padding++);
586 for (; *str && str != trimmed; str++)
591 if (str[0] == '\\' && (str[1] == '^' || str[1] == ','))
593 bufptr = save_char(bufptr, *++str);
595 else if (str[0] == '$' && str[1] == '<') /* discard padding */
598 while (isdigit(*str) || *str == '.' || *str == '*' || *str == '/' || *str == '>')
602 else if (*str != '%' || (parametrized < 1))
603 bufptr = save_char(bufptr, *str);
604 else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1,&c2) == 2)
606 str = strchr(str, ';');
607 (void) sprintf(temp, "%%>%s%s", unctrl(c1), unctrl(c2));
608 bufptr = save_string(bufptr, temp);
610 else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1,&ch2) == 2)
612 str = strchr(str, ';');
613 (void) sprintf(temp, "%%>%s%c", unctrl(c1), ch2);
614 bufptr = save_string(bufptr, temp);
616 else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1,&c2) == 2)
618 str = strchr(str, ';');
619 (void) sprintf(temp, "%%>%c%c", ch1, c2);
620 bufptr = save_string(bufptr, temp);
622 else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2)
624 str = strchr(str, ';');
625 (void) sprintf(temp, "%%>%c%c", ch1, ch2);
626 bufptr = save_string(bufptr, temp);
628 else if (strncmp(str, "%{6}%*%+", 8) == 0)
631 (void) sprintf(temp, "%%B");
632 bufptr = save_string(bufptr, temp);
634 else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
635 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
636 && (cp = strchr(str, '+')))
639 bufptr = save_char(bufptr, '%');
640 bufptr = save_char(bufptr, '+');
644 if (is7bits(c1) && isprint(c1))
645 bufptr = save_char(bufptr, (char)c1);
648 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
649 (void) strcpy(temp, unctrl(c1));
651 (void) sprintf(temp, "\\%03o", c1);
652 bufptr = save_string(bufptr, temp);
655 else if (strncmp(str, "%{2}%*%-", 8) == 0)
658 (void) sprintf(temp, "%%D");
659 bufptr = save_string(bufptr, temp);
661 else if (strncmp(str, "%{96}%^", 7) == 0)
666 (void) sprintf(temp, "%%n");
667 bufptr = save_string(bufptr, temp);
670 else if (strncmp(str, "%{127}%^", 8) == 0)
675 (void) sprintf(temp, "%%m");
676 bufptr = save_string(bufptr, temp);
684 bufptr = save_char(bufptr, '%');
697 bufptr = save_char(bufptr, '%');
698 while (isdigit(*str))
699 bufptr = save_char(bufptr, *str++);
703 _nc_warning("numeric prefix is missing trailing d in %s",
709 bufptr = save_char(bufptr, '%');
710 bufptr = save_char(bufptr, 'd');
714 bufptr = save_char(bufptr, '%');
715 bufptr = save_char(bufptr, '.');
719 * %s isn't in termcap, but it's convenient to pass it through
720 * so we can represent things like terminfo pfkey strings in
724 bufptr = save_char(bufptr, '%');
725 bufptr = save_char(bufptr, 's');
732 else if (*str == '2')
734 if (!seenone && !seentwo)
736 bufptr = save_char(bufptr, '%');
737 bufptr = save_char(bufptr, 'r');
741 else if (*str >= '3')
746 bufptr = save_char(bufptr, '%');
747 bufptr = save_char(bufptr, 'i');
753 } /* endswitch (*str) */
754 } /* endelse (*str == '%') */
759 } /* endwhile (*str) */
768 int main(int argc, char *argv[])
772 while ((c = getopt(argc, argv, "c")) != EOF)
786 if (fgets(buf, sizeof(buf), stdin) == 0)
788 buf[strlen(buf) - 1] = '\0';
793 char *cp = _nc_infotocap("to termcap", buf, 1);
796 (void) fputs(cp, stdout);
799 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
800 (void) putchar('\n');
806 /* captoinfo.c ends here */