1/****************************************************************************
2 * Copyright (c) 2007 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.10 2007/07/21 17:57:37 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 TIME_WITH_SYS_TIME
38# include <sys/time.h>
39# include <time.h>
40#else
41# if HAVE_SYS_TIME_H
42#  include <sys/time.h>
43# else
44#  include <time.h>
45# endif
46#endif
47
48static bool use_init = FALSE;
49
50static void
51setup_next(void)
52{
53    curs_set(1);
54    reset_shell_mode();
55}
56
57static void
58cleanup(char *files[])
59{
60    int n;
61
62    for (n = 0; files[n] != 0; ++n) {
63	unlink(files[n]);
64    }
65}
66
67static int
68load_screen(char *filename)
69{
70    int result;
71
72    if (use_init) {
73	if ((result = scr_init(filename)) != ERR)
74	    result = scr_restore(filename);
75    } else {
76	result = scr_set(filename);
77    }
78    return result;
79}
80
81/*
82 * scr_restore() or scr_set() operates on curscr.  If we read a character using
83 * getch() that will refresh stdscr, wiping out the result.  To avoid that,
84 * copy the data back from curscr to stdscr.
85 */
86static void
87after_load(void)
88{
89    overwrite(curscr, stdscr);
90    doupdate();
91}
92
93static void
94show_what(int which, int last)
95{
96    int y, x;
97    time_t now = time((time_t *) 0);
98
99    getyx(stdscr, y, x);
100
101    move(0, 0);
102    printw("Saved %d of %d - %s", which, last + 1, ctime(&now));
103
104    move(y, x);
105
106    refresh();
107}
108
109static int
110get_command(int which, int last)
111{
112    int ch;
113
114    timeout(100);
115
116    do {
117	show_what(which, last);
118	ch = getch();
119    } while (ch == ERR);
120
121    return ch;
122}
123
124static void
125usage(void)
126{
127    static const char *msg[] =
128    {
129	"Usage: savescreen [-r] files",
130	"",
131	"Options:",
132	" -i  use scr_init/scr_restore rather than scr_set",
133	" -r  replay the screen-dump files"
134    };
135    unsigned n;
136    for (n = 0; n < SIZEOF(msg); ++n) {
137	fprintf(stderr, "%s\n", msg[n]);
138    }
139    ExitProgram(EXIT_FAILURE);
140}
141
142int
143main(int argc, char *argv[])
144{
145    int ch;
146    int which = 0;
147    int last;
148    bool replaying = FALSE;
149    bool done = FALSE;
150    char **files;
151
152    while ((ch = getopt(argc, argv, "ir")) != -1) {
153	switch (ch) {
154	case 'i':
155	    use_init = TRUE;
156	    break;
157	case 'r':
158	    replaying = TRUE;
159	    break;
160	default:
161	    usage();
162	    break;
163	}
164    }
165
166    initscr();
167    cbreak();
168    noecho();
169    keypad(stdscr, TRUE);
170    curs_set(0);
171    if (has_colors()) {
172	start_color();
173	for (ch = 0; ch < COLOR_PAIRS; ++ch) {
174	    short pair = ch % COLOR_PAIRS;
175	    init_pair(pair, COLOR_WHITE, ch % COLORS);
176	}
177    }
178
179    files = argv + optind;
180    last = argc - optind - 1;
181    if (replaying) {
182
183	/*
184	 * Use the last file as the initial/current screen.
185	 */
186	if (last < 0) {
187	    endwin();
188	    printf("No screen-dumps given\n");
189	    ExitProgram(EXIT_FAILURE);
190	}
191
192	which = last;
193	if (load_screen(files[which]) == ERR) {
194	    endwin();
195	    printf("Cannot load screen-dump %s\n", files[which]);
196	    ExitProgram(EXIT_FAILURE);
197	}
198	after_load();
199
200	while (!done && (ch = getch()) != ERR) {
201	    switch (ch) {
202	    case 'n':
203		/*
204		 * If we got a "next" here, skip to the final screen before
205		 * moving to the next process.
206		 */
207		setup_next();
208		which = last;
209		done = TRUE;
210		break;
211	    case 'q':
212		endwin();
213		cleanup(files);
214		done = TRUE;
215		break;
216	    case KEY_BACKSPACE:
217	    case '\b':
218		if (--which < 0)
219		    which = last;
220		break;
221	    case ' ':
222		if (++which > last)
223		    which = 0;
224		break;
225	    default:
226		beep();
227		continue;
228	    }
229
230	    if (ch == 'q') {
231		;
232	    } else if (scr_restore(files[which]) == ERR) {
233		endwin();
234		printf("Cannot load screen-dump %s\n", files[which]);
235		cleanup(files);
236		ExitProgram(EXIT_FAILURE);
237	    } else {
238		wrefresh(curscr);
239	    }
240	}
241    } else {
242	int y;
243	int x;
244
245	move(2, 0);
246	printw("Use h,j,k,l or arrows to move around the screen\n");
247	printw("Press 'q' to quit, ' ' to dump a screen\n");
248	printw("When the last screen has been dumped, press 'n' to run the\n");
249	printw("screen-loader.  That allows only 'q', backspace and ' ' for\n");
250	printw("stepping through the dumped/restored screens.\n");
251	getyx(stdscr, y, x);
252
253	while (!done) {
254	    switch (ch = get_command(which, last)) {
255	    case 'n':
256		setup_next();
257		done = TRUE;
258		break;
259	    case 'q':
260		endwin();
261		cleanup(files);
262		done = TRUE;
263		break;
264	    case ' ':
265		if (files[which] != 0) {
266		    show_what(which + 1, last);
267		    if (scr_dump(files[which]) == ERR) {
268			endwin();
269			printf("Cannot write screen-dump %s\n", files[which]);
270			cleanup(files);
271			done = TRUE;
272			break;
273		    }
274		    ++which;
275		    if (has_colors()) {
276			short pair = which % COLOR_PAIRS;
277			bkgd(COLOR_PAIR(pair));
278		    }
279		} else {
280		    beep();
281		}
282		break;
283	    case KEY_LEFT:
284	    case 'h':
285		if (--x < 0)
286		    x = COLS - 1;
287		break;
288	    case KEY_DOWN:
289	    case 'j':
290		if (++y >= LINES)
291		    y = 1;
292		break;
293	    case KEY_UP:
294	    case 'k':
295		if (--y < 1)
296		    y = LINES - 1;
297		break;
298	    case KEY_RIGHT:
299	    case 'l':
300		if (++x >= COLS)
301		    x = 0;
302		break;
303	    }
304	    if (!done) {
305		time_t now = time((time_t *) 0);
306
307		move(0, 0);
308		addstr(ctime(&now));
309		move(y, x);
310		addch('#' | A_REVERSE);
311		move(y, x);
312	    }
313	}
314    }
315    ExitProgram(EXIT_SUCCESS);
316}
317