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