]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/drivers/filter_console.cpp
27aa628373dc17f7b21971cb31470de9e4196e15
[l4.git] / kernel / fiasco / src / drivers / filter_console.cpp
1 INTERFACE:
2
3 #include "console.h"
4 #include "types.h"
5
6 class Filter_console : public Console
7 {
8 public:
9
10   Filter_console( Console *o, int to = 10 );
11   ~Filter_console();
12
13   int write( char const *str, size_t len );
14   int getchar( bool blocking = true );
15   int char_avail() const;
16
17 private:
18   Console *const _o;
19   int csi_timeout;
20   enum {
21     NORMAL,
22     UNKNOWN_ESC,
23     GOT_CSI, ///< control sequence introducer
24   } state;
25   unsigned pos;
26   char ibuf[32];
27   unsigned arg;
28   int args[4];
29 };
30
31
32 IMPLEMENTATION:
33
34 #include <cstdio>
35 #include <cstring>
36 #include <cctype>
37 #include "keycodes.h"
38 #include "delayloop.h"
39
40
41 IMPLEMENT 
42 int Filter_console::char_avail() const
43 {
44   switch(state)
45     {
46     case NORMAL:
47     case UNKNOWN_ESC:
48       if(pos) 
49         return 1;
50       else
51         return _o->char_avail();
52       
53     default:
54       return -1;
55
56     } 
57 }
58
59 IMPLEMENT 
60 Filter_console::Filter_console( Console *o, int to )
61   : _o(o), csi_timeout(to), state(NORMAL), pos(0), arg(0)
62 {
63   if (o->failed())
64     fail();
65 }
66
67 IMPLEMENT
68 Filter_console::~Filter_console()
69 {}
70
71 IMPLEMENT
72 int Filter_console::write( char const *str, size_t len )
73 {
74   char const *start = str;
75   char const *stop  = str;
76
77   static char seq[18];
78   char const *const home = "\033[H";
79   char const *const cel  = "\033[K";
80   
81   for(;stop < str + len; ++stop ) {
82     switch(*stop) {
83     case 1:
84       if(stop-start)
85         _o->write(start, stop-start);
86       start = stop + 1;
87       _o->write(home,3);
88       break;
89     case 5:
90       if(stop-start)
91         _o->write(start, stop-start);
92       start = stop + 1;
93       _o->write(cel,3);
94       break;
95     case 6:
96       if(stop-start)
97         _o->write(start, stop-start);
98       if(stop + 2 < str+len) {
99         snprintf(seq, sizeof(seq), "\033[%d;%dH", stop[1]+1,stop[2]+1);
100         _o->write(seq,strlen(seq));
101       }
102       stop += 2;
103       start = stop + 1;
104       break;
105     }
106   }
107
108   if(stop-start)
109     _o->write(start, stop-start);
110
111   return len;
112 }
113
114 PRIVATE inline
115 int Filter_console::getchar_timeout( unsigned timeout )
116 {
117   int c;
118   while((c= _o->getchar(false)) == -1 && timeout--)
119     Delay::delay(1);
120   return c;
121 }
122
123
124 IMPLEMENT
125 int Filter_console::getchar( bool b )
126 {
127   unsigned loop_count = 100;
128   int ch;
129     
130  get_char:
131   if(state==UNKNOWN_ESC && pos)
132     {
133       ch = ibuf[0];
134       memmove(ibuf,ibuf+1,--pos);
135     }
136   else
137     ch = _o->getchar(b);
138
139   if(!pos) 
140     state = NORMAL;
141
142   if(ch==-1)
143     {
144       if(state == NORMAL) 
145         return -1;
146       else if( !b && loop_count-- )
147         goto get_char;
148       else
149         return -1;
150     }
151
152   switch(state)
153     {
154     case UNKNOWN_ESC:
155       return ch;
156
157     case NORMAL:
158       if(ch==27)
159         {
160           ibuf[pos++] = 27;
161           int nc = getchar_timeout(csi_timeout);
162           if(nc==-1)
163             {
164               pos = 0;
165               return 27;
166             }
167           else 
168             {
169               if(pos < sizeof(ibuf))
170                 ibuf[pos++] = nc;
171               if(nc=='[' || nc=='O')
172                 {
173                   arg = 0;
174                   memset(args,0,sizeof(args));
175                   state = GOT_CSI;
176                   break;
177                 }
178               else
179                 {
180                   state = UNKNOWN_ESC;
181                   goto get_char;
182                 }
183             }       
184         }
185       return ch;
186
187     case GOT_CSI:
188       if(isdigit(ch))
189         {
190           if(pos < sizeof(ibuf))
191             ibuf[pos++] = ch;
192
193           if(arg < (sizeof(args)/sizeof(int)))
194             args[arg] = args[arg]*10 + (ch-'0');
195         }
196       else if(ch==';')
197         {
198           if(pos < sizeof(ibuf))
199             ibuf[pos++] = ch;
200
201           arg++;
202         }
203       else 
204         {
205           state = NORMAL;
206           if(pos < sizeof(ibuf))
207             ibuf[pos++] = ch;
208           
209           switch(ch)
210             {
211             case 'A': pos = 0; return KEY_CURSOR_UP;
212             case 'B': pos = 0; return KEY_CURSOR_DOWN;
213             case 'C': pos = 0; return KEY_CURSOR_RIGHT;
214             case 'D': pos = 0; return KEY_CURSOR_LEFT;
215             case 'H': pos = 0; return KEY_CURSOR_HOME;
216             case 'F': pos = 0; return KEY_CURSOR_END;
217             case '~':
218               pos = 0;
219               switch(args[0])
220                 {
221                 case  7:
222                 case  1: return KEY_CURSOR_HOME;
223                 case  2: return KEY_INSERT;
224                 case  3: return KEY_DELETE;
225                 case  8:
226                 case  4: return KEY_CURSOR_END;
227                 case  5: return KEY_PAGE_UP;
228                 case  6: return KEY_PAGE_DOWN;
229                 case 11: return KEY_F1;
230
231                 default:
232                   arg = 0;
233                   if(b)
234                     goto get_char;
235                   else if(loop_count)
236                     {
237                       --loop_count;
238                       goto get_char;
239                     }
240                   else
241                     return -1;
242                 }
243             case 'P': return KEY_F1;
244             default:
245               state = UNKNOWN_ESC;
246               break;
247             }
248         }
249       break;
250     }
251
252   if(b)
253     goto get_char;
254   else if (loop_count)
255     {
256       loop_count --;
257       goto get_char;
258     }
259   else
260     return -1;
261
262 }
263
264
265 PUBLIC
266 Mword
267 Filter_console::get_attributes() const
268 {
269   return _o->get_attributes();
270 }
271