158314Sache/**************************************************************************** 2136759Speter * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. * 321308Sache * * 421308Sache * Permission is hereby granted, free of charge, to any person obtaining a * 5136759Speter * copy of this software and associated documentation files (the * 621308Sache * "Software"), to deal in the Software without restriction, including * 721308Sache * without limitation the rights to use, copy, modify, merge, publish, * 821308Sache * distribute, distribute with modifications, sublicense, and/or sell * 921308Sache * copies of the Software, and to permit persons to whom the Software is * 1021308Sache * furnished to do so, subject to the following conditions: * 1121308Sache * * 1258314Sache * The above copyright notice and this permission notice shall be included * 1321308Sache * in all copies or substantial portions of the Software. * 1421308Sache * * 1521308Sache * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1621308Sache * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1721308Sache * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1821308Sache * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1921308Sache * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2021308Sache * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2121308Sache * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2221308Sache * * 2358314Sache * Except as contained in this notice, the name(s) of the above copyright * 2421308Sache * holders shall not be used in advertising or otherwise to promote the * 2521308Sache * sale, use or other dealings in this Software without prior written * 2621308Sache * authorization. * 2721308Sache ****************************************************************************/ 2821308Sache 2921308Sache/**************************************************************************** 3021308Sache * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3121308Sache * and: Eric S. Raymond <esr@snark.thyrsus.com> * 3221308Sache * and: Thomas E. Dickey 1996-on * 3321308Sache ****************************************************************************/ 3421308Sache 3521308Sache/* 3626497Sache * captoinfo.c --- conversion between termcap and terminfo formats 3726497Sache * 3821308Sache * The captoinfo() code was swiped from Ross Ridge's mytinfo package, 3921308Sache * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>. 4021308Sache * 4121308Sache * There is just one entry point: 4221308Sache * 4321308Sache * char *_nc_captoinfo(n, s, parameterized) 4426497Sache * 4521308Sache * Convert value s for termcap string capability named n into terminfo 4621308Sache * format. 4721308Sache * 48119614Sache * This code recognizes all the standard 4.4BSD %-escapes: 4921308Sache * 5021308Sache * %% output `%' 5121308Sache * %d output value as in printf %d 5221308Sache * %2 output value as in printf %2d 5321308Sache * %3 output value as in printf %3d 5421308Sache * %. output value as in printf %c 5521308Sache * %+x add x to value, then do %. 5621308Sache * %>xy if value > x then add y, no output 5758314Sache * %r reverse order of two parameters, no output 5858314Sache * %i increment by one, no output 5958314Sache * %n exclusive-or all parameters with 0140 (Datamedia 2500) 6021308Sache * %B BCD (16*(value/10)) + (value%10), no output 6121308Sache * %D Reverse coding (value - 2*(value%16)), no output (Delta Data). 6221308Sache * 6321308Sache * Also, %02 and %03 are accepted as synonyms for %2 and %3. 6458314Sache * 6575409Sache * Besides all the standard termcap escapes, this translator understands 6635486Sache * the following extended escapes: 6721308Sache * 68119614Sache * used by GNU Emacs termcap libraries 69119614Sache * %a[+*-/=][cp]x GNU arithmetic. 70119614Sache * %m xor the first two parameters by 0177 71119614Sache * %b backup to previous parameter 72119614Sache * %f skip this parameter 7321308Sache * 74119614Sache * used by the University of Waterloo (MFCF) termcap libraries 75136759Speter * %-x subtract parameter FROM char x and output it as a char 76119614Sache * %ax add the character x to parameter 77119614Sache * 78119614Sache * If #define WATERLOO is on, also enable these translations: 79119614Sache * 80119614Sache * %sx subtract parameter FROM the character x 8121308Sache * 8258314Sache * By default, this Waterloo translations are not compiled in, because 8321308Sache * the Waterloo %s conflicts with the way terminfo uses %s in strings for 8421308Sache * function programming. 8521308Sache * 8621308Sache * Note the two definitions of %a: the GNU definition is translated if the 8721308Sache * characters after the 'a' are valid for it, otherwise the UW definition 8821308Sache * is translated. 8921308Sache */ 9021308Sache 9121308Sache#include <curses.priv.h> 9221308Sache 9321308Sache#include <ctype.h> 9421308Sache#include <tic.h> 9521308Sache 9621308SacheMODULE_ID("$Id: captoinfo.c,v 1.52 2008/08/16 19:24:51 tom Exp $") 9721308Sache 9821308Sache#define MAX_PUSHED 16 /* max # args we can push onto the stack */ 9921308Sache 10021308Sachestatic int stack[MAX_PUSHED]; /* the stack */ 10121308Sachestatic int stackptr; /* the next empty place on the stack */ 10221308Sachestatic int onstack; /* the top of stack */ 10321308Sachestatic int seenm; /* seen a %m */ 10421308Sachestatic int seenn; /* seen a %n */ 10521308Sachestatic int seenr; /* seen a %r */ 10621308Sachestatic int param; /* current parameter */ 10721308Sachestatic char *dp; /* pointer to end of the converted string */ 10821308Sache 10921308Sachestatic char *my_string; 11021308Sachestatic size_t my_length; 11121308Sache 11221308Sachestatic char * 11321308Sacheinit_string(void) 11421308Sache/* initialize 'my_string', 'my_length' */ 11521308Sache{ 11675409Sache if (my_string == 0) 11721308Sache my_string = typeMalloc(char, my_length = 256); 11821308Sache if (my_string == 0) 11921308Sache _nc_err_abort(MSG_NO_MEMORY); 12021308Sache 12121308Sache *my_string = '\0'; 12221308Sache return my_string; 12321308Sache} 12421308Sache 12521308Sachestatic char * 12621308Sachesave_string(char *d, const char *const s) 12721308Sache{ 12821308Sache size_t have = (d - my_string); 12921308Sache size_t need = have + strlen(s) + 2; 13021308Sache if (need > my_length) { 13121308Sache my_string = (char *) realloc(my_string, my_length = (need + need)); 13221308Sache if (my_string == 0) 13321308Sache _nc_err_abort(MSG_NO_MEMORY); 13421308Sache d = my_string + have; 13521308Sache } 13621308Sache (void) strcpy(d, s); 13721308Sache return d + strlen(d); 13821308Sache} 13921308Sache 14021308Sachestatic NCURSES_INLINE char * 14121308Sachesave_char(char *s, int c) 14221308Sache{ 14321308Sache static char temp[2]; 14421308Sache temp[0] = (char) c; 14521308Sache return save_string(s, temp); 14621308Sache} 14721308Sache 14821308Sachestatic void 14921308Sachepush(void) 15021308Sache/* push onstack on to the stack */ 15121308Sache{ 15221308Sache if (stackptr >= MAX_PUSHED) 15321308Sache _nc_warning("string too complex to convert"); 15421308Sache else 15575409Sache stack[stackptr++] = onstack; 15675409Sache} 15775409Sache 15821308Sachestatic void 15975409Sachepop(void) 16021308Sache/* pop the top of the stack into onstack */ 16121308Sache{ 16221308Sache if (stackptr == 0) { 16321308Sache if (onstack == 0) 16421308Sache _nc_warning("I'm confused"); 16575409Sache else 16675409Sache onstack = 0; 16721308Sache } else 16821308Sache onstack = stack[--stackptr]; 16975409Sache param++; 17075409Sache} 17121308Sache 17221308Sachestatic int 17321308Sachecvtchar(register const char *sp) 17421308Sache/* convert a character to a terminfo push */ 17521308Sache{ 17675409Sache unsigned char c = 0; 17775409Sache int len; 17875409Sache 17975409Sache switch (*sp) { 18075409Sache case '\\': 18175409Sache switch (*++sp) { 18275409Sache case '\'': 183136759Speter case '$': 184136759Speter case '\\': 18521308Sache case '%': 18621308Sache c = (unsigned char) (*sp); 18721308Sache len = 2; 18875409Sache break; 18975409Sache case '\0': 190136759Speter c = '\\'; 191136759Speter len = 1; 19221308Sache break; 19321308Sache case '0': 19421308Sache case '1': 19521308Sache case '2': 19621308Sache case '3': 19721308Sache len = 1; 19821308Sache while (isdigit(UChar(*sp))) { 19921308Sache c = 8 * c + (*sp++ - '0'); 20021308Sache len++; 201136759Speter } 20221308Sache break; 203136759Speter default: 20421308Sache c = (unsigned char) (*sp); 20521308Sache len = 2; 206136759Speter break; 20721308Sache } 20821308Sache break; 209136759Speter case '^': 21021308Sache c = (*++sp & 0x1f); 21121308Sache len = 2; 21221308Sache break; 21321308Sache default: 214136759Speter c = (unsigned char) (*sp); 215136759Speter len = 1; 216136759Speter } 217136759Speter if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') { 218136759Speter dp = save_string(dp, "%\'"); 219136759Speter dp = save_char(dp, c); 22021308Sache dp = save_char(dp, '\''); 22121308Sache } else { 22221308Sache dp = save_string(dp, "%{"); 22321308Sache if (c > 99) 224119614Sache dp = save_char(dp, c / 100 + '0'); 22575409Sache if (c > 9) 22675409Sache dp = save_char(dp, ((int) (c / 10)) % 10 + '0'); 227136759Speter dp = save_char(dp, c % 10 + '0'); 22875409Sache dp = save_char(dp, '}'); 229136759Speter } 23021308Sache return len; 23121308Sache} 23221308Sache 23321308Sachestatic void 23421308Sachegetparm(int parm, int n) 23521308Sache/* push n copies of param on the terminfo stack if not already there */ 23621308Sache{ 23721308Sache if (seenr) { 23821308Sache if (parm == 1) 23921308Sache parm = 2; 24021308Sache else if (parm == 2) 24121308Sache parm = 1; 24221308Sache } 24321308Sache if (onstack == parm) { 24421308Sache if (n > 1) { 24521308Sache _nc_warning("string may not be optimal"); 246136759Speter dp = save_string(dp, "%Pa"); 247136759Speter while (n--) { 248136759Speter dp = save_string(dp, "%ga"); 249136759Speter } 250136759Speter } 251136759Speter return; 252136759Speter } 253136759Speter if (onstack != 0) 254136759Speter push(); 255136759Speter 256136759Speter onstack = parm; 257136759Speter 258136759Speter while (n--) { 259136759Speter dp = save_string(dp, "%p"); 260136759Speter dp = save_char(dp, '0' + parm); 261136759Speter } 262136759Speter 26375409Sache if (seenn && parm < 3) { 264136759Speter dp = save_string(dp, "%{96}%^"); 265136759Speter } 266136759Speter 267136759Speter if (seenm && parm < 3) { 268136759Speter dp = save_string(dp, "%{127}%^"); 269136759Speter } 270136759Speter} 271136759Speter 272136759Speter/* 273136759Speter * Convert a termcap string to terminfo format. 274136759Speter * 'cap' is the relevant terminfo capability index. 275136759Speter * 's' is the string value of the capability. 276136759Speter * 'parameterized' tells what type of translations to do: 277136759Speter * % translations if 1 278136759Speter * pad translations if >=0 279136759Speter */ 280136759SpeterNCURSES_EXPORT(char *) 28121308Sache_nc_captoinfo(const char *cap, const char *s, int const parameterized) 28221308Sache{ 28321308Sache const char *capstart; 28475409Sache 28575409Sache stackptr = 0; 28675409Sache onstack = 0; 28721308Sache seenm = 0; 28821308Sache seenn = 0; 28921308Sache seenr = 0; 29021308Sache param = 1; 29121308Sache 29275409Sache dp = init_string(); 29375409Sache 294136759Speter /* skip the initial padding (if we haven't been told not to) */ 295136759Speter capstart = 0; 29621308Sache if (s == 0) 29721308Sache s = ""; 29821308Sache if (parameterized >= 0 && isdigit(UChar(*s))) 29958314Sache for (capstart = s;; s++) 30058314Sache if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.')) 30158314Sache break; 30258314Sache 30358314Sache while (*s != '\0') { 30458314Sache switch (*s) { 30558314Sache case '%': 30658314Sache s++; 307136759Speter if (parameterized < 1) { 30858314Sache dp = save_char(dp, '%'); 30958314Sache break; 31058314Sache } 31121308Sache switch (*s++) { 31221308Sache case '%': 31321308Sache dp = save_char(dp, '%'); 31421308Sache break; 31521308Sache case 'r': 31621308Sache if (seenr++ == 1) { 31721308Sache _nc_warning("saw %%r twice in %s", cap); 31821308Sache } 31975409Sache break; 32075409Sache case 'm': 32121308Sache if (seenm++ == 1) { 32221308Sache _nc_warning("saw %%m twice in %s", cap); 32321308Sache } 32421308Sache break; 32521308Sache case 'n': 32621308Sache if (seenn++ == 1) { 32721308Sache _nc_warning("saw %%n twice in %s", cap); 32821308Sache } 32921308Sache break; 33021308Sache case 'i': 33121308Sache dp = save_string(dp, "%i"); 33221308Sache break; 33321308Sache case '6': 33421308Sache case 'B': 33521308Sache getparm(param, 1); 33675409Sache dp = save_string(dp, "%{10}%/%{16}%*"); 33775409Sache getparm(param, 1); 33875409Sache dp = save_string(dp, "%{10}%m%+"); 33921308Sache break; 34075409Sache case '8': 34121308Sache case 'D': 34221308Sache getparm(param, 2); 34321308Sache dp = save_string(dp, "%{2}%*%-"); 34421308Sache break; 34521308Sache case '>': 34621308Sache getparm(param, 2); 34721308Sache /* %?%{x}%>%t%{y}%+%; */ 34875409Sache dp = save_string(dp, "%?"); 34975409Sache s += cvtchar(s); 35075409Sache dp = save_string(dp, "%>%t"); 351136759Speter s += cvtchar(s); 352136759Speter dp = save_string(dp, "%+%;"); 35321308Sache break; 35475409Sache case 'a': 35521308Sache if ((*s == '=' || *s == '+' || *s == '-' 35621308Sache || *s == '*' || *s == '/') 35721308Sache && (s[1] == 'p' || s[1] == 'c') 35821308Sache && s[2] != '\0') { 35921308Sache int l; 36075409Sache l = 2; 36175409Sache if (*s != '=') 362136759Speter getparm(param, 1); 363136759Speter if (s[1] == 'p') { 36421308Sache getparm(param + s[2] - '@', 1); 36521308Sache if (param != onstack) { 36621308Sache pop(); 36775409Sache param--; 36875409Sache } 369136759Speter l++; 370136759Speter } else 37121308Sache l += cvtchar(s + 2); 37275409Sache switch (*s) { 37321308Sache case '+': 37421308Sache dp = save_string(dp, "%+"); 37521308Sache break; 37658314Sache case '-': 37758314Sache dp = save_string(dp, "%-"); 37858314Sache break; 37958314Sache case '*': 38058314Sache dp = save_string(dp, "%*"); 38158314Sache break; 38258314Sache case '/': 38358314Sache dp = save_string(dp, "%/"); 38458314Sache break; 38558314Sache case '=': 38658314Sache if (seenr) { 38758314Sache if (param == 1) 38858314Sache onstack = 2; 38958314Sache else if (param == 2) 39058314Sache onstack = 1; 391119614Sache else 392119614Sache onstack = param; 39358314Sache } else 39458314Sache onstack = param; 39558314Sache break; 39658314Sache } 39758314Sache s += l; 39858314Sache break; 399119614Sache } 400119614Sache getparm(param, 1); 40158314Sache s += cvtchar(s); 40258314Sache dp = save_string(dp, "%+"); 40358314Sache break; 40458314Sache case '+': 40558314Sache getparm(param, 1); 40658314Sache s += cvtchar(s); 40758314Sache dp = save_string(dp, "%+%c"); 40858314Sache pop(); 40958314Sache break; 41058314Sache case 's': 41158314Sache#ifdef WATERLOO 41258314Sache s += cvtchar(s); 41358314Sache getparm(param, 1); 41458314Sache dp = save_string(dp, "%-"); 415119614Sache#else 416119614Sache getparm(param, 1); 417119614Sache dp = save_string(dp, "%s"); 41858314Sache pop(); 41958314Sache#endif /* WATERLOO */ 42058314Sache break; 42158314Sache case '-': 42221308Sache s += cvtchar(s); 42321308Sache getparm(param, 1); 42421308Sache dp = save_string(dp, "%-%c"); 42521308Sache pop(); 42621308Sache break; 42721308Sache case '.': 42821308Sache getparm(param, 1); 429136759Speter dp = save_string(dp, "%c"); 43021308Sache pop(); 431119614Sache break; 432119614Sache case '0': /* not clear any of the historical termcaps did this */ 433119614Sache if (*s == '3') 434119614Sache goto see03; 435119614Sache else if (*s != '2') 436119614Sache goto invalid; 437119614Sache /* FALLTHRU */ 43821308Sache case '2': 43921308Sache getparm(param, 1); 44021308Sache dp = save_string(dp, "%2d"); 44121308Sache pop(); 44221308Sache break; 44321308Sache case '3': 44421308Sache see03: 44521308Sache getparm(param, 1); 44621308Sache dp = save_string(dp, "%3d"); 44758314Sache pop(); 44821308Sache break; 44921308Sache case 'd': 45021308Sache getparm(param, 1); 45121308Sache dp = save_string(dp, "%d"); 45221308Sache pop(); 45321308Sache break; 45421308Sache case 'f': 45521308Sache param++; 45621308Sache break; 45721308Sache case 'b': 45821308Sache param--; 459136759Speter break; 46021308Sache case '\\': 46121308Sache dp = save_string(dp, "%\\"); 46221308Sache break; 46321308Sache default: 464136759Speter invalid: 46521308Sache dp = save_char(dp, '%'); 46621308Sache s--; 46721308Sache _nc_warning("unknown %% code %s (%#x) in %s", 46821308Sache unctrl((chtype) *s), UChar(*s), cap); 46921308Sache break; 47021308Sache } 47121308Sache break; 47221308Sache#ifdef REVISIBILIZE 47321308Sache case '\\': 47421308Sache dp = save_char(dp, *s++); 47521308Sache dp = save_char(dp, *s++); 47621308Sache break; 47721308Sache case '\n': 47821308Sache dp = save_string(dp, "\\n"); 47921308Sache s++; 48021308Sache break; 48121308Sache case '\t': 48221308Sache dp = save_string(dp, "\\t"); 48321308Sache s++; 48421308Sache break; 48547563Sache case '\r': 48647563Sache dp = save_string(dp, "\\r"); 48747563Sache s++; 48847563Sache break; 489119614Sache case '\200': 490119614Sache dp = save_string(dp, "\\0"); 49147563Sache s++; 49221308Sache break; 49321308Sache case '\f': 49421308Sache dp = save_string(dp, "\\f"); 49521308Sache s++; 49675409Sache break; 49721308Sache case '\b': 49821308Sache dp = save_string(dp, "\\b"); 49921308Sache s++; 50021308Sache break; 50121308Sache case ' ': 50221308Sache dp = save_string(dp, "\\s"); 50321308Sache s++; 50421308Sache break; 50521308Sache case '^': 50621308Sache dp = save_string(dp, "\\^"); 50758314Sache s++; 50821308Sache break; 50921308Sache case ':': 51058314Sache dp = save_string(dp, "\\:"); 51121308Sache s++; 51221308Sache break; 51358314Sache case ',': 51421308Sache dp = save_string(dp, "\\,"); 51521308Sache s++; 51621308Sache break; 51721308Sache default: 518136759Speter if (*s == '\033') { 51947563Sache dp = save_string(dp, "\\E"); 52047563Sache s++; 52147563Sache } else if (*s > 0 && *s < 32) { 52247563Sache dp = save_char(dp, '^'); 523119614Sache dp = save_char(dp, *s + '@'); 524119614Sache s++; 52547563Sache } else if (*s <= 0 || *s >= 127) { 52621308Sache dp = save_char(dp, '\\'); 52721308Sache dp = save_char(dp, ((*s & 0300) >> 6) + '0'); 52821308Sache dp = save_char(dp, ((*s & 0070) >> 3) + '0'); 52975409Sache dp = save_char(dp, (*s & 0007) + '0'); 53021308Sache s++; 53121308Sache } else 53258314Sache dp = save_char(dp, *s++); 53358314Sache break; 53458314Sache#else 53558314Sache default: 53658314Sache dp = save_char(dp, *s++); 53758314Sache break; 53858314Sache#endif 53958314Sache } 540119614Sache } 541119614Sache 54221308Sache /* 54321308Sache * Now, if we stripped off some leading padding, add it at the end 54447563Sache * of the string as mandatory padding. 54575409Sache */ 54647563Sache if (capstart) { 54758314Sache dp = save_string(dp, "$<"); 54858314Sache for (s = capstart;; s++) 54958314Sache if (isdigit(UChar(*s)) || *s == '*' || *s == '.') 55058314Sache dp = save_char(dp, *s); 551119614Sache else 55258314Sache break; 55347563Sache dp = save_string(dp, "/>"); 554119614Sache } 55547563Sache 55647563Sache (void) save_char(dp, '\0'); 55721308Sache return (my_string); 558119614Sache} 559119614Sache 560119614Sache/* 561119614Sache * Check for an expression that corresponds to "%B" (BCD): 562119614Sache * (parameter / 10) * 16 + (parameter % 10) 563119614Sache */ 564119614Sachestatic int 565119614Sachebcd_expression(const char *str) 566119614Sache{ 567119614Sache /* leave this non-const for HPUX */ 568119614Sache static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+"; 569119614Sache int len = 0; 570119614Sache char ch1, ch2; 571119614Sache 572119614Sache if (sscanf(str, fmt, &ch1, &ch2) == 2 573119614Sache && isdigit(UChar(ch1)) 57421308Sache && isdigit(UChar(ch2)) 57521308Sache && (ch1 == ch2)) { 57621308Sache len = 28; 577136759Speter#ifndef NDEBUG 57826497Sache { 579136759Speter char buffer[80]; 580136759Speter int tst; 581136759Speter sprintf(buffer, fmt, ch1, ch2); 582136759Speter tst = strlen(buffer) - 1; 583119614Sache assert(len == tst); 584119614Sache } 585136759Speter#endif 586119614Sache } 58721308Sache return len; 58875409Sache} 58975409Sache 59075409Sachestatic char * 59175409Sachesave_tc_char(char *bufptr, int c1) 59275409Sache{ 59375409Sache char temp[80]; 59426497Sache 59575409Sache if (is7bits(c1) && isprint(c1)) { 59621308Sache if (c1 == ':' || c1 == '\\') 59775409Sache bufptr = save_char(bufptr, '\\'); 59875409Sache bufptr = save_char(bufptr, c1); 59975409Sache } else { 60075409Sache if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */ 60175409Sache (void) strcpy(temp, unctrl((chtype) c1)); 602136759Speter else 603136759Speter (void) sprintf(temp, "\\%03o", c1); 604136759Speter bufptr = save_string(bufptr, temp); 605136759Speter } 606136759Speter return bufptr; 607136759Speter} 608136759Speter 609136759Speterstatic char * 610136759Spetersave_tc_inequality(char *bufptr, int c1, int c2) 611136759Speter{ 612136759Speter bufptr = save_string(bufptr, "%>"); 613136759Speter bufptr = save_tc_char(bufptr, c1); 614136759Speter bufptr = save_tc_char(bufptr, c2); 615136759Speter return bufptr; 616136759Speter} 617136759Speter 61875409Sache/* 619136759Speter * Here are the capabilities infotocap assumes it can translate to: 620136759Speter * 621136759Speter * %% output `%' 622136759Speter * %d output value as in printf %d 623136759Speter * %2 output value as in printf %2d 624136759Speter * %3 output value as in printf %3d 625136759Speter * %. output value as in printf %c 626136759Speter * %+c add character c to value, then do %. 627119614Sache * %>xy if value > x then add y, no output 628136759Speter * %r reverse order of two parameters, no output 629119614Sache * %i increment by one, no output 63026497Sache * %n exclusive-or all parameters with 0140 (Datamedia 2500) 63126497Sache * %B BCD (16*(value/10)) + (value%10), no output 63275409Sache * %D Reverse coding (value - 2*(value%16)), no output (Delta Data). 63375409Sache * %m exclusive-or all parameters with 0177 (not in 4.4BSD) 63475409Sache */ 63575409Sache 63675409Sache/* 63775409Sache * Convert a terminfo string to termcap format. Parameters are as in 63875409Sache * _nc_captoinfo(). 63926497Sache */ 640119614SacheNCURSES_EXPORT(char *) 641119614Sache_nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameterized) 642119614Sache{ 643119614Sache int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0; 644119614Sache const char *padding; 645119614Sache const char *trimmed = 0; 646119614Sache char ch1 = 0, ch2 = 0; 647119614Sache char *bufptr = init_string(); 648119614Sache int len; 649119614Sache bool syntax_error = FALSE; 650119614Sache 65126497Sache /* we may have to move some trailing mandatory padding up front */ 652119614Sache padding = str + strlen(str) - 1; 65326497Sache if (padding > str && *padding == '>' && *--padding == '/') { 65421308Sache --padding; 65521308Sache while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 656119614Sache padding--; 657119614Sache if (padding > str && *padding == '<' && *--padding == '$') 658119614Sache trimmed = padding; 659136759Speter padding += 2; 660119614Sache 661119614Sache while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 662119614Sache bufptr = save_char(bufptr, *padding++); 663119614Sache } 664119614Sache 665119614Sache for (; *str && str != trimmed; str++) { 666119614Sache int c1, c2; 667119614Sache char *cp = 0; 668136759Speter 669119614Sache if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) { 670119614Sache bufptr = save_char(bufptr, *++str); 671119614Sache } else if (str[0] == '$' && str[1] == '<') { /* discard padding */ 672119614Sache str += 2; 673136759Speter while (isdigit(UChar(*str)) 674119614Sache || *str == '.' 675119614Sache || *str == '*' 676119614Sache || *str == '/' 677119614Sache || *str == '>') 67821308Sache str++; 67921308Sache --str; 68021308Sache } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */ 681119614Sache bufptr = save_string(bufptr, "%%"); 682119614Sache ++str; 68321308Sache } else if (*str != '%' || (parameterized < 1)) { 68421308Sache bufptr = save_char(bufptr, *str); 68521308Sache } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) { 68621308Sache str = strchr(str, ';'); 68721308Sache bufptr = save_tc_inequality(bufptr, c1, c2); 68821308Sache } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) { 68921308Sache str = strchr(str, ';'); 69021308Sache bufptr = save_tc_inequality(bufptr, c1, c2); 69121308Sache } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) { 692119614Sache str = strchr(str, ';'); 693119614Sache bufptr = save_tc_inequality(bufptr, c1, c2); 694119614Sache } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) { 69521308Sache str = strchr(str, ';'); 696119614Sache bufptr = save_tc_inequality(bufptr, c1, c2); 69721308Sache } else if ((len = bcd_expression(str)) != 0) { 69821308Sache str += len; 69921308Sache bufptr = save_string(bufptr, "%B"); 70021308Sache } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1 70121308Sache || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1) 70275409Sache && (cp = strchr(str, '+'))) { 70321308Sache str = cp + 2; 70475409Sache bufptr = save_string(bufptr, "%+"); 70558314Sache 70621308Sache if (ch1) 70721308Sache c1 = ch1; 70821308Sache bufptr = save_tc_char(bufptr, c1); 70921308Sache } 71021308Sache /* FIXME: this "works" for 'delta' */ 71121308Sache else if (strncmp(str, "%{2}%*%-", 8) == 0) { 71221308Sache str += 7; 71321308Sache bufptr = save_string(bufptr, "%D"); 71421308Sache } else if (strncmp(str, "%{96}%^", 7) == 0) { 71521308Sache str += 6; 71621308Sache if (saw_m++ == 0) { 71721308Sache bufptr = save_string(bufptr, "%n"); 71821308Sache } 71921308Sache } else if (strncmp(str, "%{127}%^", 8) == 0) { 72021308Sache str += 7; 72121308Sache if (saw_n++ == 0) { 72221308Sache bufptr = save_string(bufptr, "%m"); 72375409Sache } 72447563Sache } else { /* cm-style format element */ 72547563Sache str++; 72621308Sache switch (*str) { 72747563Sache case '%': 72847563Sache bufptr = save_char(bufptr, '%'); 72947563Sache break; 73021308Sache 73175409Sache case '0': 73221308Sache case '1': 73321308Sache case '2': 73475409Sache case '3': 73558314Sache case '4': 73621308Sache case '5': 73721308Sache case '6': 73821308Sache case '7': 73921308Sache case '8': 74021308Sache case '9': 74121308Sache bufptr = save_char(bufptr, '%'); 74221308Sache while (isdigit(UChar(*str))) 74321308Sache bufptr = save_char(bufptr, *str++); 74421308Sache if (strchr("doxX.", *str)) { 74521308Sache if (*str != 'd') /* termcap doesn't have octal, hex */ 74621308Sache return 0; 74721308Sache } 74821308Sache break; 74975409Sache 75047563Sache case 'd': 75147563Sache bufptr = save_string(bufptr, "%d"); 75258314Sache break; 75347563Sache 75447563Sache case 'c': 75547563Sache bufptr = save_string(bufptr, "%."); 75621308Sache break; 75721308Sache 75821308Sache /* 75921308Sache * %s isn't in termcap, but it's convenient to pass it through 76021308Sache * so we can represent things like terminfo pfkey strings in 76121308Sache * termcap notation. 76221308Sache */ 76321308Sache case 's': 76421308Sache bufptr = save_string(bufptr, "%s"); 765119614Sache break; 766119614Sache 767119614Sache case 'p': 768119614Sache str++; 769119614Sache if (*str == '1') 770119614Sache seenone = 1; 771119614Sache else if (*str == '2') { 772119614Sache if (!seenone && !seentwo) { 773119614Sache bufptr = save_string(bufptr, "%r"); 774119614Sache seentwo++; 775119614Sache } 776119614Sache } else if (*str >= '3') 777119614Sache return (0); 778119614Sache break; 779119614Sache 780119614Sache case 'i': 781119614Sache bufptr = save_string(bufptr, "%i"); 782119614Sache break; 783119614Sache 784119614Sache default: 785119614Sache bufptr = save_char(bufptr, *str); 786119614Sache syntax_error = TRUE; 787119614Sache break; 788119614Sache } /* endswitch (*str) */ 789119614Sache } /* endelse (*str == '%') */ 790119614Sache 791119614Sache /* 792119614Sache * 'str' always points to the end of what was scanned in this step, 793119614Sache * but that may not be the end of the string. 794119614Sache */ 795119614Sache assert(str != 0); 79621308Sache if (*str == '\0') 79721308Sache break; 798119614Sache 79921308Sache } /* endwhile (*str) */ 800119614Sache 801119614Sache return (syntax_error ? NULL : my_string); 802119614Sache} 803119614Sache 804119614Sache#ifdef MAIN 805119614Sache 806119614Sacheint curr_line; 807119614Sache 808119614Sacheint 809119614Sachemain(int argc, char *argv[]) 810119614Sache{ 81121308Sache int c, tc = FALSE; 81221308Sache 81321308Sache while ((c = getopt(argc, argv, "c")) != EOF) 81421308Sache switch (c) { 81521308Sache case 'c': 81621308Sache tc = TRUE; 81721308Sache break; 81821308Sache } 81921308Sache 82058314Sache curr_line = 0; 82121308Sache for (;;) { 82221308Sache char buf[BUFSIZ]; 82321308Sache 82475409Sache ++curr_line; 82575409Sache if (fgets(buf, sizeof(buf), stdin) == 0) 82621308Sache break; 82721308Sache buf[strlen(buf) - 1] = '\0'; 82821308Sache _nc_set_source(buf); 82921308Sache 83021308Sache if (tc) { 83121308Sache char *cp = _nc_infotocap("to termcap", buf, 1); 83221308Sache 83321308Sache if (cp) 83421308Sache (void) fputs(cp, stdout); 83521308Sache } else 83675409Sache (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout); 83721308Sache (void) putchar('\n'); 83821308Sache } 83921308Sache return (0); 84021308Sache} 84121308Sache#endif /* MAIN */ 84221308Sache 84321308Sache#if NO_LEAKS 84421308SacheNCURSES_EXPORT(void) 84521308Sache_nc_captoinfo_leaks(void) 84621308Sache{ 84775409Sache if (my_string != 0) { 848119614Sache FreeAndNull(my_string); 849119614Sache } 850119614Sache my_length = 0; 851119614Sache} 852119614Sache#endif 853119614Sache