2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
25 * captoinfo.c --- conversion between termcap and terminfo formats
27 * The captoinfo() code was swiped from Ross Ridge's mytinfo package,
28 * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
30 * There is just one entry point:
32 * char *captoinfo(n, s, parametrized)
34 * Convert value s for termcap string capability named n into terminfo
37 * This code recognizes all the standard 4.4BSD %-escapes:
40 * %d output value as in printf %d
41 * %2 output value as in printf %2d
42 * %3 output value as in printf %3d
43 * %. output value as in printf %c
44 * %+x add x to value, then do %.
45 * %>xy if value > x then add y, no output
46 * %r reverse order of two parameters, no output
47 * %i increment by one, no output
48 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
49 * %B BCD (16*(value/10)) + (value%10), no output
50 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
52 * Also, %02 and %03 are accepted as synonyms for %2 and %3.
54 * Besides all the standard termcap escapes, this translator understands
55 * the following extended escapes:
57 * used by GNU Emacs termcap libraries
58 * %a[+*-/=][cp]x GNU arithmetic.
59 * %m xor the first two parameters by 0177
60 * %b backup to previous parameter
61 * %f skip this parameter
63 * used by the University of Waterloo (MFCF) termcap libraries
64 * %-x subtract parameter FROM char x and output it as a char
65 * %ax add the character x to parameter
67 * If #define WATERLOO is on, also enable these translations:
69 * %sx subtract parameter FROM the character x
71 * By default, this Waterloo translations are not compiled in, because
72 * the Waterloo %s conflicts with the way terminfo uses %s in strings for
73 * function programming.
75 * Note the two definitions of %a: the GNU definition is translated if the
76 * characters after the 'a' are valid for it, otherwise the UW definition
80 #include <curses.priv.h>
85 MODULE_ID("$Id: captoinfo.c,v 1.15 1996/12/21 14:24:06 tom Exp $")
87 #define MAX_PUSHED 16 /* max # args we can push onto the stack */
88 #define MAX_ENTRY 2048 /* maximum chars in a translated capability */
90 static int stack[MAX_PUSHED]; /* the stack */
91 static int stackptr; /* the next empty place on the stack */
92 static int onstack; /* the top of stack */
93 static int seenm; /* seen a %m */
94 static int seenn; /* seen a %n */
95 static int seenr; /* seen a %r */
96 static int param; /* current parameter */
97 static char *dp; /* pointer to end of the converted string */
99 static char *my_string;
100 static size_t my_length;
102 static char *init_string(void)
103 /* initialize 'my_string', 'my_length' */
106 my_string = malloc(my_length = 256);
108 _nc_err_abort("Out of memory");
114 static char *save_string(char *d, const char *const s)
116 size_t have = (d - my_string);
117 size_t need = have + strlen(s) + 2;
118 if (need > my_length) {
119 my_string = realloc(my_string, my_length = (need + need));
120 d = my_string + have;
123 return d + strlen(d);
126 static inline char *save_char(char *s, char c)
130 return save_string(s, temp);
133 static void push(void)
134 /* push onstack on to the stack */
136 if (stackptr > MAX_PUSHED)
137 _nc_warning("string too complex to convert");
139 stack[stackptr++] = onstack;
142 static void pop(void)
143 /* pop the top of the stack into onstack */
147 _nc_warning("I'm confused");
151 onstack = stack[--stackptr];
155 static int cvtchar(register char *sp)
156 /* convert a character to a terminfo push */
182 c = 8 * c + (*sp++ - '0');
200 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
201 *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
203 *dp++ = '%'; *dp++ = '{';
205 *dp++ = c / 100 + '0';
207 *dp++ = ((int)(c / 10)) % 10 + '0';
208 *dp++ = c % 10 + '0';
214 static void getparm(int parm, int n)
215 /* push n copies of param on the terminfo stack if not already there */
223 if (onstack == parm) {
225 _nc_warning("string may not be optimal");
226 *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
228 *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
238 while(n--) { /* %p0 */
239 *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
242 if (seenn && parm < 3) { /* %{96}%^ */
243 *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
244 *dp++ = '%'; *dp++ = '^';
247 if (seenm && parm < 3) { /* %{127}%^ */
248 *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
249 *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
254 /* convert a termcap string to terminfo format */
255 register char *const cap, /* relevant terminfo capability index */
256 register char *s, /* string value of the capability */
257 int const parametrized) /* do % translations if 1, pad translations if >=0 */
259 static char line[MAX_ENTRY];
271 /* skip the initial padding (if we haven't been told not to) */
272 capstart = (char *)NULL;
275 if (parametrized >= 0 && isdigit(*s))
276 for (capstart = s; ; s++)
277 if (!(isdigit(*s) || *s == '*' || *s == '.'))
284 if (parametrized < 1) {
289 case '%': *dp++ = '%'; break;
292 _nc_warning("saw %%r twice in %s", cap);
297 _nc_warning("saw %%m twice in %s", cap);
302 _nc_warning("saw %%n twice in %s", cap);
305 case 'i': *dp++ = '%'; *dp++ = 'i'; break;
310 *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
311 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
312 *dp++ = '%'; *dp++ = '+';
318 *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
319 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
320 *dp++ = '%'; *dp++ = '-';
324 /* %?%{x}%>%t%{y}%+%; */
325 *dp++ = '%'; *dp++ = '?';
327 *dp++ = '%'; *dp++ = '>';
328 *dp++ = '%'; *dp++ = 't';
330 *dp++ = '%'; *dp++ = '+';
331 *dp++ = '%'; *dp++ = ';';
334 if ((*s == '=' || *s == '+' || *s == '-'
335 || *s == '*' || *s == '/')
336 && (s[1] == 'p' || s[1] == 'c')
343 getparm(param + s[2] - '@', 1);
344 if (param != onstack) {
353 *dp++ = '%'; *dp++ = '+';
356 *dp++ = '%'; *dp++ = '-';
359 *dp++ = '%'; *dp++ = '*';
362 *dp++ = '%'; *dp++ = '/';
381 *dp++ = '%'; *dp++ = '+';
386 *dp++ = '%'; *dp++ = '+';
387 *dp++ = '%'; *dp++ = 'c';
394 *dp++ = '%'; *dp++ = '-';
397 *dp++ = '%'; *dp++ = 's';
399 #endif /* WATERLOO */
404 *dp++ = '%'; *dp++ = '-';
405 *dp++ = '%'; *dp++ = 'c';
410 *dp++ = '%'; *dp++ = 'c';
413 case '0': /* not clear any of the historical termcaps did this */
421 *dp++ = '%'; /* *dp++ = '0'; */
422 *dp++ = '2'; *dp++ = 'd';
427 *dp++ = '%'; /* *dp++ = '0'; */
428 *dp++ = '3'; *dp++ = 'd';
433 *dp++ = '%'; *dp++ = 'd';
449 _nc_warning("unknown %% code %s in %s",
450 _tracechar(*s), cap);
456 *dp++ = *s++; *dp++ = *s++; break;
458 *dp++ = '\\'; *dp++ = 'n'; s++; break;
460 *dp++ = '\\'; *dp++ = 't'; s++; break;
462 *dp++ = '\\'; *dp++ = 'r'; s++; break;
464 *dp++ = '\\'; *dp++ = '0'; s++; break;
466 *dp++ = '\\'; *dp++ = 'f'; s++; break;
468 *dp++ = '\\'; *dp++ = 'b'; s++; break;
470 *dp++ = '\\'; *dp++ = 's'; s++; break;
472 *dp++ = '\\'; *dp++ = '^'; s++; break;
474 *dp++ = '\\'; *dp++ = ':'; s++; break;
476 *dp++ = '\\'; *dp++ = ','; s++; break;
482 } else if (*s > 0 && *s < 32) {
486 } else if (*s <= 0 || *s >= 127) {
488 *dp++ = ((*s & 0300) >> 6) + '0';
489 *dp++ = ((*s & 0070) >> 3) + '0';
490 *dp++ = (*s & 0007) + '0';
504 * Now, if we stripped off some leading padding, add it at the end
505 * of the string as mandatory padding.
511 for (s = capstart; ; s++)
512 if (isdigit(*s) || *s == '*' || *s == '.')
525 * Here are the capabilities infotocap assumes it can translate to:
528 * %d output value as in printf %d
529 * %2 output value as in printf %2d
530 * %3 output value as in printf %3d
531 * %. output value as in printf %c
532 * %+c add character c to value, then do %.
533 * %>xy if value > x then add y, no output
534 * %r reverse order of two parameters, no output
535 * %i increment by one, no output
536 * %n exclusive-or all parameters with 0140 (Datamedia 2500)
537 * %B BCD (16*(value/10)) + (value%10), no output
538 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data).
539 * %m exclusive-or all parameters with 0177 (not in 4.4BSD)
543 /* convert a terminfo string to termcap format */
544 register char *const cap GCC_UNUSED, /* relevant termcap capability index */
545 register char *str, /* string value of the capability */
546 int const parametrized) /* do % translations if 1, pad translations if >=0 */
548 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
549 char *padding, ch1 = 0, ch2 = 0;
550 char *bufptr = init_string();
553 /* we may have to move some trailing mandatory padding up front */
554 padding = str + strlen(str) - 1;
555 if (*padding == '>' && *--padding == '/')
558 while (isdigit(*padding) || *padding == '.' || *padding == '*')
560 if (*padding == '<' && *--padding == '$')
564 while (isdigit(*padding) || *padding == '.' || *padding == '*')
565 bufptr = save_char(bufptr, *padding++);
573 if (str[0] == '\\' && (str[1] == '^' || str[1] == ','))
575 bufptr = save_char(bufptr, *++str);
577 else if (str[0] == '$' && str[1] == '<') /* discard padding */
580 while (isdigit(*str) || *str == '.' || *str == '*' || *str == '/' || *str == '>')
584 else if (*str != '%' || (parametrized < 1))
585 bufptr = save_char(bufptr, *str);
586 else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1,&c2) == 2)
588 str = strchr(str, ';');
589 (void) sprintf(temp, "%%>");
590 (void) strcat(temp, unctrl(c1));
591 (void) strcat(temp, unctrl(c2));
592 bufptr = save_string(bufptr, temp);
594 else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1,&ch2) == 2)
596 str = strchr(str, ';');
597 (void) sprintf(temp, "%%>%s%c", unctrl(c1), ch2);
598 bufptr = save_string(bufptr, temp);
600 else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1,&c2) == 2)
602 str = strchr(str, ';');
603 (void) sprintf(temp, "%%>%c%c", ch1, c2);
604 bufptr = save_string(bufptr, temp);
606 else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2)
608 str = strchr(str, ';');
609 (void) sprintf(temp, "%%>%c%c", ch1, ch2);
610 bufptr = save_string(bufptr, temp);
612 else if (strncmp(str, "%{6}%*%+", 8) == 0)
615 (void) sprintf(temp, "%%B");
616 bufptr = save_string(bufptr, temp);
618 else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
619 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
620 && (cp = strchr(str, '+')))
623 bufptr = save_char(bufptr, '%');
624 bufptr = save_char(bufptr, '+');
628 if (is7bits(c1) && isprint(c1))
629 bufptr = save_char(bufptr, (char)c1);
632 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
633 (void) strcpy(temp, unctrl(c1));
635 (void) sprintf(temp, "\\%03o", c1);
636 bufptr = save_string(bufptr, temp);
639 else if (strncmp(str, "%{2}%*%-", 8) == 0)
642 (void) sprintf(temp, "%%D");
643 bufptr = save_string(bufptr, temp);
645 else if (strncmp(str, "%{96}%^", 7) == 0)
650 (void) sprintf(temp, "%%n");
651 bufptr = save_string(bufptr, temp);
654 else if (strncmp(str, "%{127}%^", 8) == 0)
659 (void) sprintf(temp, "%%m");
660 bufptr = save_string(bufptr, temp);
668 bufptr = save_char(bufptr, '%');
681 bufptr = save_char(bufptr, '%');
682 while (isdigit(*str))
683 bufptr = save_char(bufptr, *str++);
687 _nc_warning("numeric prefix is missing trailing d in %s",
693 bufptr = save_char(bufptr, '%');
694 bufptr = save_char(bufptr, 'd');
698 bufptr = save_char(bufptr, '%');
699 bufptr = save_char(bufptr, '.');
703 * %s isn't in termcap, but it's convenient to pass it through
704 * so we can represent things like terminfo pfkey strings in
708 bufptr = save_char(bufptr, '%');
709 bufptr = save_char(bufptr, 's');
716 else if (*str == '2')
718 if (!seenone && !seentwo)
720 bufptr = save_char(bufptr, '%');
721 bufptr = save_char(bufptr, 'r');
725 else if (*str >= '3')
726 return((char *)NULL);
730 bufptr = save_char(bufptr, '%');
731 bufptr = save_char(bufptr, 'i');
735 return((char *)NULL);
737 } /* endswitch (*str) */
738 } /* endelse (*str == '%') */
743 } /* endwhile (*str) */
752 int main(int argc, char *argv[])
756 while ((c = getopt(argc, argv, "c")) != EOF)
770 if (fgets(buf, sizeof(buf), stdin) == (char *)NULL)
772 buf[strlen(buf) - 1] = '\0';
777 char *cp = _nc_infotocap("to termcap", buf, 1);
780 (void) fputs(cp, stdout);
783 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
784 (void) putchar('\n');
790 /* captoinfo.c ends here */