/****************************************************************************
- * Copyright (c) 1998-2011,2015 Free Software Foundation, Inc. *
+ * Copyright 2019,2020 Thomas E. Dickey *
+ * Copyright 1998-2017,2018 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 *
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_screen.c,v 1.64 2015/03/21 23:59:32 tom Exp $")
+MODULE_ID("$Id: lib_screen.c,v 1.99 2020/05/23 19:12:01 tom Exp $")
#define MAX_SIZE 0x3fff /* 16k is big enough for a window or pad */
#define MARKER '\\'
+#define APPEND '+'
#define GUTTER '|'
#define L_CURL '{'
#define R_CURL '}'
-#define L_MARK "\\{"
-#define R_MARK "}"
+#if USE_STRING_HACKS && HAVE_SNPRINTF
+#define ARG_SLIMIT(name) size_t name,
+#else
+#define ARG_SLIMIT(name) /* nothing */
+#endif
+
+#define CUR_SLIMIT _nc_SLIMIT(limit - (target - base))
+#define TOP_SLIMIT _nc_SLIMIT(sizeof(buffer))
/*
- * Use 0x8888 as the magic number for new-format files, since it cannot be
+ * Use 0x888888 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'};
+static const char my_magic[] =
+{'\210', '\210', '\210', '\210', 0};
-#if NCURSES_EXT_SCREEN_DUMP
+#if NCURSES_EXT_PUTWIN
typedef enum {
pINT /* int */
,pSHORT /* short */
} PARAM_TYPE;
typedef struct {
- const char *name;
+ const char name[11];
attr_t attr;
} SCR_ATTRS;
typedef struct {
- const char *name;
+ const char name[17];
PARAM_TYPE type;
size_t size;
size_t offset;
} SCR_PARAMS;
-#define DATA(name) { #name, A_##name }
-static SCR_ATTRS scr_attrs[] =
+#define DATA(name) { { #name }, A_##name }
+static const SCR_ATTRS scr_attrs[] =
{
DATA(NORMAL),
DATA(STANDOUT),
#undef DATA
#define sizeof2(type,name) sizeof(((type *)0)->name)
-#define DATA(name, type) { #name, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) }
+#define DATA(name, type) { { #name }, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) }
-static SCR_PARAMS scr_params[] =
+static const SCR_PARAMS scr_params[] =
{
DATA(_cury, pSIZE),
DATA(_curx, pSIZE),
read_txt(FILE *fp)
{
size_t limit = 1024;
- size_t used = 0;
char *result = malloc(limit);
char *buffer;
if (result != 0) {
int ch = 0;
+ size_t used = 0;
clearerr(fp);
result[used] = '\0';
result = 0;
break;
}
+ result = buffer;
}
ch = fgetc(fp);
if (ch == EOF)
++next;
} else if (*next == 'C') {
int value = 0;
+ unsigned pair;
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);
- }
+ pair = (unsigned) ((value > 256)
+ ? COLOR_PAIR(255)
+ : COLOR_PAIR(value));
+ *target |= pair;
*color = value;
} else {
while (isalnum(UChar(*next))) {
T(("decode_char '%s'", source));
*target = ' ';
switch (*source) {
- case '\\':
+ case MARKER:
switch (*++source) {
- case '\\':
- *target = '\\';
+ case APPEND:
+ break;
+ case MARKER:
+ *target = MARKER;
++source;
break;
case 's':
decode_chtype(char *source, chtype fillin, chtype *target)
{
attr_t attr = ChAttrOf(fillin);
- int color = PAIR_NUMBER(attr);
+ int color = PAIR_NUMBER((int) 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);
+ *target = (ChCharOf(value) | attr | (chtype) COLOR_PAIR(color));
+ /* FIXME - ignore combining characters */
return source;
}
int color;
attr_t attr = fillin->attr;
wchar_t chars[CCHARW_MAX];
+ int append = 0;
+ int value = 0;
T(("decode_cchar '%s'", source));
*target = blank;
#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);
+ source = decode_char(source, &value);
+ chars[0] = (wchar_t) value;
+ /* handle combining characters */
+ while (source[0] == MARKER && source[1] == APPEND) {
+ source += 2;
+ source = decode_char(source, &value);
+ if (++append < CCHARW_MAX) {
+ chars[append] = (wchar_t) value;
+ }
+ }
+ setcchar(target, chars, attr, (short) color, &color);
return source;
}
#endif
read_win(WINDOW *win, FILE *fp)
{
int code = ERR;
- char *txt;
- char *name;
- char *value;
size_t n;
int color;
#if NCURSES_WIDECHAR
memset(win, 0, sizeof(WINDOW));
for (;;) {
- txt = read_txt(fp);
+ char *name;
+ char *value;
+ char *txt = read_txt(fp);
+
if (txt == 0)
break;
if (!strcmp(txt, "rows:")) {
}
static int
-read_row(char *source, NCURSES_CH_T * prior, NCURSES_CH_T * target, int length)
+read_row(char *source, NCURSES_CH_T *prior, NCURSES_CH_T *target, int length)
{
while (*source != '\0' && length > 0) {
#if NCURSES_WIDECHAR
+ int len;
+
source = decode_cchar(source, prior, target);
+ len = _nc_wacs_width(target->chars[0]);
+ if (len > 1) {
+ int n;
+
+ SetWidecExt(CHDEREF(target), 0);
+ for (n = 1; n < len; ++n) {
+ target[n] = target[0];
+ SetWidecExt(CHDEREF(target), n);
+ }
+ target += (len - 1);
+ length -= (len - 1);
+ }
#else
source = decode_chtype(source, *prior, target);
#endif
/* FIXME - see what error conditions should apply if I need to return ERR */
return 0;
}
-#endif /* NCURSES_EXT_SCREEN_DUMP */
+#endif /* NCURSES_EXT_PUTWIN */
/*
* Originally, getwin/putwin used fread/fwrite, because they used binary data.
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));
* 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) {
+ if (read_block(&tmp, (size_t) 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 (!memcmp(&tmp, my_magic, (size_t) 4)) {
+#if NCURSES_EXT_PUTWIN
if (read_win(&tmp, filep) < 0)
#endif
returnWin(0);
* made sense is probably gone.
*/
if (nwin != 0) {
+ int n;
size_t linesize = sizeof(NCURSES_CH_T) * (size_t) (tmp._maxx + 1);
nwin->_curx = tmp._curx;
}
}
}
-#if NCURSES_EXT_SCREEN_DUMP
+#if NCURSES_EXT_PUTWIN
else {
- char *txt;
+ char *txt = 0;
bool success = TRUE;
NCURSES_CH_T prior = blank;
}
#endif
-#if NCURSES_EXT_SCREEN_DUMP
+#if NCURSES_EXT_PUTWIN
static void
-encode_attr(char *target, attr_t source, attr_t prior)
+encode_attr(char *target, ARG_SLIMIT(limit)
+ attr_t source,
+ attr_t prior,
+ int source_color,
+ int prior_color)
{
+#if USE_STRING_HACKS && HAVE_SNPRINTF
+ char *base = target;
+#endif
+ source &= ~A_CHARTEXT;
+ prior &= ~A_CHARTEXT;
+
*target = '\0';
- if (source != prior) {
+ if ((source != prior) || (source_color != prior_color)) {
size_t n;
bool first = TRUE;
- strcpy(target, L_MARK);
- target += strlen(target);
+ *target++ = MARKER;
+ *target++ = L_CURL;
for (n = 0; n < SIZEOF(scr_attrs); ++n) {
if ((source & scr_attrs[n].attr) != 0 ||
} else {
*target++ = '|';
}
- strcpy(target, scr_attrs[n].name);
+ _nc_STRCPY(target, scr_attrs[n].name, limit);
target += strlen(target);
}
}
- if ((source & A_COLOR) != (prior & A_COLOR)) {
+ if (source_color != prior_color) {
if (!first)
*target++ = '|';
- sprintf(target, "C%d", PAIR_NUMBER(source));
+ _nc_SPRINTF(target, CUR_SLIMIT "C%d", source_color);
target += strlen(target);
}
- strcpy(target, R_MARK);
+ *target++ = R_CURL;
+ *target = '\0';
}
}
static void
-encode_cell(char *target, CARG_CH_T source, CARG_CH_T previous)
+encode_cell(char *target, ARG_SLIMIT(limit) CARG_CH_T source, CARG_CH_T previous)
{
+#if USE_STRING_HACKS && HAVE_SNPRINTF
+ char *base = target;
+#endif
#if NCURSES_WIDECHAR
size_t n;
+ int source_pair = GetPair(*source);
+ int previous_pair = GetPair(*previous);
*target = '\0';
- if (previous->attr != source->attr) {
- encode_attr(target, source->attr, previous->attr);
+ if ((previous->attr != source->attr) || (previous_pair != source_pair)) {
+ encode_attr(target, CUR_SLIMIT
+ source->attr,
+ previous->attr,
+ source_pair,
+ previous_pair);
}
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);
+ _nc_SPRINTF(target, CUR_SLIMIT
+ "%c%cC%d%c", MARKER, L_CURL, source->ext_color, R_CURL);
}
#endif
for (n = 0; n < SIZEOF(source->chars); ++n) {
- if (source->chars[n] == 0)
+ unsigned uch = (unsigned) source->chars[n];
+ if (uch == 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);
+ if (n) {
+ *target++ = MARKER;
+ *target++ = APPEND;
+ }
+ *target++ = MARKER;
+ if (uch > 0xffff) {
+ _nc_SPRINTF(target, CUR_SLIMIT "U%08x", uch);
+ } else if (uch > 0xff) {
+ _nc_SPRINTF(target, CUR_SLIMIT "u%04x", uch);
+ } else if (uch < 32 || uch >= 127) {
+ _nc_SPRINTF(target, CUR_SLIMIT "%03o", uch & 0xff);
} else {
- switch (source->chars[n]) {
+ switch (uch) {
case ' ':
- strcpy(target, "\\s");
+ _nc_STRCPY(target, "s", limit);
break;
- case '\\':
- strcpy(target, "\\\\");
+ case MARKER:
+ *target++ = MARKER;
+ *target = '\0';
break;
default:
- sprintf(target, "%c", source->chars[n]);
+ --target;
+ _nc_SPRINTF(target, CUR_SLIMIT "%c", uch);
break;
}
}
*target = '\0';
if (AttrOfD(previous) != AttrOfD(source)) {
- encode_attr(target, AttrOfD(source), AttrOfD(previous));
+ encode_attr(target, CUR_SLIMIT
+ AttrOfD(source),
+ AttrOfD(previous),
+ GetPair(source),
+ GetPair(previous));
}
target += strlen(target);
+ *target++ = MARKER;
if (ch < 32 || ch >= 127) {
- sprintf(target, "\\%03o", ch);
+ _nc_SPRINTF(target, CUR_SLIMIT "%03o", UChar(ch));
} else {
switch (ch) {
case ' ':
- strcpy(target, "\\s");
+ _nc_STRCPY(target, "s", limit);
break;
- case '\\':
- strcpy(target, "\\\\");
+ case MARKER:
+ *target++ = MARKER;
+ *target = '\0';
break;
default:
- sprintf(target, "%c", ch);
+ --target;
+ _nc_SPRINTF(target, CUR_SLIMIT "%c", UChar(ch));
break;
}
}
- target += strlen(target);
#endif
}
#endif
putwin(WINDOW *win, FILE *filep)
{
int code = ERR;
- int y;
T((T_CALLED("putwin(%p,%p)"), (void *) win, (void *) filep));
-#if NCURSES_EXT_SCREEN_DUMP
+#if NCURSES_EXT_PUTWIN
if (win != 0) {
const char *version = curses_version();
char buffer[1024];
NCURSES_CH_T last_cell;
+ int y;
memset(&last_cell, 0, sizeof(last_cell));
const char *name = scr_params[y].name;
const char *data = (char *) win + scr_params[y].offset;
const void *dp = (const void *) data;
+ attr_t attr;
*buffer = '\0';
- if (!strncmp(name, "_pad.", 5) && !(win->_flags & _ISPAD)) {
+ if (!strncmp(name, "_pad.", (size_t) 5) && !(win->_flags & _ISPAD)) {
continue;
}
switch (scr_params[y].type) {
case pATTR:
- encode_attr(buffer, (*(const attr_t *) dp) & ~A_CHARTEXT, A_NORMAL);
+ attr = (*(const attr_t *) dp) & ~A_CHARTEXT;
+ encode_attr(buffer, TOP_SLIMIT
+ (*(const attr_t *) dp) & ~A_CHARTEXT,
+ A_NORMAL,
+ COLOR_PAIR((int) attr),
+ 0);
break;
case pBOOL:
if (!(*(const bool *) data)) {
continue;
}
- strcpy(buffer, name);
+ _nc_STRCPY(buffer, name, sizeof(buffer));
name = "flag";
break;
case pCHAR:
- encode_attr(buffer, *(const attr_t *) dp, A_NORMAL);
+ attr = (*(const attr_t *) dp);
+ encode_attr(buffer, TOP_SLIMIT
+ * (const attr_t *) dp,
+ A_NORMAL,
+ COLOR_PAIR((int) attr),
+ 0);
break;
case pINT:
if (!(*(const int *) dp))
continue;
- sprintf(buffer, "%d", *(const int *) dp);
+ _nc_SPRINTF(buffer, TOP_SLIMIT
+ "%d", *(const int *) dp);
break;
case pSHORT:
if (!(*(const short *) dp))
continue;
- sprintf(buffer, "%d", *(const short *) dp);
+ _nc_SPRINTF(buffer, TOP_SLIMIT
+ "%d", *(const short *) dp);
break;
case pSIZE:
if (!(*(const NCURSES_SIZE_T *) dp))
continue;
- sprintf(buffer, "%d", *(const NCURSES_SIZE_T *) dp);
+ _nc_SPRINTF(buffer, TOP_SLIMIT
+ "%d", *(const NCURSES_SIZE_T *) dp);
break;
#if NCURSES_WIDECHAR
case pCCHAR:
- encode_cell(buffer, (CARG_CH_T) dp, CHREF(last_cell));
+ encode_cell(buffer, TOP_SLIMIT
+ (CARG_CH_T) dp, CHREF(last_cell));
break;
#endif
}
|| ferror(filep))
returnCode(code);
for (x = 0; x <= win->_maxx; x++) {
- encode_cell(buffer, CHREF(data[x]), CHREF(last_cell));
+#if NCURSES_WIDECHAR
+ int len = _nc_wacs_width(data[x].chars[0]);
+ encode_cell(buffer, TOP_SLIMIT CHREF(data[x]), CHREF(last_cell));
last_cell = data[x];
PUTS(buffer);
+ if (len > 1)
+ x += (len - 1);
+#else
+ encode_cell(buffer, TOP_SLIMIT CHREF(data[x]), CHREF(last_cell));
+ last_cell = data[x];
+ PUTS(buffer);
+#endif
}
PUTS("\n");
}
+ code = OK;
}
#else
/*
*/
if (win != 0) {
size_t len = (size_t) (win->_maxx + 1);
+ int y;
clearerr(filep);
if (fwrite(win, sizeof(WINDOW), (size_t) 1, filep) != 1
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) {
+ && (fp = fopen(file, BIN_R)) != 0) {
delwin(NewScreen(SP_PARM));
NewScreen(SP_PARM) = getwin(fp);
#if !USE_REENTRANT
T((T_CALLED("scr_dump(%s)"), _nc_visbuf(file)));
if (_nc_access(file, W_OK) < 0
- || (fp = fopen(file, "wb")) == 0) {
+ || (fp = fopen(file, BIN_W)) == 0) {
result = ERR;
} else {
(void) putwin(newscr, fp);
NCURSES_EXPORT(int)
NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file)
{
- FILE *fp = 0;
int code = ERR;
T((T_CALLED("scr_init(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
!(exit_ca_mode && non_rev_rmcup)
#endif
) {
+ FILE *fp = 0;
+
if (_nc_access(file, R_OK) >= 0
- && (fp = fopen(file, "rb")) != 0) {
+ && (fp = fopen(file, BIN_R)) != 0) {
delwin(CurScreen(SP_PARM));
CurScreen(SP_PARM) = getwin(fp);
#if !USE_REENTRANT