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.17 1998/02/11 12:13:54 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 = malloc(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 = realloc(my_string, my_length = (need + need));
132 d = my_string + have;
135 return d + strlen(d);
138 static inline char *save_char(char *s, char c)
142 return save_string(s, temp);
145 static void push(void)
146 /* push onstack on to the stack */
148 if (stackptr > MAX_PUSHED)
149 _nc_warning("string too complex to convert");
151 stack[stackptr++] = onstack;
154 static void pop(void)
155 /* pop the top of the stack into onstack */
159 _nc_warning("I'm confused");
163 onstack = stack[--stackptr];
167 static int cvtchar(register const char *sp)
168 /* convert a character to a terminfo push */
194 c = 8 * c + (*sp++ - '0');
212 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
213 *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
215 *dp++ = '%'; *dp++ = '{';
217 *dp++ = c / 100 + '0';
219 *dp++ = ((int)(c / 10)) % 10 + '0';
220 *dp++ = c % 10 + '0';
226 static void getparm(int parm, int n)
227 /* push n copies of param on the terminfo stack if not already there */
235 if (onstack == parm) {
237 _nc_warning("string may not be optimal");
238 *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
240 *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
250 while(n--) { /* %p0 */
251 *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
254 if (seenn && parm < 3) { /* %{96}%^ */
255 *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
256 *dp++ = '%'; *dp++ = '^';
259 if (seenm && parm < 3) { /* %{127}%^ */
260 *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
261 *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
266 /* convert a termcap string to terminfo format */
267 register const char *cap, /* relevant terminfo capability index */
268 register const char *s, /* string value of the capability */
269 int const parametrized) /* do % translations if 1, pad translations if >=0 */
271 static char line[MAX_ENTRY];
272 const char *capstart;
283 /* skip the initial padding (if we haven't been told not to) */
287 if (parametrized >= 0 && isdigit(*s))
288 for (capstart = s; ; s++)
289 if (!(isdigit(*s) || *s == '*' || *s == '.'))
296 if (parametrized < 1) {
301 case '%': *dp++ = '%'; break;
304 _nc_warning("saw %%r twice in %s", cap);
309 _nc_warning("saw %%m twice in %s", cap);
314 _nc_warning("saw %%n twice in %s", cap);
317 case 'i': *dp++ = '%'; *dp++ = 'i'; break;
322 *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
323 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
324 *dp++ = '%'; *dp++ = '+';
330 *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
331 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
332 *dp++ = '%'; *dp++ = '-';
336 /* %?%{x}%>%t%{y}%+%; */
337 *dp++ = '%'; *dp++ = '?';
339 *dp++ = '%'; *dp++ = '>';
340 *dp++ = '%'; *dp++ = 't';
342 *dp++ = '%'; *dp++ = '+';
343 *dp++ = '%'; *dp++ = ';';
346 if ((*s == '=' || *s == '+' || *s == '-'
347 || *s == '*' || *s == '/')
348 && (s[1] == 'p' || s[1] == 'c')
355 getparm(param + s[2] - '@', 1);
356 if (param != onstack) {
365 *dp++ = '%'; *dp++ = '+';
368 *dp++ = '%'; *dp++ = '-';
371 *dp++ = '%'; *dp++ = '*';
374 *dp++ = '%'; *dp++ = '/';
393 *dp++ = '%'; *dp++ = '+';
398 *dp++ = '%'; *dp++ = '+';
399 *dp++ = '%'; *dp++ = 'c';
406 *dp++ = '%'; *dp++ = '-';
409 *dp++ = '%'; *dp++ = 's';
411 #endif /* WATERLOO */
416 *dp++ = '%'; *dp++ = '-';
417 *dp++ = '%'; *dp++ = 'c';
422 *dp++ = '%'; *dp++ = 'c';
425 case '0': /* not clear any of the historical termcaps did this */
433 *dp++ = '%'; /* *dp++ = '0'; */
434 *dp++ = '2'; *dp++ = 'd';
439 *dp++ = '%'; /* *dp++ = '0'; */
440 *dp++ = '3'; *dp++ = 'd';
445 *dp++ = '%'; *dp++ = 'd';
461 _nc_warning("unknown %% code %s in %s",
462 _tracechar(*s), cap);
468 *dp++ = *s++; *dp++ = *s++; break;
470 *dp++ = '\\'; *dp++ = 'n'; s++; break;
472 *dp++ = '\\'; *dp++ = 't'; s++; break;
474 *dp++ = '\\'; *dp++ = 'r'; s++; break;
476 *dp++ = '\\'; *dp++ = '0'; s++; break;
478 *dp++ = '\\'; *dp++ = 'f'; s++; break;
480 *dp++ = '\\'; *dp++ = 'b'; s++; break;
482 *dp++ = '\\'; *dp++ = 's'; s++; break;
484 *dp++ = '\\'; *dp++ = '^'; s++; break;
486 *dp++ = '\\'; *dp++ = ':'; s++; break;
488 *dp++ = '\\'; *dp++ = ','; s++; break;
494 } else if (*s > 0 && *s < 32) {
498 } else if (*s <= 0 || *s >= 127) {
500 *dp++ = ((*s & 0300) >> 6) + '0';
501 *dp++ = ((*s & 0070) >> 3) + '0';
502 *dp++ = (*s & 0007) + '0';
516 * Now, if we stripped off some leading padding, add it at the end
517 * of the string as mandatory padding.
523 for (s = capstart; ; s++)
524 if (isdigit(*s) || *s == '*' || *s == '.')
537 * Here are the capabilities infotocap assumes it can translate to:
540 * %d output value as in printf %d
541 * %2 output value as in printf %2d
542 * %3 output value as in printf %3d
543 * %. output value as in printf %c
544 * %+c add character c to value, then do %.
545 * %>xy if value > x then add y, no output
546 * %r reverse order of two parameters, no output
547 * %i increment by one, no output
548 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
549 * %B BCD (16*(value/10)) + (value%10), no output
550 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
551 * %m exclusive-or all parameters with 0177 (not in 4.4BSD)
555 /* convert a terminfo string to termcap format */
556 register const char *cap GCC_UNUSED, /* relevant termcap capability index */
557 register const char *str, /* string value of the capability */
558 int const parametrized) /* do % translations if 1, pad translations if >=0 */
560 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
562 const char *trimmed = 0;
563 char ch1 = 0, ch2 = 0;
564 char *bufptr = init_string();
567 /* we may have to move some trailing mandatory padding up front */
568 padding = str + strlen(str) - 1;
569 if (*padding == '>' && *--padding == '/')
572 while (isdigit(*padding) || *padding == '.' || *padding == '*')
574 if (*padding == '<' && *--padding == '$')
578 while (isdigit(*padding) || *padding == '.' || *padding == '*')
579 bufptr = save_char(bufptr, *padding++);
582 for (; *str && str != trimmed; str++)
587 if (str[0] == '\\' && (str[1] == '^' || str[1] == ','))
589 bufptr = save_char(bufptr, *++str);
591 else if (str[0] == '$' && str[1] == '<') /* discard padding */
594 while (isdigit(*str) || *str == '.' || *str == '*' || *str == '/' || *str == '>')
598 else if (*str != '%' || (parametrized < 1))
599 bufptr = save_char(bufptr, *str);
600 else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1,&c2) == 2)
602 str = strchr(str, ';');
603 (void) sprintf(temp, "%%>");
604 (void) strcat(temp, unctrl(c1));
605 (void) strcat(temp, unctrl(c2));
606 bufptr = save_string(bufptr, temp);
608 else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1,&ch2) == 2)
610 str = strchr(str, ';');
611 (void) sprintf(temp, "%%>%s%c", unctrl(c1), ch2);
612 bufptr = save_string(bufptr, temp);
614 else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1,&c2) == 2)
616 str = strchr(str, ';');
617 (void) sprintf(temp, "%%>%c%c", ch1, c2);
618 bufptr = save_string(bufptr, temp);
620 else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2)
622 str = strchr(str, ';');
623 (void) sprintf(temp, "%%>%c%c", ch1, ch2);
624 bufptr = save_string(bufptr, temp);
626 else if (strncmp(str, "%{6}%*%+", 8) == 0)
629 (void) sprintf(temp, "%%B");
630 bufptr = save_string(bufptr, temp);
632 else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
633 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
634 && (cp = strchr(str, '+')))
637 bufptr = save_char(bufptr, '%');
638 bufptr = save_char(bufptr, '+');
642 if (is7bits(c1) && isprint(c1))
643 bufptr = save_char(bufptr, (char)c1);
646 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
647 (void) strcpy(temp, unctrl(c1));
649 (void) sprintf(temp, "\\%03o", c1);
650 bufptr = save_string(bufptr, temp);
653 else if (strncmp(str, "%{2}%*%-", 8) == 0)
656 (void) sprintf(temp, "%%D");
657 bufptr = save_string(bufptr, temp);
659 else if (strncmp(str, "%{96}%^", 7) == 0)
664 (void) sprintf(temp, "%%n");
665 bufptr = save_string(bufptr, temp);
668 else if (strncmp(str, "%{127}%^", 8) == 0)
673 (void) sprintf(temp, "%%m");
674 bufptr = save_string(bufptr, temp);
682 bufptr = save_char(bufptr, '%');
695 bufptr = save_char(bufptr, '%');
696 while (isdigit(*str))
697 bufptr = save_char(bufptr, *str++);
701 _nc_warning("numeric prefix is missing trailing d in %s",
707 bufptr = save_char(bufptr, '%');
708 bufptr = save_char(bufptr, 'd');
712 bufptr = save_char(bufptr, '%');
713 bufptr = save_char(bufptr, '.');
717 * %s isn't in termcap, but it's convenient to pass it through
718 * so we can represent things like terminfo pfkey strings in
722 bufptr = save_char(bufptr, '%');
723 bufptr = save_char(bufptr, 's');
730 else if (*str == '2')
732 if (!seenone && !seentwo)
734 bufptr = save_char(bufptr, '%');
735 bufptr = save_char(bufptr, 'r');
739 else if (*str >= '3')
744 bufptr = save_char(bufptr, '%');
745 bufptr = save_char(bufptr, 'i');
751 } /* endswitch (*str) */
752 } /* endelse (*str == '%') */
757 } /* endwhile (*str) */
766 int main(int argc, char *argv[])
770 while ((c = getopt(argc, argv, "c")) != EOF)
784 if (fgets(buf, sizeof(buf), stdin) == 0)
786 buf[strlen(buf) - 1] = '\0';
791 char *cp = _nc_infotocap("to termcap", buf, 1);
794 (void) fputs(cp, stdout);
797 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
798 (void) putchar('\n');
804 /* captoinfo.c ends here */