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