ncurses 6.0 - patch 20160206
[ncurses.git] / test / savescreen.c
1 /****************************************************************************
2  * Copyright (c) 2007-2011,2015 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 /*
29  * $Id: savescreen.c,v 1.28 2015/08/22 22:40:22 tom Exp $
30  *
31  * Demonstrate save/restore functions from the curses library.
32  * Thomas Dickey - 2007/7/14
33  */
34
35 #include <test.priv.h>
36
37 #if HAVE_SCR_DUMP
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #if TIME_WITH_SYS_TIME
43 # include <sys/time.h>
44 # include <time.h>
45 #else
46 # if HAVE_SYS_TIME_H
47 #  include <sys/time.h>
48 # else
49 #  include <time.h>
50 # endif
51 #endif
52
53 static bool use_init = FALSE;
54 static bool keep_dumps = FALSE;
55
56 static int
57 fexists(const char *name)
58 {
59     struct stat sb;
60     return (stat(name, &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFREG);
61 }
62
63 static void
64 setup_next(void)
65 {
66     curs_set(1);
67     reset_shell_mode();
68 }
69
70 static void
71 cleanup(char *files[])
72 {
73     int n;
74
75     if (!keep_dumps) {
76         for (n = 0; files[n] != 0; ++n) {
77             unlink(files[n]);
78         }
79     }
80 }
81
82 static int
83 load_screen(char *filename)
84 {
85     int result;
86
87     if (use_init) {
88         if ((result = scr_init(filename)) != ERR)
89             result = scr_restore(filename);
90     } else {
91         result = scr_set(filename);
92     }
93     return result;
94 }
95
96 /*
97  * scr_restore() or scr_set() operates on curscr.  If we read a character using
98  * getch() that will refresh stdscr, wiping out the result.  To avoid that,
99  * copy the data back from curscr to stdscr.
100  */
101 static void
102 after_load(void)
103 {
104     overwrite(curscr, stdscr);
105     doupdate();
106 }
107
108 static void
109 show_what(int which, int last)
110 {
111     int y, x, n;
112     time_t now;
113     char *mytime;
114
115     getyx(stdscr, y, x);
116
117     move(0, 0);
118     printw("Saved %d of %d (? for help)", which, last + 1);
119
120     now = time((time_t *) 0);
121     mytime = ctime(&now);
122     for (n = (int) strlen(mytime) - 1; n >= 0; --n) {
123         if (isspace(UChar(mytime[n]))) {
124             mytime[n] = '\0';
125         } else {
126             break;
127         }
128     }
129     mvprintw(0, (COLS - n - 2), " %s", mytime);
130
131     move(y, x);
132
133     refresh();
134 }
135
136 static int
137 get_command(int which, int last)
138 {
139     int ch;
140
141     timeout(50);
142
143     do {
144         show_what(which, last);
145         ch = getch();
146     } while (ch == ERR);
147
148     return ch;
149 }
150
151 static void
152 show_help(const char **help)
153 {
154     WINDOW *mywin = newwin(LINES, COLS, 0, 0);
155     int n;
156
157     box(mywin, 0, 0);
158     wmove(mywin, 1, 1);
159     for (n = 0; help[n] != 0; ++n) {
160         wmove(mywin, 1 + n, 2);
161         wprintw(mywin, "%.*s", COLS - 4, help[n]);
162     }
163     wgetch(mywin);
164     delwin(mywin);
165     touchwin(stdscr);
166     refresh();
167 }
168
169 static void
170 editor_help(void)
171 {
172     static const char *msgs[] =
173     {
174         "You are now in the screen-editor, which allows you to make some",
175         "lines on the screen, as well as save copies of the screen to a",
176         "temporary file",
177         "",
178         "Keys:",
179         "   q           quit",
180         "   n           run the screen-loader to show the saved screens",
181         "   <space>     dump a screen",
182         "",
183         "   a           toggle between '#' and graphic symbol for drawing",
184         "   c           change color drawn by line to next in palette",
185         "   h,j,k,l or arrows to move around the screen, drawing",
186     };
187     show_help(msgs);
188 }
189
190 static void
191 replay_help(void)
192 {
193     static const char *msgs[] =
194     {
195         "You are now in the screen-loader, which allows you to view",
196         "the dumped/restored screens.",
197         "",
198         "Keys:",
199         "   q           quit",
200         "   <space>     load the next screen",
201         "   <backspace> load the previous screen",
202     };
203     show_help(msgs);
204 }
205
206 static void
207 usage(void)
208 {
209     static const char *msg[] =
210     {
211         "Usage: savescreen [-r] files",
212         "",
213         "Options:",
214         " -f file  fill/initialize screen using text from this file",
215         " -i       use scr_init/scr_restore rather than scr_set",
216         " -k       keep the restored dump-files rather than removing them",
217         " -r       replay the screen-dump files"
218     };
219     unsigned n;
220     for (n = 0; n < SIZEOF(msg); ++n) {
221         fprintf(stderr, "%s\n", msg[n]);
222     }
223     ExitProgram(EXIT_FAILURE);
224 }
225
226 int
227 main(int argc, char *argv[])
228 {
229     int ch;
230     int which = 0;
231     int last;
232     bool replaying = FALSE;
233     bool done = FALSE;
234     char **files;
235     char *fill_by = 0;
236 #if USE_WIDEC_SUPPORT
237     cchar_t mycc;
238     int myxx;
239 #endif
240
241     setlocale(LC_ALL, "");
242
243     while ((ch = getopt(argc, argv, "f:ikr")) != -1) {
244         switch (ch) {
245         case 'f':
246             fill_by = optarg;
247             break;
248         case 'i':
249             use_init = TRUE;
250             break;
251         case 'k':
252             keep_dumps = TRUE;
253             break;
254         case 'r':
255             replaying = TRUE;
256             break;
257         default:
258             usage();
259             break;
260         }
261     }
262
263     files = argv + optind;
264     last = argc - optind - 1;
265
266     if (replaying) {
267         while (last >= 0 && !fexists(files[last]))
268             --last;
269     }
270
271     initscr();
272     cbreak();
273     noecho();
274     keypad(stdscr, TRUE);
275     curs_set(0);
276     if (has_colors()) {
277         short pair;
278         short color;
279
280         start_color();
281         /*
282          * Assume pairs is the square of colors, and assign pairs going down
283          * so that there is minimal conflict with the background color (which
284          * counts up).  The intent is just to show how color pair values are
285          * saved and restored.
286          */
287         for (pair = 0; pair < COLOR_PAIRS; ++pair) {
288             color = (short) (pair % (COLORS - 1));
289             init_pair(pair, (short) (COLOR_WHITE - color), color);
290         }
291     }
292
293     if (fill_by != 0) {
294         FILE *fp = fopen(fill_by, "r");
295         if (fp != 0) {
296             bool filled = FALSE;
297             move(1, 0);
298             while ((ch = fgetc(fp)) != EOF) {
299                 if (addch(UChar(ch)) == ERR) {
300                     filled = TRUE;
301                     break;
302                 }
303             }
304             fclose(fp);
305             if (!filled) {
306                 while (addch(' ') != ERR) {
307                     ;
308                 }
309             }
310             move(0, 0);
311         } else {
312             endwin();
313             fprintf(stderr, "Cannot open \"%s\"\n", fill_by);
314             ExitProgram(EXIT_FAILURE);
315         }
316     }
317
318     if (replaying) {
319
320         /*
321          * Use the last file as the initial/current screen.
322          */
323         if (last < 0) {
324             endwin();
325             printf("No screen-dumps given\n");
326             ExitProgram(EXIT_FAILURE);
327         }
328
329         which = last;
330         if (load_screen(files[which]) == ERR) {
331             endwin();
332             printf("Cannot load screen-dump %s\n", files[which]);
333             ExitProgram(EXIT_FAILURE);
334         }
335         after_load();
336
337         while (!done && (ch = getch()) != ERR) {
338             switch (ch) {
339             case 'n':
340                 /*
341                  * If we got a "next" here, skip to the final screen before
342                  * moving to the next process.
343                  */
344                 setup_next();
345                 which = last;
346                 done = TRUE;
347                 break;
348             case 'q':
349                 cleanup(files);
350                 done = TRUE;
351                 break;
352             case KEY_BACKSPACE:
353             case '\b':
354                 if (--which < 0)
355                     which = last;
356                 break;
357             case ' ':
358                 if (++which > last)
359                     which = 0;
360                 break;
361             case '?':
362                 replay_help();
363                 break;
364             default:
365                 beep();
366                 continue;
367             }
368
369             if (ch == 'q') {
370                 ;
371             } else if (scr_restore(files[which]) == ERR) {
372                 endwin();
373                 printf("Cannot load screen-dump %s\n", files[which]);
374                 cleanup(files);
375                 ExitProgram(EXIT_FAILURE);
376             } else {
377                 wrefresh(curscr);
378             }
379         }
380         endwin();
381     } else {
382         int y = 0;
383         int x = 0;
384         int color = 0;
385         int altchars = 0;
386
387         while (!done) {
388             switch (get_command(which, last)) {
389             case 'n':
390                 setup_next();
391                 done = TRUE;
392                 break;
393             case 'q':
394                 cleanup(files);
395                 done = TRUE;
396                 break;
397             case ' ':
398                 if (files[which] != 0) {
399                     show_what(which + 1, last);
400                     if (scr_dump(files[which]) == ERR) {
401                         endwin();
402                         printf("Cannot write screen-dump %s\n", files[which]);
403                         cleanup(files);
404                         done = TRUE;
405                         break;
406                     }
407                     ++which;
408                     if (has_colors()) {
409                         int cx, cy;
410                         short pair = (short) (which % COLOR_PAIRS);
411                         /*
412                          * Change the background color, to make it more
413                          * obvious.  But that changes the existing text-color. 
414                          * Copy the old values from the currently displayed
415                          * screen.
416                          */
417                         bkgd((chtype) COLOR_PAIR(pair));
418                         for (cy = 1; cy < LINES; ++cy) {
419                             for (cx = 0; cx < COLS; ++cx) {
420                                 wmove(curscr, cy, cx);
421                                 wmove(stdscr, cy, cx);
422 #if USE_WIDEC_SUPPORT
423                                 if (win_wch(curscr, &mycc) != ERR) {
424                                     myxx = wcwidth(mycc.chars[0]);
425                                     if (myxx > 0) {
426                                         wadd_wchnstr(stdscr, &mycc, 1);
427                                         cx += (myxx - 1);
428                                     }
429                                 }
430 #else
431                                 waddch(stdscr, winch(curscr));
432 #endif
433                             }
434                         }
435                     }
436                 } else {
437                     beep();
438                 }
439                 break;
440             case KEY_LEFT:
441             case 'h':
442                 if (--x < 0)
443                     x = COLS - 1;
444                 break;
445             case KEY_DOWN:
446             case 'j':
447                 if (++y >= LINES)
448                     y = 1;
449                 break;
450             case KEY_UP:
451             case 'k':
452                 if (--y < 1)
453                     y = LINES - 1;
454                 break;
455             case KEY_RIGHT:
456             case 'l':
457                 if (++x >= COLS)
458                     x = 0;
459                 break;
460             case 'a':
461                 altchars = !altchars;
462                 break;
463             case 'c':
464                 color = (color + 1) % COLORS;
465                 break;
466             case '?':
467                 editor_help();
468                 break;
469             default:
470                 beep();
471                 continue;
472             }
473             if (!done) {
474                 attr_t attr = (A_REVERSE | (attr_t) COLOR_PAIR(color * COLORS));
475                 chtype ch2 = (altchars ? ACS_DIAMOND : '#');
476                 move(y, x);
477                 addch(ch2 | attr);
478                 move(y, x);
479             }
480         }
481         endwin();
482     }
483     ExitProgram(EXIT_SUCCESS);
484 }
485
486 #else
487 int
488 main(int argc, char *argv[])
489 {
490     printf("This program requires the screen-dump functions\n");
491     ExitProgram(EXIT_FAILURE);
492 }
493 #endif