]> rtime.felk.cvut.cz Git - sysless.git/blob - libs4c/cmdproc/cmd_proc.c
cmdproc: Handle returned error correctly
[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     if(des->mode&CDESM_SPACE_SEP){
132       while (*param[parcnt-1] && parcnt > (var ? 2 : 1) && parcnt < 9) {
133         p = param[parcnt-1];
134         while (*p && !isspace(*p)) p++;
135         if (*p) {
136           *p = '\0';
137           p = skip_white(p+1);
138           if (*p) {
139             parcnt++;
140             param[parcnt-1] = p;
141             continue;
142           }
143         }
144         break; /* No more parameters */
145       }
146     }
147     param[parcnt]=0;
148     if(!des->fnc) return -CMDERR_BADCMD;
149     res=des->fnc(cmd_io,des,param);
150     return res;
151   }
152   return -CMDERR_BADCMD;
153 }
154
155 /**
156  * Checks whether the the command allows the operation specified by
157  * opchar.
158  *
159  * @return opchar if perimssions allow this operations, -CMDERR_WRPERM
160  * or -CMDERR_RDPERM if the operation is not allows, -CMDERR_OPCHAR,
161  * if the opchar is not ':' or '?'.
162  */
163 int cmd_opchar_check(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
164
165   int opchar=*param[2];
166   if(opchar==':'){
167     if(!(des->mode&CDESM_WR)){
168       return -CMDERR_WRPERM;
169     }
170   }else if(opchar=='?'){
171     if(!(des->mode&CDESM_RD)){
172       return -CMDERR_RDPERM;
173     }
174   }
175   else return -CMDERR_OPCHAR;
176   return opchar;
177 }
178
179 int cmd_num_suffix(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[], unsigned *pval)
180 {
181   unsigned val=0;
182   unsigned x;
183   char *p;
184   p=param[1];
185   if(!p) return -CMDERR_BADSUF;
186
187   do{
188     x=*p-'0';
189     if((unsigned)x>9)
190       return -CMDERR_BADSUF;
191     val*=10;
192     val+=x;
193     p++;
194   }while(*p && !strchr(" :?=",*p));
195   *pval=val;
196   return 0;  
197 }
198
199
200 int cmd_do_stamp(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
201 {
202   if(*param[2]!=':') return -CMDERR_OPCHAR;
203   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
204   cmd_io_putc(cmd_io,'=');
205   cmd_io_write(cmd_io,param[3],strlen(param[3]));
206   return 0; 
207 }
208
209 /**
210  * Implementation of a command that reads or writes short pointed by des->info[0].
211  */
212 int cmd_do_rw_short(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
213 {
214   short val;
215   short *ptr;
216   int opchar;
217
218   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
219   ptr=(short*)(des->info[0]);
220   if(opchar==':'){
221     val=atoi(param[3]);
222     *ptr=val;
223   }else{
224     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
225   }
226   return 0; 
227 }
228
229 /**
230  * Implementation of a command that reads or writes int pointed by des->info[0].
231  */
232 int cmd_do_rw_int(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
233 {
234   int val;
235   int *ptr;
236   int opchar;
237
238   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
239   ptr=(int*)(des->info[0]);
240   if(opchar==':'){
241     val=atoi(param[3]);
242     *ptr=val;
243   }else{
244     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
245   }
246   return 0; 
247 }
248
249
250 /**
251  * Implementation of a command that reads or writes long pointed by des->info[0].
252  */
253 int cmd_do_rw_long(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
254 {
255   long val;
256   long *ptr;
257   int opchar;
258
259   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
260   ptr=(long*)(des->info[0]);
261   if(opchar==':'){
262     val=atol(param[3]);
263     *ptr=val;
264   }else{
265     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
266   }
267   return 0; 
268 }
269
270 /**
271  * Prints name of the command followed by '=' and the value of val.
272  */
273 int cmd_opchar_replong(cmd_io_t *cmd_io, char *param[], long val,int len,int form)
274 {
275   char str[20];
276   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
277   cmd_io_putc(cmd_io,'=');
278   i2str(str,val,len,form);
279   cmd_io_write(cmd_io,str,strlen(str));
280   return 0;
281 }
282
283 #if 0
284
285 int cmd_do_rw_bitflag(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
286 {
287   unsigned val,mask,*pval;
288   int opchar;
289
290   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
291   pval=(unsigned*)(des->info[0]);
292   mask=(unsigned)(des->info[1]);
293   if(opchar==':'){
294     val=*param[3];
295     if(val=='0')
296       atomic_clear_mask(mask,pval);
297     else if(val=='1')
298       atomic_set_mask(mask,pval);
299     else return -CMDERR_BADPAR;
300   }else{
301     cmd_io_write(cmd_io,param[0],param[2]-param[0]);
302     cmd_io_putc(cmd_io,'=');
303     cmd_io_putc(cmd_io,*pval&mask?'1':'0');
304   }
305   
306   return 0;
307 }
308
309 #endif
310
311 /**
312  * Implementation of help command
313  */
314 int cmd_do_help(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
315 {
316   char *help;
317   char *filt=param[1];
318   const cmd_des_t **des_arr=*(const cmd_des_t ***)des->info[0];
319   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
320   int arr_stack_sp=0;
321
322   /* FIXME: This should not be there unconditional */
323   if (cmd_io->priv.ed_line.io_stack)
324     cmd_io = cmd_io->priv.ed_line.io_stack;
325   
326   if(filt) {
327     filt=skip_white(filt);
328     if(!*filt) filt=NULL;
329   }
330   cmd_io_puts(cmd_io,"Help for commands\n");
331   while(1){
332     des=*(des_arr++);
333     if(!des){
334       if(!arr_stack_sp) break;
335       des_arr=arr_stack[--arr_stack_sp];
336       continue;
337     }
338     if(des==CMD_DES_CONTINUE_AT_ID){
339       /* list continues at new address */
340       des_arr=(const cmd_des_t **)*des_arr;
341       continue;
342     }
343     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
344       /* list includes commands from sublists */
345       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
346         des_arr++;
347       }else{
348         arr_stack[arr_stack_sp++]=des_arr+1;
349         des_arr=(const cmd_des_t **)*des_arr;
350         continue;
351       }
352     }
353     if(des->name){
354       if(!filt || !strncmp(des->name,filt,strlen(filt))) {
355         help=des->help;
356         if(!help) help="?";
357         cmd_io_puts(cmd_io,des->name);
358         cmd_io_puts(cmd_io," - ");
359         cmd_io_puts(cmd_io,help);
360         cmd_io_puts(cmd_io, "\r\n");
361       }
362     }
363   }
364   return 0;
365 }
366
367 /* Local Variables: */
368 /* c-basic-offset: 2 */
369 /* End */