10e3d5408SPeter Wemm /****************************************************************************
25ca44d1cSRong-En Fan * Copyright 2019,2020 Thomas E. Dickey *
30e3d5408SPeter Wemm * Copyright 1998-2017,2018 Free Software Foundation, Inc. *
40e3d5408SPeter Wemm * *
50e3d5408SPeter Wemm * Permission is hereby granted, free of charge, to any person obtaining a *
60e3d5408SPeter Wemm * copy of this software and associated documentation files (the *
70e3d5408SPeter Wemm * "Software"), to deal in the Software without restriction, including *
80e3d5408SPeter Wemm * without limitation the rights to use, copy, modify, merge, publish, *
90e3d5408SPeter Wemm * distribute, distribute with modifications, sublicense, and/or sell *
100e3d5408SPeter Wemm * copies of the Software, and to permit persons to whom the Software is *
110e3d5408SPeter Wemm * furnished to do so, subject to the following conditions: *
120e3d5408SPeter Wemm * *
130e3d5408SPeter Wemm * The above copyright notice and this permission notice shall be included *
140e3d5408SPeter Wemm * in all copies or substantial portions of the Software. *
150e3d5408SPeter Wemm * *
160e3d5408SPeter Wemm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
170e3d5408SPeter Wemm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
180e3d5408SPeter Wemm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
190e3d5408SPeter Wemm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
200e3d5408SPeter Wemm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
210e3d5408SPeter Wemm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
220e3d5408SPeter Wemm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
230e3d5408SPeter Wemm * *
240e3d5408SPeter Wemm * Except as contained in this notice, the name(s) of the above copyright *
250e3d5408SPeter Wemm * holders shall not be used in advertising or otherwise to promote the *
260e3d5408SPeter Wemm * sale, use or other dealings in this Software without prior written *
270e3d5408SPeter Wemm * authorization. *
280e3d5408SPeter Wemm ****************************************************************************/
290e3d5408SPeter Wemm
300e3d5408SPeter Wemm /****************************************************************************
310e3d5408SPeter Wemm * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
324a1a9510SRong-En Fan * and: Eric S. Raymond <esr@snark.thyrsus.com> *
330e3d5408SPeter Wemm * and: Thomas E. Dickey 1996 on *
340e3d5408SPeter Wemm * and: Juergen Pfeifer 2009 *
350e3d5408SPeter Wemm ****************************************************************************/
360e3d5408SPeter Wemm
375ca44d1cSRong-En Fan #include <curses.priv.h>
380e3d5408SPeter Wemm
397a69bbfbSPeter Wemm #include <ctype.h>
407a69bbfbSPeter Wemm
410e3d5408SPeter Wemm #ifndef CUR
420e3d5408SPeter Wemm #define CUR SP_TERMTYPE
430e3d5408SPeter Wemm #endif
440e3d5408SPeter Wemm
450e3d5408SPeter Wemm MODULE_ID("$Id: lib_screen.c,v 1.100 2020/05/25 22:48:41 tom Exp $")
460e3d5408SPeter Wemm
474a1a9510SRong-En Fan #define MAX_SIZE 0x3fff /* 16k is big enough for a window or pad */
480e3d5408SPeter Wemm
490e3d5408SPeter Wemm #define MARKER '\\'
500e3d5408SPeter Wemm #define APPEND '+'
510e3d5408SPeter Wemm #define GUTTER '|'
524a1a9510SRong-En Fan #define L_CURL '{'
534a1a9510SRong-En Fan #define R_CURL '}'
544a1a9510SRong-En Fan
554a1a9510SRong-En Fan #if USE_STRING_HACKS && HAVE_SNPRINTF
564a1a9510SRong-En Fan #define ARG_SLIMIT(name) size_t name,
570e3d5408SPeter Wemm #else
580e3d5408SPeter Wemm #define ARG_SLIMIT(name) /* nothing */
590e3d5408SPeter Wemm #endif
600e3d5408SPeter Wemm
610e3d5408SPeter Wemm #define CUR_SLIMIT _nc_SLIMIT(limit - (size_t) (target - base))
620e3d5408SPeter Wemm #define TOP_SLIMIT _nc_SLIMIT(sizeof(buffer))
634a1a9510SRong-En Fan
640e3d5408SPeter Wemm /*
650e3d5408SPeter Wemm * Use 0x888888 as the magic number for new-format files, since it cannot be
660e3d5408SPeter Wemm * mistaken for the _cury/_curx pair of 16-bit numbers which start the old
670e3d5408SPeter Wemm * format. It happens to be unused in the file 5.22 database (2015/03/07).
680e3d5408SPeter Wemm */
690e3d5408SPeter Wemm static const char my_magic[] =
700e3d5408SPeter Wemm {'\210', '\210', '\210', '\210', 0};
714a1a9510SRong-En Fan
720e3d5408SPeter Wemm #if NCURSES_EXT_PUTWIN
734a1a9510SRong-En Fan typedef enum {
7439f2269fSPeter Wemm pINT /* int */
750e3d5408SPeter Wemm ,pSHORT /* short */
764a1a9510SRong-En Fan ,pBOOL /* bool */
770e3d5408SPeter Wemm ,pATTR /* attr_t */
780e3d5408SPeter Wemm ,pCHAR /* chtype */
794a1a9510SRong-En Fan ,pSIZE /* NCURSES_SIZE_T */
804a1a9510SRong-En Fan #if NCURSES_WIDECHAR
814a1a9510SRong-En Fan ,pCCHAR /* cchar_t */
824a1a9510SRong-En Fan #endif
834a1a9510SRong-En Fan } PARAM_TYPE;
840e3d5408SPeter Wemm
850e3d5408SPeter Wemm typedef struct {
860e3d5408SPeter Wemm const char name[11];
870e3d5408SPeter Wemm attr_t attr;
880e3d5408SPeter Wemm } SCR_ATTRS;
890e3d5408SPeter Wemm
904a1a9510SRong-En Fan typedef struct {
914a1a9510SRong-En Fan const char name[17];
924a1a9510SRong-En Fan PARAM_TYPE type;
934a1a9510SRong-En Fan size_t size;
944a1a9510SRong-En Fan size_t offset;
950e3d5408SPeter Wemm } SCR_PARAMS;
964a1a9510SRong-En Fan
974a1a9510SRong-En Fan #define DATA(name) { { #name }, A_##name }
984a1a9510SRong-En Fan static const SCR_ATTRS scr_attrs[] =
997a69bbfbSPeter Wemm {
1000e3d5408SPeter Wemm DATA(NORMAL),
1010e3d5408SPeter Wemm DATA(STANDOUT),
1020e3d5408SPeter Wemm DATA(UNDERLINE),
1030e3d5408SPeter Wemm DATA(REVERSE),
1040e3d5408SPeter Wemm DATA(BLINK),
1054a1a9510SRong-En Fan DATA(DIM),
1060e3d5408SPeter Wemm DATA(BOLD),
1070e3d5408SPeter Wemm DATA(ALTCHARSET),
1080e3d5408SPeter Wemm DATA(INVIS),
1097a69bbfbSPeter Wemm DATA(PROTECT),
1107a69bbfbSPeter Wemm DATA(HORIZONTAL),
1110e3d5408SPeter Wemm DATA(LEFT),
1120e3d5408SPeter Wemm DATA(LOW),
1130e3d5408SPeter Wemm DATA(RIGHT),
1140e3d5408SPeter Wemm DATA(TOP),
1150e3d5408SPeter Wemm DATA(VERTICAL),
1160e3d5408SPeter Wemm
1174a1a9510SRong-En Fan #ifdef A_ITALIC
1184a1a9510SRong-En Fan DATA(ITALIC),
1194a1a9510SRong-En Fan #endif
1204a1a9510SRong-En Fan };
1214a1a9510SRong-En Fan #undef DATA
1224a1a9510SRong-En Fan
1230e3d5408SPeter Wemm #define sizeof2(type,name) sizeof(((type *)0)->name)
1240e3d5408SPeter Wemm #define DATA(name, type) { { #name }, type, sizeof2(WINDOW, name), offsetof(WINDOW, name) }
1254a1a9510SRong-En Fan
1264a1a9510SRong-En Fan static const SCR_PARAMS scr_params[] =
1274a1a9510SRong-En Fan {
1284a1a9510SRong-En Fan DATA(_cury, pSIZE),
1290e3d5408SPeter Wemm DATA(_curx, pSIZE),
1300e3d5408SPeter Wemm DATA(_maxy, pSIZE),
1314a1a9510SRong-En Fan DATA(_maxx, pSIZE),
1320e3d5408SPeter Wemm DATA(_begy, pSIZE),
1330e3d5408SPeter Wemm DATA(_begx, pSIZE),
1340e3d5408SPeter Wemm DATA(_flags, pSHORT),
1350e3d5408SPeter Wemm DATA(_attrs, pATTR),
1360e3d5408SPeter Wemm DATA(_bkgd, pCHAR),
1377a69bbfbSPeter Wemm DATA(_notimeout, pBOOL),
1387a69bbfbSPeter Wemm DATA(_clear, pBOOL),
1390e3d5408SPeter Wemm DATA(_leaveok, pBOOL),
1400e3d5408SPeter Wemm DATA(_scroll, pBOOL),
1410e3d5408SPeter Wemm DATA(_idlok, pBOOL),
1420e3d5408SPeter Wemm DATA(_idcok, pBOOL),
1430e3d5408SPeter Wemm DATA(_immed, pBOOL),
1440e3d5408SPeter Wemm DATA(_sync, pBOOL),
1454a1a9510SRong-En Fan DATA(_use_keypad, pBOOL),
1460e3d5408SPeter Wemm DATA(_delay, pINT),
1474a1a9510SRong-En Fan DATA(_regtop, pSIZE),
1480e3d5408SPeter Wemm DATA(_regbottom, pSIZE),
1495ca44d1cSRong-En Fan DATA(_pad._pad_y, pSIZE),
1505ca44d1cSRong-En Fan DATA(_pad._pad_x, pSIZE),
1515ca44d1cSRong-En Fan DATA(_pad._pad_top, pSIZE),
1525ca44d1cSRong-En Fan DATA(_pad._pad_left, pSIZE),
1530e3d5408SPeter Wemm DATA(_pad._pad_bottom, pSIZE),
1540e3d5408SPeter Wemm DATA(_pad._pad_right, pSIZE),
1550e3d5408SPeter Wemm DATA(_yoffset, pSIZE),
1560e3d5408SPeter Wemm #if NCURSES_WIDECHAR
1570e3d5408SPeter Wemm DATA(_bkgrnd, pCCHAR),
1587a69bbfbSPeter Wemm #if NCURSES_EXT_COLORS
1597a69bbfbSPeter Wemm DATA(_color, pINT),
1600e3d5408SPeter Wemm #endif
1610e3d5408SPeter Wemm #endif
1620e3d5408SPeter Wemm };
1630e3d5408SPeter Wemm #undef DATA
1640e3d5408SPeter Wemm
1650e3d5408SPeter Wemm static const NCURSES_CH_T blank = NewChar(BLANK_TEXT);
1664a1a9510SRong-En Fan
1670e3d5408SPeter Wemm /*
1684a1a9510SRong-En Fan * Allocate and read a line of text. Caller must free it.
1690e3d5408SPeter Wemm */
1700e3d5408SPeter Wemm static char *
read_txt(FILE * fp)1710e3d5408SPeter Wemm read_txt(FILE *fp)
1720e3d5408SPeter Wemm {
1730e3d5408SPeter Wemm size_t limit = 1024;
1740e3d5408SPeter Wemm char *result = malloc(limit);
1757a69bbfbSPeter Wemm char *buffer;
1767a69bbfbSPeter Wemm
1770e3d5408SPeter Wemm if (result != 0) {
1780e3d5408SPeter Wemm int ch = 0;
1790e3d5408SPeter Wemm size_t used = 0;
1800e3d5408SPeter Wemm
1810e3d5408SPeter Wemm clearerr(fp);
1820e3d5408SPeter Wemm result[used] = '\0';
1830e3d5408SPeter Wemm do {
1840e3d5408SPeter Wemm if (used + 2 >= limit) {
1850e3d5408SPeter Wemm limit += 1024;
1864a1a9510SRong-En Fan buffer = realloc(result, limit);
1870e3d5408SPeter Wemm if (buffer == 0) {
1884a1a9510SRong-En Fan free(result);
1890e3d5408SPeter Wemm result = 0;
1905ca44d1cSRong-En Fan break;
1915ca44d1cSRong-En Fan }
1925ca44d1cSRong-En Fan result = buffer;
1935ca44d1cSRong-En Fan }
1940e3d5408SPeter Wemm ch = fgetc(fp);
1950e3d5408SPeter Wemm if (ch == EOF)
1960e3d5408SPeter Wemm break;
1970e3d5408SPeter Wemm result[used++] = (char) ch;
1980e3d5408SPeter Wemm result[used] = '\0';
1997a69bbfbSPeter Wemm } while (ch != '\n');
2007a69bbfbSPeter Wemm
2010e3d5408SPeter Wemm if (ch == '\n') {
2020e3d5408SPeter Wemm result[--used] = '\0';
2030e3d5408SPeter Wemm T(("READ:%s", result));
2044a1a9510SRong-En Fan } else if (used == 0) {
2050e3d5408SPeter Wemm free(result);
2064a1a9510SRong-En Fan result = 0;
2070e3d5408SPeter Wemm }
2085ca44d1cSRong-En Fan }
2095ca44d1cSRong-En Fan return result;
2105ca44d1cSRong-En Fan }
2115ca44d1cSRong-En Fan
2120e3d5408SPeter Wemm static char *
decode_attr(char * source,attr_t * target,int * color)2130e3d5408SPeter Wemm decode_attr(char *source, attr_t *target, int *color)
2140e3d5408SPeter Wemm {
215 bool found = FALSE;
216
217 T(("decode_attr '%s'", source));
218
219 while (*source) {
220 if (source[0] == MARKER && source[1] == L_CURL) {
221 source += 2;
222 found = TRUE;
223 } else if (source[0] == R_CURL) {
224 source++;
225 found = FALSE;
226 } else if (found) {
227 size_t n;
228 char *next = source;
229
230 if (source[0] == GUTTER) {
231 ++next;
232 } else if (*next == 'C') {
233 int value = 0;
234 unsigned pair;
235 next++;
236 while (isdigit(UChar(*next))) {
237 value = value * 10 + (*next++ - '0');
238 }
239 *target &= ~A_COLOR;
240 pair = (unsigned) ((value > 256)
241 ? COLOR_PAIR(255)
242 : COLOR_PAIR(value));
243 *target |= pair;
244 *color = value;
245 } else {
246 while (isalnum(UChar(*next))) {
247 ++next;
248 }
249 for (n = 0; n < SIZEOF(scr_attrs); ++n) {
250 if ((size_t) (next - source) == strlen(scr_attrs[n].name)) {
251 if (scr_attrs[n].attr) {
252 *target |= scr_attrs[n].attr;
253 } else {
254 *target = A_NORMAL;
255 }
256 break;
257 }
258 }
259 }
260 source = next;
261 } else {
262 break;
263 }
264 }
265 return source;
266 }
267
268 static char *
decode_char(char * source,int * target)269 decode_char(char *source, int *target)
270 {
271 int limit = 0;
272 int base = 16;
273 const char digits[] = "0123456789abcdef";
274
275 T(("decode_char '%s'", source));
276 *target = ' ';
277 switch (*source) {
278 case MARKER:
279 switch (*++source) {
280 case APPEND:
281 break;
282 case MARKER:
283 *target = MARKER;
284 ++source;
285 break;
286 case 's':
287 *target = ' ';
288 ++source;
289 break;
290 case '0':
291 case '1':
292 case '2':
293 case '3':
294 base = 8;
295 limit = 3;
296 break;
297 case 'u':
298 limit = 4;
299 ++source;
300 break;
301 case 'U':
302 limit = 8;
303 ++source;
304 break;
305 }
306 if (limit) {
307 *target = 0;
308 while (limit-- > 0) {
309 char *find = strchr(digits, *source++);
310 int ch = (find != 0) ? (int) (find - digits) : -1;
311 *target *= base;
312 if (ch >= 0 && ch < base) {
313 *target += ch;
314 }
315 }
316 }
317 break;
318 default:
319 *target = *source++;
320 break;
321 }
322 return source;
323 }
324
325 static char *
decode_chtype(char * source,chtype fillin,chtype * target)326 decode_chtype(char *source, chtype fillin, chtype *target)
327 {
328 attr_t attr = ChAttrOf(fillin);
329 int color = PAIR_NUMBER((int) attr);
330 int value;
331
332 T(("decode_chtype '%s'", source));
333 source = decode_attr(source, &attr, &color);
334 source = decode_char(source, &value);
335 *target = (ChCharOf(value) | attr | (chtype) COLOR_PAIR(color));
336 /* FIXME - ignore combining characters */
337 return source;
338 }
339
340 #if NCURSES_WIDECHAR
341 static char *
decode_cchar(char * source,cchar_t * fillin,cchar_t * target)342 decode_cchar(char *source, cchar_t *fillin, cchar_t *target)
343 {
344 int color;
345 attr_t attr = fillin->attr;
346 wchar_t chars[CCHARW_MAX];
347 int append = 0;
348 int value = 0;
349
350 T(("decode_cchar '%s'", source));
351 *target = blank;
352 #if NCURSES_EXT_COLORS
353 color = fillin->ext_color;
354 #else
355 color = (int) PAIR_NUMBER(attr);
356 #endif
357 source = decode_attr(source, &attr, &color);
358 memset(chars, 0, sizeof(chars));
359 source = decode_char(source, &value);
360 chars[0] = (wchar_t) value;
361 /* handle combining characters */
362 while (source[0] == MARKER && source[1] == APPEND) {
363 source += 2;
364 source = decode_char(source, &value);
365 if (++append < CCHARW_MAX) {
366 chars[append] = (wchar_t) value;
367 }
368 }
369 setcchar(target, chars, attr, (short) color, &color);
370 return source;
371 }
372 #endif
373
374 static int
read_win(WINDOW * win,FILE * fp)375 read_win(WINDOW *win, FILE *fp)
376 {
377 int code = ERR;
378 size_t n;
379 int color;
380 #if NCURSES_WIDECHAR
381 NCURSES_CH_T prior;
382 #endif
383 chtype prior2;
384
385 memset(win, 0, sizeof(WINDOW));
386 for (;;) {
387 char *name;
388 char *value;
389 char *txt = read_txt(fp);
390
391 if (txt == 0)
392 break;
393 if (!strcmp(txt, "rows:")) {
394 free(txt);
395 code = OK;
396 break;
397 }
398 if ((value = strchr(txt, '=')) == 0) {
399 free(txt);
400 continue;
401 }
402 *value++ = '\0';
403 name = !strcmp(txt, "flag") ? value : txt;
404 for (n = 0; n < SIZEOF(scr_params); ++n) {
405 if (!strcmp(name, scr_params[n].name)) {
406 void *data = (void *) ((char *) win + scr_params[n].offset);
407
408 switch (scr_params[n].type) {
409 case pATTR:
410 (void) decode_attr(value, data, &color);
411 break;
412 case pBOOL:
413 *(bool *) data = TRUE;
414 break;
415 case pCHAR:
416 prior2 = ' ';
417 decode_chtype(value, prior2, data);
418 break;
419 case pINT:
420 *(int *) data = atoi(value);
421 break;
422 case pSHORT:
423 *(short *) data = (short) atoi(value);
424 break;
425 case pSIZE:
426 *(NCURSES_SIZE_T *) data = (NCURSES_SIZE_T) atoi(value);
427 break;
428 #if NCURSES_WIDECHAR
429 case pCCHAR:
430 prior = blank;
431 decode_cchar(value, &prior, data);
432 break;
433 #endif
434 }
435 break;
436 }
437 }
438 free(txt);
439 }
440 return code;
441 }
442
443 static int
read_row(char * source,NCURSES_CH_T * prior,NCURSES_CH_T * target,int length)444 read_row(char *source, NCURSES_CH_T *prior, NCURSES_CH_T *target, int length)
445 {
446 while (*source != '\0' && length > 0) {
447 #if NCURSES_WIDECHAR
448 int len;
449
450 source = decode_cchar(source, prior, target);
451 len = _nc_wacs_width(target->chars[0]);
452 if (len > 1) {
453 int n;
454
455 SetWidecExt(CHDEREF(target), 0);
456 for (n = 1; n < len; ++n) {
457 target[n] = target[0];
458 SetWidecExt(CHDEREF(target), n);
459 }
460 target += (len - 1);
461 length -= (len - 1);
462 }
463 #else
464 source = decode_chtype(source, *prior, target);
465 #endif
466 *prior = *target;
467 ++target;
468 --length;
469 }
470 while (length-- > 0) {
471 *target++ = blank;
472 }
473 /* FIXME - see what error conditions should apply if I need to return ERR */
474 return 0;
475 }
476 #endif /* NCURSES_EXT_PUTWIN */
477
478 /*
479 * Originally, getwin/putwin used fread/fwrite, because they used binary data.
480 * The new format uses printable ASCII, which does not have as predictable
481 * sizes. Consequently, we use buffered I/O, e.g., fgetc/fprintf, which need
482 * special handling if we want to read screen dumps from an older library.
483 */
484 static int
read_block(void * target,size_t length,FILE * fp)485 read_block(void *target, size_t length, FILE *fp)
486 {
487 int result = 0;
488 char *buffer = target;
489
490 clearerr(fp);
491 while (length-- != 0) {
492 int ch = fgetc(fp);
493 if (ch == EOF) {
494 result = -1;
495 break;
496 }
497 *buffer++ = (char) ch;
498 }
499 return result;
500 }
501
502 NCURSES_EXPORT(WINDOW *)
NCURSES_SP_NAME(getwin)503 NCURSES_SP_NAME(getwin) (NCURSES_SP_DCLx FILE *filep)
504 {
505 WINDOW tmp, *nwin;
506 bool old_format = FALSE;
507
508 T((T_CALLED("getwin(%p)"), (void *) filep));
509
510 if (filep == 0) {
511 returnWin(0);
512 }
513
514 /*
515 * Read the first 4 bytes to determine first if this is an old-format
516 * screen-dump, or new-format.
517 */
518 if (read_block(&tmp, (size_t) 4, filep) < 0) {
519 returnWin(0);
520 }
521 /*
522 * If this is a new-format file, and we do not support it, give up.
523 */
524 if (!memcmp(&tmp, my_magic, (size_t) 4)) {
525 #if NCURSES_EXT_PUTWIN
526 if (read_win(&tmp, filep) < 0)
527 #endif
528 returnWin(0);
529 } else if (read_block(((char *) &tmp) + 4, sizeof(WINDOW) - 4, filep) < 0) {
530 returnWin(0);
531 } else {
532 old_format = TRUE;
533 }
534
535 /*
536 * Check the window-size:
537 */
538 if (tmp._maxy == 0 ||
539 tmp._maxy > MAX_SIZE ||
540 tmp._maxx == 0 ||
541 tmp._maxx > MAX_SIZE) {
542 returnWin(0);
543 }
544
545 if (tmp._flags & _ISPAD) {
546 nwin = NCURSES_SP_NAME(newpad) (NCURSES_SP_ARGx
547 tmp._maxy + 1,
548 tmp._maxx + 1);
549 } else {
550 nwin = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
551 tmp._maxy + 1,
552 tmp._maxx + 1, 0, 0);
553 }
554
555 /*
556 * We deliberately do not restore the _parx, _pary, or _parent
557 * fields, because the window hierarchy within which they
558 * made sense is probably gone.
559 */
560 if (nwin != 0) {
561 int n;
562 size_t linesize = sizeof(NCURSES_CH_T) * (size_t) (tmp._maxx + 1);
563
564 nwin->_curx = tmp._curx;
565 nwin->_cury = tmp._cury;
566 nwin->_maxy = tmp._maxy;
567 nwin->_maxx = tmp._maxx;
568 nwin->_begy = tmp._begy;
569 nwin->_begx = tmp._begx;
570 nwin->_yoffset = tmp._yoffset;
571 nwin->_flags = tmp._flags & ~(_SUBWIN);
572
573 WINDOW_ATTRS(nwin) = WINDOW_ATTRS(&tmp);
574 nwin->_nc_bkgd = tmp._nc_bkgd;
575
576 nwin->_notimeout = tmp._notimeout;
577 nwin->_clear = tmp._clear;
578 nwin->_leaveok = tmp._leaveok;
579 nwin->_idlok = tmp._idlok;
580 nwin->_idcok = tmp._idcok;
581 nwin->_immed = tmp._immed;
582 nwin->_scroll = tmp._scroll;
583 nwin->_sync = tmp._sync;
584 nwin->_use_keypad = tmp._use_keypad;
585 nwin->_delay = tmp._delay;
586
587 nwin->_regtop = tmp._regtop;
588 nwin->_regbottom = tmp._regbottom;
589
590 if (tmp._flags & _ISPAD)
591 nwin->_pad = tmp._pad;
592
593 if (old_format) {
594 T(("reading old-format screen dump"));
595 for (n = 0; n <= nwin->_maxy; n++) {
596 if (read_block(nwin->_line[n].text, linesize, filep) < 0) {
597 delwin(nwin);
598 returnWin(0);
599 }
600 }
601 }
602 #if NCURSES_EXT_PUTWIN
603 else {
604 char *txt = 0;
605 bool success = TRUE;
606 NCURSES_CH_T prior = blank;
607
608 T(("reading new-format screen dump"));
609 for (n = 0; n <= nwin->_maxy; n++) {
610 long row;
611 char *next;
612
613 if ((txt = read_txt(filep)) == 0) {
614 T(("...failed to read string for row %d", n + 1));
615 success = FALSE;
616 break;
617 }
618 row = strtol(txt, &next, 10);
619 if (row != (n + 1) || *next != ':') {
620 T(("...failed to read row-number %d", n + 1));
621 success = FALSE;
622 break;
623 }
624
625 if (read_row(++next, &prior, nwin->_line[n].text, tmp._maxx
626 + 1) < 0) {
627 T(("...failed to read cells for row %d", n + 1));
628 success = FALSE;
629 break;
630 }
631 free(txt);
632 txt = 0;
633 }
634
635 if (!success) {
636 free(txt);
637 delwin(nwin);
638 returnWin(0);
639 }
640 }
641 #endif
642 touchwin(nwin);
643 }
644 returnWin(nwin);
645 }
646
647 #if NCURSES_SP_FUNCS
648 NCURSES_EXPORT(WINDOW *)
getwin(FILE * filep)649 getwin(FILE *filep)
650 {
651 return NCURSES_SP_NAME(getwin) (CURRENT_SCREEN, filep);
652 }
653 #endif
654
655 #if NCURSES_EXT_PUTWIN
656 static void
encode_attr(char * target,ARG_SLIMIT (limit)attr_t source,attr_t prior,int source_color,int prior_color)657 encode_attr(char *target, ARG_SLIMIT(limit)
658 attr_t source,
659 attr_t prior,
660 int source_color,
661 int prior_color)
662 {
663 #if USE_STRING_HACKS && HAVE_SNPRINTF
664 char *base = target;
665 #endif
666 source &= ~A_CHARTEXT;
667 prior &= ~A_CHARTEXT;
668
669 *target = '\0';
670 if ((source != prior) || (source_color != prior_color)) {
671 size_t n;
672 bool first = TRUE;
673
674 *target++ = MARKER;
675 *target++ = L_CURL;
676
677 for (n = 0; n < SIZEOF(scr_attrs); ++n) {
678 if ((source & scr_attrs[n].attr) != 0 ||
679 ((source & ALL_BUT_COLOR) == 0 &&
680 (scr_attrs[n].attr == A_NORMAL))) {
681 if (first) {
682 first = FALSE;
683 } else {
684 *target++ = '|';
685 }
686 _nc_STRCPY(target, scr_attrs[n].name, limit);
687 target += strlen(target);
688 }
689 }
690 if (source_color != prior_color) {
691 if (!first)
692 *target++ = '|';
693 _nc_SPRINTF(target, CUR_SLIMIT "C%d", source_color);
694 target += strlen(target);
695 }
696
697 *target++ = R_CURL;
698 *target = '\0';
699 }
700 }
701
702 static void
encode_cell(char * target,ARG_SLIMIT (limit)CARG_CH_T source,CARG_CH_T previous)703 encode_cell(char *target, ARG_SLIMIT(limit) CARG_CH_T source, CARG_CH_T previous)
704 {
705 #if USE_STRING_HACKS && HAVE_SNPRINTF
706 char *base = target;
707 #endif
708 #if NCURSES_WIDECHAR
709 size_t n;
710 int source_pair = GetPair(*source);
711 int previous_pair = GetPair(*previous);
712
713 *target = '\0';
714 if ((previous->attr != source->attr) || (previous_pair != source_pair)) {
715 encode_attr(target, CUR_SLIMIT
716 source->attr,
717 previous->attr,
718 source_pair,
719 previous_pair);
720 }
721 target += strlen(target);
722 #if NCURSES_EXT_COLORS
723 if (previous->ext_color != source->ext_color) {
724 _nc_SPRINTF(target, CUR_SLIMIT
725 "%c%cC%d%c", MARKER, L_CURL, source->ext_color, R_CURL);
726 }
727 #endif
728 for (n = 0; n < SIZEOF(source->chars); ++n) {
729 unsigned uch = (unsigned) source->chars[n];
730 if (uch == 0)
731 continue;
732 if (n) {
733 *target++ = MARKER;
734 *target++ = APPEND;
735 }
736 *target++ = MARKER;
737 if (uch > 0xffff) {
738 _nc_SPRINTF(target, CUR_SLIMIT "U%08x", uch);
739 } else if (uch > 0xff) {
740 _nc_SPRINTF(target, CUR_SLIMIT "u%04x", uch);
741 } else if (uch < 32 || uch >= 127) {
742 _nc_SPRINTF(target, CUR_SLIMIT "%03o", uch & 0xff);
743 } else {
744 switch (uch) {
745 case ' ':
746 _nc_STRCPY(target, "s", limit);
747 break;
748 case MARKER:
749 *target++ = MARKER;
750 *target = '\0';
751 break;
752 default:
753 --target;
754 _nc_SPRINTF(target, CUR_SLIMIT "%c", uch);
755 break;
756 }
757 }
758 target += strlen(target);
759 }
760 #else
761 chtype ch = CharOfD(source);
762
763 *target = '\0';
764 if (AttrOfD(previous) != AttrOfD(source)) {
765 encode_attr(target, CUR_SLIMIT
766 AttrOfD(source),
767 AttrOfD(previous),
768 GetPair(source),
769 GetPair(previous));
770 }
771 target += strlen(target);
772 *target++ = MARKER;
773 if (ch < 32 || ch >= 127) {
774 _nc_SPRINTF(target, CUR_SLIMIT "%03o", UChar(ch));
775 } else {
776 switch (ch) {
777 case ' ':
778 _nc_STRCPY(target, "s", limit);
779 break;
780 case MARKER:
781 *target++ = MARKER;
782 *target = '\0';
783 break;
784 default:
785 --target;
786 _nc_SPRINTF(target, CUR_SLIMIT "%c", UChar(ch));
787 break;
788 }
789 }
790 #endif
791 }
792 #endif
793
794 NCURSES_EXPORT(int)
putwin(WINDOW * win,FILE * filep)795 putwin(WINDOW *win, FILE *filep)
796 {
797 int code = ERR;
798
799 T((T_CALLED("putwin(%p,%p)"), (void *) win, (void *) filep));
800
801 #if NCURSES_EXT_PUTWIN
802 if (win != 0) {
803 const char *version = curses_version();
804 char buffer[1024];
805 NCURSES_CH_T last_cell;
806 int y;
807
808 memset(&last_cell, 0, sizeof(last_cell));
809
810 clearerr(filep);
811
812 /*
813 * Our magic number is technically nonprinting, but aside from that,
814 * all of the file is printable ASCII.
815 */
816 #define PUTS(s) if (fputs(s, filep) == EOF || ferror(filep)) returnCode(code)
817 PUTS(my_magic);
818 PUTS(version);
819 PUTS("\n");
820 for (y = 0; y < (int) SIZEOF(scr_params); ++y) {
821 const char *name = scr_params[y].name;
822 const char *data = (char *) win + scr_params[y].offset;
823 const void *dp = (const void *) data;
824 attr_t attr;
825
826 *buffer = '\0';
827 if (!strncmp(name, "_pad.", (size_t) 5) && !(win->_flags & _ISPAD)) {
828 continue;
829 }
830 switch (scr_params[y].type) {
831 case pATTR:
832 attr = (*(const attr_t *) dp) & ~A_CHARTEXT;
833 encode_attr(buffer, TOP_SLIMIT
834 (*(const attr_t *) dp) & ~A_CHARTEXT,
835 A_NORMAL,
836 COLOR_PAIR((int) attr),
837 0);
838 break;
839 case pBOOL:
840 if (!(*(const bool *) data)) {
841 continue;
842 }
843 _nc_STRCPY(buffer, name, sizeof(buffer));
844 name = "flag";
845 break;
846 case pCHAR:
847 attr = (*(const attr_t *) dp);
848 encode_attr(buffer, TOP_SLIMIT
849 * (const attr_t *) dp,
850 A_NORMAL,
851 COLOR_PAIR((int) attr),
852 0);
853 break;
854 case pINT:
855 if (!(*(const int *) dp))
856 continue;
857 _nc_SPRINTF(buffer, TOP_SLIMIT
858 "%d", *(const int *) dp);
859 break;
860 case pSHORT:
861 if (!(*(const short *) dp))
862 continue;
863 _nc_SPRINTF(buffer, TOP_SLIMIT
864 "%d", *(const short *) dp);
865 break;
866 case pSIZE:
867 if (!(*(const NCURSES_SIZE_T *) dp))
868 continue;
869 _nc_SPRINTF(buffer, TOP_SLIMIT
870 "%d", *(const NCURSES_SIZE_T *) dp);
871 break;
872 #if NCURSES_WIDECHAR
873 case pCCHAR:
874 encode_cell(buffer, TOP_SLIMIT
875 (CARG_CH_T) dp, CHREF(last_cell));
876 break;
877 #endif
878 }
879 /*
880 * Only write non-default data.
881 */
882 if (*buffer != '\0') {
883 if (fprintf(filep, "%s=%s\n", name, buffer) <= 0
884 || ferror(filep))
885 returnCode(code);
886 }
887 }
888 /* Write row-data */
889 fprintf(filep, "rows:\n");
890 for (y = 0; y <= win->_maxy; y++) {
891 NCURSES_CH_T *data = win->_line[y].text;
892 int x;
893 if (fprintf(filep, "%d:", y + 1) <= 0
894 || ferror(filep))
895 returnCode(code);
896 for (x = 0; x <= win->_maxx; x++) {
897 #if NCURSES_WIDECHAR
898 int len = _nc_wacs_width(data[x].chars[0]);
899 encode_cell(buffer, TOP_SLIMIT CHREF(data[x]), CHREF(last_cell));
900 last_cell = data[x];
901 PUTS(buffer);
902 if (len > 1)
903 x += (len - 1);
904 #else
905 encode_cell(buffer, TOP_SLIMIT CHREF(data[x]), CHREF(last_cell));
906 last_cell = data[x];
907 PUTS(buffer);
908 #endif
909 }
910 PUTS("\n");
911 }
912 code = OK;
913 }
914 #else
915 /*
916 * This is the original putwin():
917 * A straight binary dump is simple, but its format can depend on whether
918 * ncurses is compiled with wide-character support, and also may depend
919 * on the version of ncurses, e.g., if the WINDOW structure is extended.
920 */
921 if (win != 0) {
922 size_t len = (size_t) (win->_maxx + 1);
923 int y;
924
925 clearerr(filep);
926 if (fwrite(win, sizeof(WINDOW), (size_t) 1, filep) != 1
927 || ferror(filep))
928 returnCode(code);
929
930 for (y = 0; y <= win->_maxy; y++) {
931 if (fwrite(win->_line[y].text,
932 sizeof(NCURSES_CH_T), len, filep) != len
933 || ferror(filep)) {
934 returnCode(code);
935 }
936 }
937 code = OK;
938 }
939 #endif
940 returnCode(code);
941 }
942
943 NCURSES_EXPORT(int)
NCURSES_SP_NAME(scr_restore)944 NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file)
945 {
946 FILE *fp = 0;
947 int code = ERR;
948
949 T((T_CALLED("scr_restore(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
950
951 if (_nc_access(file, R_OK) >= 0
952 && (fp = fopen(file, BIN_R)) != 0) {
953 delwin(NewScreen(SP_PARM));
954 NewScreen(SP_PARM) = getwin(fp);
955 #if !USE_REENTRANT
956 newscr = NewScreen(SP_PARM);
957 #endif
958 (void) fclose(fp);
959 if (NewScreen(SP_PARM) != 0) {
960 code = OK;
961 }
962 }
963 returnCode(code);
964 }
965
966 #if NCURSES_SP_FUNCS
967 NCURSES_EXPORT(int)
scr_restore(const char * file)968 scr_restore(const char *file)
969 {
970 return NCURSES_SP_NAME(scr_restore) (CURRENT_SCREEN, file);
971 }
972 #endif
973
974 NCURSES_EXPORT(int)
scr_dump(const char * file)975 scr_dump(const char *file)
976 {
977 int result;
978 FILE *fp = 0;
979
980 T((T_CALLED("scr_dump(%s)"), _nc_visbuf(file)));
981
982 if (_nc_access(file, W_OK) < 0
983 || (fp = fopen(file, BIN_W)) == 0) {
984 result = ERR;
985 } else {
986 (void) putwin(newscr, fp);
987 (void) fclose(fp);
988 result = OK;
989 }
990 returnCode(result);
991 }
992
993 NCURSES_EXPORT(int)
NCURSES_SP_NAME(scr_init)994 NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file)
995 {
996 int code = ERR;
997
998 T((T_CALLED("scr_init(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
999
1000 if (SP_PARM != 0 &&
1001 #ifdef USE_TERM_DRIVER
1002 InfoOf(SP_PARM).caninit
1003 #else
1004 !(exit_ca_mode && non_rev_rmcup)
1005 #endif
1006 ) {
1007 FILE *fp = 0;
1008
1009 if (_nc_access(file, R_OK) >= 0
1010 && (fp = fopen(file, BIN_R)) != 0) {
1011 delwin(CurScreen(SP_PARM));
1012 CurScreen(SP_PARM) = getwin(fp);
1013 #if !USE_REENTRANT
1014 curscr = CurScreen(SP_PARM);
1015 #endif
1016 (void) fclose(fp);
1017 if (CurScreen(SP_PARM) != 0) {
1018 code = OK;
1019 }
1020 }
1021 }
1022 returnCode(code);
1023 }
1024
1025 #if NCURSES_SP_FUNCS
1026 NCURSES_EXPORT(int)
scr_init(const char * file)1027 scr_init(const char *file)
1028 {
1029 return NCURSES_SP_NAME(scr_init) (CURRENT_SCREEN, file);
1030 }
1031 #endif
1032
1033 NCURSES_EXPORT(int)
NCURSES_SP_NAME(scr_set)1034 NCURSES_SP_NAME(scr_set) (NCURSES_SP_DCLx const char *file)
1035 {
1036 int code = ERR;
1037
1038 T((T_CALLED("scr_set(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));
1039
1040 if (NCURSES_SP_NAME(scr_init) (NCURSES_SP_ARGx file) == OK) {
1041 delwin(NewScreen(SP_PARM));
1042 NewScreen(SP_PARM) = dupwin(curscr);
1043 #if !USE_REENTRANT
1044 newscr = NewScreen(SP_PARM);
1045 #endif
1046 if (NewScreen(SP_PARM) != 0) {
1047 code = OK;
1048 }
1049 }
1050 returnCode(code);
1051 }
1052
1053 #if NCURSES_SP_FUNCS
1054 NCURSES_EXPORT(int)
scr_set(const char * file)1055 scr_set(const char *file)
1056 {
1057 return NCURSES_SP_NAME(scr_set) (CURRENT_SCREEN, file);
1058 }
1059 #endif
1060