|
|
1.1 ! root 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 ([email protected]) ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.