From 87f20fc6e737084b06b6343c8c7206404daec4a2 Mon Sep 17 00:00:00 2001 From: "Thomas E. Dickey" Date: Sun, 22 Mar 2015 01:12:56 +0000 Subject: [PATCH] ncurses 5.9 - patch 20150321 + in-progress changes to provide an extended version of putwin and getwin which will be capable of reading screen-dumps between the wide/normal ncurses configurations. These are text files, except for a magic code at the beginning: 0 string \210\210 Screen-dump (ncurses) --- NEWS | 9 +- VERSION | 2 +- dist.mk | 4 +- include/ncurses_defs | 5 +- man/curs_util.3x | 83 ++-- ncurses/base/lib_screen.c | 742 +++++++++++++++++++++++++++++-- package/debian-mingw/changelog | 4 +- package/debian-mingw64/changelog | 4 +- package/debian/changelog | 4 +- package/mingw-ncurses.nsi | 4 +- package/mingw-ncurses.spec | 2 +- package/ncurses.spec | 2 +- progs/tset.c | 10 +- test/savescreen.c | 19 +- 14 files changed, 816 insertions(+), 78 deletions(-) diff --git a/NEWS b/NEWS index 7ede0a20..ab171a15 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,7 @@ -- sale, use or other dealings in this Software without prior written -- -- authorization. -- ------------------------------------------------------------------------------- --- $Id: NEWS,v 1.2357 2015/03/07 23:38:25 tom Exp $ +-- $Id: NEWS,v 1.2360 2015/03/21 23:44:50 tom Exp $ ------------------------------------------------------------------------------- This is a log of changes that ncurses has gone through since Zeyd started @@ -45,6 +45,13 @@ See the AUTHORS file for the corresponding full names. Changes through 1.9.9e did not credit all contributions; it is not possible to add this information. +20150321 + + in-progress changes to provide an extended version of putwin and + getwin which will be capable of reading screen-dumps between the + wide/normal ncurses configurations. These are text files, except + for a magic code at the beginning: + 0 string \210\210 Screen-dump (ncurses) + 20150307 + document limitations of getwin in manual page (prompted by discussion with John S Urban). diff --git a/VERSION b/VERSION index d602f6c3..3dc8c803 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5:0:9 5.9 20150307 +5:0:9 5.9 20150321 diff --git a/dist.mk b/dist.mk index 04650d0e..a6574f40 100644 --- a/dist.mk +++ b/dist.mk @@ -25,7 +25,7 @@ # use or other dealings in this Software without prior written # # authorization. # ############################################################################## -# $Id: dist.mk,v 1.1037 2015/03/07 16:12:58 tom Exp $ +# $Id: dist.mk,v 1.1039 2015/03/21 16:25:11 tom Exp $ # Makefile for creating ncurses distributions. # # This only needs to be used directly as a makefile by developers, but @@ -37,7 +37,7 @@ SHELL = /bin/sh # These define the major/minor/patch versions of ncurses. NCURSES_MAJOR = 5 NCURSES_MINOR = 9 -NCURSES_PATCH = 20150307 +NCURSES_PATCH = 20150321 # We don't append the patch to the version, since this only applies to releases VERSION = $(NCURSES_MAJOR).$(NCURSES_MINOR) diff --git a/include/ncurses_defs b/include/ncurses_defs index 5a63b256..73811182 100644 --- a/include/ncurses_defs +++ b/include/ncurses_defs @@ -1,6 +1,6 @@ -# $Id: ncurses_defs,v 1.66 2014/09/05 08:46:16 tom Exp $ +# $Id: ncurses_defs,v 1.68 2015/03/21 16:52:07 tom Exp $ ############################################################################## -# Copyright (c) 2000-2013,2014 Free Software Foundation, Inc. # +# Copyright (c) 2000-2014,2015 Free Software Foundation, Inc. # # # # Permission is hereby granted, free of charge, to any person obtaining a # # copy of this software and associated documentation files (the "Software"), # @@ -189,6 +189,7 @@ NCURSES_CHAR_EQ NCURSES_EXPANDED NCURSES_EXT_COLORS NCURSES_EXT_FUNCS +NCURSES_EXT_SCREEN_DUMP NCURSES_NO_PADDING NCURSES_OSPEED_COMPAT NCURSES_PATHSEP ':' diff --git a/man/curs_util.3x b/man/curs_util.3x index a0c05fe4..1b7b9e80 100644 --- a/man/curs_util.3x +++ b/man/curs_util.3x @@ -27,7 +27,7 @@ .\" authorization. * .\"*************************************************************************** .\" -.\" $Id: curs_util.3x,v 1.38 2015/03/07 23:33:38 tom Exp $ +.\" $Id: curs_util.3x,v 1.40 2015/03/15 13:58:59 tom Exp $ .TH curs_util 3X "" .ie \n(.g .ds `` \(lq .el .ds `` `` @@ -90,7 +90,6 @@ a wide character. .PP The \fBkeyname\fR routine returns a character string corresponding to the key \fIc\fR: -.RS 3 .bP Printable characters are displayed as themselves, e.g., a one-character string containing the key. @@ -113,7 +112,6 @@ Otherwise (if there is no corresponding name) the function returns null, to denote an error. X/Open also lists an "UNKNOWN KEY" return value, which some implementations return rather than null. -.RE .LP The corresponding \fBkey_name\fR returns a character string corresponding to the wide-character value \fIw\fR. @@ -216,6 +214,7 @@ the data written is a copy of the \fBWINDOW\fP structure, and its associated character cells. The format differs between the wide-character (ncursesw) and non-wide (ncurses) libraries. +You can transfer data between the two, however. .bP the retrieved window is always created as a top-level window (or pad), rather than a subwindow. @@ -256,11 +255,65 @@ returns an error if the terminal was not initialized. returns an error if the associated \fBfwrite\fP calls return an error. .RE .SH PORTABILITY +.SS filter +.PP +The SVr4 documentation describes the action of \fBfilter\fR only in the vaguest +terms. +The description here is adapted from the XSI Curses standard (which +erroneously fails to describe the disabling of \fBcuu\fR). +.SS keyname +.PP +The \fBkeyname\fP function may return the names of user-defined +string capabilities which are defined in the terminfo entry via the \fB\-x\fP +option of \fB@TIC@\fP. +This implementation automatically assigns at run-time keycodes to +user-defined strings which begin with "k". +The keycodes start at KEY_MAX, but are not guaranteed to be +the same value for different runs because user-defined codes are +merged from all terminal descriptions which have been loaded. +The \fBuse_extended_names\fP function controls whether this data is +loaded when the terminal description is read by the library. +.SS nofilter/use_tioctl +.PP +The \fBnofilter\fP and \fBuse_tioctl\fP routines are specific to ncurses. +They were not supported on Version 7, BSD or System V implementations. +It is recommended that any code depending on ncurses extensions +be conditioned using NCURSES_VERSION. +.SS putwin/getwin +.PP +The \fBputwin\fP and \fBgetwin\fP functions have several issues with +portability: +.bP +The files written and read by these functions +use an implementation-specific format. +Although the format is an obvious target for standardization, +it has been overlooked. +.IP +Interestingly enough, according to the copyright dates in Solaris source, +the functions (along with \fBscr_init\fP, etc.) originated with +the University of California, Berkeley (in 1982) +and were later (in 1988) incorporated into SVr4. +Oddly, there are no such functions in the 4.3BSD curses sources. +.bP +Most implementations simply dump the binary \fBWINDOW\fP structure to the file. +These include SVr4 curses, NetBSD and PDCurses, as well as older ncurses versions. +This implementation (as well as the X/Open variant of Solaris curses, dated 1995) +uses textual dumps. +.IP +The implementations which use binary dumps use block-I/O +(the \fBfwrite\fP and \fBfread\fP functions). +Those that use textual dumps use buffered-I/O. +A few applications may happen to write extra data in the file using +these functions. +Doing that can run into problems mixing block- and buffered-I/O. +This implementation reduces the problem on writes by flushing the output. +However, reading from a file written using mixed schemes may not be succesful. +.SS unctrl/wunctrl +.PP The XSI Curses standard, Issue 4 describes these functions. It states that \fBunctrl\fR and \fBwunctrl\fR will return a null pointer if unsuccessful, but does not define any error conditions. This implementation checks for three cases: -.RS 3 .bP the parameter is a 7-bit US\-ASCII code. This is the case that X/Open Curses documented. @@ -279,12 +332,6 @@ and returns the \*(``~@\*('', etc., values in that case. .bP parameter values outside the 0 to 255 range. \fBunctrl\fP returns a null pointer. -.RE -.PP -The SVr4 documentation describes the action of \fBfilter\fR only in the vaguest -terms. -The description here is adapted from the XSI Curses standard (which -erroneously fails to describe the disabling of \fBcuu\fR). .PP The strings returned by \fBunctrl\fR in this implementation are determined at compile time, @@ -309,22 +356,6 @@ X/Open Curses does not document the treatment of codes 128 to 159. When treating them as \*(``meta\*('' keys (or if \fBkeyname\fP is called before initializing curses), this implementation returns strings \*(``M\-^@\*('', \*(``M\-^A\*('', etc. -.PP -The \fBkeyname\fP function may return the names of user-defined -string capabilities which are defined in the terminfo entry via the \fB\-x\fP -option of \fB@TIC@\fP. -This implementation automatically assigns at run-time keycodes to -user-defined strings which begin with "k". -The keycodes start at KEY_MAX, but are not guaranteed to be -the same value for different runs because user-defined codes are -merged from all terminal descriptions which have been loaded. -The \fBuse_extended_names\fP function controls whether this data is -loaded when the terminal description is read by the library. -.PP -The \fBnofilter\fP and \fBuse_tioctl\fP routines are specific to ncurses. -They were not supported on Version 7, BSD or System V implementations. -It is recommended that any code depending on ncurses extensions -be conditioned using NCURSES_VERSION. .SH SEE ALSO \fBlegacy_coding\fR(3X), \fBcurses\fR(3X), diff --git a/ncurses/base/lib_screen.c b/ncurses/base/lib_screen.c index 695ed30e..63ef7f5b 100644 --- a/ncurses/base/lib_screen.c +++ b/ncurses/base/lib_screen.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2009,2011 Free Software Foundation, Inc. * + * Copyright (c) 1998-2011,2015 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -35,32 +35,475 @@ #include +#include + #ifndef CUR #define CUR SP_TERMTYPE #endif -MODULE_ID("$Id: lib_screen.c,v 1.41 2011/10/22 15:03:11 tom Exp $") +MODULE_ID("$Id: lib_screen.c,v 1.64 2015/03/21 23:59:32 tom Exp $") #define MAX_SIZE 0x3fff /* 16k is big enough for a window or pad */ +#define MARKER '\\' +#define GUTTER '|' +#define L_CURL '{' +#define R_CURL '}' + +#define L_MARK "\\{" +#define R_MARK "}" + +/* + * Use 0x8888 as the magic number for new-format files, since it cannot be + * mistaken for the _cury/_curx pair of 16-bit numbers which start the old + * format. It happens to be unused in the file 5.22 database (2015/03/07). + */ +static char my_magic[] = +{'\210', '\210', '\210', '\210'}; + +#if NCURSES_EXT_SCREEN_DUMP +typedef enum { + pINT /* int */ + ,pSHORT /* short */ + ,pBOOL /* bool */ + ,pATTR /* attr_t */ + ,pCHAR /* chtype */ + ,pSIZE /* NCURSES_SIZE_T */ +#if NCURSES_WIDECHAR + ,pCCHAR /* cchar_t */ +#endif +} PARAM_TYPE; + +typedef struct { + const char *name; + attr_t attr; +} SCR_ATTRS; + +typedef struct { + const char *name; + PARAM_TYPE type; + size_t size; + size_t offset; +} SCR_PARAMS; + +#define DATA(name) { #name, A_##name } +static SCR_ATTRS scr_attrs[] = +{ + DATA(NORMAL), + DATA(STANDOUT), + DATA(UNDERLINE), + DATA(REVERSE), + DATA(BLINK), + DATA(DIM), + DATA(BOLD), + DATA(ALTCHARSET), + DATA(INVIS), + DATA(PROTECT), + DATA(HORIZONTAL), + DATA(LEFT), + DATA(LOW), + DATA(RIGHT), + DATA(TOP), + DATA(VERTICAL), + +#ifdef A_ITALIC + DATA(ITALIC), +#endif +}; +#undef DATA + +#define sizeof2(type,name) sizeof(((type *)0)->name) +#define DATA(name, type) { #name, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) } + +static SCR_PARAMS scr_params[] = +{ + DATA(_cury, pSIZE), + DATA(_curx, pSIZE), + DATA(_maxy, pSIZE), + DATA(_maxx, pSIZE), + DATA(_begy, pSIZE), + DATA(_begx, pSIZE), + DATA(_flags, pSHORT), + DATA(_attrs, pATTR), + DATA(_bkgd, pCHAR), + DATA(_notimeout, pBOOL), + DATA(_clear, pBOOL), + DATA(_leaveok, pBOOL), + DATA(_scroll, pBOOL), + DATA(_idlok, pBOOL), + DATA(_idcok, pBOOL), + DATA(_immed, pBOOL), + DATA(_sync, pBOOL), + DATA(_use_keypad, pBOOL), + DATA(_delay, pINT), + DATA(_regtop, pSIZE), + DATA(_regbottom, pSIZE), + DATA(_pad._pad_y, pSIZE), + DATA(_pad._pad_x, pSIZE), + DATA(_pad._pad_top, pSIZE), + DATA(_pad._pad_left, pSIZE), + DATA(_pad._pad_bottom, pSIZE), + DATA(_pad._pad_right, pSIZE), + DATA(_yoffset, pSIZE), +#if NCURSES_WIDECHAR + DATA(_bkgrnd, pCCHAR), +#if NCURSES_EXT_COLORS + DATA(_color, pINT), +#endif +#endif +}; +#undef DATA + +static const NCURSES_CH_T blank = NewChar(BLANK_TEXT); + +/* + * Allocate and read a line of text. Caller must free it. + */ +static char * +read_txt(FILE *fp) +{ + size_t limit = 1024; + size_t used = 0; + char *result = malloc(limit); + char *buffer; + + if (result != 0) { + int ch = 0; + + clearerr(fp); + result[used] = '\0'; + do { + if (used + 2 >= limit) { + limit += 1024; + buffer = realloc(result, limit); + if (buffer == 0) { + free(result); + result = 0; + break; + } + } + ch = fgetc(fp); + if (ch == EOF) + break; + result[used++] = (char) ch; + result[used] = '\0'; + } while (ch != '\n'); + + if (ch == '\n') { + result[--used] = '\0'; + T(("READ:%s", result)); + } else if (used == 0) { + free(result); + result = 0; + } + } + return result; +} + +static char * +decode_attr(char *source, attr_t *target, int *color) +{ + bool found = FALSE; + + T(("decode_attr '%s'", source)); + + while (*source) { + if (source[0] == MARKER && source[1] == L_CURL) { + source += 2; + found = TRUE; + } else if (source[0] == R_CURL) { + source++; + found = FALSE; + } else if (found) { + size_t n; + char *next = source; + + if (source[0] == GUTTER) { + ++next; + } else if (*next == 'C') { + int value = 0; + next++; + while (isdigit(UChar(*next))) { + value = value * 10 + (*next++ - '0'); + } + *target &= ~A_COLOR; + if (value > 256) { + *target |= COLOR_PAIR(255); + } else { + *target |= COLOR_PAIR(value); + } + *color = value; + } else { + while (isalnum(UChar(*next))) { + ++next; + } + for (n = 0; n < SIZEOF(scr_attrs); ++n) { + if ((size_t) (next - source) == strlen(scr_attrs[n].name)) { + if (scr_attrs[n].attr) { + *target |= scr_attrs[n].attr; + } else { + *target = A_NORMAL; + } + break; + } + } + } + source = next; + } else { + break; + } + } + return source; +} + +static char * +decode_char(char *source, int *target) +{ + int limit = 0; + int base = 16; + const char digits[] = "0123456789abcdef"; + + T(("decode_char '%s'", source)); + *target = ' '; + switch (*source) { + case '\\': + switch (*++source) { + case '\\': + *target = '\\'; + ++source; + break; + case 's': + *target = ' '; + ++source; + break; + case '0': + case '1': + case '2': + case '3': + base = 8; + limit = 3; + break; + case 'u': + limit = 4; + ++source; + break; + case 'U': + limit = 8; + ++source; + break; + } + if (limit) { + *target = 0; + while (limit-- > 0) { + char *find = strchr(digits, *source++); + int ch = (find != 0) ? (int) (find - digits) : -1; + *target *= base; + if (ch >= 0 && ch < base) { + *target += ch; + } + } + } + break; + default: + *target = *source++; + break; + } + return source; +} + +static char * +decode_chtype(char *source, chtype fillin, chtype *target) +{ + attr_t attr = ChAttrOf(fillin); + int color = PAIR_NUMBER(attr); + int value; + + T(("decode_chtype '%s'", source)); + source = decode_attr(source, &attr, &color); + source = decode_char(source, &value); + *target = ChCharOf(value) | attr | COLOR_PAIR(color); + return source; +} + +#if NCURSES_WIDECHAR +static char * +decode_cchar(char *source, cchar_t *fillin, cchar_t *target) +{ + int color; + attr_t attr = fillin->attr; + wchar_t chars[CCHARW_MAX]; + + T(("decode_cchar '%s'", source)); + *target = blank; +#if NCURSES_EXT_COLORS + color = fillin->ext_color; +#else + color = (int) PAIR_NUMBER(attr); +#endif + source = decode_attr(source, &attr, &color); + memset(chars, 0, sizeof(chars)); + source = decode_char(source, &chars[0]); + /* FIXME - handle combining characters at this point */ + setcchar(target, chars, attr, (short) color, NULL); + return source; +} +#endif + +static int +read_win(WINDOW *win, FILE *fp) +{ + int code = ERR; + char *txt; + char *name; + char *value; + size_t n; + int color; +#if NCURSES_WIDECHAR + NCURSES_CH_T prior; +#endif + chtype prior2; + + memset(win, 0, sizeof(WINDOW)); + for (;;) { + txt = read_txt(fp); + if (txt == 0) + break; + if (!strcmp(txt, "rows:")) { + free(txt); + code = OK; + break; + } + if ((value = strchr(txt, '=')) == 0) { + free(txt); + continue; + } + *value++ = '\0'; + name = !strcmp(txt, "flag") ? value : txt; + for (n = 0; n < SIZEOF(scr_params); ++n) { + if (!strcmp(name, scr_params[n].name)) { + void *data = (void *) ((char *) win + scr_params[n].offset); + + switch (scr_params[n].type) { + case pATTR: + (void) decode_attr(value, data, &color); + break; + case pBOOL: + *(bool *) data = TRUE; + break; + case pCHAR: + prior2 = ' '; + decode_chtype(value, prior2, data); + break; + case pINT: + *(int *) data = atoi(value); + break; + case pSHORT: + *(short *) data = (short) atoi(value); + break; + case pSIZE: + *(NCURSES_SIZE_T *) data = (NCURSES_SIZE_T) atoi(value); + break; +#if NCURSES_WIDECHAR + case pCCHAR: + prior = blank; + decode_cchar(value, &prior, data); + break; +#endif + } + break; + } + } + free(txt); + } + return code; +} + +static int +read_row(char *source, NCURSES_CH_T * prior, NCURSES_CH_T * target, int length) +{ + while (*source != '\0' && length > 0) { +#if NCURSES_WIDECHAR + source = decode_cchar(source, prior, target); +#else + source = decode_chtype(source, *prior, target); +#endif + *prior = *target; + ++target; + --length; + } + while (length-- > 0) { + *target++ = blank; + } + /* FIXME - see what error conditions should apply if I need to return ERR */ + return 0; +} +#endif /* NCURSES_EXT_SCREEN_DUMP */ + +/* + * Originally, getwin/putwin used fread/fwrite, because they used binary data. + * The new format uses printable ASCII, which does not have as predictable + * sizes. Consequently, we use buffered I/O, e.g., fgetc/fprintf, which need + * special handling if we want to read screen dumps from an older library. + */ +static int +read_block(void *target, size_t length, FILE *fp) +{ + int result = 0; + char *buffer = target; + + clearerr(fp); + while (length-- != 0) { + int ch = fgetc(fp); + if (ch == EOF) { + result = -1; + break; + } + *buffer++ = (char) ch; + } + return result; +} + NCURSES_EXPORT(WINDOW *) NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep) { WINDOW tmp, *nwin; int n; + bool old_format = FALSE; T((T_CALLED("getwin(%p)"), (void *) filep)); if (filep == 0) { returnWin(0); } - clearerr(filep); - if (fread(&tmp, (size_t) 1, sizeof(WINDOW), filep) < sizeof(WINDOW) - || ferror(filep) - || tmp._maxy == 0 - || tmp._maxy > MAX_SIZE - || tmp._maxx == 0 - || tmp._maxx > MAX_SIZE) { + + /* + * Read the first 4 bytes to determine first if this is an old-format + * screen-dump, or new-format. + */ + if (read_block(&tmp, 4, filep) < 0) { + returnWin(0); + } + /* + * If this is a new-format file, and we do not support it, give up. + */ + if (!memcmp(&tmp, my_magic, 4)) { +#if NCURSES_EXT_SCREEN_DUMP + if (read_win(&tmp, filep) < 0) +#endif + returnWin(0); + } else if (read_block(((char *) &tmp) + 4, sizeof(WINDOW) - 4, filep) < 0) { + returnWin(0); + } else { + old_format = TRUE; + } + + /* + * Check the window-size: + */ + if (tmp._maxy == 0 || + tmp._maxy > MAX_SIZE || + tmp._maxx == 0 || + tmp._maxx > MAX_SIZE) { returnWin(0); } @@ -111,14 +554,55 @@ NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep) if (tmp._flags & _ISPAD) nwin->_pad = tmp._pad; - for (n = 0; n <= nwin->_maxy; n++) { - clearerr(filep); - if (fread(nwin->_line[n].text, (size_t) 1, linesize, filep) < linesize - || ferror(filep)) { + if (old_format) { + T(("reading old-format screen dump")); + for (n = 0; n <= nwin->_maxy; n++) { + if (read_block(nwin->_line[n].text, linesize, filep) < 0) { + delwin(nwin); + returnWin(0); + } + } + } +#if NCURSES_EXT_SCREEN_DUMP + else { + char *txt; + bool success = TRUE; + NCURSES_CH_T prior = blank; + + T(("reading new-format screen dump")); + for (n = 0; n <= nwin->_maxy; n++) { + long row; + char *next; + + if ((txt = read_txt(filep)) == 0) { + T(("...failed to read string for row %d", n + 1)); + success = FALSE; + break; + } + row = strtol(txt, &next, 10); + if (row != (n + 1) || *next != ':') { + T(("...failed to read row-number %d", n + 1)); + success = FALSE; + break; + } + + if (read_row(++next, &prior, nwin->_line[n].text, tmp._maxx + + 1) < 0) { + T(("...failed to read cells for row %d", n + 1)); + success = FALSE; + break; + } + free(txt); + txt = 0; + } + + if (!success) { + free(txt); delwin(nwin); returnWin(0); } } +#endif touchwin(nwin); } returnWin(nwin); @@ -132,14 +616,212 @@ getwin(FILE *filep) } #endif +#if NCURSES_EXT_SCREEN_DUMP +static void +encode_attr(char *target, attr_t source, attr_t prior) +{ + *target = '\0'; + if (source != prior) { + size_t n; + bool first = TRUE; + + strcpy(target, L_MARK); + target += strlen(target); + + for (n = 0; n < SIZEOF(scr_attrs); ++n) { + if ((source & scr_attrs[n].attr) != 0 || + ((source & ALL_BUT_COLOR) == 0 && + (scr_attrs[n].attr == A_NORMAL))) { + if (first) { + first = FALSE; + } else { + *target++ = '|'; + } + strcpy(target, scr_attrs[n].name); + target += strlen(target); + } + } + if ((source & A_COLOR) != (prior & A_COLOR)) { + if (!first) + *target++ = '|'; + sprintf(target, "C%d", PAIR_NUMBER(source)); + target += strlen(target); + } + + strcpy(target, R_MARK); + } +} + +static void +encode_cell(char *target, CARG_CH_T source, CARG_CH_T previous) +{ +#if NCURSES_WIDECHAR + size_t n; + + *target = '\0'; + if (previous->attr != source->attr) { + encode_attr(target, source->attr, previous->attr); + } + target += strlen(target); +#if NCURSES_EXT_COLORS + if (previous->ext_color != source->ext_color) { + sprintf(target, "%sC%d%s", L_MARK, source->ext_color, R_MARK); + } +#endif + for (n = 0; n < SIZEOF(source->chars); ++n) { + if (source->chars[n] == 0) + continue; + if (source->chars[n] > 0xffff) { + sprintf(target, "\\U%08x", source->chars[n]); + } else if (source->chars[n] > 0xff) { + sprintf(target, "\\u%04x", source->chars[n]); + } else if (source->chars[n] < 32 || source->chars[n] >= 127) { + sprintf(target, "\\%03o", source->chars[n] & 0xff); + } else { + switch (source->chars[n]) { + case ' ': + strcpy(target, "\\s"); + break; + case '\\': + strcpy(target, "\\\\"); + break; + default: + sprintf(target, "%c", source->chars[n]); + break; + } + } + target += strlen(target); + } +#else + chtype ch = CharOfD(source); + + *target = '\0'; + if (AttrOfD(previous) != AttrOfD(source)) { + encode_attr(target, AttrOfD(source), AttrOfD(previous)); + } + target += strlen(target); + if (ch < 32 || ch >= 127) { + sprintf(target, "\\%03o", ch); + } else { + switch (ch) { + case ' ': + strcpy(target, "\\s"); + break; + case '\\': + strcpy(target, "\\\\"); + break; + default: + sprintf(target, "%c", ch); + break; + } + } + target += strlen(target); +#endif +} +#endif + NCURSES_EXPORT(int) putwin(WINDOW *win, FILE *filep) { int code = ERR; - int n; + int y; T((T_CALLED("putwin(%p,%p)"), (void *) win, (void *) filep)); +#if NCURSES_EXT_SCREEN_DUMP + if (win != 0) { + const char *version = curses_version(); + char buffer[1024]; + NCURSES_CH_T last_cell; + + memset(&last_cell, 0, sizeof(last_cell)); + + clearerr(filep); + + /* + * Our magic number is technically nonprinting, but aside from that, + * all of the file is printable ASCII. + */ +#define PUTS(s) if (fputs(s, filep) == EOF || ferror(filep)) returnCode(code) + PUTS(my_magic); + PUTS(version); + PUTS("\n"); + for (y = 0; y < (int) SIZEOF(scr_params); ++y) { + const char *name = scr_params[y].name; + const char *data = (char *) win + scr_params[y].offset; + const void *dp = (const void *) data; + + *buffer = '\0'; + if (!strncmp(name, "_pad.", 5) && !(win->_flags & _ISPAD)) { + continue; + } + switch (scr_params[y].type) { + case pATTR: + encode_attr(buffer, (*(const attr_t *) dp) & ~A_CHARTEXT, A_NORMAL); + break; + case pBOOL: + if (!(*(const bool *) data)) { + continue; + } + strcpy(buffer, name); + name = "flag"; + break; + case pCHAR: + encode_attr(buffer, *(const attr_t *) dp, A_NORMAL); + break; + case pINT: + if (!(*(const int *) dp)) + continue; + sprintf(buffer, "%d", *(const int *) dp); + break; + case pSHORT: + if (!(*(const short *) dp)) + continue; + sprintf(buffer, "%d", *(const short *) dp); + break; + case pSIZE: + if (!(*(const NCURSES_SIZE_T *) dp)) + continue; + sprintf(buffer, "%d", *(const NCURSES_SIZE_T *) dp); + break; +#if NCURSES_WIDECHAR + case pCCHAR: + encode_cell(buffer, (CARG_CH_T) dp, CHREF(last_cell)); + break; +#endif + } + /* + * Only write non-default data. + */ + if (*buffer != '\0') { + if (fprintf(filep, "%s=%s\n", name, buffer) <= 0 + || ferror(filep)) + returnCode(code); + } + } + /* Write row-data */ + fprintf(filep, "rows:\n"); + for (y = 0; y <= win->_maxy; y++) { + NCURSES_CH_T *data = win->_line[y].text; + int x; + if (fprintf(filep, "%d:", y + 1) <= 0 + || ferror(filep)) + returnCode(code); + for (x = 0; x <= win->_maxx; x++) { + encode_cell(buffer, CHREF(data[x]), CHREF(last_cell)); + last_cell = data[x]; + PUTS(buffer); + } + PUTS("\n"); + } + } +#else + /* + * This is the original putwin(): + * A straight binary dump is simple, but its format can depend on whether + * ncurses is compiled with wide-character support, and also may depend + * on the version of ncurses, e.g., if the WINDOW structure is extended. + */ if (win != 0) { size_t len = (size_t) (win->_maxx + 1); @@ -148,8 +830,8 @@ putwin(WINDOW *win, FILE *filep) || ferror(filep)) returnCode(code); - for (n = 0; n <= win->_maxy; n++) { - if (fwrite(win->_line[n].text, + for (y = 0; y <= win->_maxy; y++) { + if (fwrite(win->_line[y].text, sizeof(NCURSES_CH_T), len, filep) != len || ferror(filep)) { returnCode(code); @@ -157,6 +839,7 @@ putwin(WINDOW *win, FILE *filep) } code = OK; } +#endif returnCode(code); } @@ -164,21 +847,23 @@ NCURSES_EXPORT(int) NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file) { FILE *fp = 0; + int code = ERR; T((T_CALLED("scr_restore(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file))); - if (_nc_access(file, R_OK) < 0 - || (fp = fopen(file, "rb")) == 0) { - returnCode(ERR); - } else { + if (_nc_access(file, R_OK) >= 0 + && (fp = fopen(file, "rb")) != 0) { delwin(NewScreen(SP_PARM)); NewScreen(SP_PARM) = getwin(fp); #if !USE_REENTRANT newscr = NewScreen(SP_PARM); #endif (void) fclose(fp); - returnCode(OK); + if (NewScreen(SP_PARM) != 0) { + code = OK; + } } + returnCode(code); } #if NCURSES_SP_FUNCS @@ -231,7 +916,9 @@ NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file) curscr = CurScreen(SP_PARM); #endif (void) fclose(fp); - code = OK; + if (CurScreen(SP_PARM) != 0) { + code = OK; + } } } returnCode(code); @@ -248,18 +935,21 @@ scr_init(const char *file) NCURSES_EXPORT(int) NCURSES_SP_NAME(scr_set) (NCURSES_SP_DCLx const char *file) { + int code = ERR; + T((T_CALLED("scr_set(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file))); - if (NCURSES_SP_NAME(scr_init) (NCURSES_SP_ARGx file) == ERR) { - returnCode(ERR); - } else { + if (NCURSES_SP_NAME(scr_init) (NCURSES_SP_ARGx file) == OK) { delwin(NewScreen(SP_PARM)); NewScreen(SP_PARM) = dupwin(curscr); #if !USE_REENTRANT newscr = NewScreen(SP_PARM); #endif - returnCode(OK); + if (NewScreen(SP_PARM) != 0) { + code = OK; + } } + returnCode(code); } #if NCURSES_SP_FUNCS diff --git a/package/debian-mingw/changelog b/package/debian-mingw/changelog index 1856c656..c35d9db2 100644 --- a/package/debian-mingw/changelog +++ b/package/debian-mingw/changelog @@ -1,8 +1,8 @@ -ncurses6 (5.9+20150307) unstable; urgency=low +ncurses6 (5.9+20150321) unstable; urgency=low * latest weekly patch - -- Thomas E. Dickey Sat, 07 Mar 2015 11:12:58 -0500 + -- Thomas E. Dickey Sat, 21 Mar 2015 12:25:03 -0400 ncurses6 (5.9-20131005) unstable; urgency=low diff --git a/package/debian-mingw64/changelog b/package/debian-mingw64/changelog index 1856c656..c35d9db2 100644 --- a/package/debian-mingw64/changelog +++ b/package/debian-mingw64/changelog @@ -1,8 +1,8 @@ -ncurses6 (5.9+20150307) unstable; urgency=low +ncurses6 (5.9+20150321) unstable; urgency=low * latest weekly patch - -- Thomas E. Dickey Sat, 07 Mar 2015 11:12:58 -0500 + -- Thomas E. Dickey Sat, 21 Mar 2015 12:25:03 -0400 ncurses6 (5.9-20131005) unstable; urgency=low diff --git a/package/debian/changelog b/package/debian/changelog index 96cfae73..4de0db50 100644 --- a/package/debian/changelog +++ b/package/debian/changelog @@ -1,8 +1,8 @@ -ncurses6 (5.9+20150307) unstable; urgency=low +ncurses6 (5.9+20150321) unstable; urgency=low * latest weekly patch - -- Thomas E. Dickey Sat, 07 Mar 2015 11:12:58 -0500 + -- Thomas E. Dickey Sat, 21 Mar 2015 12:25:03 -0400 ncurses6 (5.9-20120608) unstable; urgency=low diff --git a/package/mingw-ncurses.nsi b/package/mingw-ncurses.nsi index 52259929..2c3dc8bb 100644 --- a/package/mingw-ncurses.nsi +++ b/package/mingw-ncurses.nsi @@ -1,4 +1,4 @@ -; $Id: mingw-ncurses.nsi,v 1.90 2015/03/07 16:12:58 tom Exp $ +; $Id: mingw-ncurses.nsi,v 1.92 2015/03/21 16:25:11 tom Exp $ ; TODO add examples ; TODO bump ABI to 6 @@ -10,7 +10,7 @@ !define VERSION_MAJOR "5" !define VERSION_MINOR "9" !define VERSION_YYYY "2015" -!define VERSION_MMDD "0307" +!define VERSION_MMDD "0321" !define VERSION_PATCH ${VERSION_YYYY}${VERSION_MMDD} !define MY_ABI "5" diff --git a/package/mingw-ncurses.spec b/package/mingw-ncurses.spec index a02b15ea..89896ca8 100644 --- a/package/mingw-ncurses.spec +++ b/package/mingw-ncurses.spec @@ -3,7 +3,7 @@ Summary: shared libraries for terminal handling Name: mingw32-ncurses6 Version: 5.9 -Release: 20150307 +Release: 20150321 License: X11 Group: Development/Libraries Source: ncurses-%{version}-%{release}.tgz diff --git a/package/ncurses.spec b/package/ncurses.spec index 00e1edd9..f724253f 100644 --- a/package/ncurses.spec +++ b/package/ncurses.spec @@ -1,7 +1,7 @@ Summary: shared libraries for terminal handling Name: ncurses6 Version: 5.9 -Release: 20150307 +Release: 20150321 License: X11 Group: Development/Libraries Source: ncurses-%{version}-%{release}.tgz diff --git a/progs/tset.c b/progs/tset.c index f01acd72..475b3e63 100644 --- a/progs/tset.c +++ b/progs/tset.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * + * Copyright (c) 1998-2013,2015 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -119,7 +119,7 @@ char *ttyname(int fd); #include #include -MODULE_ID("$Id: tset.c,v 1.93 2013/12/15 01:05:56 tom Exp $") +MODULE_ID("$Id: tset.c,v 1.94 2015/03/21 16:34:59 tom Exp $") /* * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, @@ -745,7 +745,7 @@ get_termcap_entry(char *userarg) #define DISABLED(val) ((int)(val) <= 0) #endif -#define CHK(val, dft) (DISABLED(val) ? dft : val) +#define CHK(val, dft) (unsigned char) (DISABLED(val) ? dft : val) static bool set_tabs(void); @@ -1305,8 +1305,8 @@ main(int argc, char **argv) if (WINSIZE_ROWS(win) == 0 && WINSIZE_COLS(win) == 0 && tlines > 0 && tcolumns > 0) { - WINSIZE_ROWS(win) = tlines; - WINSIZE_COLS(win) = tcolumns; + WINSIZE_ROWS(win) = (unsigned short) tlines; + WINSIZE_COLS(win) = (unsigned short) tcolumns; (void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win); } } diff --git a/test/savescreen.c b/test/savescreen.c index 44d7d1ca..3bdf8710 100644 --- a/test/savescreen.c +++ b/test/savescreen.c @@ -26,7 +26,7 @@ * authorization. * ****************************************************************************/ /* - * $Id: savescreen.c,v 1.21 2015/03/07 21:55:35 tom Exp $ + * $Id: savescreen.c,v 1.23 2015/03/21 21:35:00 tom Exp $ * * Demonstrate save/restore functions from the curses library. * Thomas Dickey - 2007/7/14 @@ -51,6 +51,7 @@ #endif static bool use_init = FALSE; +static bool keep_dumps = FALSE; static int fexists(const char *name) @@ -71,8 +72,10 @@ cleanup(char *files[]) { int n; - for (n = 0; files[n] != 0; ++n) { - unlink(files[n]); + if (!keep_dumps) { + for (n = 0; files[n] != 0; ++n) { + unlink(files[n]); + } } } @@ -209,6 +212,7 @@ usage(void) "", "Options:", " -i use scr_init/scr_restore rather than scr_set", + " -k keep the restored dump-files rather than removing them", " -r replay the screen-dump files" }; unsigned n; @@ -228,11 +232,16 @@ main(int argc, char *argv[]) bool done = FALSE; char **files; - while ((ch = getopt(argc, argv, "ir")) != -1) { + setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "ikr")) != -1) { switch (ch) { case 'i': use_init = TRUE; break; + case 'k': + keep_dumps = TRUE; + break; case 'r': replaying = TRUE; break; @@ -268,7 +277,7 @@ main(int argc, char *argv[]) */ for (pair = 0; pair < COLOR_PAIRS; ++pair) { color = (short) (pair % (COLORS - 1)); - init_pair(pair, COLOR_WHITE - color, color); + init_pair(pair, (short) (COLOR_WHITE - color), color); } } -- 2.44.0