diff options
Diffstat (limited to 'qemu/roms/openbios/packages/cmdline.c')
-rw-r--r-- | qemu/roms/openbios/packages/cmdline.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/qemu/roms/openbios/packages/cmdline.c b/qemu/roms/openbios/packages/cmdline.c new file mode 100644 index 000000000..ea6bca3db --- /dev/null +++ b/qemu/roms/openbios/packages/cmdline.c @@ -0,0 +1,415 @@ +/* + * Creation Date: <2003/12/28 14:16:31 samuel> + * Time-stamp: <2004/01/07 10:37:40 samuel> + * + * <cmdline.c> + * + * OpenFirmwware User Interface + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "packages.h" +#include "libc/vsprintf.h" + +typedef struct { + char *buf; /* size: ncol+1 */ + char *killbuf; /* size: ncol+1 */ + char *history; + int hsize; /* size of history buffer */ + int ncol; /* #columns */ +} cmdline_info_t; + +DECLARE_NODE( cmdline, INSTALL_OPEN, sizeof(cmdline_info_t), + "+/packages/cmdline" ); + +static void +emit( int ch ) +{ + PUSH( ch ); + fword("emit"); +} + +static int +emit_str( const char *str ) +{ + int n = 0; + while( *str ) { + n++; + emit( *str++ ); + } + return n; +} + +static void +move_cursor( int n ) +{ + if( n >= 0 ) { + while( n-- ) + emit( '\f' ); + } else { + while( n++ ) + emit( 8 ); + } +} + +static void +clear( int n ) +{ + int i; + for( i=0; i<n; i++ ) + emit(' '); + move_cursor( -n ); +} + +static void +clearline( int pos, int n ) +{ + move_cursor( -pos ); + clear( n ); +} + +static int +key( void ) +{ + fword("key"); + return POP(); +} + +/* ( -- flag ) */ +static void +cmdline_open( cmdline_info_t *ci ) +{ + ci->ncol = 80; + ci->buf = malloc( ci->ncol + 1 ); + ci->killbuf = malloc( ci->ncol + 1 ); + + ci->hsize = 40; + ci->history = malloc( ci->hsize ); + ci->history[0] = 0; + + RET( -1 ); +} + +/* ( -- ) */ +static void +cmdline_close( cmdline_info_t *ci ) +{ + free( ci->buf ); + free( ci->killbuf ); + free( ci->history ); +} + + +static char * +history_get( cmdline_info_t *ci, int n ) +{ + char *p = ci->history; + int len; + + while( n-- && p ) + if( (p=strchr(p,'\n')) ) + p++; + + ci->buf[0] = 0; + if( !p ) + return NULL; + + for( len=0; len <= ci->ncol && p[len] != '\n' && p[len] ; len++ ) + ; + memcpy( ci->buf, p, len ); + ci->buf[len] = 0; + return p; +} + +static int +history_remove( cmdline_info_t *ci, int line ) +{ + char *s, *p = history_get( ci, line ); + + if( !p || !(s=strchr(p, '\n')) ) + return 1; + s++; + memmove( p, s, strlen(s)+1 ); + return 0; +} + +static int /* ( -- ) */ +add_to_history( cmdline_info_t *ci, char *str ) +{ + int n, len; + + if( !ci->history ) + return 0; + len = strlen(str); + if( !len ) + return 0; + + /* make room for line in history */ + for( ;; ) { + char *p; + n = strlen(ci->history) + 1; + + if( n + len + 1 <= ci->hsize ) + break; + + if( !(p=strrchr(ci->history,'\n')) ) + return 0; + *p = 0; + if( !(p=strrchr(ci->history, '\n')) ) + p = ci->history-1; + p[1] = 0; + } + + memmove( ci->history + len + 1, ci->history, n ); + memcpy( ci->history, str, len ); + ci->history[ len ] = '\n'; + return 1; +} + +static void /* ( -- ) */ +cmdline_prompt( cmdline_info_t *ci ) +{ + int cur_added=0, histind=0, ch, i, pos=0, n=0, prompt=1; + char *buf; + int terminate = 0; + + buf = ci->buf; + selfword("prepare"); + + emit('\n'); +#ifdef NOLEAVE + for (;;) +#else + while (rstackcnt && !terminate) +#endif + { + int drop = 0; + terminate = 0; + + if( prompt ) { + fword("print-prompt"); + buf[0] = 0; + cur_added = prompt = histind = pos = n = 0; + } + + ch = key(); + switch( ch ) { + case 27: + switch( key() ) { + case 'f': + while( buf[pos] == ' ' ) + emit( buf[pos++] ); + while( buf[pos] && buf[pos] != ' ' ) + emit( buf[pos++] ); + break; + + case 'b': + while( pos && buf[pos-1] == ' ' ) { + move_cursor( -1 ); + pos--; + } + while( pos && buf[pos-1] != ' ' ) { + move_cursor( -1 ); + pos--; + } + break; + case '[': + switch( key() ) { + case 'A': + goto go_up; + case 'B': + goto go_down; + case 'C': + goto go_right; + case 'D': + goto go_left; + case '3': + key(); + goto delete; + } + break; + case 'O': + switch(key()) { + case 'F': + goto go_end; + case 'H': + goto go_home; + } + break; + } + break; + case '\n': + case '\r': + if( cur_added ) + history_remove( ci, 0 ); + add_to_history( ci, ci->buf ); + + emit_str( &buf[pos] ); + emit(' '); + PUSH( feval(buf) ); + fword("print-status"); + + /* Leave the interpreter if terminate? value set */ + fword("terminate?"); + if (POP()) + terminate = 1; + + prompt = 1; + break; + + case 3: /* ^c */ + emit_str("\n"); + prompt = 1; + if( cur_added ) + history_remove( ci, 0 ); + break; + + case 4: /* ^d */ +delete: + if( pos == n ) + break; + emit( buf[pos++] ); + /* fall through */ + + case 8: /* ^h */ + case 127: /* backspace */ + drop = 1; + if( !pos ) + break; + move_cursor( -1 ); + emit_str( &buf[pos] ); + emit(' '); + memmove( &buf[pos-1], &buf[pos], n+1-pos ); + move_cursor( pos-n-1 ); + pos--; + n--; + break; + + case 1: /* ^a */ +go_home: + move_cursor( -pos ); + pos = 0; + break; + + case 5: /* ^e */ +go_end: + pos += emit_str( &buf[pos] ); + break; + + //case 68: /* left */ + // drop = 1; + case 2: /* ^b */ +go_left: + if( pos ) { + move_cursor( -1 ); + pos--; + } + break; + + //case 67: /* right */ + // drop = 1; + case 6: /* ^f */ +go_right: + if( pos < n ) + emit( buf[pos++] ); + break; + + case 11: /* ^k */ + strcpy( ci->killbuf, &buf[pos] ); + clear( n-pos ); + n = pos; + buf[pos] = 0; + break; + + case 25: /* ^y */ + for( i=0; n < ci->ncol && ci->killbuf[i] ; i++, n++ ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + buf[pos] = ci->killbuf[i]; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + break; + + case 9: /* TAB */ + for( i=0; n < ci->ncol && (!i || (pos%4)) ; i++, n++ ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + buf[pos] = ' '; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + break; + + case 12: /* ^l */ + move_cursor( -ci->ncol -pos ); + fword("print-prompt"); + move_cursor( pos-emit_str(buf) ); + break; + + //case 66: /* down */ + // drop = 1; + case 14: /* ^n */ +go_down: + if( !histind ) + break; + history_get( ci, --histind - 1); + clearline( pos, n ); + emit_str( buf ); + pos = n = strlen( buf ); + if( !histind && cur_added ) { + cur_added = 0; + history_remove( ci, 0 ); + } + break; + + //case 65: /* up */ + // drop = 1; + case 16: /* ^p */ +go_up: + if( !histind && add_to_history(ci, ci->buf) ) { + cur_added = 1; + histind++; + } + if( history_get(ci, histind) ) + histind++; + clearline( pos, n ); + emit_str( buf ); + pos = n = strlen( buf ); + break; + } + if( (unsigned int)ch < 32 ) + drop = 1; + + if( !drop && n < ci->ncol ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + n++; + buf[pos] = ch; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + } + + /* we only get here if terminate? is non-zero; this should + * only ever be done for a subordinate forth interpreter + * e.g. for debugging */ + + /* Reset stack and terminate? */ + rstackcnt = dbgrstackcnt; + feval("0 to terminate?"); +} + +NODE_METHODS( cmdline ) = { + { "open", cmdline_open }, + { "close", cmdline_close }, + { "cmdline", cmdline_prompt }, +}; + +void +cmdline_init( void ) +{ + REGISTER_NODE( cmdline ); +} |