Line data Source code
1 : /*
2 : Mosh: the mobile shell
3 : Copyright 2012 Keith Winstein
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 3 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, see <http://www.gnu.org/licenses/>.
17 :
18 : In addition, as a special exception, the copyright holders give
19 : permission to link the code of portions of this program with the
20 : OpenSSL library under certain conditions as described in each
21 : individual source file, and distribute linked combinations including
22 : the two.
23 :
24 : You must obey the GNU General Public License in all respects for all
25 : of the code used other than OpenSSL. If you modify file(s) with this
26 : exception, you may extend this exception to your version of the
27 : file(s), but you are not obligated to do so. If you do not wish to do
28 : so, delete this exception statement from your version. If you delete
29 : this exception statement from all source files in the program, then
30 : also delete it here.
31 : */
32 :
33 : #include <stdio.h>
34 : #include <assert.h>
35 : #include <string.h>
36 : #include <errno.h>
37 : #include <stdlib.h>
38 :
39 : #include "terminaldispatcher.h"
40 : #include "parseraction.h"
41 : #include "terminalframebuffer.h"
42 :
43 : using namespace Terminal;
44 :
45 : static const size_t MAXIMUM_CLIPBOARD_SIZE = 16*1024;
46 :
47 11654 : Dispatcher::Dispatcher()
48 11654 : : params(), parsed_params(), parsed( false ), dispatch_chars(),
49 11654 : OSC_string(), terminal_to_host()
50 11654 : {}
51 :
52 187351 : void Dispatcher::newparamchar( const Parser::Param *act )
53 : {
54 187351 : assert( act->char_present );
55 187351 : assert( (act->ch == ';') || ( (act->ch >= '0') && (act->ch <= '9') ) );
56 187351 : if ( params.length() < 100 ) {
57 : /* enough for 16 five-char params plus 15 semicolons */
58 187351 : params.push_back( act->ch );
59 : }
60 187351 : parsed = false;
61 187351 : }
62 :
63 39253 : void Dispatcher::collect( const Parser::Collect *act )
64 : {
65 39253 : assert( act->char_present );
66 39253 : if ( ( dispatch_chars.length() < 8 ) /* never should need more than 2 */
67 39253 : && ( act->ch <= 255 ) ) { /* ignore non-8-bit */
68 39253 : dispatch_chars.push_back( act->ch );
69 : }
70 39253 : }
71 :
72 60038 : void Dispatcher::clear( const Parser::Clear *act __attribute((unused)) )
73 : {
74 60038 : params.clear();
75 60038 : dispatch_chars.clear();
76 60038 : parsed = false;
77 60038 : }
78 :
79 30013 : void Dispatcher::parse_params( void )
80 : {
81 30013 : if ( parsed ) {
82 0 : return;
83 : }
84 :
85 30013 : parsed_params.clear();
86 30013 : const char *str = params.c_str();
87 30013 : const char *segment_begin = str;
88 :
89 130707 : while ( 1 ) {
90 80360 : const char *segment_end = strchr( segment_begin, ';' );
91 80360 : if ( segment_end == NULL ) {
92 : break;
93 : }
94 :
95 50347 : errno = 0;
96 50347 : char *endptr;
97 50347 : long val = strtol( segment_begin, &endptr, 10 );
98 50347 : if ( endptr == segment_begin ) {
99 : val = -1;
100 : }
101 :
102 50347 : if ( val > PARAM_MAX || errno == ERANGE ) {
103 0 : val = -1;
104 0 : errno = 0;
105 : }
106 :
107 50347 : if ( errno == 0 || segment_begin == endptr ) {
108 50347 : parsed_params.push_back( val );
109 : }
110 :
111 50347 : segment_begin = segment_end + 1;
112 50347 : }
113 :
114 : /* get last param */
115 30013 : errno = 0;
116 30013 : char *endptr;
117 30013 : long val = strtol( segment_begin, &endptr, 10 );
118 30013 : if ( endptr == segment_begin ) {
119 : val = -1;
120 : }
121 :
122 30013 : if ( val > PARAM_MAX || errno == ERANGE ) {
123 0 : val = -1;
124 0 : errno = 0;
125 : }
126 :
127 30013 : if ( errno == 0 || segment_begin == endptr ) {
128 30013 : parsed_params.push_back( val );
129 : }
130 :
131 30013 : parsed = true;
132 : }
133 :
134 91935 : int Dispatcher::getparam( size_t N, int defaultval )
135 : {
136 91935 : int ret = defaultval;
137 91935 : if ( !parsed ) {
138 6689 : parse_params();
139 : }
140 :
141 91935 : if ( parsed_params.size() > N ) {
142 91519 : ret = parsed_params[ N ];
143 : }
144 :
145 91935 : if ( ret < 1 ) ret = defaultval;
146 :
147 91935 : return ret;
148 : }
149 :
150 75696 : int Dispatcher::param_count( void )
151 : {
152 75696 : if ( !parsed ) {
153 23324 : parse_params();
154 : }
155 :
156 75696 : return parsed_params.size();
157 : }
158 :
159 0 : std::string Dispatcher::str( void )
160 : {
161 0 : char assum[ 64 ];
162 0 : snprintf( assum, 64, "[dispatch=\"%s\" params=\"%s\"]",
163 : dispatch_chars.c_str(), params.c_str() );
164 0 : return std::string( assum );
165 : }
166 :
167 : /* construct on first use to avoid static initialization order crash */
168 47965661 : DispatchRegistry & Terminal::get_global_dispatch_registry( void )
169 : {
170 47965661 : static DispatchRegistry global_dispatch_registry;
171 47965661 : return global_dispatch_registry;
172 : }
173 :
174 62192 : static void register_function( Function_Type type,
175 : const std::string & dispatch_chars,
176 : Function f )
177 : {
178 62192 : switch ( type ) {
179 5408 : case ESCAPE:
180 5408 : get_global_dispatch_registry().escape.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
181 5408 : break;
182 41912 : case CSI:
183 41912 : get_global_dispatch_registry().CSI.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
184 41912 : break;
185 14872 : case CONTROL:
186 14872 : get_global_dispatch_registry().control.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
187 14872 : break;
188 : }
189 62192 : }
190 :
191 62192 : Function::Function( Function_Type type, const std::string & dispatch_chars,
192 : void (*s_function)( Framebuffer *, Dispatcher * ),
193 62192 : bool s_clears_wrap_state )
194 62192 : : function( s_function ), clears_wrap_state( s_clears_wrap_state )
195 : {
196 62192 : register_function( type, dispatch_chars, *this );
197 62192 : }
198 :
199 47903469 : void Dispatcher::dispatch( Function_Type type, const Parser::Action *act, Framebuffer *fb )
200 : {
201 : /* add final char to dispatch key */
202 47903469 : if ( (type == ESCAPE) || (type == CSI) ) {
203 30021 : assert( act->char_present );
204 30021 : Parser::Collect act2;
205 30021 : act2.char_present = true;
206 30021 : act2.ch = act->ch;
207 30021 : collect( &act2 );
208 30021 : }
209 :
210 47903469 : dispatch_map_t *map = NULL;
211 47903469 : switch ( type ) {
212 4 : case ESCAPE: map = &get_global_dispatch_registry().escape; break;
213 30017 : case CSI: map = &get_global_dispatch_registry().CSI; break;
214 47873448 : case CONTROL: map = &get_global_dispatch_registry().control; break;
215 : }
216 :
217 95806930 : std::string key = dispatch_chars;
218 47903469 : if ( type == CONTROL ) {
219 47873448 : assert( act->ch <= 255 );
220 47873448 : char ctrlstr[ 2 ] = { (char)act->ch, 0 };
221 95746896 : key = std::string( ctrlstr, 1 );
222 : }
223 :
224 47903469 : dispatch_map_t::const_iterator i = map->find( key );
225 47903469 : if ( i == map->end() ) {
226 : /* unknown function */
227 8 : fb->ds.next_print_will_wrap = false;
228 8 : return;
229 : }
230 47903461 : if ( i->second.clears_wrap_state ) {
231 47880127 : fb->ds.next_print_will_wrap = false;
232 : }
233 47903461 : i->second.function( fb, this );
234 : }
235 :
236 0 : void Dispatcher::OSC_put( const Parser::OSC_Put *act )
237 : {
238 0 : assert( act->char_present );
239 0 : if ( OSC_string.size() < MAXIMUM_CLIPBOARD_SIZE) {
240 0 : OSC_string.push_back( act->ch );
241 : }
242 0 : }
243 :
244 0 : void Dispatcher::OSC_start( const Parser::OSC_Start *act __attribute((unused)) )
245 : {
246 0 : OSC_string.clear();
247 0 : }
248 :
249 0 : bool Dispatcher::operator==( const Dispatcher &x ) const
250 : {
251 0 : return ( params == x.params )
252 0 : && ( parsed_params == x.parsed_params )
253 0 : && ( parsed == x.parsed )
254 0 : && ( dispatch_chars == x.dispatch_chars )
255 0 : && ( OSC_string == x.OSC_string )
256 0 : && ( terminal_to_host == x.terminal_to_host );
257 : }
|