1 #include <stdlib.h>
2 #include <curses.h>
3 #include <stdio.h>
4 #include <string.h>
5 
6 /* Curses based powwow movie player.
7  * Author: Steve Slaven - http://hoopajoo.net
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  */
15 
16 #define JUMP_SMALL     1000
17 #define JUMP_BIG       5000
18 #define MAX_SPEED      20
19 
20 /* Speed is a variable from 0 - 9, where 5 = normal and > 5 is faster */
main(int argc,char * argv[])21 int main( int argc, char *argv[] ) {
22 	WINDOW *text, *status;
23 	int speed = 5;
24 	int key, sleep, orig, i, color, looping, cursx, cursy;
25 	FILE *in;
26 	char line[ 1000 ], *displine, action[ 100 ];
27 	long curr_pos, file_size, new_pos;
28 
29 	if( argc < 2 ) {
30 		fprintf( stderr,
31 			"powwow mud cinema v%s\n"
32 			"Author: Steve Slaven - http://hoopajoo.net\n"
33 			"\n"
34 			"Usage: powwow-muc file\n"
35 			"\n"
36 			"file should be a #movie file generated in powwow\n",
37 			VERSION );
38 		exit( 1 );
39 	}
40 
41 	/* Validate our file passed */
42 	if( ! ( in = fopen( argv[ 1 ], "ro" ) ) ) {
43 		perror( "Unable to open file" );
44 		exit( 1 );
45 	}
46 
47 	/* Get file size */
48 	fseek( in, 0, SEEK_END );
49 	file_size = ftell( in );
50 	rewind( in );
51 
52 	/* Setup some basic stuff */
53 	initscr();
54 	cbreak();
55 	noecho();
56 
57 	/* Initialize color */
58 	start_color();
59 
60 	/* this *should* init the default ansi colors... :/ */
61 	for( i = 0; i < 16; i++ )
62 		init_pair( i, i, COLOR_BLACK );
63 
64 	/* Create our windows, a status bar on the bottom and a
65 	   scrollable window on top */
66 	text = newwin( LINES - 2, COLS, 0, 0 );
67 	status = newwin( 2, COLS, LINES - 2, 0 );
68 
69 	keypad( stdscr, TRUE );
70 	scrollok( text, TRUE );
71 	leaveok( text, TRUE );
72 	leaveok( status, TRUE );
73 	/* wattron( status, A_BOLD ); */
74 	wbkgd( status, A_REVERSE );
75 
76 	/* instructions */
77 	mvwprintw( status, 0, 0,
78 		"(q)uit (r)ew small (R)ew large (f)orw small (F)orw large (0-9)(+)(-) speed" );
79 
80 	/* Main loop */
81 	refresh();
82 	timeout( 0 );
83 	looping = 1;
84 	while( looping ) {
85 		memset( line, 0, sizeof line );
86 		fgets( line, sizeof line, in );
87 
88 		/* get file pos */
89 		new_pos = curr_pos = ftell( in );
90 
91 		/* handle disp or other */
92 		displine = NULL;
93 		if( strncmp( line, "line", 4 ) == 0 ) {
94 			displine = &line[ 5 ];
95 			sleep = 0;
96 		}else if( strncmp( line, "prompt", 5 ) == 0 ) {
97 			displine = &line[ 7 ];
98 			/* Munch newline */
99 			line[ strlen( line ) - 1 ] = 0;
100 			sleep = 0;
101 		}else if( strncmp( line, "sleep", 5 ) == 0 ) {
102 			sscanf( line, "sleep %d", &sleep );
103 		}else if( line[ 0 ] == '#' ) { /* custom extension for commenting logs */
104 			sscanf( line, "#%d", &sleep );
105 			if( sleep > 0 )
106 				sleep *= 100; /* comment sleep is in seconds */
107 
108 			/* Skip to space */
109 			displine = line;
110 			while( displine[ 0 ] != ' ' && displine[ 0 ] != 0 ) {
111 				displine++;
112 			}
113 			displine++;
114 
115 			/* We will go ahead and display it here, in bold, then
116 			   null out displine so it will not display later */
117 			wattron( text, A_REVERSE );
118 			wprintw( text, "##==> %s", displine );
119 			wattroff( text, A_REVERSE );
120 			displine = NULL;
121 		}
122 
123 		/* suck out action for display */
124 		sscanf( line, "%100s", action );
125 
126 		/* Modify sleep time according to speed, zero is fast as you can go, 1 == pause */
127 		orig = sleep;
128 		if( speed > 5 ) {
129 			sleep 	 /= ( ( speed - 5 ) * 2 );
130 		}else{
131 			sleep *= ( 6 - speed );
132 		}
133 
134 		/* Handle pause */
135 		if( speed == 0 )
136 			sleep = -1;
137 
138 		/* handle insane speed */
139 		/* if( speed == 9 )
140 			sleep = 0; */
141 
142 		/* Setup sleeptime for getch() */
143 		timeout( sleep );
144 
145 		/* Update status line */
146 		mvwprintw( status, 1, 0,
147 			"%7d/%7d/%2d%% Speed: %d (5=normal,0=pause) Cmd: %-6s (%d/%d)\n",
148 			curr_pos, file_size, curr_pos * 100 / file_size,
149 			speed, action, sleep, orig );
150 		wrefresh( status );
151 
152 		/* Disp if we found an offset to do */
153 		if( displine != NULL ) {
154 			/* handle converting ansi colors to curses attrs */
155 			for( i = 0; i < strlen( displine ); i++ ) {
156 				if( displine[ i ] == 0x1b ) {
157 					/* this is super crappy ansi color decoding */
158 					i++;
159 					if( strncmp( &displine[ i ], "[3", 2 ) == 0 ) {
160 						/* start a color */
161 						sscanf( &displine[ i ], "[3%dm", &color );
162 						wattron( text, COLOR_PAIR( color ) );
163 					}else if( strncmp( &displine[ i ], "[9", 2 ) == 0 ) {
164 						/* start a high color */
165 						sscanf( &displine[ i ], "[9%dm", &color );
166 						wattron( text, COLOR_PAIR( color ) );
167 						wattron( text, A_BOLD );
168 					}else if( strncmp( &displine[ i ], "[1", 2 ) == 0 ) {
169 						wattron( text, A_BOLD );
170 					}else if( strncmp( &displine[ i ], "[0", 2 ) == 0 ) {
171 						/* end color, color will (should?) still be set from last color */
172 						/* wattr_off( text, COLOR_PAIR( color ), NULL ); */
173 						wattrset( text, A_NORMAL );
174 					}
175 					/* eat chars to the next m */
176 					while( displine[ i ] != 'm' && displine != 0 )
177 						i++;
178 				}else{
179 					waddch( text, (unsigned char)displine[ i ] );
180 				}
181 			}
182 		}
183 
184 		/* check if we are at EOF and override timeout */
185 		if( curr_pos == file_size ) {
186 			wprintw( text, "\n**** END ***\n" );
187 			timeout( -1 );
188 		}
189 
190 		wrefresh( text );
191 
192 		/* Move the cursor to the end of the text window, so it looks
193 		   like a real session */
194 		getyx( text, cursy, cursx );
195 		move( cursy, cursx );
196 
197 		key = getch();
198 
199 		switch( key ) {
200 			case 'Q':
201 			case 'q':
202 				looping = 0;
203 				break;
204 			case '+':
205 			case '=':
206 				speed++;
207 				break;
208 			case '-':
209 				speed--;
210 				break;
211 
212 			case '1':
213 				speed = 1;
214 				break;
215 			case '2':
216 				speed = 2;
217 				break;
218 			case '3':
219 				speed = 3;
220 				break;
221 			case '4':
222 				speed = 4;
223 				break;
224 			case '5':
225 				speed = 5;
226 				break;
227 			case '6':
228 				speed = 6;
229 				break;
230 			case '7':
231 				speed = 7;
232 				break;
233 			case '8':
234 				speed = 8;
235 				break;
236 			case '9':
237 				speed = 9;
238 				break;
239 			case '0':
240 				speed = 0;
241 				break;
242 
243 			case 'r':
244 				new_pos -= JUMP_SMALL;
245 				break;
246 			case 'R':
247 				new_pos -= JUMP_BIG;
248 				break;
249 			case 'f':
250 				new_pos += JUMP_SMALL;
251 				break;
252 			case 'F':
253 				new_pos += JUMP_BIG;
254 				break;
255 
256 			default:
257 				break;
258 		}
259 
260 		/* Validate speed is ok */
261 		if( speed > MAX_SPEED )
262 			speed = MAX_SPEED;
263 
264 		if( speed < 0 )
265 			speed = 0;
266 
267 		/* Check if we are moving the seek */
268 		if( new_pos != curr_pos ) {
269 			wattron( text, A_BOLD );
270 			if( new_pos > file_size )
271 				new_pos = file_size;
272 
273 			if( new_pos < 0 )
274 				new_pos = 0;
275 
276 			wprintw( text,
277 				"\n=============\nMoving from %d to file offset %d\n",
278 				curr_pos, new_pos );
279 
280 			/* calcs offsets because we may want to seek to
281 			   0, which using SEEK_CUR won't let us do without
282 			   some other error checking that I don't want to do */
283 			fseek( in, new_pos, SEEK_SET );
284 
285 			/* read to next newline so we don't break up
286 			   lines seeking around */
287 			fgets( line, sizeof line, in );
288 			new_pos = ftell( in );
289 
290 			/* Make a note of moving */
291 			wprintw( text,
292 				"Final offset after adjusting for newline: %d (%d)\n=============\n",
293 				new_pos, new_pos - curr_pos );
294 			wattroff( text, A_BOLD );
295 		}
296 	}
297 
298 	/* Cleanup */
299 	delwin( text );
300 	delwin( status );
301 	endwin();
302 
303 	fclose( in );
304 
305 	return( 0 );
306 }
307