]> git.cryptolib.org Git - avr-crypto-lib.git/blob - test_src/cli.c
b9659fe2cd544fe1a9814a31343d8faf6cdb75ad
[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 "string-extras.h"
35 #include "cli.h"
36 #include "config.h"
37
38 cli_rx_fpt cli_rx = NULL;
39 cli_tx_fpt cli_tx = NULL;
40 uint8_t cli_echo=1;
41
42 void cli_putc(char c){
43         if(cli_tx)
44                 cli_tx(c);
45 }
46
47 uint16_t cli_getc(void){
48         if(cli_rx)
49                 return cli_rx();
50         return ((uint16_t)-1);
51 }
52
53
54 uint16_t cli_getc_cecho(void){
55         char c;
56         if(cli_rx){
57                 c = cli_rx();
58                 if(cli_tx && cli_echo)
59                         cli_tx(c);
60                 return c;
61         }
62         return ((uint16_t)-1);
63 }
64
65 void cli_putstr(char* s){
66         if(!cli_tx)
67                 return;
68         while(*s)
69                 cli_tx(*s++);
70 }
71
72 void cli_putstr_P(PGM_P s){
73         char c;
74         if(!cli_tx)
75                 return;
76         for(;;){
77                 c = pgm_read_byte(s++);
78                 if(!c)
79                         return;
80                 cli_tx(c);
81         }
82 }
83
84 uint8_t cli_getsn(char* s, uint16_t n){
85         char c;
86         if(n==0)
87                 return 2;
88         while((c=cli_getc_cecho())!='\0' && c!='\r' && n--){
89                 *s++=c;
90         }
91         *s='\0';
92         return (c=='\r')?0:1;
93 }
94
95 void cli_hexdump(void* data, uint16_t length){
96         char hex_tab[] = {'0', '1', '2', '3', 
97                           '4', '5', '6', '7', 
98                                           '8', '9', 'A', 'B', 
99                                           'C', 'D', 'E', 'F'};
100         if(!cli_tx)
101                 return;
102         while(length--){
103                 cli_tx(hex_tab[(*((uint8_t*)data))>>4]);
104                 cli_tx(hex_tab[(*((uint8_t*)data))&0xf]);
105                 data = (uint8_t*)data +1;
106         }
107 }
108
109 void cli_hexdump2(void* data, uint16_t length){
110         char hex_tab[] = {'0', '1', '2', '3', 
111                           '4', '5', '6', '7', 
112                                           '8', '9', 'A', 'B', 
113                                           'C', 'D', 'E', 'F'};
114         if(!cli_tx)
115                 return;
116         while(length--){
117                 cli_tx(hex_tab[(*((uint8_t*)data))>>4]);
118                 cli_tx(hex_tab[(*((uint8_t*)data))&0xf]);
119                 cli_tx(' ');
120                 data = (uint8_t*)data +1;
121         }
122 }
123
124 static
125 void cli_auto_help(uint16_t maxcmdlength, PGM_VOID_P cmdlist){
126         cmdlist_entry_t item;
127         uint16_t i;
128         if(!cli_tx)
129                 return;
130         
131         cli_putstr_P(PSTR("\r\n[auto help] available commands:\r\n"
132                           " <command> - <params> - <address>\r\n"));
133         for(;;){
134                 item.cmd_name      = (void*)pgm_read_word(cmdlist+0);
135                 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
136                 item.cmd_function  = (void_fpt)pgm_read_word(cmdlist+4);
137                 cmdlist = (uint8_t*)cmdlist+CMDLIST_ENTRY_SIZE;
138                 if(item.cmd_name==NULL){
139                         return;
140                 }
141                 cli_tx(' ');
142                 cli_putstr_P(item.cmd_name);
143                 i=maxcmdlength-strlen_P(item.cmd_name);
144                 while(i--)
145                         cli_tx(' ');
146                 cli_putstr_P(PSTR(" - "));
147                 if(item.cmd_param_str==NULL){
148                         cli_putstr_P(PSTR("none \t- 0x"));
149                 } else {
150                         if(item.cmd_param_str==(void*)1){
151                                 cli_putstr_P(PSTR("yes  \t- 0x"));
152                         } else {
153                                 cli_putstr_P(item.cmd_param_str);
154                                 cli_putstr_P(PSTR(" \t- 0x"));
155                         }
156                 }
157                 cli_hexdump(&item.cmd_function, 2);     
158                 cli_putstr_P(PSTR("\r\n"));
159         }
160 }
161
162 void echo_ctrl(char* s){
163         s = strstrip(s);
164         if(s==NULL || *s=='\0'){
165                 cli_putstr_P(PSTR("\r\necho is "));
166                 cli_putstr_P(cli_echo?PSTR("on"):PSTR("off"));
167                 cli_putstr_P(PSTR("\r\n"));             
168         }
169         strlwr(s);
170         if(!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("on")) || *s=='1'){
171                 cli_echo=1;
172         }
173         if(!strcmp_P(s, PSTR("false")) || !strcmp_P(s, PSTR("off")) || *s=='0'){
174                 cli_echo=0;
175         }
176 }
177
178 typedef void(*str_fpt)(char*);
179 #define CLI_ENTER     13
180 #define CLI_BACKSPACE  8
181 #define CLI_TABULATOR  9
182
183 int8_t search_and_call(char* cmd, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
184         PGM_VOID_P cmdlist_orig = cmdlist;
185         if(*cmd=='\0' || *cmd=='#')
186                 return 1;
187         if(!strcmp_P(cmd, PSTR("exit")))
188                 return 0;
189         if((!strcmp_P(cmd, PSTR("help"))) || (!strcmp_P(cmd, PSTR("?")))){
190                 cli_auto_help(maxcmdlength, cmdlist);
191                 return 1;
192         }
193         uint16_t fwlength=firstword_length(cmd);
194         char fw[fwlength+1];
195         memcpy(fw, cmd, fwlength);
196         fw[fwlength] = '\0';
197         cmdlist_entry_t item;
198         do{
199                 item.cmd_name =      (void*)pgm_read_word(cmdlist+0);
200                 item.cmd_param_str = (void*)pgm_read_word(cmdlist+2);
201                 item.cmd_function =  (void_fpt)pgm_read_word(cmdlist+4);
202                 cmdlist = (uint8_t*)cmdlist+CMDLIST_ENTRY_SIZE;
203         }while(item.cmd_name!=NULL && strcmp_P(fw, item.cmd_name));
204         if(item.cmd_name==NULL){
205                 cli_auto_help(maxcmdlength, cmdlist_orig);
206         } else {
207                 if(item.cmd_function==NULL)
208                         return 2;
209                 switch((uint16_t)item.cmd_param_str){
210                         case 0:
211                                 item.cmd_function();
212                                 break;
213                         case 1:
214                                 if(cmd[fwlength]=='\0'){
215                                         ((str_fpt)item.cmd_function)(cmd+fwlength);
216                                 } else {
217                                         ((str_fpt)item.cmd_function)(cmd+fwlength+1);
218                                 }
219                                 break;
220                         default:
221                                 cli_putstr_P(PSTR("\r\nparam parsing currently not implemented!\r\n"));
222                                 break;
223                 }       
224                 
225         }       
226         return 1;        
227 }
228
229 uint16_t max_cmd_length(PGM_VOID_P cmdlist){
230         uint16_t t,ret=0;
231         char* str;
232         for(;;){
233                 str = (char*)pgm_read_word(cmdlist);
234                 cmdlist = (uint8_t*)cmdlist + CMDLIST_ENTRY_SIZE;
235                 if(str==NULL)
236                         return ret;
237                 t = strlen_P(str);
238                 if(t>ret)
239                         ret=t;
240         }
241 }
242
243 uint8_t cli_completion(char* buffer, uint16_t maxcmdlength, PGM_VOID_P cmdlist){
244         uint8_t i=0;
245         char ref[maxcmdlength+1];
246         char* itemstr;
247         ref[0]='\0';
248         /* check if we are behind the first word */
249         while(buffer[i]){
250                 if(!isgraph(buffer[i++]))
251                         return 0;
252         }
253         for(;;){
254                 itemstr = (char*)pgm_read_word(cmdlist);
255                 if(itemstr==NULL)
256                         break;
257                 cmdlist = (uint8_t*)cmdlist +CMDLIST_ENTRY_SIZE;
258                 if(!strncmp_P(buffer, itemstr, i)){
259                         if(!ref[0]){
260                                 strcpy_P(ref, itemstr);
261                         }else{
262                                 ref[stridentcnt_P(ref, itemstr)]='\0';
263                         }
264                 }
265         }
266         i = strcmp(buffer, ref);
267         if(i)
268                 strcpy(buffer, ref);
269         return ~i;
270 }
271
272 void cli_option_listing(char* buffer, PGM_VOID_P cmdlist){
273         char* itemstr;
274         uint16_t len=strlen(buffer);
275         for(;;){
276                 itemstr = (char*)pgm_read_word(cmdlist);
277                 if(itemstr==NULL){
278                         cli_putstr_P(PSTR("\r\n>"));
279                         cli_putstr(buffer);
280                         return;
281                 }
282                 cmdlist = (uint8_t*)cmdlist +CMDLIST_ENTRY_SIZE;
283                 if(!strncmp_P(buffer, itemstr, len)){
284                         cli_putstr_P(PSTR("\r\n    "));
285                         cli_putstr_P(itemstr);
286                 }
287         }
288 }
289
290 int8_t cmd_interface(PGM_VOID_P cmd_desc){
291         uint16_t cli_buffer_size;
292         uint16_t cli_buffer_index;
293         int8_t exit_code;
294         uint8_t completion_failed=0;
295         char* cli_buffer;
296         char c;
297         uint16_t maxcmdlength = max_cmd_length(cmd_desc);
298         cli_buffer = calloc(1,cli_buffer_size=maxcmdlength+2);
299         cli_buffer_index=0;
300         if(!cli_rx)
301                 return -1;
302         if(cli_tx)
303                 cli_tx('>');
304         for(;;){
305                 c = cli_rx();
306                 switch (c){
307                 case CLI_ENTER:
308                         if((exit_code=search_and_call(cli_buffer, maxcmdlength, cmd_desc))<=0){
309                                 free(cli_buffer);
310                                 return exit_code;
311                         }
312                         memset(cli_buffer, 0, cli_buffer_size);
313                         cli_buffer_index=0;
314                         cli_putstr_P(PSTR("\r\n>"));
315                         completion_failed=0;
316                         break;
317                 case CLI_BACKSPACE:
318                         completion_failed=0;
319                         if(cli_buffer_index==0)
320                                 break;
321                         cli_buffer_index--;
322                         cli_buffer[cli_buffer_index] = '\0';
323                         if(cli_echo && cli_tx){
324                                 cli_tx(c);
325                         }
326                         break;
327                 case CLI_TABULATOR:
328                         if(completion_failed || cli_buffer_index==0){
329                                 if(cli_tx)
330                                         cli_option_listing(cli_buffer, cmd_desc);
331                         } else {
332                                 uint16_t old_idx = cli_buffer_index;
333                                 completion_failed = 
334                                         ~cli_completion(cli_buffer, maxcmdlength, cmd_desc);
335                                 cli_buffer_index = strlen(cli_buffer);
336                                 if(cli_echo && cli_tx){
337                                         while(old_idx<cli_buffer_index){
338                                                 cli_tx(cli_buffer[old_idx++]);
339                                         }
340                                 }
341                         }
342                         break;
343                 default:
344                         completion_failed=0;
345                         if(cli_echo && cli_tx){
346                                 cli_tx(c);
347                         }
348                         if(cli_buffer_index+1==cli_buffer_size){
349                                 cli_buffer = realloc(cli_buffer, cli_buffer_size+=CLI_BUFFER_BS);
350                                 if(!cli_buffer){
351                                         return -2;
352                                 }
353                                 memset(cli_buffer+cli_buffer_index+1, 0, CLI_BUFFER_BS);
354                         }
355                         cli_buffer[cli_buffer_index++] = c;
356                 }
357         }
358 }