|
|
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.