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