ESP : Fix SCSI READ command length
[openbios.git] / packages / cmdline.c
blobea6bca3db962661d2f45e3a08a8d846d62e0d6d5
1 /*
2 * Creation Date: <2003/12/28 14:16:31 samuel>
3 * Time-stamp: <2004/01/07 10:37:40 samuel>
5 * <cmdline.c>
7 * OpenFirmwware User Interface
9 * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
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
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "packages.h"
20 #include "libc/vsprintf.h"
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;
30 DECLARE_NODE( cmdline, INSTALL_OPEN, sizeof(cmdline_info_t),
31 "+/packages/cmdline" );
33 static void
34 emit( int ch )
36 PUSH( ch );
37 fword("emit");
40 static int
41 emit_str( const char *str )
43 int n = 0;
44 while( *str ) {
45 n++;
46 emit( *str++ );
48 return n;
51 static void
52 move_cursor( int n )
54 if( n >= 0 ) {
55 while( n-- )
56 emit( '\f' );
57 } else {
58 while( n++ )
59 emit( 8 );
63 static void
64 clear( int n )
66 int i;
67 for( i=0; i<n; i++ )
68 emit(' ');
69 move_cursor( -n );
72 static void
73 clearline( int pos, int n )
75 move_cursor( -pos );
76 clear( n );
79 static int
80 key( void )
82 fword("key");
83 return POP();
86 /* ( -- flag ) */
87 static void
88 cmdline_open( cmdline_info_t *ci )
90 ci->ncol = 80;
91 ci->buf = malloc( ci->ncol + 1 );
92 ci->killbuf = malloc( ci->ncol + 1 );
94 ci->hsize = 40;
95 ci->history = malloc( ci->hsize );
96 ci->history[0] = 0;
98 RET( -1 );
101 /* ( -- ) */
102 static void
103 cmdline_close( cmdline_info_t *ci )
105 free( ci->buf );
106 free( ci->killbuf );
107 free( ci->history );
111 static char *
112 history_get( cmdline_info_t *ci, int n )
114 char *p = ci->history;
115 int len;
117 while( n-- && p )
118 if( (p=strchr(p,'\n')) )
119 p++;
121 ci->buf[0] = 0;
122 if( !p )
123 return NULL;
125 for( len=0; len <= ci->ncol && p[len] != '\n' && p[len] ; len++ )
127 memcpy( ci->buf, p, len );
128 ci->buf[len] = 0;
129 return p;
132 static int
133 history_remove( cmdline_info_t *ci, int line )
135 char *s, *p = history_get( ci, line );
137 if( !p || !(s=strchr(p, '\n')) )
138 return 1;
139 s++;
140 memmove( p, s, strlen(s)+1 );
141 return 0;
144 static int /* ( -- ) */
145 add_to_history( cmdline_info_t *ci, char *str )
147 int n, len;
149 if( !ci->history )
150 return 0;
151 len = strlen(str);
152 if( !len )
153 return 0;
155 /* make room for line in history */
156 for( ;; ) {
157 char *p;
158 n = strlen(ci->history) + 1;
160 if( n + len + 1 <= ci->hsize )
161 break;
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;
171 memmove( ci->history + len + 1, ci->history, n );
172 memcpy( ci->history, str, len );
173 ci->history[ len ] = '\n';
174 return 1;
177 static void /* ( -- ) */
178 cmdline_prompt( cmdline_info_t *ci )
180 int cur_added=0, histind=0, ch, i, pos=0, n=0, prompt=1;
181 char *buf;
182 int terminate = 0;
184 buf = ci->buf;
185 selfword("prepare");
187 emit('\n');
188 #ifdef NOLEAVE
189 for (;;)
190 #else
191 while (rstackcnt && !terminate)
192 #endif
194 int drop = 0;
195 terminate = 0;
197 if( prompt ) {
198 fword("print-prompt");
199 buf[0] = 0;
200 cur_added = prompt = histind = pos = n = 0;
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;
214 case 'b':
215 while( pos && buf[pos-1] == ' ' ) {
216 move_cursor( -1 );
217 pos--;
219 while( pos && buf[pos-1] != ' ' ) {
220 move_cursor( -1 );
221 pos--;
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;
238 break;
239 case 'O':
240 switch(key()) {
241 case 'F':
242 goto go_end;
243 case 'H':
244 goto go_home;
246 break;
248 break;
249 case '\n':
250 case '\r':
251 if( cur_added )
252 history_remove( ci, 0 );
253 add_to_history( ci, ci->buf );
255 emit_str( &buf[pos] );
256 emit(' ');
257 PUSH( feval(buf) );
258 fword("print-status");
260 /* Leave the interpreter if terminate? value set */
261 fword("terminate?");
262 if (POP())
263 terminate = 1;
265 prompt = 1;
266 break;
268 case 3: /* ^c */
269 emit_str("\n");
270 prompt = 1;
271 if( cur_added )
272 history_remove( ci, 0 );
273 break;
275 case 4: /* ^d */
276 delete:
277 if( pos == n )
278 break;
279 emit( buf[pos++] );
280 /* fall through */
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;
296 case 1: /* ^a */
297 go_home:
298 move_cursor( -pos );
299 pos = 0;
300 break;
302 case 5: /* ^e */
303 go_end:
304 pos += emit_str( &buf[pos] );
305 break;
307 //case 68: /* left */
308 // drop = 1;
309 case 2: /* ^b */
310 go_left:
311 if( pos ) {
312 move_cursor( -1 );
313 pos--;
315 break;
317 //case 67: /* right */
318 // drop = 1;
319 case 6: /* ^f */
320 go_right:
321 if( pos < n )
322 emit( buf[pos++] );
323 break;
325 case 11: /* ^k */
326 strcpy( ci->killbuf, &buf[pos] );
327 clear( n-pos );
328 n = pos;
329 buf[pos] = 0;
330 break;
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++]) );
338 break;
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++]) );
346 break;
348 case 12: /* ^l */
349 move_cursor( -ci->ncol -pos );
350 fword("print-prompt");
351 move_cursor( pos-emit_str(buf) );
352 break;
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 );
368 break;
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++;
378 if( history_get(ci, histind) )
379 histind++;
380 clearline( pos, n );
381 emit_str( buf );
382 pos = n = strlen( buf );
383 break;
385 if( (unsigned int)ch < 32 )
386 drop = 1;
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++]) );
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 */
400 /* Reset stack and terminate? */
401 rstackcnt = dbgrstackcnt;
402 feval("0 to terminate?");
405 NODE_METHODS( cmdline ) = {
406 { "open", cmdline_open },
407 { "close", cmdline_close },
408 { "cmdline", cmdline_prompt },
411 void
412 cmdline_init( void )
414 REGISTER_NODE( cmdline );