]> rtime.felk.cvut.cz Git - sysless.git/blob - libs4c/cmdproc/cmd_proc.c
Included unified version of the command processor - cmdproc.
[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 <inttypes.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  *
39  * @return Zero if no command was given in line, -CMDERR_BADCMD if
40  * command is not known or has no function assigned to it. If a
41  * command is executed, then the return value of the command function
42  * is returned.
43  */
44 int proc_cmd_line(cmd_io_t *cmd_io, cmd_des_t const **des_arr, char *line)
45 {
46   char *p=line, *r, *var;
47   const cmd_des_t *des;
48   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
49   int arr_stack_sp=0;
50   char *param[10];
51   short cmd_len;
52   int res, i, parcnt; 
53   param[0]=p=skip_white(p);
54   if(!*p) return 0;
55   /* Determine the name of the command */
56   if(!isalnum((uint8_t)*p)){
57     cmd_len=1;
58     p++;
59   }else{
60     while(isalnum((uint8_t)*p)) p++;
61     cmd_len=p-param[0];
62   }
63   param[1]=param[2]=skip_white(p);
64   
65   /* Find the command in des_arr */
66   while(1){
67     des=*(des_arr++);
68     if(!des){
69       if(!arr_stack_sp) break;
70       des_arr=arr_stack[--arr_stack_sp];
71       continue;
72     }
73     if(des==CMD_DES_CONTINUE_AT_ID){
74       /* list continues at new address */
75       des_arr=(const cmd_des_t **)*des_arr;continue;
76     }
77     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
78       /* list includes commands from sublists */
79       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
80         des_arr++;
81       }else{
82         arr_stack[arr_stack_sp++]=des_arr+1;
83         des_arr=(const cmd_des_t **)*des_arr;
84         continue;
85       }
86     }
87     p=param[0];
88     if(!(r=des->name))continue;
89     i=cmd_len;
90     var=NULL;
91     while(*r){
92       while((*p==*r)&&i){i--;r++;p++;};
93       if((i==0)&&!*r) break;    /* We've found the command */
94       if((*r=='?')&&i){
95         if(!var) var=p;
96         p++; r++; i--;
97         continue;
98       }
99       if((*r=='#')&&i&&isdigit((uint8_t)*p)){
100         if(!var) var=p;
101         p++; r++; i--;
102         continue;
103       }
104       if(*r=='*'){
105         if(!var) var=p;
106         i=0;
107         break;
108       }
109       i=1;
110       break;      
111     }
112     if(i!=0) continue; /* Try next command */
113     if(des->mode&CDESM_OPCHR){
114       if(!param[2])continue;
115       if(!*param[2])continue;
116       param[3]=skip_white(param[2]+1);
117       param[1]=var;
118       parcnt=4;
119     }else{
120       parcnt=1;
121       if(var){param[1]=var;parcnt++;}
122       if(param[parcnt])
123         if(*param[parcnt]) parcnt++;
124     }
125     param[parcnt]=0;
126     if(!des->fnc) return -CMDERR_BADCMD;
127     res=des->fnc(cmd_io,des,param);
128     return res;
129   }
130   return -CMDERR_BADCMD;
131 }
132
133 /**
134  * Checks whether the the command allows the operation specified by
135  * opchar.
136  *
137  * @return opchar if perimssions allow this operations, -CMDERR_WRPERM
138  * or -CMDERR_RDPERM if the operation is not allows, -CMDERR_OPCHAR,
139  * if the opchar is not ':' or '?'.
140  */
141 int cmd_opchar_check(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
142
143   int opchar=*param[2];
144   if(opchar==':'){
145     if(!(des->mode&CDESM_WR)){
146       return -CMDERR_WRPERM;
147     }
148   }else if(opchar=='?'){
149     if(!(des->mode&CDESM_RD)){
150       return -CMDERR_RDPERM;
151     }
152   }
153   else return -CMDERR_OPCHAR;
154   return opchar;
155 }
156
157 int cmd_num_suffix(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[], unsigned *pval)
158 {
159   unsigned val=0;
160   unsigned x;
161   char *p;
162   p=param[1];
163   if(!p) return -CMDERR_BADSUF;
164
165   do{
166     x=*p-'0';
167     if((unsigned)x>9)
168       return -CMDERR_BADSUF;
169     val*=10;
170     val+=x;
171     p++;
172   }while(*p && !strchr(" :?=",*p));
173   *pval=val;
174   return 0;  
175 }
176
177
178 int cmd_do_stamp(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
179 {
180   if(*param[2]!=':') return -CMDERR_OPCHAR;
181   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
182   cmd_io_putc(cmd_io,'=');
183   cmd_io_write(cmd_io,param[3],strlen(param[3]));
184   return 0; 
185 }
186
187 /**
188  * Implementation of a command that reads or writes short pointed by des->info[0].
189  */
190 int cmd_do_rw_short(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
191 {
192   short val;
193   short *ptr;
194   int opchar;
195
196   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
197   ptr=(short*)(des->info[0]);
198   if(opchar==':'){
199     val=atoi(param[3]);
200     *ptr=val;
201   }else{
202     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
203   }
204   return 0; 
205 }
206
207 /**
208  * Implementation of a command that reads or writes int pointed by des->info[0].
209  */
210 int cmd_do_rw_int(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
211 {
212   int val;
213   int *ptr;
214   int opchar;
215
216   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
217   ptr=(int*)(des->info[0]);
218   if(opchar==':'){
219     val=atoi(param[3]);
220     *ptr=val;
221   }else{
222     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
223   }
224   return 0; 
225 }
226
227
228 /**
229  * Implementation of a command that reads or writes long pointed by des->info[0].
230  */
231 int cmd_do_rw_long(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
232 {
233   long val;
234   long *ptr;
235   int opchar;
236
237   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
238   ptr=(long*)(des->info[0]);
239   if(opchar==':'){
240     val=atol(param[3]);
241     *ptr=val;
242   }else{
243     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
244   }
245   return 0; 
246 }
247
248 /**
249  * Prints name of the command followed by '=' and the value of val.
250  */
251 int cmd_opchar_replong(cmd_io_t *cmd_io, char *param[], long val,int len,int form)
252 {
253   char str[20];
254   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
255   cmd_io_putc(cmd_io,'=');
256   i2str(str,val,len,form);
257   cmd_io_write(cmd_io,str,strlen(str));
258   return 0;
259 }
260
261 #if 0
262
263 int cmd_do_rw_bitflag(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
264 {
265   unsigned val,mask,*pval;
266   int opchar;
267
268   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
269   pval=(unsigned*)(des->info[0]);
270   mask=(unsigned)(des->info[1]);
271   if(opchar==':'){
272     val=*param[3];
273     if(val=='0')
274       atomic_clear_mask(mask,pval);
275     else if(val=='1')
276       atomic_set_mask(mask,pval);
277     else return -CMDERR_BADPAR;
278   }else{
279     cmd_io_write(cmd_io,param[0],param[2]-param[0]);
280     cmd_io_putc(cmd_io,'=');
281     cmd_io_putc(cmd_io,*pval&mask?'1':'0');
282   }
283   
284   return 0;
285 }
286
287 #endif
288
289 /**
290  * Implementation of help command
291  */
292 int cmd_do_help(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
293 {
294   char *help;
295   char *filt=param[1];
296   const cmd_des_t **des_arr=*(const cmd_des_t ***)des->info[0];
297   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
298   int arr_stack_sp=0;
299
300   /* FIXME: This should not be there unconditional */
301   if (cmd_io->priv.ed_line.io_stack)
302     cmd_io = cmd_io->priv.ed_line.io_stack;
303   
304   if(filt) {
305     filt=skip_white(filt);
306     if(!*filt) filt=NULL;
307   }
308   cmd_io_puts(cmd_io,"Help for commands\n");
309   while(1){
310     des=*(des_arr++);
311     if(!des){
312       if(!arr_stack_sp) break;
313       des_arr=arr_stack[--arr_stack_sp];
314       continue;
315     }
316     if(des==CMD_DES_CONTINUE_AT_ID){
317       /* list continues at new address */
318       des_arr=(const cmd_des_t **)*des_arr;
319       continue;
320     }
321     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
322       /* list includes commands from sublists */
323       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
324         des_arr++;
325       }else{
326         arr_stack[arr_stack_sp++]=des_arr+1;
327         des_arr=(const cmd_des_t **)*des_arr;
328         continue;
329       }
330     }
331     if(des->name){
332       if(!filt || !strncmp(des->name,filt,strlen(filt))) {
333         help=des->help;
334         if(!help) help="?";
335         cmd_io_puts(cmd_io,des->name);
336         cmd_io_puts(cmd_io," - ");
337         cmd_io_puts(cmd_io,help);
338         cmd_io_puts(cmd_io, "\r\n");
339       }
340     }
341   }
342   return 0;
343 }
344
345 /* Local Variables: */
346 /* c-basic-offset: 2 */
347 /* End */