summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/packages/cmdline.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/packages/cmdline.c')
-rw-r--r--qemu/roms/openbios/packages/cmdline.c415
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 );
+}