]> git.cryptolib.org Git - avr-crypto-lib.git/blob - test_src/cli.c
new cli system
[avr-crypto-lib.git] / test_src / cli.c
1 /* cli.c */
2 /*
3     This file is part of the AVR-Crypto-Lib.
4     Copyright (C) 2008  Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /**
20  * 
21  * author: Daniel Otte
22  * email:  daniel.otte@rub.de
23  * license: GPLv3 or later
24  * 
25  * components to help implementing simple command based interaction
26  * 
27  **/
28  
29 #include <stdlib.h> 
30 #include <stdint.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <avr/pgmspace.h>
34 #include "cli.h"
35 #include "config.h"
36
37 int16_t findstring_d0(const char* str, const char* v){
38         uint8_t i=0;
39         while(*v){      
40                 if(!strcmp(str, v)){
41                         return i;
42                 }
43                 while(*v++) /* go to the next string */
44                 ;
45                 ++i;
46         }
47         return -1;
48 }
49
50 #ifdef CLI_OLD
51  
52 int16_t findstring_d0_P(const char* str, PGM_P v){
53         uint8_t i=0;
54         while(pgm_read_byte(v)){        
55                 if(!strcmp_P(str, v)){
56                         return i;
57                 }
58                 while(pgm_read_byte(v++)) /* go to the next string */
59                 ;
60                 ++i;
61         }
62         return -1;
63
64
65 #ifdef CLI_AUTO_HELP
66 #include "uart.h"
67
68 void cli_auto_help_P(PGM_P dbzstr){
69         char c;
70         uart_putstr_P(PSTR("\r\n[auto help] available commands are:\r\n\t"));
71         do{
72                 while((c=pgm_read_byte(dbzstr++))!=0){
73                         uart_putc(c);
74                 }
75                 uart_putstr_P(PSTR("\r\n\t"));
76         }while((c=pgm_read_byte(dbzstr))!=0);
77         uart_putstr_P(PSTR("\r\n"));
78 }
79
80 int16_t execcommand_d0_P(const char* str, PGM_P v, void(*fpt[])(void) ){
81         int16_t i=0;
82         i=findstring_d0_P(str, v);
83         if(i!=-1){
84                 if(fpt[i])
85                         fpt[i]();
86                 return i;
87         }else{
88                 cli_auto_help_P(v);
89                 return -1;
90         }
91 }
92
93 #endif
94
95 #else /* CLI_OLD */
96
97 cli_rx_fpt cli_rx = NULL;
98 cli_tx_fpt cli_tx = NULL;
99 uint8_t cli_echo=1;
100
101 void cli_putstr(char* s){
102         if(!cli_tx)
103                 return;
104         while(*s)
105                 cli_tx(*s++);
106 }
107
108 void cli_putstr_P(PGM_P s){
109         char c;
110         if(!cli_tx)
111                 return;
112         for(;;){
113                 c = pgm_read_byte(s++);
114                 if(!c)
115                         return;
116                 cli_tx(c);
117         }
118 }
119
120 void cli_hexdump(void* data, uint16_t length){
121         char hex_tab[] = {'0', '1', '2', '3', 
122                           '4', '5', '6', '7', 
123                                           '8', '9', 'A', 'B', 
124                                           'C', 'D', 'E', 'F'};
125         if(!cli_tx)
126                 return;
127         while(length--){
128                 cli_tx(hex_tab[(*((uint8_t*)data))>>4]);
129                 cli_tx(hex_tab[(*((uint8_t*)data))&0xf]);
130                 data = (uint8_t*)data +1;
131         }
132 }
133
134 void cli_auto_help(uint16_t maxcmdlength, PGM_VOID_P cmdlist){
135         cmdlist_entry_t item;
136         uint16_t i;
137         if(!cli_tx)
138                 return;
139         
140         cli_putstr_P(PSTR("\r\n[auto help] available commands:\r\n"
141                           " <command> - <params> - <address>\r\n"));
142         for(;;){
143                 item.cmd_name      = (void*)pgm_read_word(cmdlist+0);
144                 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
145                 item.cmd_function  = (void_fpt)pgm_read_word(cmdlist+4);
146                 cmdlist = (uint8_t*)cmdlist+6;
147                 if(item.cmd_name==NULL){
148                         return;
149                 }
150                 cli_tx(' ');
151                 cli_putstr_P(item.cmd_name);
152                 i=maxcmdlength-strlen_P(item.cmd_name);
153                 while(i--)
154                         cli_tx(' ');
155                 cli_putstr_P(PSTR(" - "));
156                 if(item.cmd_param_str==NULL){
157                         cli_putstr_P(PSTR("none \t- 0x"));
158                 } else {
159                         if(item.cmd_param_str==(void*)1){
160                                 cli_putstr_P(PSTR("yes  \t- 0x"));
161                         } else {
162                                 cli_putstr_P(item.cmd_param_str);
163                                 cli_putstr_P(PSTR(" \t- 0x"));
164                         }
165                 }
166                 cli_hexdump(&item.cmd_function, 2);     
167                 cli_putstr_P(PSTR("\r\n"));
168         }
169 }
170
171 uint16_t firstword_length(char* s){
172         uint16_t ret=0;
173         while(isalnum(*s++))
174                 ret++;
175         return ret; 
176 }
177
178 void echo_ctrl(char* s){
179         if(s==NULL || *s=='\0'){
180                 cli_putstr_P(PSTR("\r\necho is "));
181                 cli_putstr_P(cli_echo?PSTR("on"):PSTR("off"));
182                 cli_putstr_P(PSTR("\r\n"));             
183         }
184         strlwr(s);
185         if(!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("on")) || *s=='1'){
186                 cli_echo=1;
187         }
188         if(!strcmp_P(s, PSTR("false")) || !strcmp_P(s, PSTR("off")) || *s=='0'){
189                 cli_echo=0;
190         }
191 }
192
193 typedef void(*str_fpt)(char*);
194 #define CLI_ENTER     13
195 #define CLI_BACKSPACE  8
196 #define CLI_TABULATOR  9
197
198 int8_t search_and_call(char* cmd, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
199         PGM_VOID_P cmdlist_orig = cmdlist;
200         if(*cmd=='\0' || *cmd=='#')
201                 return 1;
202         if(!strcmp_P(cmd, PSTR("exit")))
203                 return 0;
204         if((!strcmp_P(cmd, PSTR("help"))) || (!strcmp_P(cmd, PSTR("?")))){
205                 cli_auto_help(maxcmdlength, cmdlist);
206                 return 1;
207         }
208         uint16_t fwlength=firstword_length(cmd);
209         char fw[fwlength+1];
210         memcpy(fw, cmd, fwlength);
211         fw[fwlength] = '\0';
212         cmdlist_entry_t item;
213         do{
214                 item.cmd_name =      (void*)pgm_read_word(cmdlist+0);
215                 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
216                 item.cmd_function =  (void_fpt)pgm_read_word(cmdlist+4);
217                 cmdlist = (uint8_t*)cmdlist+6;
218         }while(item.cmd_name!=NULL && strcmp_P(fw, item.cmd_name));
219         if(item.cmd_name==NULL){
220                 cli_auto_help(maxcmdlength, cmdlist_orig);
221         } else {
222                 if(item.cmd_function==NULL)
223                         return 2;
224                 switch((uint16_t)item.cmd_param_str){
225                         case 0:
226                                 item.cmd_function();
227                                 break;
228                         case 1:
229                                 if(cmd[fwlength]=='\0'){
230                                         ((str_fpt)item.cmd_function)(cmd+fwlength);
231                                 } else {
232                                         ((str_fpt)item.cmd_function)(cmd+fwlength+1);
233                                 }
234                                 break;
235                         default:
236                                 cli_putstr_P(PSTR("\r\nparam parsing currently not implemented!\r\n"));
237                                 break;
238                 }       
239                 
240         }       
241         return 1;        
242 }
243
244 uint16_t max_cmd_length(PGM_VOID_P cmdlist){
245         uint16_t t,ret=0;
246         char* str;
247         for(;;){
248                 str = (char*)pgm_read_word(cmdlist);
249                 cmdlist = (uint8_t*)cmdlist + 6;
250                 if(str==NULL)
251                         return ret;
252                 t = strlen_P(str);
253                 if(t>ret)
254                         ret=t;
255         }
256 }
257
258 uint16_t stridentcnt_P(char* a, PGM_P b){
259         uint16_t i=0;
260         char c;
261         for(;;){
262                 c = pgm_read_byte(b++);
263                 if(*a != c || c=='\0')
264                         return i;
265                 i++;
266                 a++;
267         }
268 }
269
270 uint8_t cli_completion(char* buffer, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
271         uint8_t i=0;
272         char ref[maxcmdlength+1];
273         char* itemstr;
274         ref[0]='\0';
275         /* check if we are behind the first word */
276         while(buffer[i]){
277                 if(!isalnum(buffer[i++]))
278                         return 0;
279         }
280         for(;;){
281                 itemstr = (char*)pgm_read_word(cmdlist);
282                 if(itemstr==NULL)
283                         break;
284                 cmdlist = (uint8_t*)cmdlist +6;
285                 if(!strncmp_P(buffer, itemstr, i)){
286                         if(!ref[0]){
287                                 strcpy_P(ref, itemstr);
288                         }else{
289                                 ref[stridentcnt_P(ref, itemstr)]='\0';
290                         }
291                 }
292         }
293         i = strcmp(buffer, ref);
294         if(i)
295                 strcpy(buffer, ref);
296         return ~i;
297 }
298
299 void cli_option_listing(char* buffer, PGM_VOID_P cmdlist){
300         char* itemstr;
301         uint16_t len=strlen(buffer);
302         for(;;){
303                 itemstr = (char*)pgm_read_word(cmdlist);
304                 if(itemstr==NULL){
305                         cli_putstr_P(PSTR("\r\n>"));
306                         cli_putstr(buffer);
307                         return;
308                 }
309                 cmdlist = (uint8_t*)cmdlist +6;
310                 if(!strncmp_P(buffer, itemstr, len)){
311                         cli_putstr_P(PSTR("\r\n    "));
312                         cli_putstr_P(itemstr);
313                 }
314         }
315 }
316
317 int8_t cmd_interface(PGM_VOID_P cmd_desc){
318         uint16_t cli_buffer_size;
319         uint16_t cli_buffer_index;
320         int8_t exit_code;
321         uint8_t completion_failed=0;
322         char* cli_buffer;
323         char c;
324         uint16_t maxcmdlength = max_cmd_length(cmd_desc);
325         cli_buffer = calloc(1,cli_buffer_size=maxcmdlength+2);
326         cli_buffer_index=0;
327         if(!cli_rx)
328                 return -1;
329         if(cli_tx)
330                 cli_tx('>');
331         for(;;){
332                 c = cli_rx();
333                 switch (c){
334                 case CLI_ENTER:
335                         if((exit_code=search_and_call(cli_buffer, maxcmdlength, cmd_desc))<=0){
336                                 free(cli_buffer);
337                                 return exit_code;
338                         }
339                         memset(cli_buffer, 0, cli_buffer_size);
340                         cli_buffer_index=0;
341                         cli_putstr_P(PSTR("\r\n>"));
342                         completion_failed=0;
343                         break;
344                 case CLI_BACKSPACE:
345                         completion_failed=0;
346                         if(cli_buffer_index==0)
347                                 break;
348                         cli_buffer_index--;
349                         cli_buffer[cli_buffer_index] = '\0';
350                         if(cli_echo && cli_tx){
351                                 cli_tx(c);
352                         }
353                         break;
354                 case CLI_TABULATOR:
355                         if(completion_failed || cli_buffer_index==0){
356                                 if(cli_tx)
357                                         cli_option_listing(cli_buffer, cmd_desc);
358                         } else {
359                                 uint16_t old_idx = cli_buffer_index;
360                                 completion_failed = 
361                                         ~cli_completion(cli_buffer, maxcmdlength, cmd_desc);
362                                 cli_buffer_index = strlen(cli_buffer);
363                                 if(cli_echo && cli_tx){
364                                         while(old_idx<cli_buffer_index){
365                                                 cli_tx(cli_buffer[old_idx++]);
366                                         }
367                                 }
368                         }
369                         break;
370                 default:
371                         completion_failed=0;
372                         if(cli_echo && cli_tx){
373                                 cli_tx(c);
374                         }
375                         if(cli_buffer_index+1==cli_buffer_size){
376                                 cli_buffer = realloc(cli_buffer, cli_buffer_size+=CLI_BUFFER_BS);
377                                 if(!cli_buffer){
378                                         return -2;
379                                 }
380                                 memset(cli_buffer+cli_buffer_index+1, 0, CLI_BUFFER_BS);
381                         }
382                         cli_buffer[cli_buffer_index++] = c;
383                 }
384         }
385 }
386
387 #endif
388