]> rtime.felk.cvut.cz Git - sysless.git/blob - libs4c/cmdproc/cmd_proc.c
fe667b733d1c0578029c7137ed9d82af4a8e8ead
[sysless.git] / libs4c / cmdproc / cmd_proc.c
1 /*******************************************************************
2   Components for embedded applications builded for
3   laboratory and medical instruments firmware  
4  
5   cmd_proc.c - text command processor
6                enables to define multilevel tables of commands
7                which can be received from more inputs and send reply
8                to respective I/O stream output
9  
10   Copyright (C) 2001-2009 by Pavel Pisa pisa@cmp.felk.cvut.cz
11             (C) 2002-2009 by PiKRON Ltd. http://www.pikron.com
12             (C) 2007 by Michal Sojka <sojkam1@fel.cvut.cz>
13
14   This file can be used and copied according to next
15   license alternatives
16    - MPL - Mozilla Public License
17    - GPL - GNU Public License
18    - other license provided by project originators
19  *******************************************************************/
20
21 #include <stdint.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <i2str.h>
26 #include <cmd_proc.h>
27 #include "cmd_proc_priv.h"
28
29 /* cmd_line processing */
30
31 char *skip_white(char *p)
32 {
33   while(isspace((uint8_t)*p)) p++;
34   return p;
35 }
36
37 /**
38  * Process a command line
39  *
40  * @param cmd_io I/O stack
41  * @param des_arr Pointer to the command descriptors.
42  * @param line Command line to process.
43  *
44  * @return Zero if no command was given in line, -CMDERR_BADCMD if
45  * command is not known or has no function assigned to it. If a
46  * command is executed, then the return value of the command function
47  * is returned.
48  */
49 int proc_cmd_line(cmd_io_t *cmd_io, cmd_des_t const **des_arr, char *line)
50 {
51   char *p=line, *r, *var;
52   const cmd_des_t *des;
53   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
54   int arr_stack_sp=0;
55   char *param[10];
56   short cmd_len;
57   int res, i, parcnt; 
58   param[0]=p=skip_white(p);
59   if(!*p) return 0;
60   /* Determine the name of the command */
61   if(!isalnum((uint8_t)*p)){
62     cmd_len=1;
63     p++;
64   }else{
65     while(isalnum((uint8_t)*p)) p++;
66     cmd_len=p-param[0];
67   }
68   param[1]=param[2]=skip_white(p);
69   
70   /* Find the command in des_arr */
71   while(1){
72     des=*(des_arr++);
73     if(!des){
74       if(!arr_stack_sp) break;
75       des_arr=arr_stack[--arr_stack_sp];
76       continue;
77     }
78     if(des==CMD_DES_CONTINUE_AT_ID){
79       /* list continues at new address */
80       des_arr=(const cmd_des_t **)*des_arr;continue;
81     }
82     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
83       /* list includes commands from sublists */
84       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
85         des_arr++;
86       }else{
87         arr_stack[arr_stack_sp++]=des_arr+1;
88         des_arr=(const cmd_des_t **)*des_arr;
89         continue;
90       }
91     }
92     p=param[0];
93     if(!(r=des->name))continue;
94     i=cmd_len;
95     var=NULL;
96     while(*r){
97       while((*p==*r)&&i){i--;r++;p++;};
98       if((i==0)&&!*r) break;    /* We've found the command (full match) */
99       if((*r=='?')&&i){         /* '?' stands for an arbitrary character */
100         if(!var) var=p;
101         p++; r++; i--;
102         continue;
103       }
104       if((*r=='#')&&i&&isdigit((uint8_t)*p)){ /* '#' stands for a digit */
105         if(!var) var=p;
106         p++; r++; i--;
107         continue;
108       }
109       if(*r=='*'){              /* '*' stands for any number of any characters */
110         if(!var) var=p;
111         i=0;
112         break;
113       }
114       i=1;                      /* Signal no match */
115       break;      
116     }
117     if(i!=0) continue; /* Try next command */
118     /* Setup parameters */
119     if(des->mode&CDESM_OPCHR){
120       if(!param[2])continue;
121       if(!*param[2])continue;
122       param[3]=skip_white(param[2]+1);
123       param[1]=var;
124       parcnt=4;
125     }else{
126       parcnt=1;
127       if(var){param[1]=var;parcnt++;}
128       if(param[parcnt])
129         if(*param[parcnt]) parcnt++;
130     }
131     param[parcnt]=0;
132     if(!des->fnc) return -CMDERR_BADCMD;
133     res=des->fnc(cmd_io,des,param);
134     return res;
135   }
136   return -CMDERR_BADCMD;
137 }
138
139 /**
140  * Checks whether the the command allows the operation specified by
141  * opchar.
142  *
143  * @return opchar if perimssions allow this operations, -CMDERR_WRPERM
144  * or -CMDERR_RDPERM if the operation is not allows, -CMDERR_OPCHAR,
145  * if the opchar is not ':' or '?'.
146  */
147 int cmd_opchar_check(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
148
149   int opchar=*param[2];
150   if(opchar==':'){
151     if(!(des->mode&CDESM_WR)){
152       return -CMDERR_WRPERM;
153     }
154   }else if(opchar=='?'){
155     if(!(des->mode&CDESM_RD)){
156       return -CMDERR_RDPERM;
157     }
158   }
159   else return -CMDERR_OPCHAR;
160   return opchar;
161 }
162
163 int cmd_num_suffix(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[], unsigned *pval)
164 {
165   unsigned val=0;
166   unsigned x;
167   char *p;
168   p=param[1];
169   if(!p) return -CMDERR_BADSUF;
170
171   do{
172     x=*p-'0';
173     if((unsigned)x>9)
174       return -CMDERR_BADSUF;
175     val*=10;
176     val+=x;
177     p++;
178   }while(*p && !strchr(" :?=",*p));
179   *pval=val;
180   return 0;  
181 }
182
183
184 int cmd_do_stamp(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
185 {
186   if(*param[2]!=':') return -CMDERR_OPCHAR;
187   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
188   cmd_io_putc(cmd_io,'=');
189   cmd_io_write(cmd_io,param[3],strlen(param[3]));
190   return 0; 
191 }
192
193 /**
194  * Implementation of a command that reads or writes short pointed by des->info[0].
195  */
196 int cmd_do_rw_short(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
197 {
198   short val;
199   short *ptr;
200   int opchar;
201
202   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
203   ptr=(short*)(des->info[0]);
204   if(opchar==':'){
205     val=atoi(param[3]);
206     *ptr=val;
207   }else{
208     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
209   }
210   return 0; 
211 }
212
213 /**
214  * Implementation of a command that reads or writes int pointed by des->info[0].
215  */
216 int cmd_do_rw_int(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
217 {
218   int val;
219   int *ptr;
220   int opchar;
221
222   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
223   ptr=(int*)(des->info[0]);
224   if(opchar==':'){
225     val=atoi(param[3]);
226     *ptr=val;
227   }else{
228     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
229   }
230   return 0; 
231 }
232
233
234 /**
235  * Implementation of a command that reads or writes long pointed by des->info[0].
236  */
237 int cmd_do_rw_long(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
238 {
239   long val;
240   long *ptr;
241   int opchar;
242
243   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
244   ptr=(long*)(des->info[0]);
245   if(opchar==':'){
246     val=atol(param[3]);
247     *ptr=val;
248   }else{
249     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
250   }
251   return 0; 
252 }
253
254 /**
255  * Prints name of the command followed by '=' and the value of val.
256  */
257 int cmd_opchar_replong(cmd_io_t *cmd_io, char *param[], long val,int len,int form)
258 {
259   char str[20];
260   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
261   cmd_io_putc(cmd_io,'=');
262   i2str(str,val,len,form);
263   cmd_io_write(cmd_io,str,strlen(str));
264   return 0;
265 }
266
267 #if 0
268
269 int cmd_do_rw_bitflag(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
270 {
271   unsigned val,mask,*pval;
272   int opchar;
273
274   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
275   pval=(unsigned*)(des->info[0]);
276   mask=(unsigned)(des->info[1]);
277   if(opchar==':'){
278     val=*param[3];
279     if(val=='0')
280       atomic_clear_mask(mask,pval);
281     else if(val=='1')
282       atomic_set_mask(mask,pval);
283     else return -CMDERR_BADPAR;
284   }else{
285     cmd_io_write(cmd_io,param[0],param[2]-param[0]);
286     cmd_io_putc(cmd_io,'=');
287     cmd_io_putc(cmd_io,*pval&mask?'1':'0');
288   }
289   
290   return 0;
291 }
292
293 #endif
294
295 /**
296  * Implementation of help command
297  */
298 int cmd_do_help(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
299 {
300   char *help;
301   char *filt=param[1];
302   const cmd_des_t **des_arr=*(const cmd_des_t ***)des->info[0];
303   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
304   int arr_stack_sp=0;
305
306   /* FIXME: This should not be there unconditional */
307   if (cmd_io->priv.ed_line.io_stack)
308     cmd_io = cmd_io->priv.ed_line.io_stack;
309   
310   if(filt) {
311     filt=skip_white(filt);
312     if(!*filt) filt=NULL;
313   }
314   cmd_io_puts(cmd_io,"Help for commands\n");
315   while(1){
316     des=*(des_arr++);
317     if(!des){
318       if(!arr_stack_sp) break;
319       des_arr=arr_stack[--arr_stack_sp];
320       continue;
321     }
322     if(des==CMD_DES_CONTINUE_AT_ID){
323       /* list continues at new address */
324       des_arr=(const cmd_des_t **)*des_arr;
325       continue;
326     }
327     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
328       /* list includes commands from sublists */
329       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
330         des_arr++;
331       }else{
332         arr_stack[arr_stack_sp++]=des_arr+1;
333         des_arr=(const cmd_des_t **)*des_arr;
334         continue;
335       }
336     }
337     if(des->name){
338       if(!filt || !strncmp(des->name,filt,strlen(filt))) {
339         help=des->help;
340         if(!help) help="?";
341         cmd_io_puts(cmd_io,des->name);
342         cmd_io_puts(cmd_io," - ");
343         cmd_io_puts(cmd_io,help);
344         cmd_io_puts(cmd_io, "\r\n");
345       }
346     }
347   }
348   return 0;
349 }
350
351 /* Local Variables: */
352 /* c-basic-offset: 2 */
353 /* End */