1 /****************************************************************************
2 * Copyright (c) 1998-2011,2015 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
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 ****************************************************************************/
36 #include <curses.priv.h>
41 #define CUR SP_TERMTYPE
44 MODULE_ID("$Id: lib_screen.c,v 1.64 2015/03/21 23:59:32 tom Exp $")
46 #define MAX_SIZE 0x3fff /* 16k is big enough for a window or pad */
57 * Use 0x8888 as the magic number for new-format files, since it cannot be
58 * mistaken for the _cury/_curx pair of 16-bit numbers which start the old
59 * format. It happens to be unused in the file 5.22 database (2015/03/07).
61 static char my_magic[] =
62 {'\210', '\210', '\210', '\210'};
64 #if NCURSES_EXT_SCREEN_DUMP
71 ,pSIZE /* NCURSES_SIZE_T */
89 #define DATA(name) { #name, A_##name }
90 static SCR_ATTRS scr_attrs[] =
115 #define sizeof2(type,name) sizeof(((type *)0)->name)
116 #define DATA(name, type) { #name, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) }
118 static SCR_PARAMS scr_params[] =
126 DATA(_flags, pSHORT),
129 DATA(_notimeout, pBOOL),
131 DATA(_leaveok, pBOOL),
132 DATA(_scroll, pBOOL),
137 DATA(_use_keypad, pBOOL),
139 DATA(_regtop, pSIZE),
140 DATA(_regbottom, pSIZE),
141 DATA(_pad._pad_y, pSIZE),
142 DATA(_pad._pad_x, pSIZE),
143 DATA(_pad._pad_top, pSIZE),
144 DATA(_pad._pad_left, pSIZE),
145 DATA(_pad._pad_bottom, pSIZE),
146 DATA(_pad._pad_right, pSIZE),
147 DATA(_yoffset, pSIZE),
149 DATA(_bkgrnd, pCCHAR),
150 #if NCURSES_EXT_COLORS
157 static const NCURSES_CH_T blank = NewChar(BLANK_TEXT);
160 * Allocate and read a line of text. Caller must free it.
167 char *result = malloc(limit);
176 if (used + 2 >= limit) {
178 buffer = realloc(result, limit);
188 result[used++] = (char) ch;
190 } while (ch != '\n');
193 result[--used] = '\0';
194 T(("READ:%s", result));
195 } else if (used == 0) {
204 decode_attr(char *source, attr_t *target, int *color)
208 T(("decode_attr '%s'", source));
211 if (source[0] == MARKER && source[1] == L_CURL) {
214 } else if (source[0] == R_CURL) {
221 if (source[0] == GUTTER) {
223 } else if (*next == 'C') {
226 while (isdigit(UChar(*next))) {
227 value = value * 10 + (*next++ - '0');
231 *target |= COLOR_PAIR(255);
233 *target |= COLOR_PAIR(value);
237 while (isalnum(UChar(*next))) {
240 for (n = 0; n < SIZEOF(scr_attrs); ++n) {
241 if ((size_t) (next - source) == strlen(scr_attrs[n].name)) {
242 if (scr_attrs[n].attr) {
243 *target |= scr_attrs[n].attr;
260 decode_char(char *source, int *target)
264 const char digits[] = "0123456789abcdef";
266 T(("decode_char '%s'", source));
297 while (limit-- > 0) {
298 char *find = strchr(digits, *source++);
299 int ch = (find != 0) ? (int) (find - digits) : -1;
301 if (ch >= 0 && ch < base) {
315 decode_chtype(char *source, chtype fillin, chtype *target)
317 attr_t attr = ChAttrOf(fillin);
318 int color = PAIR_NUMBER(attr);
321 T(("decode_chtype '%s'", source));
322 source = decode_attr(source, &attr, &color);
323 source = decode_char(source, &value);
324 *target = ChCharOf(value) | attr | COLOR_PAIR(color);
330 decode_cchar(char *source, cchar_t *fillin, cchar_t *target)
333 attr_t attr = fillin->attr;
334 wchar_t chars[CCHARW_MAX];
336 T(("decode_cchar '%s'", source));
338 #if NCURSES_EXT_COLORS
339 color = fillin->ext_color;
341 color = (int) PAIR_NUMBER(attr);
343 source = decode_attr(source, &attr, &color);
344 memset(chars, 0, sizeof(chars));
345 source = decode_char(source, &chars[0]);
346 /* FIXME - handle combining characters at this point */
347 setcchar(target, chars, attr, (short) color, NULL);
353 read_win(WINDOW *win, FILE *fp)
366 memset(win, 0, sizeof(WINDOW));
371 if (!strcmp(txt, "rows:")) {
376 if ((value = strchr(txt, '=')) == 0) {
381 name = !strcmp(txt, "flag") ? value : txt;
382 for (n = 0; n < SIZEOF(scr_params); ++n) {
383 if (!strcmp(name, scr_params[n].name)) {
384 void *data = (void *) ((char *) win + scr_params[n].offset);
386 switch (scr_params[n].type) {
388 (void) decode_attr(value, data, &color);
391 *(bool *) data = TRUE;
395 decode_chtype(value, prior2, data);
398 *(int *) data = atoi(value);
401 *(short *) data = (short) atoi(value);
404 *(NCURSES_SIZE_T *) data = (NCURSES_SIZE_T) atoi(value);
409 decode_cchar(value, &prior, data);
422 read_row(char *source, NCURSES_CH_T * prior, NCURSES_CH_T * target, int length)
424 while (*source != '\0' && length > 0) {
426 source = decode_cchar(source, prior, target);
428 source = decode_chtype(source, *prior, target);
434 while (length-- > 0) {
437 /* FIXME - see what error conditions should apply if I need to return ERR */
440 #endif /* NCURSES_EXT_SCREEN_DUMP */
443 * Originally, getwin/putwin used fread/fwrite, because they used binary data.
444 * The new format uses printable ASCII, which does not have as predictable
445 * sizes. Consequently, we use buffered I/O, e.g., fgetc/fprintf, which need
446 * special handling if we want to read screen dumps from an older library.
449 read_block(void *target, size_t length, FILE *fp)
452 char *buffer = target;
455 while (length-- != 0) {
461 *buffer++ = (char) ch;
466 NCURSES_EXPORT(WINDOW *)
467 NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep)
471 bool old_format = FALSE;
473 T((T_CALLED("getwin(%p)"), (void *) filep));
480 * Read the first 4 bytes to determine first if this is an old-format
481 * screen-dump, or new-format.
483 if (read_block(&tmp, 4, filep) < 0) {
487 * If this is a new-format file, and we do not support it, give up.
489 if (!memcmp(&tmp, my_magic, 4)) {
490 #if NCURSES_EXT_SCREEN_DUMP
491 if (read_win(&tmp, filep) < 0)
494 } else if (read_block(((char *) &tmp) + 4, sizeof(WINDOW) - 4, filep) < 0) {
501 * Check the window-size:
503 if (tmp._maxy == 0 ||
504 tmp._maxy > MAX_SIZE ||
506 tmp._maxx > MAX_SIZE) {
510 if (tmp._flags & _ISPAD) {
511 nwin = NCURSES_SP_NAME(newpad) (NCURSES_SP_ARGx
515 nwin = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
517 tmp._maxx + 1, 0, 0);
521 * We deliberately do not restore the _parx, _pary, or _parent
522 * fields, because the window hierarchy within which they
523 * made sense is probably gone.
526 size_t linesize = sizeof(NCURSES_CH_T) * (size_t) (tmp._maxx + 1);
528 nwin->_curx = tmp._curx;
529 nwin->_cury = tmp._cury;
530 nwin->_maxy = tmp._maxy;
531 nwin->_maxx = tmp._maxx;
532 nwin->_begy = tmp._begy;
533 nwin->_begx = tmp._begx;
534 nwin->_yoffset = tmp._yoffset;
535 nwin->_flags = tmp._flags & ~(_SUBWIN);
537 WINDOW_ATTRS(nwin) = WINDOW_ATTRS(&tmp);
538 nwin->_nc_bkgd = tmp._nc_bkgd;
540 nwin->_notimeout = tmp._notimeout;
541 nwin->_clear = tmp._clear;
542 nwin->_leaveok = tmp._leaveok;
543 nwin->_idlok = tmp._idlok;
544 nwin->_idcok = tmp._idcok;
545 nwin->_immed = tmp._immed;
546 nwin->_scroll = tmp._scroll;
547 nwin->_sync = tmp._sync;
548 nwin->_use_keypad = tmp._use_keypad;
549 nwin->_delay = tmp._delay;
551 nwin->_regtop = tmp._regtop;
552 nwin->_regbottom = tmp._regbottom;
554 if (tmp._flags & _ISPAD)
555 nwin->_pad = tmp._pad;
558 T(("reading old-format screen dump"));
559 for (n = 0; n <= nwin->_maxy; n++) {
560 if (read_block(nwin->_line[n].text, linesize, filep) < 0) {
566 #if NCURSES_EXT_SCREEN_DUMP
570 NCURSES_CH_T prior = blank;
572 T(("reading new-format screen dump"));
573 for (n = 0; n <= nwin->_maxy; n++) {
577 if ((txt = read_txt(filep)) == 0) {
578 T(("...failed to read string for row %d", n + 1));
582 row = strtol(txt, &next, 10);
583 if (row != (n + 1) || *next != ':') {
584 T(("...failed to read row-number %d", n + 1));
589 if (read_row(++next, &prior, nwin->_line[n].text, tmp._maxx
591 T(("...failed to read cells for row %d", n + 1));
612 NCURSES_EXPORT(WINDOW *)
615 return NCURSES_SP_NAME(getwin) (CURRENT_SCREEN, filep);
619 #if NCURSES_EXT_SCREEN_DUMP
621 encode_attr(char *target, attr_t source, attr_t prior)
624 if (source != prior) {
628 strcpy(target, L_MARK);
629 target += strlen(target);
631 for (n = 0; n < SIZEOF(scr_attrs); ++n) {
632 if ((source & scr_attrs[n].attr) != 0 ||
633 ((source & ALL_BUT_COLOR) == 0 &&
634 (scr_attrs[n].attr == A_NORMAL))) {
640 strcpy(target, scr_attrs[n].name);
641 target += strlen(target);
644 if ((source & A_COLOR) != (prior & A_COLOR)) {
647 sprintf(target, "C%d", PAIR_NUMBER(source));
648 target += strlen(target);
651 strcpy(target, R_MARK);
656 encode_cell(char *target, CARG_CH_T source, CARG_CH_T previous)
662 if (previous->attr != source->attr) {
663 encode_attr(target, source->attr, previous->attr);
665 target += strlen(target);
666 #if NCURSES_EXT_COLORS
667 if (previous->ext_color != source->ext_color) {
668 sprintf(target, "%sC%d%s", L_MARK, source->ext_color, R_MARK);
671 for (n = 0; n < SIZEOF(source->chars); ++n) {
672 if (source->chars[n] == 0)
674 if (source->chars[n] > 0xffff) {
675 sprintf(target, "\\U%08x", source->chars[n]);
676 } else if (source->chars[n] > 0xff) {
677 sprintf(target, "\\u%04x", source->chars[n]);
678 } else if (source->chars[n] < 32 || source->chars[n] >= 127) {
679 sprintf(target, "\\%03o", source->chars[n] & 0xff);
681 switch (source->chars[n]) {
683 strcpy(target, "\\s");
686 strcpy(target, "\\\\");
689 sprintf(target, "%c", source->chars[n]);
693 target += strlen(target);
696 chtype ch = CharOfD(source);
699 if (AttrOfD(previous) != AttrOfD(source)) {
700 encode_attr(target, AttrOfD(source), AttrOfD(previous));
702 target += strlen(target);
703 if (ch < 32 || ch >= 127) {
704 sprintf(target, "\\%03o", ch);
708 strcpy(target, "\\s");
711 strcpy(target, "\\\\");
714 sprintf(target, "%c", ch);
718 target += strlen(target);
724 putwin(WINDOW *win, FILE *filep)
729 T((T_CALLED("putwin(%p,%p)"), (void *) win, (void *) filep));
731 #if NCURSES_EXT_SCREEN_DUMP
733 const char *version = curses_version();
735 NCURSES_CH_T last_cell;
737 memset(&last_cell, 0, sizeof(last_cell));
742 * Our magic number is technically nonprinting, but aside from that,
743 * all of the file is printable ASCII.
745 #define PUTS(s) if (fputs(s, filep) == EOF || ferror(filep)) returnCode(code)
749 for (y = 0; y < (int) SIZEOF(scr_params); ++y) {
750 const char *name = scr_params[y].name;
751 const char *data = (char *) win + scr_params[y].offset;
752 const void *dp = (const void *) data;
755 if (!strncmp(name, "_pad.", 5) && !(win->_flags & _ISPAD)) {
758 switch (scr_params[y].type) {
760 encode_attr(buffer, (*(const attr_t *) dp) & ~A_CHARTEXT, A_NORMAL);
763 if (!(*(const bool *) data)) {
766 strcpy(buffer, name);
770 encode_attr(buffer, *(const attr_t *) dp, A_NORMAL);
773 if (!(*(const int *) dp))
775 sprintf(buffer, "%d", *(const int *) dp);
778 if (!(*(const short *) dp))
780 sprintf(buffer, "%d", *(const short *) dp);
783 if (!(*(const NCURSES_SIZE_T *) dp))
785 sprintf(buffer, "%d", *(const NCURSES_SIZE_T *) dp);
789 encode_cell(buffer, (CARG_CH_T) dp, CHREF(last_cell));
794 * Only write non-default data.
796 if (*buffer != '\0') {
797 if (fprintf(filep, "%s=%s\n", name, buffer) <= 0
803 fprintf(filep, "rows:\n");
804 for (y = 0; y <= win->_maxy; y++) {
805 NCURSES_CH_T *data = win->_line[y].text;
807 if (fprintf(filep, "%d:", y + 1) <= 0
810 for (x = 0; x <= win->_maxx; x++) {
811 encode_cell(buffer, CHREF(data[x]), CHREF(last_cell));
820 * This is the original putwin():
821 * A straight binary dump is simple, but its format can depend on whether
822 * ncurses is compiled with wide-character support, and also may depend
823 * on the version of ncurses, e.g., if the WINDOW structure is extended.
826 size_t len = (size_t) (win->_maxx + 1);
829 if (fwrite(win, sizeof(WINDOW), (size_t) 1, filep) != 1
833 for (y = 0; y <= win->_maxy; y++) {
834 if (fwrite(win->_line[y].text,
835 sizeof(NCURSES_CH_T), len, filep) != len
847 NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file)
852 T((T_CALLED("scr_restore(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
854 if (_nc_access(file, R_OK) >= 0
855 && (fp = fopen(file, "rb")) != 0) {
856 delwin(NewScreen(SP_PARM));
857 NewScreen(SP_PARM) = getwin(fp);
859 newscr = NewScreen(SP_PARM);
862 if (NewScreen(SP_PARM) != 0) {
871 scr_restore(const char *file)
873 return NCURSES_SP_NAME(scr_restore) (CURRENT_SCREEN, file);
878 scr_dump(const char *file)
883 T((T_CALLED("scr_dump(%s)"), _nc_visbuf(file)));
885 if (_nc_access(file, W_OK) < 0
886 || (fp = fopen(file, "wb")) == 0) {
889 (void) putwin(newscr, fp);
897 NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file)
902 T((T_CALLED("scr_init(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
905 #ifdef USE_TERM_DRIVER
906 InfoOf(SP_PARM).caninit
908 !(exit_ca_mode && non_rev_rmcup)
911 if (_nc_access(file, R_OK) >= 0
912 && (fp = fopen(file, "rb")) != 0) {
913 delwin(CurScreen(SP_PARM));
914 CurScreen(SP_PARM) = getwin(fp);
916 curscr = CurScreen(SP_PARM);
919 if (CurScreen(SP_PARM) != 0) {
929 scr_init(const char *file)
931 return NCURSES_SP_NAME(scr_init) (CURRENT_SCREEN, file);
936 NCURSES_SP_NAME(scr_set) (NCURSES_SP_DCLx const char *file)
940 T((T_CALLED("scr_set(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
942 if (NCURSES_SP_NAME(scr_init) (NCURSES_SP_ARGx file) == OK) {
943 delwin(NewScreen(SP_PARM));
944 NewScreen(SP_PARM) = dupwin(curscr);
946 newscr = NewScreen(SP_PARM);
948 if (NewScreen(SP_PARM) != 0) {
957 scr_set(const char *file)
959 return NCURSES_SP_NAME(scr_set) (CURRENT_SCREEN, file);