1 /**************************************************************************** 2 * Copyright (c) 1998-2011,2015 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 * and: Juergen Pfeifer 2009 * 34 ****************************************************************************/ 35 36 #include <curses.priv.h> 37 38 #include <ctype.h> 39 40 #ifndef CUR 41 #define CUR SP_TERMTYPE 42 #endif 43 44 MODULE_ID("$Id: lib_screen.c,v 1.79 2015/12/20 01:22:59 tom Exp $") 45 46 #define MAX_SIZE 0x3fff /* 16k is big enough for a window or pad */ 47 48 #define MARKER '\\' 49 #define APPEND '+' 50 #define GUTTER '|' 51 #define L_CURL '{' 52 #define R_CURL '}' 53 54 /* 55 * Use 0x8888 as the magic number for new-format files, since it cannot be 56 * mistaken for the _cury/_curx pair of 16-bit numbers which start the old 57 * format. It happens to be unused in the file 5.22 database (2015/03/07). 58 */ 59 static const char my_magic[] = 60 {'\210', '\210', '\210', '\210'}; 61 62 #if NCURSES_EXT_PUTWIN 63 typedef enum { 64 pINT /* int */ 65 ,pSHORT /* short */ 66 ,pBOOL /* bool */ 67 ,pATTR /* attr_t */ 68 ,pCHAR /* chtype */ 69 ,pSIZE /* NCURSES_SIZE_T */ 70 #if NCURSES_WIDECHAR 71 ,pCCHAR /* cchar_t */ 72 #endif 73 } PARAM_TYPE; 74 75 typedef struct { 76 const char name[11]; 77 attr_t attr; 78 } SCR_ATTRS; 79 80 typedef struct { 81 const char name[17]; 82 PARAM_TYPE type; 83 size_t size; 84 size_t offset; 85 } SCR_PARAMS; 86 87 #define DATA(name) { { #name }, A_##name } 88 static const SCR_ATTRS scr_attrs[] = 89 { 90 DATA(NORMAL), 91 DATA(STANDOUT), 92 DATA(UNDERLINE), 93 DATA(REVERSE), 94 DATA(BLINK), 95 DATA(DIM), 96 DATA(BOLD), 97 DATA(ALTCHARSET), 98 DATA(INVIS), 99 DATA(PROTECT), 100 DATA(HORIZONTAL), 101 DATA(LEFT), 102 DATA(LOW), 103 DATA(RIGHT), 104 DATA(TOP), 105 DATA(VERTICAL), 106 107 #ifdef A_ITALIC 108 DATA(ITALIC), 109 #endif 110 }; 111 #undef DATA 112 113 #define sizeof2(type,name) sizeof(((type *)0)->name) 114 #define DATA(name, type) { { #name }, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) } 115 116 static const SCR_PARAMS scr_params[] = 117 { 118 DATA(_cury, pSIZE), 119 DATA(_curx, pSIZE), 120 DATA(_maxy, pSIZE), 121 DATA(_maxx, pSIZE), 122 DATA(_begy, pSIZE), 123 DATA(_begx, pSIZE), 124 DATA(_flags, pSHORT), 125 DATA(_attrs, pATTR), 126 DATA(_bkgd, pCHAR), 127 DATA(_notimeout, pBOOL), 128 DATA(_clear, pBOOL), 129 DATA(_leaveok, pBOOL), 130 DATA(_scroll, pBOOL), 131 DATA(_idlok, pBOOL), 132 DATA(_idcok, pBOOL), 133 DATA(_immed, pBOOL), 134 DATA(_sync, pBOOL), 135 DATA(_use_keypad, pBOOL), 136 DATA(_delay, pINT), 137 DATA(_regtop, pSIZE), 138 DATA(_regbottom, pSIZE), 139 DATA(_pad._pad_y, pSIZE), 140 DATA(_pad._pad_x, pSIZE), 141 DATA(_pad._pad_top, pSIZE), 142 DATA(_pad._pad_left, pSIZE), 143 DATA(_pad._pad_bottom, pSIZE), 144 DATA(_pad._pad_right, pSIZE), 145 DATA(_yoffset, pSIZE), 146 #if NCURSES_WIDECHAR 147 DATA(_bkgrnd, pCCHAR), 148 #if NCURSES_EXT_COLORS 149 DATA(_color, pINT), 150 #endif 151 #endif 152 }; 153 #undef DATA 154 155 static const NCURSES_CH_T blank = NewChar(BLANK_TEXT); 156 157 /* 158 * Allocate and read a line of text. Caller must free it. 159 */ 160 static char * 161 read_txt(FILE *fp) 162 { 163 size_t limit = 1024; 164 size_t used = 0; 165 char *result = malloc(limit); 166 char *buffer; 167 168 if (result != 0) { 169 int ch = 0; 170 171 clearerr(fp); 172 result[used] = '\0'; 173 do { 174 if (used + 2 >= limit) { 175 limit += 1024; 176 buffer = realloc(result, limit); 177 if (buffer == 0) { 178 free(result); 179 result = 0; 180 break; 181 } 182 result = buffer; 183 } 184 ch = fgetc(fp); 185 if (ch == EOF) 186 break; 187 result[used++] = (char) ch; 188 result[used] = '\0'; 189 } while (ch != '\n'); 190 191 if (ch == '\n') { 192 result[--used] = '\0'; 193 T(("READ:%s", result)); 194 } else if (used == 0) { 195 free(result); 196 result = 0; 197 } 198 } 199 return result; 200 } 201 202 static char * 203 decode_attr(char *source, attr_t *target, int *color) 204 { 205 bool found = FALSE; 206 207 T(("decode_attr '%s'", source)); 208 209 while (*source) { 210 if (source[0] == MARKER && source[1] == L_CURL) { 211 source += 2; 212 found = TRUE; 213 } else if (source[0] == R_CURL) { 214 source++; 215 found = FALSE; 216 } else if (found) { 217 size_t n; 218 char *next = source; 219 220 if (source[0] == GUTTER) { 221 ++next; 222 } else if (*next == 'C') { 223 int value = 0; 224 unsigned pair; 225 next++; 226 while (isdigit(UChar(*next))) { 227 value = value * 10 + (*next++ - '0'); 228 } 229 *target &= ~A_COLOR; 230 pair = (unsigned) ((value > 256) 231 ? COLOR_PAIR(255) 232 : COLOR_PAIR(value)); 233 *target |= pair; 234 *color = value; 235 } else { 236 while (isalnum(UChar(*next))) { 237 ++next; 238 } 239 for (n = 0; n < SIZEOF(scr_attrs); ++n) { 240 if ((size_t) (next - source) == strlen(scr_attrs[n].name)) { 241 if (scr_attrs[n].attr) { 242 *target |= scr_attrs[n].attr; 243 } else { 244 *target = A_NORMAL; 245 } 246 break; 247 } 248 } 249 } 250 source = next; 251 } else { 252 break; 253 } 254 } 255 return source; 256 } 257 258 static char * 259 decode_char(char *source, int *target) 260 { 261 int limit = 0; 262 int base = 16; 263 const char digits[] = "0123456789abcdef"; 264 265 T(("decode_char '%s'", source)); 266 *target = ' '; 267 switch (*source) { 268 case MARKER: 269 switch (*++source) { 270 case APPEND: 271 break; 272 case MARKER: 273 *target = MARKER; 274 ++source; 275 break; 276 case 's': 277 *target = ' '; 278 ++source; 279 break; 280 case '0': 281 case '1': 282 case '2': 283 case '3': 284 base = 8; 285 limit = 3; 286 break; 287 case 'u': 288 limit = 4; 289 ++source; 290 break; 291 case 'U': 292 limit = 8; 293 ++source; 294 break; 295 } 296 if (limit) { 297 *target = 0; 298 while (limit-- > 0) { 299 char *find = strchr(digits, *source++); 300 int ch = (find != 0) ? (int) (find - digits) : -1; 301 *target *= base; 302 if (ch >= 0 && ch < base) { 303 *target += ch; 304 } 305 } 306 } 307 break; 308 default: 309 *target = *source++; 310 break; 311 } 312 return source; 313 } 314 315 static char * 316 decode_chtype(char *source, chtype fillin, chtype *target) 317 { 318 attr_t attr = ChAttrOf(fillin); 319 int color = PAIR_NUMBER((int) attr); 320 int value; 321 322 T(("decode_chtype '%s'", source)); 323 source = decode_attr(source, &attr, &color); 324 source = decode_char(source, &value); 325 *target = (ChCharOf(value) | attr | (chtype) COLOR_PAIR(color)); 326 /* FIXME - ignore combining characters */ 327 return source; 328 } 329 330 #if NCURSES_WIDECHAR 331 static char * 332 decode_cchar(char *source, cchar_t *fillin, cchar_t *target) 333 { 334 int color; 335 attr_t attr = fillin->attr; 336 wchar_t chars[CCHARW_MAX]; 337 int append = 0; 338 int value = 0; 339 340 T(("decode_cchar '%s'", source)); 341 *target = blank; 342 #if NCURSES_EXT_COLORS 343 color = fillin->ext_color; 344 #else 345 color = (int) PAIR_NUMBER(attr); 346 #endif 347 source = decode_attr(source, &attr, &color); 348 memset(chars, 0, sizeof(chars)); 349 source = decode_char(source, &value); 350 chars[0] = (wchar_t) value; 351 /* handle combining characters */ 352 while (source[0] == MARKER && source[1] == APPEND) { 353 source += 2; 354 source = decode_char(source, &value); 355 if (++append < CCHARW_MAX) { 356 chars[append] = (wchar_t) value; 357 } 358 } 359 setcchar(target, chars, attr, (short) color, NULL); 360 return source; 361 } 362 #endif 363 364 static int 365 read_win(WINDOW *win, FILE *fp) 366 { 367 int code = ERR; 368 char *txt; 369 char *name; 370 char *value; 371 size_t n; 372 int color; 373 #if NCURSES_WIDECHAR 374 NCURSES_CH_T prior; 375 #endif 376 chtype prior2; 377 378 memset(win, 0, sizeof(WINDOW)); 379 for (;;) { 380 txt = read_txt(fp); 381 if (txt == 0) 382 break; 383 if (!strcmp(txt, "rows:")) { 384 free(txt); 385 code = OK; 386 break; 387 } 388 if ((value = strchr(txt, '=')) == 0) { 389 free(txt); 390 continue; 391 } 392 *value++ = '\0'; 393 name = !strcmp(txt, "flag") ? value : txt; 394 for (n = 0; n < SIZEOF(scr_params); ++n) { 395 if (!strcmp(name, scr_params[n].name)) { 396 void *data = (void *) ((char *) win + scr_params[n].offset); 397 398 switch (scr_params[n].type) { 399 case pATTR: 400 (void) decode_attr(value, data, &color); 401 break; 402 case pBOOL: 403 *(bool *) data = TRUE; 404 break; 405 case pCHAR: 406 prior2 = ' '; 407 decode_chtype(value, prior2, data); 408 break; 409 case pINT: 410 *(int *) data = atoi(value); 411 break; 412 case pSHORT: 413 *(short *) data = (short) atoi(value); 414 break; 415 case pSIZE: 416 *(NCURSES_SIZE_T *) data = (NCURSES_SIZE_T) atoi(value); 417 break; 418 #if NCURSES_WIDECHAR 419 case pCCHAR: 420 prior = blank; 421 decode_cchar(value, &prior, data); 422 break; 423 #endif 424 } 425 break; 426 } 427 } 428 free(txt); 429 } 430 return code; 431 } 432 433 static int 434 read_row(char *source, NCURSES_CH_T * prior, NCURSES_CH_T * target, int length) 435 { 436 while (*source != '\0' && length > 0) { 437 #if NCURSES_WIDECHAR 438 int n, len; 439 source = decode_cchar(source, prior, target); 440 len = wcwidth(target->chars[0]); 441 if (len > 1) { 442 SetWidecExt(CHDEREF(target), 0); 443 for (n = 1; n < len; ++n) { 444 target[n] = target[0]; 445 SetWidecExt(CHDEREF(target), n); 446 } 447 target += (len - 1); 448 length -= (len - 1); 449 } 450 #else 451 source = decode_chtype(source, *prior, target); 452 #endif 453 *prior = *target; 454 ++target; 455 --length; 456 } 457 while (length-- > 0) { 458 *target++ = blank; 459 } 460 /* FIXME - see what error conditions should apply if I need to return ERR */ 461 return 0; 462 } 463 #endif /* NCURSES_EXT_PUTWIN */ 464 465 /* 466 * Originally, getwin/putwin used fread/fwrite, because they used binary data. 467 * The new format uses printable ASCII, which does not have as predictable 468 * sizes. Consequently, we use buffered I/O, e.g., fgetc/fprintf, which need 469 * special handling if we want to read screen dumps from an older library. 470 */ 471 static int 472 read_block(void *target, size_t length, FILE *fp) 473 { 474 int result = 0; 475 char *buffer = target; 476 477 clearerr(fp); 478 while (length-- != 0) { 479 int ch = fgetc(fp); 480 if (ch == EOF) { 481 result = -1; 482 break; 483 } 484 *buffer++ = (char) ch; 485 } 486 return result; 487 } 488 489 NCURSES_EXPORT(WINDOW *) 490 NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep) 491 { 492 WINDOW tmp, *nwin; 493 int n; 494 bool old_format = FALSE; 495 496 T((T_CALLED("getwin(%p)"), (void *) filep)); 497 498 if (filep == 0) { 499 returnWin(0); 500 } 501 502 /* 503 * Read the first 4 bytes to determine first if this is an old-format 504 * screen-dump, or new-format. 505 */ 506 if (read_block(&tmp, 4, filep) < 0) { 507 returnWin(0); 508 } 509 /* 510 * If this is a new-format file, and we do not support it, give up. 511 */ 512 if (!memcmp(&tmp, my_magic, 4)) { 513 #if NCURSES_EXT_PUTWIN 514 if (read_win(&tmp, filep) < 0) 515 #endif 516 returnWin(0); 517 } else if (read_block(((char *) &tmp) + 4, sizeof(WINDOW) - 4, filep) < 0) { 518 returnWin(0); 519 } else { 520 old_format = TRUE; 521 } 522 523 /* 524 * Check the window-size: 525 */ 526 if (tmp._maxy == 0 || 527 tmp._maxy > MAX_SIZE || 528 tmp._maxx == 0 || 529 tmp._maxx > MAX_SIZE) { 530 returnWin(0); 531 } 532 533 if (tmp._flags & _ISPAD) { 534 nwin = NCURSES_SP_NAME(newpad) (NCURSES_SP_ARGx 535 tmp._maxy + 1, 536 tmp._maxx + 1); 537 } else { 538 nwin = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx 539 tmp._maxy + 1, 540 tmp._maxx + 1, 0, 0); 541 } 542 543 /* 544 * We deliberately do not restore the _parx, _pary, or _parent 545 * fields, because the window hierarchy within which they 546 * made sense is probably gone. 547 */ 548 if (nwin != 0) { 549 size_t linesize = sizeof(NCURSES_CH_T) * (size_t) (tmp._maxx + 1); 550 551 nwin->_curx = tmp._curx; 552 nwin->_cury = tmp._cury; 553 nwin->_maxy = tmp._maxy; 554 nwin->_maxx = tmp._maxx; 555 nwin->_begy = tmp._begy; 556 nwin->_begx = tmp._begx; 557 nwin->_yoffset = tmp._yoffset; 558 nwin->_flags = tmp._flags & ~(_SUBWIN); 559 560 WINDOW_ATTRS(nwin) = WINDOW_ATTRS(&tmp); 561 nwin->_nc_bkgd = tmp._nc_bkgd; 562 563 nwin->_notimeout = tmp._notimeout; 564 nwin->_clear = tmp._clear; 565 nwin->_leaveok = tmp._leaveok; 566 nwin->_idlok = tmp._idlok; 567 nwin->_idcok = tmp._idcok; 568 nwin->_immed = tmp._immed; 569 nwin->_scroll = tmp._scroll; 570 nwin->_sync = tmp._sync; 571 nwin->_use_keypad = tmp._use_keypad; 572 nwin->_delay = tmp._delay; 573 574 nwin->_regtop = tmp._regtop; 575 nwin->_regbottom = tmp._regbottom; 576 577 if (tmp._flags & _ISPAD) 578 nwin->_pad = tmp._pad; 579 580 if (old_format) { 581 T(("reading old-format screen dump")); 582 for (n = 0; n <= nwin->_maxy; n++) { 583 if (read_block(nwin->_line[n].text, linesize, filep) < 0) { 584 delwin(nwin); 585 returnWin(0); 586 } 587 } 588 } 589 #if NCURSES_EXT_PUTWIN 590 else { 591 char *txt = 0; 592 bool success = TRUE; 593 NCURSES_CH_T prior = blank; 594 595 T(("reading new-format screen dump")); 596 for (n = 0; n <= nwin->_maxy; n++) { 597 long row; 598 char *next; 599 600 if ((txt = read_txt(filep)) == 0) { 601 T(("...failed to read string for row %d", n + 1)); 602 success = FALSE; 603 break; 604 } 605 row = strtol(txt, &next, 10); 606 if (row != (n + 1) || *next != ':') { 607 T(("...failed to read row-number %d", n + 1)); 608 success = FALSE; 609 break; 610 } 611 612 if (read_row(++next, &prior, nwin->_line[n].text, tmp._maxx 613 + 1) < 0) { 614 T(("...failed to read cells for row %d", n + 1)); 615 success = FALSE; 616 break; 617 } 618 free(txt); 619 txt = 0; 620 } 621 622 if (!success) { 623 free(txt); 624 delwin(nwin); 625 returnWin(0); 626 } 627 } 628 #endif 629 touchwin(nwin); 630 } 631 returnWin(nwin); 632 } 633 634 #if NCURSES_SP_FUNCS 635 NCURSES_EXPORT(WINDOW *) 636 getwin(FILE *filep) 637 { 638 return NCURSES_SP_NAME(getwin) (CURRENT_SCREEN, filep); 639 } 640 #endif 641 642 #if NCURSES_EXT_PUTWIN 643 static void 644 encode_attr(char *target, attr_t source, attr_t prior) 645 { 646 source &= ~A_CHARTEXT; 647 prior &= ~A_CHARTEXT; 648 649 *target = '\0'; 650 if (source != prior) { 651 size_t n; 652 bool first = TRUE; 653 654 *target++ = MARKER; 655 *target++ = L_CURL; 656 657 for (n = 0; n < SIZEOF(scr_attrs); ++n) { 658 if ((source & scr_attrs[n].attr) != 0 || 659 ((source & ALL_BUT_COLOR) == 0 && 660 (scr_attrs[n].attr == A_NORMAL))) { 661 if (first) { 662 first = FALSE; 663 } else { 664 *target++ = '|'; 665 } 666 strcpy(target, scr_attrs[n].name); 667 target += strlen(target); 668 } 669 } 670 if ((source & A_COLOR) != (prior & A_COLOR)) { 671 if (!first) 672 *target++ = '|'; 673 sprintf(target, "C%d", PAIR_NUMBER((int) source)); 674 target += strlen(target); 675 } 676 677 *target++ = R_CURL; 678 *target = '\0'; 679 } 680 } 681 682 static void 683 encode_cell(char *target, CARG_CH_T source, CARG_CH_T previous) 684 { 685 #if NCURSES_WIDECHAR 686 size_t n; 687 688 *target = '\0'; 689 if (previous->attr != source->attr) { 690 encode_attr(target, source->attr, previous->attr); 691 } 692 target += strlen(target); 693 #if NCURSES_EXT_COLORS 694 if (previous->ext_color != source->ext_color) { 695 sprintf(target, "%c%cC%d%c", MARKER, L_CURL, source->ext_color, R_CURL); 696 } 697 #endif 698 for (n = 0; n < SIZEOF(source->chars); ++n) { 699 unsigned uch = (unsigned) source->chars[n]; 700 if (uch == 0) 701 continue; 702 if (n) { 703 *target++ = MARKER; 704 *target++ = APPEND; 705 } 706 *target++ = MARKER; 707 if (uch > 0xffff) { 708 sprintf(target, "U%08x", uch); 709 } else if (uch > 0xff) { 710 sprintf(target, "u%04x", uch); 711 } else if (uch < 32 || uch >= 127) { 712 sprintf(target, "%03o", uch & 0xff); 713 } else { 714 switch (uch) { 715 case ' ': 716 strcpy(target, "s"); 717 break; 718 case MARKER: 719 *target++ = MARKER; 720 *target = '\0'; 721 break; 722 default: 723 sprintf(--target, "%c", uch); 724 break; 725 } 726 } 727 target += strlen(target); 728 } 729 #else 730 chtype ch = CharOfD(source); 731 732 *target = '\0'; 733 if (AttrOfD(previous) != AttrOfD(source)) { 734 encode_attr(target, AttrOfD(source), AttrOfD(previous)); 735 } 736 target += strlen(target); 737 *target++ = MARKER; 738 if (ch < 32 || ch >= 127) { 739 sprintf(target, "%03o", UChar(ch)); 740 } else { 741 switch (ch) { 742 case ' ': 743 strcpy(target, "s"); 744 break; 745 case MARKER: 746 *target++ = MARKER; 747 *target = '\0'; 748 break; 749 default: 750 sprintf(--target, "%c", UChar(ch)); 751 break; 752 } 753 } 754 #endif 755 } 756 #endif 757 758 NCURSES_EXPORT(int) 759 putwin(WINDOW *win, FILE *filep) 760 { 761 int code = ERR; 762 int y; 763 764 T((T_CALLED("putwin(%p,%p)"), (void *) win, (void *) filep)); 765 766 #if NCURSES_EXT_PUTWIN 767 if (win != 0) { 768 const char *version = curses_version(); 769 char buffer[1024]; 770 NCURSES_CH_T last_cell; 771 772 memset(&last_cell, 0, sizeof(last_cell)); 773 774 clearerr(filep); 775 776 /* 777 * Our magic number is technically nonprinting, but aside from that, 778 * all of the file is printable ASCII. 779 */ 780 #define PUTS(s) if (fputs(s, filep) == EOF || ferror(filep)) returnCode(code) 781 PUTS(my_magic); 782 PUTS(version); 783 PUTS("\n"); 784 for (y = 0; y < (int) SIZEOF(scr_params); ++y) { 785 const char *name = scr_params[y].name; 786 const char *data = (char *) win + scr_params[y].offset; 787 const void *dp = (const void *) data; 788 789 *buffer = '\0'; 790 if (!strncmp(name, "_pad.", 5) && !(win->_flags & _ISPAD)) { 791 continue; 792 } 793 switch (scr_params[y].type) { 794 case pATTR: 795 encode_attr(buffer, (*(const attr_t *) dp) & ~A_CHARTEXT, A_NORMAL); 796 break; 797 case pBOOL: 798 if (!(*(const bool *) data)) { 799 continue; 800 } 801 strcpy(buffer, name); 802 name = "flag"; 803 break; 804 case pCHAR: 805 encode_attr(buffer, *(const attr_t *) dp, A_NORMAL); 806 break; 807 case pINT: 808 if (!(*(const int *) dp)) 809 continue; 810 sprintf(buffer, "%d", *(const int *) dp); 811 break; 812 case pSHORT: 813 if (!(*(const short *) dp)) 814 continue; 815 sprintf(buffer, "%d", *(const short *) dp); 816 break; 817 case pSIZE: 818 if (!(*(const NCURSES_SIZE_T *) dp)) 819 continue; 820 sprintf(buffer, "%d", *(const NCURSES_SIZE_T *) dp); 821 break; 822 #if NCURSES_WIDECHAR 823 case pCCHAR: 824 encode_cell(buffer, (CARG_CH_T) dp, CHREF(last_cell)); 825 break; 826 #endif 827 } 828 /* 829 * Only write non-default data. 830 */ 831 if (*buffer != '\0') { 832 if (fprintf(filep, "%s=%s\n", name, buffer) <= 0 833 || ferror(filep)) 834 returnCode(code); 835 } 836 } 837 /* Write row-data */ 838 fprintf(filep, "rows:\n"); 839 for (y = 0; y <= win->_maxy; y++) { 840 NCURSES_CH_T *data = win->_line[y].text; 841 int x; 842 if (fprintf(filep, "%d:", y + 1) <= 0 843 || ferror(filep)) 844 returnCode(code); 845 for (x = 0; x <= win->_maxx; x++) { 846 #if NCURSES_WIDECHAR 847 int len = wcwidth(data[x].chars[0]); 848 encode_cell(buffer, CHREF(data[x]), CHREF(last_cell)); 849 last_cell = data[x]; 850 PUTS(buffer); 851 if (len > 1) 852 x += (len - 1); 853 #else 854 encode_cell(buffer, CHREF(data[x]), CHREF(last_cell)); 855 last_cell = data[x]; 856 PUTS(buffer); 857 #endif 858 } 859 PUTS("\n"); 860 } 861 } 862 #else 863 /* 864 * This is the original putwin(): 865 * A straight binary dump is simple, but its format can depend on whether 866 * ncurses is compiled with wide-character support, and also may depend 867 * on the version of ncurses, e.g., if the WINDOW structure is extended. 868 */ 869 if (win != 0) { 870 size_t len = (size_t) (win->_maxx + 1); 871 872 clearerr(filep); 873 if (fwrite(win, sizeof(WINDOW), (size_t) 1, filep) != 1 874 || ferror(filep)) 875 returnCode(code); 876 877 for (y = 0; y <= win->_maxy; y++) { 878 if (fwrite(win->_line[y].text, 879 sizeof(NCURSES_CH_T), len, filep) != len 880 || ferror(filep)) { 881 returnCode(code); 882 } 883 } 884 code = OK; 885 } 886 #endif 887 returnCode(code); 888 } 889 890 NCURSES_EXPORT(int) 891 NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file) 892 { 893 FILE *fp = 0; 894 int code = ERR; 895 896 T((T_CALLED("scr_restore(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file))); 897 898 if (_nc_access(file, R_OK) >= 0 899 && (fp = fopen(file, "rb")) != 0) { 900 delwin(NewScreen(SP_PARM)); 901 NewScreen(SP_PARM) = getwin(fp); 902 #if !USE_REENTRANT 903 newscr = NewScreen(SP_PARM); 904 #endif 905 (void) fclose(fp); 906 if (NewScreen(SP_PARM) != 0) { 907 code = OK; 908 } 909 } 910 returnCode(code); 911 } 912 913 #if NCURSES_SP_FUNCS 914 NCURSES_EXPORT(int) 915 scr_restore(const char *file) 916 { 917 return NCURSES_SP_NAME(scr_restore) (CURRENT_SCREEN, file); 918 } 919 #endif 920 921 NCURSES_EXPORT(int) 922 scr_dump(const char *file) 923 { 924 int result; 925 FILE *fp = 0; 926 927 T((T_CALLED("scr_dump(%s)"), _nc_visbuf(file))); 928 929 if (_nc_access(file, W_OK) < 0 930 || (fp = fopen(file, "wb")) == 0) { 931 result = ERR; 932 } else { 933 (void) putwin(newscr, fp); 934 (void) fclose(fp); 935 result = OK; 936 } 937 returnCode(result); 938 } 939 940 NCURSES_EXPORT(int) 941 NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file) 942 { 943 FILE *fp = 0; 944 int code = ERR; 945 946 T((T_CALLED("scr_init(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file))); 947 948 if (SP_PARM != 0 && 949 #ifdef USE_TERM_DRIVER 950 InfoOf(SP_PARM).caninit 951 #else 952 !(exit_ca_mode && non_rev_rmcup) 953 #endif 954 ) { 955 if (_nc_access(file, R_OK) >= 0 956 && (fp = fopen(file, "rb")) != 0) { 957 delwin(CurScreen(SP_PARM)); 958 CurScreen(SP_PARM) = getwin(fp); 959 #if !USE_REENTRANT 960 curscr = CurScreen(SP_PARM); 961 #endif 962 (void) fclose(fp); 963 if (CurScreen(SP_PARM) != 0) { 964 code = OK; 965 } 966 } 967 } 968 returnCode(code); 969 } 970 971 #if NCURSES_SP_FUNCS 972 NCURSES_EXPORT(int) 973 scr_init(const char *file) 974 { 975 return NCURSES_SP_NAME(scr_init) (CURRENT_SCREEN, file); 976 } 977 #endif 978 979 NCURSES_EXPORT(int) 980 NCURSES_SP_NAME(scr_set) (NCURSES_SP_DCLx const char *file) 981 { 982 int code = ERR; 983 984 T((T_CALLED("scr_set(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file))); 985 986 if (NCURSES_SP_NAME(scr_init) (NCURSES_SP_ARGx file) == OK) { 987 delwin(NewScreen(SP_PARM)); 988 NewScreen(SP_PARM) = dupwin(curscr); 989 #if !USE_REENTRANT 990 newscr = NewScreen(SP_PARM); 991 #endif 992 if (NewScreen(SP_PARM) != 0) { 993 code = OK; 994 } 995 } 996 returnCode(code); 997 } 998 999 #if NCURSES_SP_FUNCS 1000 NCURSES_EXPORT(int) 1001 scr_set(const char *file) 1002 { 1003 return NCURSES_SP_NAME(scr_set) (CURRENT_SCREEN, file); 1004 } 1005 #endif 1006