Use new minimal shell
[people/xl0/gpxe.git] / src / commandline / cmdlinelib.c
1 #include "cmdlinelib.h"
2 #include <gpxe/command.h>
3 #include <gpxe/tables.h>
4 #include <console.h>
5 #include <malloc.h>
6 #include <string.h>
7 #include <stdarg.h>
8
9 static struct command cmd_start[0] __table_start ( commands );
10 static struct command cmd_end[0] __table_end ( commands );
11
12 void cmdl_setgetchar(cmd_line* cmd, cmdl_getchar_t in)
13 {
14         cmd->getchar = in;
15 }
16
17 void cmdl_setputchar(cmd_line* cmd, cmdl_putchar_t in)
18 {
19         cmd->putchar = in;
20 }
21
22 void cmdl_setprintf(cmd_line* cmd, cmdl_printf_t in)
23 {
24         cmd->printf = in;
25 }
26       
27 int cmdl_printf(cmd_line* cmd, const char *format, ...)
28 {
29         int ret;
30         char string[CMDL_BUFFER_SIZE];
31         va_list ap;
32
33         va_start(ap, format);
34         ret = vsprintf(string, format, ap);
35         cmdl_addstr(cmd, string);
36         va_end(ap);
37         return ret;
38 }
39
40 void cmdl_addstr(cmd_line* cmd, char* str)
41 {
42         unsigned int i;
43         for(i = 0; i < strlen(str); i++){
44                 cmdl_addchar(cmd, str[i]);
45         }
46 }
47
48 void cmdl_setpropmt(cmd_line* cmd, char prompt[CMDL_PROMPT_SIZE])
49 {
50         if(cmdl_check(cmd) && prompt != NULL){
51                 strncat(cmd->prompt, prompt, CMDL_PROMPT_SIZE);
52         }
53 }
54
55 char *cmdl_getprompt(cmd_line* cmd)
56 {
57         if(cmdl_check(cmd)){
58                 return cmd->prompt;
59         }else{
60                 return "";
61         }
62 }
63
64 char* cmdl_getbuffer(cmd_line* cmd){
65         if(cmdl_check(cmd)){
66                 return cmd->buffer;
67         }else{
68                 return "";
69         }
70 }
71
72 static int cmdl_exit = 0;
73
74 static int exit_exec ( int argc __unused, char **argv __unused ) {
75         cmdl_exit = 1;
76         return 0;
77 }
78
79 struct command exit_command __command = {
80         .name = "exit",
81         .exec = exit_exec,
82 };
83
84 void cmdl_enterloop(cmd_line* cmd)
85 {
86         cmdl_exit = 0;
87         do {
88                 if(cmd->refresh){
89                         cmd->printf("%s %s", cmd->prompt, cmd->buffer);
90                         cmd->refresh = 0;
91                 }
92 //              cmd->printf("Got %d\n", cmd->getchar());
93                 cmdl_parsechar(cmd, cmd->getchar());
94         } while ( ! cmdl_exit );
95 }
96
97 void cmdl_addreplace(cmd_line* cmd, char in)
98 {
99         if(cmd->cursor < CMDL_BUFFER_SIZE - 2){
100                 cmd->buffer[cmd->cursor] = in;
101                 cmd->cursor++;
102                 cmd->putchar((int)in);
103         }
104 }
105
106 void cmdl_addinsert(cmd_line* cmd, char in)
107 {
108         int i;
109         int to;
110         if(cmd->cursor < CMDL_BUFFER_SIZE - 2 && cmd->cursor >= 0){
111                 if(strlen(cmd->buffer) < CMDL_BUFFER_SIZE - 2){
112                         to = strlen(cmd->buffer);
113                 }else{
114                         to = CMDL_BUFFER_SIZE - 2;
115                 }
116                         for(i=to; i > cmd->cursor; i--){
117                                 cmd->buffer[i] = cmd->buffer[i-1];
118                         }
119                         cmd->buffer[cmd->cursor] = in;
120
121                         for(i=cmd->cursor; i < to; i++){
122                                 cmd->putchar(cmd->buffer[i]);
123                         }
124                         
125                         for(i=cmd->cursor; i < to - 1; i++){
126                                 cmd->putchar(CMDLK_BS);
127                         }
128                         cmd->cursor++;
129                         //cmdl_movecursor(cmd, CMDL_RIGHT);
130         }
131 }
132
133 void cmdl_addchar(cmd_line* cmd, char in){
134         if(cmd->insert){
135                 cmdl_addinsert(cmd, in);
136         }else{
137                 cmdl_addreplace(cmd, in);
138         }
139 }
140
141 void cmdl_parsechar(cmd_line* cmd, char in)
142 {
143         if(cmdl_check(cmd)){
144                 if(in >= 32){
145                         cmdl_addchar(cmd, in);
146                 }else{
147                         switch(in){
148                                 case CMDLK_BS:
149                                         if(cmdl_movecursor(cmd, CMDL_LEFT)){
150                                                 cmdl_del(cmd);
151                                         }
152                                         break;
153
154                                 case CMDLK_RETURN:
155                                         cmd->putchar('\n');
156                                         system ( cmd->buffer );
157                                         cmdl_clearbuffer(cmd);
158                                         cmd->refresh = 1;
159                                         break;
160
161                                 case CMDLK_BW:
162                                         cmdl_movecursor(cmd, CMDL_LEFT);
163                                         break;
164
165                                 case CMDLK_FW:
166                                         //cmdl_movecursor(cmd, CMDL_RIGHT);
167                                         break;
168                                 
169                                 case CMDLK_TAB:
170                                         cmdl_tabcomplete(cmd);
171                                         break;
172
173                         }
174                 }
175         }
176 }
177
178 void cmdl_tabcomplete(cmd_line *cmd)
179 {
180         struct command *ccmd;
181         int count=0;
182         char* result[CMDL_MAX_TAB_COMPLETE_RESULT];
183
184         for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) {
185                 if(!strncmp(ccmd->name, cmd->buffer, strlen(cmd->buffer))){
186                         if(count <= CMDL_MAX_TAB_COMPLETE_RESULT){
187                                 result[count++] = (char*)(ccmd->name);
188                         }
189                 }
190         }
191         
192
193         if( count == 1 ){
194                 cmdl_addstr(cmd, (char*)(result[0] + strlen(cmd->buffer)));
195                 cmd->tabstate = 0;
196                 cmdl_addchar(cmd, ' ');
197         } else if( count > 1 ) {
198                 int i, i2, minlen=CMDL_BUFFER_SIZE, same=1;
199                 char last;
200
201                 for(i = 0; i < count; i ++) {
202                         if(minlen > (int)strlen( result[i] ) ){
203                                 minlen = strlen(result[i]);
204                         }
205                 
206                 }
207                 if((int)strlen(cmd->buffer) < minlen){
208                         for(i = strlen(cmd->buffer); i < minlen; i++){
209                                 last = result[0][i];
210                                 for(i2 = 1; i2 < count; i2 ++) {
211                                         if(result[i2][i] != last){
212                                                 same = 0;
213                                                 break;
214                                         }
215                                 }
216                                 if(same){
217                                         cmdl_addchar(cmd, last);
218                                 }
219                                 
220                         }
221                 }
222                 cmd->tabstate++;
223         }
224         
225         if(count > 1 && cmd->tabstate > 1){
226                 int i;
227                 cmd->tabstate = 0;
228                 cmd->refresh = 1;
229                 cmd->putchar('\n');
230                 for(i = 0; i < count; i ++){
231                         cmd->printf("%s\t", result[i]);
232                 }
233                 cmd->putchar('\n');
234         }
235
236         
237
238 }
239
240 void cmdl_clearbuffer(cmd_line* cmd)
241 {
242         if(cmdl_check(cmd)){
243                 int i;
244                 cmd->cursor = 0;
245                 for(i=0; i < CMDL_BUFFER_SIZE; i++){
246                         cmd->buffer[i] = 0;
247                 }
248         }
249 }
250
251 int cmdl_movecursor(cmd_line* cmd, int direction)
252 {
253         if(cmdl_check(cmd)){
254                 switch(direction){
255                         case CMDL_LEFT:
256                                 if(cmd->cursor > 0){
257                                         cmd->cursor--;
258                                         cmd->putchar(CMDLK_BS);
259                                 }else{
260                                         return 0;
261                                 }
262                                 break;
263                         case CMDL_RIGHT:
264                                 if(cmd->cursor < CMDL_BUFFER_SIZE - 2){
265                                         cmd->cursor++;
266                                         cmd->putchar(' ');
267                                 }else{
268                                         return 0;
269                                 }
270                                 break;
271                 }
272         }
273         return 1;
274 }
275
276 void cmdl_del(cmd_line* cmd)
277 {
278         if(cmdl_check(cmd) && cmd->cursor < CMDL_BUFFER_SIZE - 2 && cmd->cursor >= 0){
279                 int i;
280                 for(i = cmd->cursor; i < (int)strlen(cmd->buffer); i++){
281                         cmd->buffer[i] = cmd->buffer[i + 1];
282                         if(!cmd->buffer[i]){
283                                 cmd->putchar(' ');
284                         }else{
285                                 cmd->putchar(cmd->buffer[i]);
286                         }
287                 }
288                 for(i = cmd->cursor; i < (int)strlen(cmd->buffer) + 1; i++){
289                         cmd->putchar(CMDLK_BS);
290                 }
291         }
292 }
293
294
295 int cmdl_check(cmd_line* cmd)
296 {
297         if(
298                 cmd != NULL && 
299                 cmd->buffer != NULL &&
300                 cmd->prompt != NULL &&
301                 cmd->cursor >= 0 && 
302                 cmd->cursor < CMDL_BUFFER_SIZE - 1 &&
303                 cmd->buffer[CMDL_BUFFER_SIZE - 1] == 0 &&
304                 cmd->prompt[CMDL_PROMPT_SIZE - 1] == 0
305         ){
306                 return 1;
307         }else{
308                 return 0;
309         }
310 }
311
312 cmd_line* cmdl_create()
313 {
314         cmd_line* this;
315         int i;
316         
317         /* Initiate the command line */
318         
319         this = (cmd_line*)malloc(sizeof(cmd_line));
320         
321         if(this == NULL){
322                 return NULL;
323         }
324         
325
326         /* Allocate output buffer */
327         
328         /*this->output = (char*)malloc(CMDL_OUTPUT_SIZE);
329         if(this->output == NULL){
330                 free(this);
331                 return NULL;
332         }*/
333         
334 /*      for(i = 0; i < CMDL_OUTPUT_SIZE; i++){
335                 this->output[i] = 0;
336         }*/
337
338         /* Allocate command line buffer */
339         
340         this->buffer = (char*)malloc(CMDL_BUFFER_SIZE);
341         if(this->buffer == NULL){
342                 free(this);
343                 return NULL;
344         }
345         
346         for(i = 0; i < CMDL_BUFFER_SIZE; i++){
347                 this->buffer[i] = 0;
348         }
349         
350         /* Allocate prompt buffer */
351         
352         this->prompt = (char*)malloc(CMDL_PROMPT_SIZE);
353         if(this->prompt == NULL){
354                 free(this);
355                 return NULL;
356         }
357         
358         for(i = 0; i < CMDL_PROMPT_SIZE; i++){
359                 this->prompt[i] = 0;
360         }
361         
362         /* Initiate cursor position etc.*/
363         
364         this->cursor = 0;
365         //this->has_output = 0;
366         this->refresh = 1;
367         this->tabstate = 0;
368         this->insert = 0;
369
370         /* set callbacks to NULL */
371
372         this->getchar = NULL;
373         this->putchar = NULL;
374         this->printf = NULL;
375
376         /* List the commands */
377
378         struct command *cmd;
379
380         printf ( "Available commands: ");
381         for ( cmd = cmd_start ; cmd < cmd_end ; cmd++ ) {
382                 printf("%s ", cmd->name);
383         }
384         printf("\n\n");
385
386         return this;
387 }
388
389 void cmdl_free(cmd_line* cmd)
390 {
391         free(cmd);
392 }
393