1 /*
2  * io.c -- melt input/output
3  * Copyright (C) 2002-2015 Meltytech, LLC
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 /* System header files */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #ifndef _WIN32
30 #include <termios.h>
31 #else
32 // MinGW defines struct timespec in pthread.h
33 #include <pthread.h>
34 // for nanosleep()
35 #include <framework/mlt_types.h>
36 #include <windows.h>
37 #endif
38 #include <unistd.h>
39 #include <sys/time.h>
40 
41 /* Application header files */
42 #include "io.h"
43 
chomp(char * input)44 char *chomp( char *input )
45 {
46 	if ( input != NULL )
47 	{
48 		int length = strlen( input );
49 		if ( length && input[ length - 1 ] == '\n' )
50 			input[ length - 1 ] = '\0';
51 		if ( length > 1 && input[ length - 2 ] == '\r' )
52 			input[ length - 2 ] = '\0';
53 	}
54 	return input;
55 }
56 
trim(char * input)57 char *trim( char *input )
58 {
59 	if ( input != NULL )
60 	{
61 		int length = strlen( input );
62 		int first = 0;
63 		while( first < length && isspace( input[ first ] ) )
64 			first ++;
65 		memmove( input, input + first, length - first + 1 );
66 		length = length - first;
67 		while ( length > 0 && isspace( input[ length - 1 ] ) )
68 			input[ -- length ] = '\0';
69 	}
70 	return input;
71 }
72 
strip_quotes(char * input)73 char *strip_quotes( char *input )
74 {
75 	if ( input != NULL )
76 	{
77 		char *ptr = strrchr( input, '\"' );
78 		if ( ptr != NULL )
79 			*ptr = '\0';
80 		if ( input[ 0 ] == '\"' )
81 			strcpy( input, input + 1 );
82 	}
83 	return input;
84 }
85 
get_int(int * output,int use)86 int *get_int( int *output, int use )
87 {
88 	int *value = NULL;
89 	char temp[ 132 ];
90 	*output = use;
91 	if ( trim( chomp( fgets( temp, 132, stdin ) ) ) != NULL )
92 	{
93 		if ( strcmp( temp, "" ) )
94 			*output = atoi( temp );
95 		value = output;
96 	}
97 	return value;
98 }
99 
100 /** This stores the previous settings
101 */
102 
103 #ifndef _WIN32
104 static struct termios oldtty;
105 #else
106 static DWORD oldtty;
107 #endif
108 static int mode = 0;
109 
110 /** This is called automatically on application exit to restore the
111 	previous tty settings.
112 */
113 
term_exit(void)114 void term_exit(void)
115 {
116 	if ( mode == 1 )
117 	{
118 #ifndef _WIN32
119 		tcsetattr( 0, TCSANOW, &oldtty );
120 #else
121 		HANDLE h = GetStdHandle( STD_INPUT_HANDLE );
122 		if (h) {
123 			SetConsoleMode( h, oldtty );
124 		}
125 #endif
126 		mode = 0;
127 	}
128 }
129 
130 /** Init terminal so that we can grab keys without blocking.
131 */
132 
term_init()133 void term_init( )
134 {
135 #ifndef _WIN32
136 	struct termios tty;
137 
138 	tcgetattr( 0, &tty );
139 	oldtty = tty;
140 
141 	tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
142 	tty.c_oflag |= OPOST;
143 	tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
144 	tty.c_cflag &= ~(CSIZE|PARENB);
145 	tty.c_cflag |= CS8;
146 	tty.c_cc[ VMIN ] = 1;
147 	tty.c_cc[ VTIME ] = 0;
148 
149 	tcsetattr( 0, TCSANOW, &tty );
150 #else
151 	HANDLE h = GetStdHandle( STD_INPUT_HANDLE );
152 	if (h) {
153 		DWORD tty;
154 		GetConsoleMode( h, &tty );
155 		oldtty = tty;
156 		SetConsoleMode( h, mode & ~( ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ) );
157 	}
158 #endif
159 
160 	mode = 1;
161 
162 	atexit( term_exit );
163 }
164 
165 /** Check for a keypress without blocking infinitely.
166 	Returns: ASCII value of keypress or -1 if no keypress detected.
167 */
168 
term_read()169 int term_read( )
170 {
171 #ifndef _WIN32
172 	int n = 1;
173 	unsigned char ch;
174 	struct timeval tv;
175 	fd_set rfds;
176 
177 	FD_ZERO( &rfds );
178 	FD_SET( 0, &rfds );
179 	tv.tv_sec = 0;
180 	tv.tv_usec = 40000;
181 	n = select( 1, &rfds, NULL, NULL, &tv );
182 	if (n > 0)
183 	{
184 		n = read( 0, &ch, 1 );
185 		tcflush( 0, TCIFLUSH );
186 		if (n == 1)
187 			return ch;
188 		return n;
189 	}
190 #else
191 	HANDLE h = GetStdHandle( STD_INPUT_HANDLE );
192 	if ( h && WaitForSingleObject( h, 0 ) == WAIT_OBJECT_0 )
193 	{
194 		DWORD count;
195 		TCHAR c = 0;
196 		ReadConsole( h, &c, 1, &count, NULL );
197 		return (int) c;
198 	} else {
199 		struct timespec tm = { 0, 40000000 };
200 		nanosleep( &tm, NULL );
201 		return 0;
202 	}
203 #endif
204     return -1;
205 }
206 
get_keypress()207 char get_keypress( )
208 {
209 	char value = '\0';
210 	int pressed = 0;
211 
212 	fflush( stdout );
213 
214 	term_init( );
215 	while ( ( pressed = term_read( ) ) == -1 ) ;
216 	term_exit( );
217 
218 	value = (char)pressed;
219 
220 	return value;
221 }
222 
wait_for_any_key(char * message)223 void wait_for_any_key( char *message )
224 {
225 	if ( message == NULL )
226 		printf( "Press any key to continue: " );
227 	else
228 		printf( "%s", message );
229 
230 	get_keypress( );
231 
232 	printf( "\n\n" );
233 }
234 
beep()235 void beep( )
236 {
237 	printf( "%c", 7 );
238 	fflush( stdout );
239 }
240