1279377Simp/**************************************************************************** 2279377Simp * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. * 3279377Simp * * 4279377Simp * Permission is hereby granted, free of charge, to any person obtaining a * 5279377Simp * copy of this software and associated documentation files (the * 6279377Simp * "Software"), to deal in the Software without restriction, including * 7279377Simp * without limitation the rights to use, copy, modify, merge, publish, * 8279377Simp * distribute, distribute with modifications, sublicense, and/or sell * 9279377Simp * copies of the Software, and to permit persons to whom the Software is * 10279377Simp * furnished to do so, subject to the following conditions: * 11279377Simp * * 12279377Simp * The above copyright notice and this permission notice shall be included * 13279377Simp * in all copies or substantial portions of the Software. * 14279377Simp * * 15279377Simp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16279377Simp * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17279377Simp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18279377Simp * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19279377Simp * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20279377Simp * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21279377Simp * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22279377Simp * * 23279377Simp * Except as contained in this notice, the name(s) of the above copyright * 24279377Simp * holders shall not be used in advertising or otherwise to promote the * 25279377Simp * sale, use or other dealings in this Software without prior written * 26279377Simp * authorization. * 27279377Simp ****************************************************************************/ 28279377Simp 29279377Simp/**************************************************************************** 30279377Simp * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31279377Simp * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32279377Simp * and: Thomas E. Dickey 1996-on * 33279377Simp ****************************************************************************/ 34279377Simp 35279377Simp/* 36279377Simp * captoinfo.c --- conversion between termcap and terminfo formats 37279377Simp * 38279377Simp * The captoinfo() code was swiped from Ross Ridge's mytinfo package, 39279377Simp * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>. 40279377Simp * 41279377Simp * There is just one entry point: 42279377Simp * 43279377Simp * char *_nc_captoinfo(n, s, parameterized) 44279377Simp * 45279377Simp * Convert value s for termcap string capability named n into terminfo 46279377Simp * format. 47279377Simp * 48279377Simp * This code recognizes all the standard 4.4BSD %-escapes: 49279377Simp * 50279377Simp * %% output `%' 51279377Simp * %d output value as in printf %d 52279377Simp * %2 output value as in printf %2d 53279377Simp * %3 output value as in printf %3d 54279377Simp * %. output value as in printf %c 55279377Simp * %+x add x to value, then do %. 56279377Simp * %>xy if value > x then add y, no output 57279377Simp * %r reverse order of two parameters, no output 58279377Simp * %i increment by one, no output 59279377Simp * %n exclusive-or all parameters with 0140 (Datamedia 2500) 60279377Simp * %B BCD (16*(value/10)) + (value%10), no output 61279377Simp * %D Reverse coding (value - 2*(value%16)), no output (Delta Data). 62279377Simp * 63279377Simp * Also, %02 and %03 are accepted as synonyms for %2 and %3. 64279377Simp * 65279377Simp * Besides all the standard termcap escapes, this translator understands 66279377Simp * the following extended escapes: 67279377Simp * 68279377Simp * used by GNU Emacs termcap libraries 69279377Simp * %a[+*-/=][cp]x GNU arithmetic. 70279377Simp * %m xor the first two parameters by 0177 71279377Simp * %b backup to previous parameter 72279377Simp * %f skip this parameter 73279377Simp * 74279377Simp * used by the University of Waterloo (MFCF) termcap libraries 75279377Simp * %-x subtract parameter FROM char x and output it as a char 76279377Simp * %ax add the character x to parameter 77279377Simp * 78279377Simp * If #define WATERLOO is on, also enable these translations: 79279377Simp * 80279377Simp * %sx subtract parameter FROM the character x 81279377Simp * 82279377Simp * By default, this Waterloo translations are not compiled in, because 83279377Simp * the Waterloo %s conflicts with the way terminfo uses %s in strings for 84279377Simp * function programming. 85279377Simp * 86279377Simp * Note the two definitions of %a: the GNU definition is translated if the 87279377Simp * characters after the 'a' are valid for it, otherwise the UW definition 88279377Simp * is translated. 89279377Simp */ 90279377Simp 91279377Simp#include <curses.priv.h> 92279377Simp 93279377Simp#include <ctype.h> 94279377Simp#include <tic.h> 95279377Simp 96279377SimpMODULE_ID("$Id: captoinfo.c,v 1.52 2008/08/16 19:24:51 tom Exp $") 97279377Simp 98279377Simp#define MAX_PUSHED 16 /* max # args we can push onto the stack */ 99279377Simp 100279377Simpstatic int stack[MAX_PUSHED]; /* the stack */ 101279377Simpstatic int stackptr; /* the next empty place on the stack */ 102279377Simpstatic int onstack; /* the top of stack */ 103279377Simpstatic int seenm; /* seen a %m */ 104279377Simpstatic int seenn; /* seen a %n */ 105279377Simpstatic int seenr; /* seen a %r */ 106279377Simpstatic int param; /* current parameter */ 107279377Simpstatic char *dp; /* pointer to end of the converted string */ 108279377Simp 109279377Simpstatic char *my_string; 110279377Simpstatic size_t my_length; 111279377Simp 112279377Simpstatic char * 113279377Simpinit_string(void) 114279377Simp/* initialize 'my_string', 'my_length' */ 115279377Simp{ 116279377Simp if (my_string == 0) 117279377Simp my_string = typeMalloc(char, my_length = 256); 118279377Simp if (my_string == 0) 119279377Simp _nc_err_abort(MSG_NO_MEMORY); 120279377Simp 121279377Simp *my_string = '\0'; 122279377Simp return my_string; 123279377Simp} 124279377Simp 125279377Simpstatic char * 126279377Simpsave_string(char *d, const char *const s) 127279377Simp{ 128279377Simp size_t have = (d - my_string); 129279377Simp size_t need = have + strlen(s) + 2; 130279377Simp if (need > my_length) { 131279377Simp my_string = (char *) realloc(my_string, my_length = (need + need)); 132279377Simp if (my_string == 0) 133279377Simp _nc_err_abort(MSG_NO_MEMORY); 134279377Simp d = my_string + have; 135279377Simp } 136279377Simp (void) strcpy(d, s); 137279377Simp return d + strlen(d); 138279377Simp} 139279377Simp 140279377Simpstatic NCURSES_INLINE char * 141279377Simpsave_char(char *s, int c) 142279377Simp{ 143279377Simp static char temp[2]; 144279377Simp temp[0] = (char) c; 145279377Simp return save_string(s, temp); 146279377Simp} 147279377Simp 148279377Simpstatic void 149279377Simppush(void) 150279377Simp/* push onstack on to the stack */ 151279377Simp{ 152279377Simp if (stackptr >= MAX_PUSHED) 153279377Simp _nc_warning("string too complex to convert"); 154279377Simp else 155279377Simp stack[stackptr++] = onstack; 156279377Simp} 157279377Simp 158279377Simpstatic void 159279377Simppop(void) 160279377Simp/* pop the top of the stack into onstack */ 161279377Simp{ 162279377Simp if (stackptr == 0) { 163279377Simp if (onstack == 0) 164279377Simp _nc_warning("I'm confused"); 165279377Simp else 166279377Simp onstack = 0; 167279377Simp } else 168279377Simp onstack = stack[--stackptr]; 169279377Simp param++; 170279377Simp} 171279377Simp 172279377Simpstatic int 173279377Simpcvtchar(register const char *sp) 174279377Simp/* convert a character to a terminfo push */ 175279377Simp{ 176279377Simp unsigned char c = 0; 177279377Simp int len; 178279377Simp 179279377Simp switch (*sp) { 180279377Simp case '\\': 181279377Simp switch (*++sp) { 182279377Simp case '\'': 183279377Simp case '$': 184279377Simp case '\\': 185279377Simp case '%': 186279377Simp c = (unsigned char) (*sp); 187279377Simp len = 2; 188279377Simp break; 189279377Simp case '\0': 190279377Simp c = '\\'; 191279377Simp len = 1; 192279377Simp break; 193279377Simp case '0': 194279377Simp case '1': 195279377Simp case '2': 196279377Simp case '3': 197279377Simp len = 1; 198279377Simp while (isdigit(UChar(*sp))) { 199279377Simp c = 8 * c + (*sp++ - '0'); 200279377Simp len++; 201279377Simp } 202279377Simp break; 203279377Simp default: 204279377Simp c = (unsigned char) (*sp); 205279377Simp len = 2; 206279377Simp break; 207279377Simp } 208279377Simp break; 209279377Simp case '^': 210279377Simp c = (*++sp & 0x1f); 211279377Simp len = 2; 212279377Simp break; 213279377Simp default: 214279377Simp c = (unsigned char) (*sp); 215279377Simp len = 1; 216279377Simp } 217279377Simp if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') { 218279377Simp dp = save_string(dp, "%\'"); 219279377Simp dp = save_char(dp, c); 220279377Simp dp = save_char(dp, '\''); 221279377Simp } else { 222279377Simp dp = save_string(dp, "%{"); 223279377Simp if (c > 99) 224279377Simp dp = save_char(dp, c / 100 + '0'); 225279377Simp if (c > 9) 226279377Simp dp = save_char(dp, ((int) (c / 10)) % 10 + '0'); 227279377Simp dp = save_char(dp, c % 10 + '0'); 228279377Simp dp = save_char(dp, '}'); 229279377Simp } 230279377Simp return len; 231279377Simp} 232279377Simp 233279377Simpstatic void 234279377Simpgetparm(int parm, int n) 235279377Simp/* push n copies of param on the terminfo stack if not already there */ 236279377Simp{ 237279377Simp if (seenr) { 238279377Simp if (parm == 1) 239279377Simp parm = 2; 240279377Simp else if (parm == 2) 241279377Simp parm = 1; 242279377Simp } 243279377Simp if (onstack == parm) { 244279377Simp if (n > 1) { 245279377Simp _nc_warning("string may not be optimal"); 246279377Simp dp = save_string(dp, "%Pa"); 247279377Simp while (n--) { 248279377Simp dp = save_string(dp, "%ga"); 249279377Simp } 250279377Simp } 251279377Simp return; 252279377Simp } 253279377Simp if (onstack != 0) 254279377Simp push(); 255279377Simp 256279377Simp onstack = parm; 257279377Simp 258279377Simp while (n--) { 259279377Simp dp = save_string(dp, "%p"); 260279377Simp dp = save_char(dp, '0' + parm); 261279377Simp } 262279377Simp 263279377Simp if (seenn && parm < 3) { 264279377Simp dp = save_string(dp, "%{96}%^"); 265279377Simp } 266279377Simp 267279377Simp if (seenm && parm < 3) { 268279377Simp dp = save_string(dp, "%{127}%^"); 269279377Simp } 270279377Simp} 271279377Simp 272279377Simp/* 273279377Simp * Convert a termcap string to terminfo format. 274279377Simp * 'cap' is the relevant terminfo capability index. 275279377Simp * 's' is the string value of the capability. 276279377Simp * 'parameterized' tells what type of translations to do: 277279377Simp * % translations if 1 278279377Simp * pad translations if >=0 279279377Simp */ 280279377SimpNCURSES_EXPORT(char *) 281279377Simp_nc_captoinfo(const char *cap, const char *s, int const parameterized) 282279377Simp{ 283279377Simp const char *capstart; 284279377Simp 285279377Simp stackptr = 0; 286279377Simp onstack = 0; 287279377Simp seenm = 0; 288279377Simp seenn = 0; 289279377Simp seenr = 0; 290279377Simp param = 1; 291279377Simp 292279377Simp dp = init_string(); 293279377Simp 294279377Simp /* skip the initial padding (if we haven't been told not to) */ 295279377Simp capstart = 0; 296279377Simp if (s == 0) 297279377Simp s = ""; 298279377Simp if (parameterized >= 0 && isdigit(UChar(*s))) 299279377Simp for (capstart = s;; s++) 300279377Simp if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.')) 301279377Simp break; 302279377Simp 303279377Simp while (*s != '\0') { 304279377Simp switch (*s) { 305279377Simp case '%': 306279377Simp s++; 307279377Simp if (parameterized < 1) { 308279377Simp dp = save_char(dp, '%'); 309279377Simp break; 310279377Simp } 311279377Simp switch (*s++) { 312279377Simp case '%': 313279377Simp dp = save_char(dp, '%'); 314279377Simp break; 315279377Simp case 'r': 316279377Simp if (seenr++ == 1) { 317279377Simp _nc_warning("saw %%r twice in %s", cap); 318279377Simp } 319279377Simp break; 320279377Simp case 'm': 321279377Simp if (seenm++ == 1) { 322279377Simp _nc_warning("saw %%m twice in %s", cap); 323279377Simp } 324279377Simp break; 325279377Simp case 'n': 326279377Simp if (seenn++ == 1) { 327279377Simp _nc_warning("saw %%n twice in %s", cap); 328279377Simp } 329279377Simp break; 330279377Simp case 'i': 331279377Simp dp = save_string(dp, "%i"); 332279377Simp break; 333279377Simp case '6': 334279377Simp case 'B': 335 getparm(param, 1); 336 dp = save_string(dp, "%{10}%/%{16}%*"); 337 getparm(param, 1); 338 dp = save_string(dp, "%{10}%m%+"); 339 break; 340 case '8': 341 case 'D': 342 getparm(param, 2); 343 dp = save_string(dp, "%{2}%*%-"); 344 break; 345 case '>': 346 getparm(param, 2); 347 /* %?%{x}%>%t%{y}%+%; */ 348 dp = save_string(dp, "%?"); 349 s += cvtchar(s); 350 dp = save_string(dp, "%>%t"); 351 s += cvtchar(s); 352 dp = save_string(dp, "%+%;"); 353 break; 354 case 'a': 355 if ((*s == '=' || *s == '+' || *s == '-' 356 || *s == '*' || *s == '/') 357 && (s[1] == 'p' || s[1] == 'c') 358 && s[2] != '\0') { 359 int l; 360 l = 2; 361 if (*s != '=') 362 getparm(param, 1); 363 if (s[1] == 'p') { 364 getparm(param + s[2] - '@', 1); 365 if (param != onstack) { 366 pop(); 367 param--; 368 } 369 l++; 370 } else 371 l += cvtchar(s + 2); 372 switch (*s) { 373 case '+': 374 dp = save_string(dp, "%+"); 375 break; 376 case '-': 377 dp = save_string(dp, "%-"); 378 break; 379 case '*': 380 dp = save_string(dp, "%*"); 381 break; 382 case '/': 383 dp = save_string(dp, "%/"); 384 break; 385 case '=': 386 if (seenr) { 387 if (param == 1) 388 onstack = 2; 389 else if (param == 2) 390 onstack = 1; 391 else 392 onstack = param; 393 } else 394 onstack = param; 395 break; 396 } 397 s += l; 398 break; 399 } 400 getparm(param, 1); 401 s += cvtchar(s); 402 dp = save_string(dp, "%+"); 403 break; 404 case '+': 405 getparm(param, 1); 406 s += cvtchar(s); 407 dp = save_string(dp, "%+%c"); 408 pop(); 409 break; 410 case 's': 411#ifdef WATERLOO 412 s += cvtchar(s); 413 getparm(param, 1); 414 dp = save_string(dp, "%-"); 415#else 416 getparm(param, 1); 417 dp = save_string(dp, "%s"); 418 pop(); 419#endif /* WATERLOO */ 420 break; 421 case '-': 422 s += cvtchar(s); 423 getparm(param, 1); 424 dp = save_string(dp, "%-%c"); 425 pop(); 426 break; 427 case '.': 428 getparm(param, 1); 429 dp = save_string(dp, "%c"); 430 pop(); 431 break; 432 case '0': /* not clear any of the historical termcaps did this */ 433 if (*s == '3') 434 goto see03; 435 else if (*s != '2') 436 goto invalid; 437 /* FALLTHRU */ 438 case '2': 439 getparm(param, 1); 440 dp = save_string(dp, "%2d"); 441 pop(); 442 break; 443 case '3': 444 see03: 445 getparm(param, 1); 446 dp = save_string(dp, "%3d"); 447 pop(); 448 break; 449 case 'd': 450 getparm(param, 1); 451 dp = save_string(dp, "%d"); 452 pop(); 453 break; 454 case 'f': 455 param++; 456 break; 457 case 'b': 458 param--; 459 break; 460 case '\\': 461 dp = save_string(dp, "%\\"); 462 break; 463 default: 464 invalid: 465 dp = save_char(dp, '%'); 466 s--; 467 _nc_warning("unknown %% code %s (%#x) in %s", 468 unctrl((chtype) *s), UChar(*s), cap); 469 break; 470 } 471 break; 472#ifdef REVISIBILIZE 473 case '\\': 474 dp = save_char(dp, *s++); 475 dp = save_char(dp, *s++); 476 break; 477 case '\n': 478 dp = save_string(dp, "\\n"); 479 s++; 480 break; 481 case '\t': 482 dp = save_string(dp, "\\t"); 483 s++; 484 break; 485 case '\r': 486 dp = save_string(dp, "\\r"); 487 s++; 488 break; 489 case '\200': 490 dp = save_string(dp, "\\0"); 491 s++; 492 break; 493 case '\f': 494 dp = save_string(dp, "\\f"); 495 s++; 496 break; 497 case '\b': 498 dp = save_string(dp, "\\b"); 499 s++; 500 break; 501 case ' ': 502 dp = save_string(dp, "\\s"); 503 s++; 504 break; 505 case '^': 506 dp = save_string(dp, "\\^"); 507 s++; 508 break; 509 case ':': 510 dp = save_string(dp, "\\:"); 511 s++; 512 break; 513 case ',': 514 dp = save_string(dp, "\\,"); 515 s++; 516 break; 517 default: 518 if (*s == '\033') { 519 dp = save_string(dp, "\\E"); 520 s++; 521 } else if (*s > 0 && *s < 32) { 522 dp = save_char(dp, '^'); 523 dp = save_char(dp, *s + '@'); 524 s++; 525 } else if (*s <= 0 || *s >= 127) { 526 dp = save_char(dp, '\\'); 527 dp = save_char(dp, ((*s & 0300) >> 6) + '0'); 528 dp = save_char(dp, ((*s & 0070) >> 3) + '0'); 529 dp = save_char(dp, (*s & 0007) + '0'); 530 s++; 531 } else 532 dp = save_char(dp, *s++); 533 break; 534#else 535 default: 536 dp = save_char(dp, *s++); 537 break; 538#endif 539 } 540 } 541 542 /* 543 * Now, if we stripped off some leading padding, add it at the end 544 * of the string as mandatory padding. 545 */ 546 if (capstart) { 547 dp = save_string(dp, "$<"); 548 for (s = capstart;; s++) 549 if (isdigit(UChar(*s)) || *s == '*' || *s == '.') 550 dp = save_char(dp, *s); 551 else 552 break; 553 dp = save_string(dp, "/>"); 554 } 555 556 (void) save_char(dp, '\0'); 557 return (my_string); 558} 559 560/* 561 * Check for an expression that corresponds to "%B" (BCD): 562 * (parameter / 10) * 16 + (parameter % 10) 563 */ 564static int 565bcd_expression(const char *str) 566{ 567 /* leave this non-const for HPUX */ 568 static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+"; 569 int len = 0; 570 char ch1, ch2; 571 572 if (sscanf(str, fmt, &ch1, &ch2) == 2 573 && isdigit(UChar(ch1)) 574 && isdigit(UChar(ch2)) 575 && (ch1 == ch2)) { 576 len = 28; 577#ifndef NDEBUG 578 { 579 char buffer[80]; 580 int tst; 581 sprintf(buffer, fmt, ch1, ch2); 582 tst = strlen(buffer) - 1; 583 assert(len == tst); 584 } 585#endif 586 } 587 return len; 588} 589 590static char * 591save_tc_char(char *bufptr, int c1) 592{ 593 char temp[80]; 594 595 if (is7bits(c1) && isprint(c1)) { 596 if (c1 == ':' || c1 == '\\') 597 bufptr = save_char(bufptr, '\\'); 598 bufptr = save_char(bufptr, c1); 599 } else { 600 if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */ 601 (void) strcpy(temp, unctrl((chtype) c1)); 602 else 603 (void) sprintf(temp, "\\%03o", c1); 604 bufptr = save_string(bufptr, temp); 605 } 606 return bufptr; 607} 608 609static char * 610save_tc_inequality(char *bufptr, int c1, int c2) 611{ 612 bufptr = save_string(bufptr, "%>"); 613 bufptr = save_tc_char(bufptr, c1); 614 bufptr = save_tc_char(bufptr, c2); 615 return bufptr; 616} 617 618/* 619 * Here are the capabilities infotocap assumes it can translate to: 620 * 621 * %% output `%' 622 * %d output value as in printf %d 623 * %2 output value as in printf %2d 624 * %3 output value as in printf %3d 625 * %. output value as in printf %c 626 * %+c add character c to value, then do %. 627 * %>xy if value > x then add y, no output 628 * %r reverse order of two parameters, no output 629 * %i increment by one, no output 630 * %n exclusive-or all parameters with 0140 (Datamedia 2500) 631 * %B BCD (16*(value/10)) + (value%10), no output 632 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data). 633 * %m exclusive-or all parameters with 0177 (not in 4.4BSD) 634 */ 635 636/* 637 * Convert a terminfo string to termcap format. Parameters are as in 638 * _nc_captoinfo(). 639 */ 640NCURSES_EXPORT(char *) 641_nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameterized) 642{ 643 int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0; 644 const char *padding; 645 const char *trimmed = 0; 646 char ch1 = 0, ch2 = 0; 647 char *bufptr = init_string(); 648 int len; 649 bool syntax_error = FALSE; 650 651 /* we may have to move some trailing mandatory padding up front */ 652 padding = str + strlen(str) - 1; 653 if (padding > str && *padding == '>' && *--padding == '/') { 654 --padding; 655 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 656 padding--; 657 if (padding > str && *padding == '<' && *--padding == '$') 658 trimmed = padding; 659 padding += 2; 660 661 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 662 bufptr = save_char(bufptr, *padding++); 663 } 664 665 for (; *str && str != trimmed; str++) { 666 int c1, c2; 667 char *cp = 0; 668 669 if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) { 670 bufptr = save_char(bufptr, *++str); 671 } else if (str[0] == '$' && str[1] == '<') { /* discard padding */ 672 str += 2; 673 while (isdigit(UChar(*str)) 674 || *str == '.' 675 || *str == '*' 676 || *str == '/' 677 || *str == '>') 678 str++; 679 --str; 680 } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */ 681 bufptr = save_string(bufptr, "%%"); 682 ++str; 683 } else if (*str != '%' || (parameterized < 1)) { 684 bufptr = save_char(bufptr, *str); 685 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) { 686 str = strchr(str, ';'); 687 bufptr = save_tc_inequality(bufptr, c1, c2); 688 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) { 689 str = strchr(str, ';'); 690 bufptr = save_tc_inequality(bufptr, c1, c2); 691 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) { 692 str = strchr(str, ';'); 693 bufptr = save_tc_inequality(bufptr, c1, c2); 694 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) { 695 str = strchr(str, ';'); 696 bufptr = save_tc_inequality(bufptr, c1, c2); 697 } else if ((len = bcd_expression(str)) != 0) { 698 str += len; 699 bufptr = save_string(bufptr, "%B"); 700 } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1 701 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1) 702 && (cp = strchr(str, '+'))) { 703 str = cp + 2; 704 bufptr = save_string(bufptr, "%+"); 705 706 if (ch1) 707 c1 = ch1; 708 bufptr = save_tc_char(bufptr, c1); 709 } 710 /* FIXME: this "works" for 'delta' */ 711 else if (strncmp(str, "%{2}%*%-", 8) == 0) { 712 str += 7; 713 bufptr = save_string(bufptr, "%D"); 714 } else if (strncmp(str, "%{96}%^", 7) == 0) { 715 str += 6; 716 if (saw_m++ == 0) { 717 bufptr = save_string(bufptr, "%n"); 718 } 719 } else if (strncmp(str, "%{127}%^", 8) == 0) { 720 str += 7; 721 if (saw_n++ == 0) { 722 bufptr = save_string(bufptr, "%m"); 723 } 724 } else { /* cm-style format element */ 725 str++; 726 switch (*str) { 727 case '%': 728 bufptr = save_char(bufptr, '%'); 729 break; 730 731 case '0': 732 case '1': 733 case '2': 734 case '3': 735 case '4': 736 case '5': 737 case '6': 738 case '7': 739 case '8': 740 case '9': 741 bufptr = save_char(bufptr, '%'); 742 while (isdigit(UChar(*str))) 743 bufptr = save_char(bufptr, *str++); 744 if (strchr("doxX.", *str)) { 745 if (*str != 'd') /* termcap doesn't have octal, hex */ 746 return 0; 747 } 748 break; 749 750 case 'd': 751 bufptr = save_string(bufptr, "%d"); 752 break; 753 754 case 'c': 755 bufptr = save_string(bufptr, "%."); 756 break; 757 758 /* 759 * %s isn't in termcap, but it's convenient to pass it through 760 * so we can represent things like terminfo pfkey strings in 761 * termcap notation. 762 */ 763 case 's': 764 bufptr = save_string(bufptr, "%s"); 765 break; 766 767 case 'p': 768 str++; 769 if (*str == '1') 770 seenone = 1; 771 else if (*str == '2') { 772 if (!seenone && !seentwo) { 773 bufptr = save_string(bufptr, "%r"); 774 seentwo++; 775 } 776 } else if (*str >= '3') 777 return (0); 778 break; 779 780 case 'i': 781 bufptr = save_string(bufptr, "%i"); 782 break; 783 784 default: 785 bufptr = save_char(bufptr, *str); 786 syntax_error = TRUE; 787 break; 788 } /* endswitch (*str) */ 789 } /* endelse (*str == '%') */ 790 791 /* 792 * 'str' always points to the end of what was scanned in this step, 793 * but that may not be the end of the string. 794 */ 795 assert(str != 0); 796 if (*str == '\0') 797 break; 798 799 } /* endwhile (*str) */ 800 801 return (syntax_error ? NULL : my_string); 802} 803 804#ifdef MAIN 805 806int curr_line; 807 808int 809main(int argc, char *argv[]) 810{ 811 int c, tc = FALSE; 812 813 while ((c = getopt(argc, argv, "c")) != EOF) 814 switch (c) { 815 case 'c': 816 tc = TRUE; 817 break; 818 } 819 820 curr_line = 0; 821 for (;;) { 822 char buf[BUFSIZ]; 823 824 ++curr_line; 825 if (fgets(buf, sizeof(buf), stdin) == 0) 826 break; 827 buf[strlen(buf) - 1] = '\0'; 828 _nc_set_source(buf); 829 830 if (tc) { 831 char *cp = _nc_infotocap("to termcap", buf, 1); 832 833 if (cp) 834 (void) fputs(cp, stdout); 835 } else 836 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout); 837 (void) putchar('\n'); 838 } 839 return (0); 840} 841#endif /* MAIN */ 842 843#if NO_LEAKS 844NCURSES_EXPORT(void) 845_nc_captoinfo_leaks(void) 846{ 847 if (my_string != 0) { 848 FreeAndNull(my_string); 849 } 850 my_length = 0; 851} 852#endif 853