]> rtime.felk.cvut.cz Git - sysless.git/blob - libs4c/cmdproc/cmd_proc.c
Standardize use of uint8_t type instead of __u8 in source.
[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 by Pavel Pisa pisa@cmp.felk.cvut.cz
11             (C) 2002 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 <types.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <cmd_proc.h>
26 #include "cmd_proc_priv.h"
27
28 /* cmd_line processing */
29
30 char *skip_white(char *p)
31 {
32   while(isspace((uint8_t)*p)) p++;
33   return p;
34 }
35
36 /**
37  *
38  * @return Zero if no command was given in line, -CMDERR_BADCMD if
39  * command is not known or has no function assigned to it. If a
40  * command is executed, then the return value of the command function
41  * is returned.
42  */
43 int proc_cmd_line(cmd_io_t *cmd_io, cmd_des_t const **des_arr, char *line)
44 {
45   char *p=line, *r, *var;
46   const cmd_des_t *des;
47   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
48   int arr_stack_sp=0;
49   char *param[10];
50   short cmd_len;
51   int res, i, parcnt; 
52   param[0]=p=skip_white(p);
53   if(!*p) return 0;
54   /* Determine the name of the command */
55   if(!isalnum((uint8_t)*p)){
56     cmd_len=1;
57     p++;
58   }else{
59     while(isalnum((uint8_t)*p)) p++;
60     cmd_len=p-param[0];
61   }
62   param[1]=param[2]=skip_white(p);
63   
64   /* Find the command in des_arr */
65   while(1){
66     des=*(des_arr++);
67     if(!des){
68       if(!arr_stack_sp) break;
69       des_arr=arr_stack[--arr_stack_sp];
70       continue;
71     }
72     if(des==CMD_DES_CONTINUE_AT_ID){
73       /* list continues at new address */
74       des_arr=(const cmd_des_t **)*des_arr;continue;
75     }
76     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
77       /* list includes commands from sublists */
78       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
79         des_arr++;
80       }else{
81         arr_stack[arr_stack_sp++]=des_arr+1;
82         des_arr=(const cmd_des_t **)*des_arr;
83         continue;
84       }
85     }
86     p=param[0];
87     if(!(r=des->name))continue;
88     i=cmd_len;
89     var=NULL;
90     while(*r){
91       while((*p==*r)&&i){i--;r++;p++;};
92       if((i==0)&&!*r) break;    /* We've found the command */
93       if((*r=='?')&&i){
94         if(!var) var=p;
95         p++; r++; i--;
96         continue;
97       }
98       if((*r=='#')&&i&&isdigit((uint8_t)*p)){
99         if(!var) var=p;
100         p++; r++; i--;
101         continue;
102       }
103       if(*r=='*'){
104         if(!var) var=p;
105         i=0;
106         break;
107       }
108       i=1;
109       break;      
110     }
111     if(i!=0) continue; /* Try next command */
112     if(des->mode&CDESM_OPCHR){
113       if(!param[2])continue;
114       if(!*param[2])continue;
115       param[3]=skip_white(param[2]+1);
116       param[1]=var;
117       parcnt=4;
118     }else{
119       parcnt=1;
120       if(var){param[1]=var;parcnt++;}
121       if(param[parcnt])
122         if(*param[parcnt]) parcnt++;
123     }
124     param[parcnt]=0;
125     if(!des->fnc) return -CMDERR_BADCMD;
126     res=des->fnc(cmd_io,des,param);
127     return res;
128   }
129   return -CMDERR_BADCMD;
130 }
131
132 /**
133  * Checks whether the the command allows the operation specified by
134  * opchar.
135  *
136  * @return opchar if perimssions allow this operations, -CMDERR_WRPERM
137  * or -CMDERR_RDPERM if the operation is not allows, -CMDERR_OPCHAR,
138  * if the opchar is not ':' or '?'.
139  */
140 int cmd_opchar_check(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
141
142   int opchar=*param[2];
143   if(opchar==':'){
144     if(!(des->mode&CDESM_WR)){
145       return -CMDERR_WRPERM;
146     }
147   }else if(opchar=='?'){
148     if(!(des->mode&CDESM_RD)){
149       return -CMDERR_RDPERM;
150     }
151   }
152   else return -CMDERR_OPCHAR;
153   return opchar;
154 }
155
156 int cmd_do_stamp(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
157 {
158   if(*param[2]!=':') return -CMDERR_OPCHAR;
159   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
160   cmd_io_putc(cmd_io,'=');
161   cmd_io_write(cmd_io,param[3],strlen(param[3]));
162   return 0; 
163 }
164
165 /**
166  * Converts integer to string.
167  * @param s Buffer to store the result.
168  * @param val Value to convert.
169  * @param len Minimal width of the converted strign (padded by ' ').
170  * @param form Unused.
171  * @return 0
172  */
173 int i2str(char *s,long val,int len,int form)
174 {
175   int sig;
176   int dig=1;
177   int padd=0;
178   unsigned base=10;
179   unsigned long u;
180   unsigned long mag;
181   unsigned long num;
182   if((sig=val<0))num=-val;
183     else num=val;
184   mag=1;
185   u=base*mag;
186   while(num>=u){
187     dig++;
188     mag=u;
189     if(mag>~(unsigned long)0/base) break;
190     u*=base;
191   }
192   
193   if(len){
194     padd=len-dig;
195     if(sig) padd--;
196   }
197   if(padd<0) padd=0;
198   
199   while(padd){*(s++)=' ';padd--;}
200   if(sig) *(s++)='-';
201   
202   while(dig--){
203     *(s++)='0'+num/mag;
204     num=num%mag;
205     mag/=base;
206   }
207   *s=0;
208   return 0;
209 }
210
211 /**
212  * Implementation of a command that reads or writes short pointed by des->info[0].
213  */
214 int cmd_do_rw_short(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
215 {
216   short val;
217   short *ptr;
218   int opchar;
219
220   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
221   ptr=(short*)(des->info[0]);
222   if(opchar==':'){
223     val=atoi(param[3]);
224     *ptr=val;
225   }else{
226     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
227   }
228   return 0; 
229 }
230
231 /**
232  * Implementation of a command that reads or writes int pointed by des->info[0].
233  */
234 int cmd_do_rw_int(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
235 {
236   int val;
237   int *ptr;
238   int opchar;
239
240   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
241   ptr=(int*)(des->info[0]);
242   if(opchar==':'){
243     val=atoi(param[3]);
244     *ptr=val;
245   }else{
246     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
247   }
248   return 0; 
249 }
250
251
252 /**
253  * Implementation of a command that reads or writes long pointed by des->info[0].
254  */
255 int cmd_do_rw_long(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
256 {
257   long val;
258   long *ptr;
259   int opchar;
260
261   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
262   ptr=(long*)(des->info[0]);
263   if(opchar==':'){
264     val=atol(param[3]);
265     *ptr=val;
266   }else{
267     return cmd_opchar_replong(cmd_io, param, (long)*ptr, 0, 0);
268   }
269   return 0; 
270 }
271
272 /**
273  * Prints name of the command followed by '=' and the value of val.
274  */
275 int cmd_opchar_replong(cmd_io_t *cmd_io, char *param[], long val,int len,int form)
276 {
277   char str[20];
278   cmd_io_write(cmd_io,param[0],param[2]-param[0]);
279   cmd_io_putc(cmd_io,'=');
280   i2str(str,val,len,form);
281   cmd_io_write(cmd_io,str,strlen(str));
282   return 0;
283 }
284
285 #if 0
286
287 int cmd_do_rw_bitflag(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
288 {
289   unsigned val,mask,*pval;
290   int opchar;
291
292   if((opchar=cmd_opchar_check(cmd_io,des,param))<0) return opchar;
293   pval=(unsigned*)(des->info[0]);
294   mask=(unsigned)(des->info[1]);
295   if(opchar==':'){
296     val=*param[3];
297     if(val=='0')
298       atomic_clear_mask(mask,pval);
299     else if(val=='1')
300       atomic_set_mask(mask,pval);
301     else return -CMDERR_BADPAR;
302   }else{
303     cmd_io_write(cmd_io,param[0],param[2]-param[0]);
304     cmd_io_putc(cmd_io,'=');
305     cmd_io_putc(cmd_io,*pval&mask?'1':'0');
306   }
307   
308   return 0;
309 }
310
311 #endif
312
313 /**
314  * Implementation of help command
315  */
316 int cmd_do_help(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
317 {
318   char *help;
319   char *filt=param[1];
320   const cmd_des_t **des_arr=*(const cmd_des_t ***)des->info[0];
321   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
322   int arr_stack_sp=0;
323
324   if (cmd_io->priv.ed_line.io_stack)
325     cmd_io = cmd_io->priv.ed_line.io_stack;
326   
327   if(filt) {
328     filt=skip_white(filt);
329     if(!*filt) filt=NULL;
330   }
331   cmd_io_puts(cmd_io,"Help for commands\n");
332   while(1){
333     des=*(des_arr++);
334     if(!des){
335       if(!arr_stack_sp) break;
336       des_arr=arr_stack[--arr_stack_sp];
337       continue;
338     }
339     if(des==CMD_DES_CONTINUE_AT_ID){
340       /* list continues at new address */
341       des_arr=(const cmd_des_t **)*des_arr;
342       continue;
343     }
344     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
345       /* list includes commands from sublists */
346       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
347         des_arr++;
348       }else{
349         arr_stack[arr_stack_sp++]=des_arr+1;
350         des_arr=(const cmd_des_t **)*des_arr;
351         continue;
352       }
353     }
354     if(des->name){
355       if(!filt || !strncmp(des->name,filt,strlen(filt))) {
356         help=des->help;
357         if(!help) help="?";
358         cmd_io_puts(cmd_io,des->name);
359         cmd_io_puts(cmd_io," - ");
360         cmd_io_puts(cmd_io,help);
361         cmd_io_puts(cmd_io, "\r\n");
362       }
363     }
364   }
365   return 0;
366 }
367
368 /**
369  * Executes command processor. This function is usually called from
370  * application's main loop.
371  */
372 int cmd_processor_run(cmd_io_t *cmd_io, cmd_des_t const **commands)
373 {
374   int val;
375
376   if(cmd_io_line_out(cmd_io))
377     return 1; /* Not all the output has been sent. */
378         
379   if(cmd_io_line_in(cmd_io)<=0)
380     return 0; /* Input line not finished or error. */
381
382   if(commands){
383     val=proc_cmd_line(cmd_io, commands, cmd_io->priv.ed_line.in->buf);
384   }else{
385     val=-CMDERR_BADCMD;
386   }
387
388   if(cmd_io->priv.ed_line.out->inbuf){
389     cmd_io_putc(cmd_io,'\r');
390     cmd_io_putc(cmd_io,'\n');
391   }else if(val<0){
392     char s[20];
393     cmd_io_puts(cmd_io,"ERROR ");
394     i2str(s,-val,0,0);
395     cmd_io_puts(cmd_io,s);
396     cmd_io_putc(cmd_io,'\r');
397     cmd_io_putc(cmd_io,'\n');
398   }
399   return 1; /* Command line processed */
400 }
401
402
403 /* Local Variables: */
404 /* c-basic-offset: 2 */
405 /* End */