X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Fbase%2Flib_screen.c;h=9e942eaf8494013f9c240551302c1121133cab70;hp=63ef7f5bcf1737ececa1c1f8297a3f69ca0b9e6a;hb=a8dfaf0998c91b39c5c0a4913987cd67ca622bff;hpb=87f20fc6e737084b06b6343c8c7206404daec4a2 diff --git a/ncurses/base/lib_screen.c b/ncurses/base/lib_screen.c index 63ef7f5b..9e942eaf 100644 --- a/ncurses/base/lib_screen.c +++ b/ncurses/base/lib_screen.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2011,2015 Free Software Foundation, Inc. * + * Copyright (c) 1998-2018,2019 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 * @@ -41,27 +41,34 @@ #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.96 2019/07/20 20:23:21 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[] = +static const char my_magic[] = {'\210', '\210', '\210', '\210'}; -#if NCURSES_EXT_SCREEN_DUMP +#if NCURSES_EXT_PUTWIN typedef enum { pINT /* int */ ,pSHORT /* short */ @@ -75,19 +82,19 @@ typedef enum { } 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), @@ -113,9 +120,9 @@ static SCR_ATTRS scr_attrs[] = #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), @@ -163,12 +170,12 @@ 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; + size_t used = 0; clearerr(fp); result[used] = '\0'; @@ -181,6 +188,7 @@ read_txt(FILE *fp) result = 0; break; } + result = buffer; } ch = fgetc(fp); if (ch == EOF) @@ -222,16 +230,16 @@ decode_attr(char *source, attr_t *target, int *color) ++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))) { @@ -266,10 +274,12 @@ decode_char(char *source, int *target) 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': @@ -315,13 +325,14 @@ static char * 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; } @@ -332,6 +343,8 @@ decode_cchar(char *source, cchar_t *fillin, cchar_t *target) 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; @@ -342,9 +355,17 @@ decode_cchar(char *source, cchar_t *fillin, cchar_t *target) #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 @@ -353,9 +374,6 @@ 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 @@ -365,7 +383,10 @@ read_win(WINDOW *win, FILE *fp) 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:")) { @@ -423,7 +444,21 @@ 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 @@ -437,7 +472,7 @@ read_row(char *source, NCURSES_CH_T * prior, NCURSES_CH_T * target, int length) /* 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. @@ -467,7 +502,6 @@ 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)); @@ -480,14 +514,14 @@ NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *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); @@ -523,6 +557,7 @@ NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep) * 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; @@ -563,9 +598,9 @@ NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep) } } } -#if NCURSES_EXT_SCREEN_DUMP +#if NCURSES_EXT_PUTWIN else { - char *txt; + char *txt = 0; bool success = TRUE; NCURSES_CH_T prior = blank; @@ -616,17 +651,27 @@ getwin(FILE *filep) } #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 || @@ -637,56 +682,75 @@ encode_attr(char *target, attr_t source, attr_t prior) } 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; } } @@ -697,25 +761,31 @@ encode_cell(char *target, CARG_CH_T source, CARG_CH_T previous) *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 @@ -724,15 +794,15 @@ NCURSES_EXPORT(int) 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)); @@ -750,43 +820,58 @@ putwin(WINDOW *win, FILE *filep) 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 } @@ -808,12 +893,22 @@ putwin(WINDOW *win, FILE *filep) || 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 /* @@ -824,6 +919,7 @@ putwin(WINDOW *win, FILE *filep) */ 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 @@ -852,7 +948,7 @@ NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file) 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 @@ -883,7 +979,7 @@ scr_dump(const char *file) 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); @@ -896,7 +992,6 @@ scr_dump(const char *file) 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))); @@ -908,8 +1003,10 @@ NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *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