1 /**************************************************************************** 2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. * 3 * * 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: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 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. * 22 * * 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 * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 * and: Thomas E. Dickey 1996-on * 33 ****************************************************************************/ 34 35 /* 36 * captoinfo.c --- conversion between termcap and terminfo formats 37 * 38 * The captoinfo() code was swiped from Ross Ridge's mytinfo package, 39 * adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>. 40 * 41 * There is just one entry point: 42 * 43 * char *_nc_captoinfo(n, s, parameterized) 44 * 45 * Convert value s for termcap string capability named n into terminfo 46 * format. 47 * 48 * This code recognizes all the standard 4.4BSD %-escapes: 49 * 50 * %% output `%' 51 * %d output value as in printf %d 52 * %2 output value as in printf %2d 53 * %3 output value as in printf %3d 54 * %. output value as in printf %c 55 * %+x add x to value, then do %. 56 * %>xy if value > x then add y, no output 57 * %r reverse order of two parameters, no output 58 * %i increment by one, no output 59 * %n exclusive-or all parameters with 0140 (Datamedia 2500) 60 * %B BCD (16*(value/10)) + (value%10), no output 61 * %D Reverse coding (value - 2*(value%16)), no output (Delta Data). 62 * 63 * Also, %02 and %03 are accepted as synonyms for %2 and %3. 64 * 65 * Besides all the standard termcap escapes, this translator understands 66 * the following extended escapes: 67 * 68 * used by GNU Emacs termcap libraries 69 * %a[+*-/=][cp]x GNU arithmetic. 70 * %m xor the first two parameters by 0177 71 * %b backup to previous parameter 72 * %f skip this parameter 73 * 74 * used by the University of Waterloo (MFCF) termcap libraries 75 * %-x subtract parameter FROM char x and output it as a char 76 * %ax add the character x to parameter 77 * 78 * If #define WATERLOO is on, also enable these translations: 79 * 80 * %sx subtract parameter FROM the character x 81 * 82 * By default, this Waterloo translations are not compiled in, because 83 * the Waterloo %s conflicts with the way terminfo uses %s in strings for 84 * function programming. 85 * 86 * Note the two definitions of %a: the GNU definition is translated if the 87 * characters after the 'a' are valid for it, otherwise the UW definition 88 * is translated. 89 */ 90 91 #include <curses.priv.h> 92 93 #include <ctype.h> 94 #include <tic.h> 95 96 MODULE_ID("$Id: captoinfo.c,v 1.58 2010/12/04 20:08:19 tom Exp $") 97 98 #define MAX_PUSHED 16 /* max # args we can push onto the stack */ 99 100 static int stack[MAX_PUSHED]; /* the stack */ 101 static int stackptr; /* the next empty place on the stack */ 102 static int onstack; /* the top of stack */ 103 static int seenm; /* seen a %m */ 104 static int seenn; /* seen a %n */ 105 static int seenr; /* seen a %r */ 106 static int param; /* current parameter */ 107 static char *dp; /* pointer to end of the converted string */ 108 109 static char *my_string; 110 static size_t my_length; 111 112 static char * 113 init_string(void) 114 /* initialize 'my_string', 'my_length' */ 115 { 116 if (my_string == 0) 117 my_string = typeMalloc(char, my_length = 256); 118 if (my_string == 0) 119 _nc_err_abort(MSG_NO_MEMORY); 120 121 *my_string = '\0'; 122 return my_string; 123 } 124 125 static char * 126 save_string(char *d, const char *const s) 127 { 128 size_t have = (size_t) (d - my_string); 129 size_t need = have + strlen(s) + 2; 130 if (need > my_length) { 131 my_string = (char *) _nc_doalloc(my_string, my_length = (need + need)); 132 if (my_string == 0) 133 _nc_err_abort(MSG_NO_MEMORY); 134 d = my_string + have; 135 } 136 (void) strcpy(d, s); 137 return d + strlen(d); 138 } 139 140 static NCURSES_INLINE char * 141 save_char(char *s, int c) 142 { 143 static char temp[2]; 144 temp[0] = (char) c; 145 return save_string(s, temp); 146 } 147 148 static void 149 push(void) 150 /* push onstack on to the stack */ 151 { 152 if (stackptr >= MAX_PUSHED) 153 _nc_warning("string too complex to convert"); 154 else 155 stack[stackptr++] = onstack; 156 } 157 158 static void 159 pop(void) 160 /* pop the top of the stack into onstack */ 161 { 162 if (stackptr == 0) { 163 if (onstack == 0) 164 _nc_warning("I'm confused"); 165 else 166 onstack = 0; 167 } else 168 onstack = stack[--stackptr]; 169 param++; 170 } 171 172 static int 173 cvtchar(register const char *sp) 174 /* convert a character to a terminfo push */ 175 { 176 unsigned char c = 0; 177 int len; 178 179 switch (*sp) { 180 case '\\': 181 switch (*++sp) { 182 case '\'': 183 case '$': 184 case '\\': 185 case '%': 186 c = (unsigned char) (*sp); 187 len = 2; 188 break; 189 case '\0': 190 c = '\\'; 191 len = 1; 192 break; 193 case '0': 194 case '1': 195 case '2': 196 case '3': 197 len = 1; 198 while (isdigit(UChar(*sp))) { 199 c = (unsigned char) (8 * c + (*sp++ - '0')); 200 len++; 201 } 202 break; 203 default: 204 c = (unsigned char) (*sp); 205 len = 2; 206 break; 207 } 208 break; 209 case '^': 210 c = (unsigned char) (*++sp & 0x1f); 211 len = 2; 212 break; 213 default: 214 c = (unsigned char) (*sp); 215 len = 1; 216 } 217 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') { 218 dp = save_string(dp, "%\'"); 219 dp = save_char(dp, c); 220 dp = save_char(dp, '\''); 221 } else { 222 dp = save_string(dp, "%{"); 223 if (c > 99) 224 dp = save_char(dp, c / 100 + '0'); 225 if (c > 9) 226 dp = save_char(dp, ((int) (c / 10)) % 10 + '0'); 227 dp = save_char(dp, c % 10 + '0'); 228 dp = save_char(dp, '}'); 229 } 230 return len; 231 } 232 233 static void 234 getparm(int parm, int n) 235 /* push n copies of param on the terminfo stack if not already there */ 236 { 237 if (seenr) { 238 if (parm == 1) 239 parm = 2; 240 else if (parm == 2) 241 parm = 1; 242 } 243 if (onstack == parm) { 244 if (n > 1) { 245 _nc_warning("string may not be optimal"); 246 dp = save_string(dp, "%Pa"); 247 while (n--) { 248 dp = save_string(dp, "%ga"); 249 } 250 } 251 return; 252 } 253 if (onstack != 0) 254 push(); 255 256 onstack = parm; 257 258 while (n--) { 259 dp = save_string(dp, "%p"); 260 dp = save_char(dp, '0' + parm); 261 } 262 263 if (seenn && parm < 3) { 264 dp = save_string(dp, "%{96}%^"); 265 } 266 267 if (seenm && parm < 3) { 268 dp = save_string(dp, "%{127}%^"); 269 } 270 } 271 272 /* 273 * Convert a termcap string to terminfo format. 274 * 'cap' is the relevant terminfo capability index. 275 * 's' is the string value of the capability. 276 * 'parameterized' tells what type of translations to do: 277 * % translations if 1 278 * pad translations if >=0 279 */ 280 NCURSES_EXPORT(char *) 281 _nc_captoinfo(const char *cap, const char *s, int const parameterized) 282 { 283 const char *capstart; 284 285 stackptr = 0; 286 onstack = 0; 287 seenm = 0; 288 seenn = 0; 289 seenr = 0; 290 param = 1; 291 292 dp = init_string(); 293 294 /* skip the initial padding (if we haven't been told not to) */ 295 capstart = 0; 296 if (s == 0) 297 s = ""; 298 if (parameterized >= 0 && isdigit(UChar(*s))) 299 for (capstart = s;; s++) 300 if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.')) 301 break; 302 303 while (*s != '\0') { 304 switch (*s) { 305 case '%': 306 s++; 307 if (parameterized < 1) { 308 dp = save_char(dp, '%'); 309 break; 310 } 311 switch (*s++) { 312 case '%': 313 dp = save_char(dp, '%'); 314 break; 315 case 'r': 316 if (seenr++ == 1) { 317 _nc_warning("saw %%r twice in %s", cap); 318 } 319 break; 320 case 'm': 321 if (seenm++ == 1) { 322 _nc_warning("saw %%m twice in %s", cap); 323 } 324 break; 325 case 'n': 326 if (seenn++ == 1) { 327 _nc_warning("saw %%n twice in %s", cap); 328 } 329 break; 330 case 'i': 331 dp = save_string(dp, "%i"); 332 break; 333 case '6': 334 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 */ 564 static int 565 bcd_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 590 static char * 591 save_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 609 static char * 610 save_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 */ 640 NCURSES_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 int in0, in1, in2; 647 char ch1 = 0, ch2 = 0; 648 char *bufptr = init_string(); 649 int len; 650 bool syntax_error = FALSE; 651 652 /* we may have to move some trailing mandatory padding up front */ 653 padding = str + strlen(str) - 1; 654 if (padding > str && *padding == '>' && *--padding == '/') { 655 --padding; 656 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 657 padding--; 658 if (padding > str && *padding == '<' && *--padding == '$') 659 trimmed = padding; 660 padding += 2; 661 662 while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') 663 bufptr = save_char(bufptr, *padding++); 664 } 665 666 for (; *str && str != trimmed; str++) { 667 int c1, c2; 668 char *cp = 0; 669 670 if (str[0] == '^') { 671 if (str[1] == '\0' || (str + 1) == trimmed) { 672 bufptr = save_string(bufptr, "\\136"); 673 ++str; 674 } else { 675 bufptr = save_char(bufptr, *str++); 676 bufptr = save_char(bufptr, *str); 677 } 678 } else if (str[0] == '\\') { 679 if (str[1] == '\0' || (str + 1) == trimmed) { 680 bufptr = save_string(bufptr, "\\134"); 681 ++str; 682 } else if (str[1] == '^') { 683 bufptr = save_string(bufptr, "\\136"); 684 ++str; 685 } else if (str[1] == ',') { 686 bufptr = save_char(bufptr, *++str); 687 } else { 688 bufptr = save_char(bufptr, *str++); 689 bufptr = save_char(bufptr, *str); 690 } 691 } else if (str[0] == '$' && str[1] == '<') { /* discard padding */ 692 str += 2; 693 while (isdigit(UChar(*str)) 694 || *str == '.' 695 || *str == '*' 696 || *str == '/' 697 || *str == '>') 698 str++; 699 --str; 700 } else if (sscanf(str, 701 "[%%?%%p1%%{8}%%<%%t%d%%p1%%d%%e%%p1%%{16}%%<%%t%d%%p1%%{8}%%-%%d%%e%d;5;%%p1%%d%%;m", 702 &in0, &in1, &in2) == 3 703 && ((in0 == 4 && in1 == 10 && in2 == 48) 704 || (in0 == 3 && in1 == 9 && in2 == 38))) { 705 /* dumb-down an optimized case from xterm-256color for termcap */ 706 str = strstr(str, ";m"); 707 ++str; 708 if (in2 == 48) { 709 bufptr = save_string(bufptr, "[48;5;%dm"); 710 } else { 711 bufptr = save_string(bufptr, "[38;5;%dm"); 712 } 713 } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */ 714 bufptr = save_string(bufptr, "%%"); 715 ++str; 716 } else if (*str != '%' || (parameterized < 1)) { 717 bufptr = save_char(bufptr, *str); 718 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) { 719 str = strchr(str, ';'); 720 bufptr = save_tc_inequality(bufptr, c1, c2); 721 } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) { 722 str = strchr(str, ';'); 723 bufptr = save_tc_inequality(bufptr, c1, c2); 724 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) { 725 str = strchr(str, ';'); 726 bufptr = save_tc_inequality(bufptr, c1, c2); 727 } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) { 728 str = strchr(str, ';'); 729 bufptr = save_tc_inequality(bufptr, c1, c2); 730 } else if ((len = bcd_expression(str)) != 0) { 731 str += len; 732 bufptr = save_string(bufptr, "%B"); 733 } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1 734 || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1) 735 && (cp = strchr(str, '+'))) { 736 str = cp + 2; 737 bufptr = save_string(bufptr, "%+"); 738 739 if (ch1) 740 c1 = ch1; 741 bufptr = save_tc_char(bufptr, c1); 742 } 743 /* FIXME: this "works" for 'delta' */ 744 else if (strncmp(str, "%{2}%*%-", 8) == 0) { 745 str += 7; 746 bufptr = save_string(bufptr, "%D"); 747 } else if (strncmp(str, "%{96}%^", 7) == 0) { 748 str += 6; 749 if (saw_m++ == 0) { 750 bufptr = save_string(bufptr, "%n"); 751 } 752 } else if (strncmp(str, "%{127}%^", 8) == 0) { 753 str += 7; 754 if (saw_n++ == 0) { 755 bufptr = save_string(bufptr, "%m"); 756 } 757 } else { /* cm-style format element */ 758 str++; 759 switch (*str) { 760 case '%': 761 bufptr = save_char(bufptr, '%'); 762 break; 763 764 case '0': 765 case '1': 766 case '2': 767 case '3': 768 case '4': 769 case '5': 770 case '6': 771 case '7': 772 case '8': 773 case '9': 774 bufptr = save_char(bufptr, '%'); 775 while (isdigit(UChar(*str))) 776 bufptr = save_char(bufptr, *str++); 777 if (strchr("doxX.", *str)) { 778 if (*str != 'd') /* termcap doesn't have octal, hex */ 779 return 0; 780 } 781 break; 782 783 case 'd': 784 bufptr = save_string(bufptr, "%d"); 785 break; 786 787 case 'c': 788 bufptr = save_string(bufptr, "%."); 789 break; 790 791 /* 792 * %s isn't in termcap, but it's convenient to pass it through 793 * so we can represent things like terminfo pfkey strings in 794 * termcap notation. 795 */ 796 case 's': 797 bufptr = save_string(bufptr, "%s"); 798 break; 799 800 case 'p': 801 str++; 802 if (*str == '1') 803 seenone = 1; 804 else if (*str == '2') { 805 if (!seenone && !seentwo) { 806 bufptr = save_string(bufptr, "%r"); 807 seentwo++; 808 } 809 } else if (*str >= '3') 810 return (0); 811 break; 812 813 case 'i': 814 bufptr = save_string(bufptr, "%i"); 815 break; 816 817 default: 818 bufptr = save_char(bufptr, *str); 819 syntax_error = TRUE; 820 break; 821 } /* endswitch (*str) */ 822 } /* endelse (*str == '%') */ 823 824 /* 825 * 'str' always points to the end of what was scanned in this step, 826 * but that may not be the end of the string. 827 */ 828 assert(str != 0); 829 if (*str == '\0') 830 break; 831 832 } /* endwhile (*str) */ 833 834 return (syntax_error ? NULL : my_string); 835 } 836 837 #ifdef MAIN 838 839 int curr_line; 840 841 int 842 main(int argc, char *argv[]) 843 { 844 int c, tc = FALSE; 845 846 while ((c = getopt(argc, argv, "c")) != EOF) 847 switch (c) { 848 case 'c': 849 tc = TRUE; 850 break; 851 } 852 853 curr_line = 0; 854 for (;;) { 855 char buf[BUFSIZ]; 856 857 ++curr_line; 858 if (fgets(buf, sizeof(buf), stdin) == 0) 859 break; 860 buf[strlen(buf) - 1] = '\0'; 861 _nc_set_source(buf); 862 863 if (tc) { 864 char *cp = _nc_infotocap("to termcap", buf, 1); 865 866 if (cp) 867 (void) fputs(cp, stdout); 868 } else 869 (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout); 870 (void) putchar('\n'); 871 } 872 return (0); 873 } 874 #endif /* MAIN */ 875 876 #if NO_LEAKS 877 NCURSES_EXPORT(void) 878 _nc_captoinfo_leaks(void) 879 { 880 if (my_string != 0) { 881 FreeAndNull(my_string); 882 } 883 my_length = 0; 884 } 885 #endif 886