Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / packages / cmdline.c
1 /*
2  *   Creation Date: <2003/12/28 14:16:31 samuel>
3  *   Time-stamp: <2004/01/07 10:37:40 samuel>
4  *
5  *      <cmdline.c>
6  *
7  *      OpenFirmwware User Interface
8  *
9  *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "packages.h"
20 #include "libc/vsprintf.h"
21
22 typedef struct {
23         char    *buf;           /* size: ncol+1 */
24         char    *killbuf;       /* size: ncol+1 */
25         char    *history;
26         int     hsize;          /* size of history buffer */
27         int     ncol;           /* #columns */
28 } cmdline_info_t;
29
30 DECLARE_NODE( cmdline, INSTALL_OPEN, sizeof(cmdline_info_t),
31               "+/packages/cmdline" );
32
33 static void
34 emit( int ch )
35 {
36         PUSH( ch );
37         fword("emit");
38 }
39
40 static int
41 emit_str( const char *str )
42 {
43         int n = 0;
44         while( *str ) {
45                 n++;
46                 emit( *str++ );
47         }
48         return n;
49 }
50
51 static void
52 move_cursor( int n )
53 {
54         if( n >= 0 ) {
55                 while( n-- )
56                         emit( '\f' );
57         } else {
58                 while( n++ )
59                         emit( 8 );
60         }
61 }
62
63 static void
64 clear( int n )
65 {
66         int i;
67         for( i=0; i<n; i++ )
68                 emit(' ');
69         move_cursor( -n );
70 }
71
72 static void
73 clearline( int pos, int n )
74 {
75         move_cursor( -pos );
76         clear( n );
77 }
78
79 static int
80 key( void )
81 {
82         fword("key");
83         return POP();
84 }
85
86 /* ( -- flag ) */
87 static void
88 cmdline_open( cmdline_info_t *ci )
89 {
90         ci->ncol = 80;
91         ci->buf = malloc( ci->ncol + 1 );
92         ci->killbuf = malloc( ci->ncol + 1 );
93
94         ci->hsize = 40;
95         ci->history = malloc( ci->hsize );
96         ci->history[0] = 0;
97
98         RET( -1 );
99 }
100
101 /* ( -- ) */
102 static void
103 cmdline_close( cmdline_info_t *ci )
104 {
105         free( ci->buf );
106         free( ci->killbuf );
107         free( ci->history );
108 }
109
110
111 static char *
112 history_get( cmdline_info_t *ci, int n )
113 {
114         char *p = ci->history;
115         int len;
116
117         while( n-- && p )
118                 if( (p=strchr(p,'\n')) )
119                         p++;
120
121         ci->buf[0] = 0;
122         if( !p )
123                 return NULL;
124
125         for( len=0; len <= ci->ncol && p[len] != '\n' && p[len] ; len++ )
126                 ;
127         memcpy( ci->buf, p, len );
128         ci->buf[len] = 0;
129         return p;
130 }
131
132 static int
133 history_remove( cmdline_info_t *ci, int line )
134 {
135         char *s, *p = history_get( ci, line );
136
137         if( !p || !(s=strchr(p, '\n')) )
138                 return 1;
139         s++;
140         memmove( p, s, strlen(s)+1 );
141         return 0;
142 }
143
144 static int /* ( -- ) */
145 add_to_history( cmdline_info_t *ci, char *str )
146 {
147         int n, len;
148
149         if( !ci->history )
150                 return 0;
151         len = strlen(str);
152         if( !len )
153                 return 0;
154
155         /* make room for line in history */
156         for( ;; ) {
157                 char *p;
158                 n = strlen(ci->history) + 1;
159
160                 if( n + len + 1 <= ci->hsize )
161                         break;
162
163                 if( !(p=strrchr(ci->history,'\n')) )
164                         return 0;
165                 *p = 0;
166                 if( !(p=strrchr(ci->history, '\n')) )
167                         p = ci->history-1;
168                 p[1] = 0;
169         }
170
171         memmove( ci->history + len + 1, ci->history, n );
172         memcpy( ci->history, str, len );
173         ci->history[ len ] = '\n';
174         return 1;
175 }
176
177 static void /* ( -- ) */
178 cmdline_prompt( cmdline_info_t *ci )
179 {
180         int cur_added=0, histind=0, ch, i, pos=0, n=0, prompt=1;
181         char *buf;
182         int terminate = 0;
183
184         buf = ci->buf;
185         selfword("prepare");
186
187         emit('\n');
188 #ifdef NOLEAVE
189         for (;;)
190 #else
191         while (rstackcnt && !terminate)
192 #endif
193         {
194                 int drop = 0;
195                 terminate = 0;
196
197                 if( prompt ) {
198                         fword("print-prompt");
199                         buf[0] = 0;
200                         cur_added = prompt = histind = pos = n = 0;
201                 }
202
203                 ch = key();
204                 switch( ch ) {
205                 case 27:
206                         switch( key() ) {
207                         case 'f':
208                                 while( buf[pos] == ' ' )
209                                         emit( buf[pos++] );
210                                 while( buf[pos] && buf[pos] != ' ' )
211                                         emit( buf[pos++] );
212                                 break;
213
214                         case 'b':
215                                 while( pos && buf[pos-1] == ' ' ) {
216                                         move_cursor( -1 );
217                                         pos--;
218                                 }
219                                 while( pos && buf[pos-1] != ' ' ) {
220                                         move_cursor( -1 );
221                                         pos--;
222                                 }
223                                 break;
224                         case '[':
225                                 switch( key() ) {
226                                 case 'A':
227                                         goto go_up;
228                                 case 'B':
229                                         goto go_down;
230                                 case 'C':
231                                         goto go_right;
232                                 case 'D':
233                                         goto go_left;
234                                 case '3':
235                                         key();
236                                         goto delete;
237                                 }
238                                 break;
239                         case 'O':
240                                 switch(key()) {
241                                 case 'F':
242                                         goto go_end;
243                                 case 'H':
244                                         goto go_home;
245                                 }
246                                 break;
247                         }
248                         break;
249                 case '\n':
250                 case '\r':
251                         if( cur_added )
252                                 history_remove( ci, 0 );
253                         add_to_history( ci, ci->buf );
254
255                         emit_str( &buf[pos] );
256                         emit(' ');
257                         PUSH( feval(buf) );
258                         fword("print-status");
259
260                         /* Leave the interpreter if terminate? value set */
261                         fword("terminate?");
262                         if (POP())
263                                 terminate = 1;
264
265                         prompt = 1;
266                         break;
267
268                 case 3: /* ^c */
269                         emit_str("\n");
270                         prompt = 1;
271                         if( cur_added )
272                                 history_remove( ci, 0 );
273                         break;
274
275                 case 4: /* ^d */
276 delete:
277                         if( pos == n )
278                                 break;
279                         emit( buf[pos++] );
280                         /* fall through */
281
282                 case 8: /* ^h */
283                 case 127: /* backspace */
284                         drop = 1;
285                         if( !pos )
286                                 break;
287                         move_cursor( -1 );
288                         emit_str( &buf[pos] );
289                         emit(' ');
290                         memmove( &buf[pos-1], &buf[pos], n+1-pos );
291                         move_cursor( pos-n-1 );
292                         pos--;
293                         n--;
294                         break;
295
296                 case 1: /* ^a */
297 go_home:
298                         move_cursor( -pos );
299                         pos = 0;
300                         break;
301
302                 case 5: /* ^e */
303 go_end:
304                         pos += emit_str( &buf[pos] );
305                         break;
306
307                 //case 68: /* left */
308                 //      drop = 1;
309                 case 2: /* ^b */
310 go_left:
311                         if( pos ) {
312                                 move_cursor( -1 );
313                                 pos--;
314                         }
315                         break;
316
317                 //case 67: /* right */
318                 //      drop = 1;
319                 case 6: /* ^f */
320 go_right:
321                         if( pos < n )
322                                 emit( buf[pos++] );
323                         break;
324
325                 case 11: /* ^k */
326                         strcpy( ci->killbuf, &buf[pos] );
327                         clear( n-pos );
328                         n = pos;
329                         buf[pos] = 0;
330                         break;
331
332                 case 25: /* ^y */
333                         for( i=0; n < ci->ncol && ci->killbuf[i] ; i++, n++ ) {
334                                 memmove( &buf[pos+1], &buf[pos], n+1-pos );
335                                 buf[pos] = ci->killbuf[i];
336                                 move_cursor( 1-emit_str(&buf[pos++]) );
337                         }
338                         break;
339
340                 case 9: /* TAB */
341                         for( i=0; n < ci->ncol && (!i || (pos%4)) ; i++, n++ ) {
342                                 memmove( &buf[pos+1], &buf[pos], n+1-pos );
343                                 buf[pos] = ' ';
344                                 move_cursor( 1-emit_str(&buf[pos++]) );
345                         }
346                         break;
347
348                 case 12: /* ^l */
349                         move_cursor( -ci->ncol -pos );
350                         fword("print-prompt");
351                         move_cursor( pos-emit_str(buf) );
352                         break;
353
354                 //case 66: /* down */
355                 //      drop = 1;
356                 case 14: /* ^n */
357 go_down:
358                         if( !histind )
359                                 break;
360                         history_get( ci, --histind - 1);
361                         clearline( pos, n );
362                         emit_str( buf );
363                         pos = n = strlen( buf );
364                         if( !histind && cur_added ) {
365                                 cur_added = 0;
366                                 history_remove( ci, 0 );
367                         }
368                         break;
369
370                 //case 65: /* up */
371                 //      drop = 1;
372                 case 16: /* ^p */
373 go_up:
374                         if( !histind && add_to_history(ci, ci->buf) ) {
375                                 cur_added = 1;
376                                 histind++;
377                         }
378                         if( history_get(ci, histind) )
379                                 histind++;
380                         clearline( pos, n );
381                         emit_str( buf );
382                         pos = n = strlen( buf );
383                         break;
384                 }
385                 if( (unsigned int)ch < 32 )
386                         drop = 1;
387
388                 if( !drop && n < ci->ncol ) {
389                         memmove( &buf[pos+1], &buf[pos], n+1-pos );
390                         n++;
391                         buf[pos] = ch;
392                         move_cursor( 1-emit_str(&buf[pos++]) );
393                 }
394         }
395
396         /* we only get here if terminate? is non-zero; this should
397          * only ever be done for a subordinate forth interpreter 
398          * e.g. for debugging */
399
400         /* Reset stack and terminate? */
401         rstackcnt = dbgrstackcnt;
402         feval("0 to terminate?");
403 }
404
405 NODE_METHODS( cmdline ) = {
406         { "open",       cmdline_open      },
407         { "close",      cmdline_close       },
408         { "cmdline",     cmdline_prompt      },
409 };
410
411 void
412 cmdline_init( void )
413 {
414         REGISTER_NODE( cmdline );
415 }