Another shell patch by Jeroen van Iddekinge:
[newos.git] / apps / shell / parse.c
blob37e3402e8efebf586fc102e1aed723d2fe61b518
1 #include <string.h>
2 #include <ctype.h>
3 #include <sys/syscalls.h>
4 #include <stdio.h>
5 #include <stdlib.h>
7 #include "parse.h"
8 #include "commands.h"
9 #include "shell_defs.h"
10 #include "shell_vars.h"
11 #include "script.h"
15 struct token_info{
16 char *token;
17 int code;
20 struct token_info tokens[]={
21 {"echo",SVO_ECHO},
22 {"exec",SVO_EXEC},
23 {"exit",SVO_EXIT},
24 {"if",SVO_IF},
25 {"goto",SVO_GOTO},
26 {"number",SVO_NUMBER_CAST},
27 {"string",SVO_STRING_CAST},
28 {"+",SVO_ADD},
29 {"-",SVO_SUB},
30 {"*",SVO_MUL},
31 {"/",SVO_DIV},
32 {"=",SVO_LOAD},
33 {"==",SVO_EQUAL},
34 {"!=",SVO_NOT_EQUAL},
35 {">",SVO_BIGGER},
36 {">=",SVO_BIGGER_E},
37 {"<",SVO_LESS},
38 {"<=",SVO_LESS_E},
39 {"$",SVO_DOLLAR},
40 {",",SVO_COMMA},
41 {"(",SVO_PARENL},
42 {")",SVO_PARENR},
43 {":",SVO_DOTDOT},
44 {NULL,SVO_NONE}
48 static int token_to_id(const char *token)
50 int cnt = 0;
52 while((tokens[cnt].token != NULL) && (strcmp(tokens[cnt].token,token) != 0)) cnt++;
54 return tokens[cnt].code;
57 char *id_to_token(int id)
59 int cnt = 0;
61 switch(id){
63 case SVO_IDENT :return "ident";
64 case SVO_SQ_STRING :
65 case SVO_DQ_STRING :return "string";
66 case SVO_NUMBER :return "number";
67 case SVO_END :return "end";
70 while((tokens[cnt].token != NULL) && (tokens[cnt].code != id)) cnt++;
72 if(tokens[cnt].token != NULL){
74 return tokens[cnt].token;
76 } else {
78 return "unkown";
83 static bool scan_string(scan_info *info,int max_len)
85 const char **in=&(info->scanner);
86 char ch=**in;
87 char *scan=info->token;
88 int len_cnt = max_len;
89 bool err = false;
91 (*in)++;
93 while((**in != 0) && (**in != ch)){
95 if(len_cnt > 0){
97 *scan = **in;
98 scan++;
99 len_cnt--;
103 (*in)++;
107 if(**in != 0) {
108 (*in)++;
109 } else {
110 info->scan_error = SHE_MISSING_QOUTE;
111 err = true;
114 *scan = 0;
115 return err;
120 int parse_line(const char *buf, char *argv[], int max_args, char *redirect_in, char *redirect_out)
122 const char *scan=buf;
123 const char *type_char;
124 const char *start;
125 char out[SCAN_SIZE+1];
126 char tmp[SCAN_SIZE+1];
127 char *arg_tmp;
128 int arg_cnt = 0;
129 int len = 0;
130 bool replace;
131 bool param;
132 redirect_in[0] = 0;
133 redirect_out[0] = 0;
135 while(true){
137 while((*scan != 0) && (isspace(*scan))) scan++;
139 if(*scan == 0) break;
141 replace = true;
142 type_char = scan;
143 start = scan;
144 param = true;
146 switch(*type_char){
147 case '\'':
148 replace = false;
150 case '"':
151 scan++;
152 start++;
153 while((*scan != 0) && (*scan != *start)) scan++;
154 break;
156 case '>':
157 case '<':
158 start++;
159 while((*start != 0) && (isspace(*start))) start++;
160 scan = start;
162 default:
164 while((*scan != 0) && (!isspace(*scan))) scan++;
168 len = scan - start;
169 if(*scan != 0) scan++;
171 if(replace){
173 memcpy(tmp,start,len);
174 tmp[len]=0;
175 parse_vars_in_string(tmp,out,SCAN_SIZE);
177 } else {
179 memcpy(out,start,len);
180 out[len]=0;
184 switch(*type_char){
186 case '>':
187 strcpy(redirect_out,out);
188 break;
190 case '<':
191 strcpy(redirect_in,out);
192 break;
194 default:
195 if(arg_cnt < max_args){
197 arg_tmp = shell_strdup(out);
198 if(arg_tmp != NULL) argv[arg_cnt++] = arg_tmp;
205 return arg_cnt;
210 static void scan_ident(const char **in,char *out,int max_len)
212 char *scan = out;
213 int len_cnt = max_len;
215 while ((**in != 0) && (IS_IDENT_CHAR(**in))){
216 if(len_cnt > 0){
217 *scan = **in;
218 scan++;
219 len_cnt--;
221 (*in)++;
223 *scan = 0;
226 static void scan_number(const char **in,char *out,int max_len)
228 char *scan = out;
229 int len_cnt = max_len;
231 while ( (**in != 0) && (isdigit(**in)) ){
233 if(len_cnt > 0){
235 *scan = **in;
236 scan++;
237 len_cnt--;
241 (*in)++;
244 *scan = 0;
248 static void scan_comp(const char **in,char *out,int max_len)
250 int num_cnt = max_len;
251 char *out_scan = out;
253 *out_scan = **in;
254 out_scan++;
255 (*in)++;
256 num_cnt--;
258 if(num_cnt > 0) {
260 if(**in == '='){
262 *out_scan = **in;
263 out_scan++;
264 (*in)++;
265 num_cnt--;
269 *out_scan = 0;
272 bool expect(scan_info *info,int check)
274 if(info->sym_code == check){
276 scan(info);
277 return false;
279 } else {
281 return true;
287 bool scan_info_next_line(scan_info *info)
289 if(info->current == NULL) return false;
291 info->current = info->current->next;
293 if(info->current == NULL) return false;
295 info->line_no++;
297 return set_scan_info_line(info);
300 bool scan_info_home(scan_info *info)
302 info->current = info->data.list;
303 info->line_no = 1;
304 return set_scan_info_line(info);
308 bool init_scan_info_by_file(const char *file_name,scan_info *info)
310 int err = SHE_NO_ERROR;
312 err = read_text_file(file_name,&(info->data));
314 if(err != SHE_NO_ERROR) return err;
316 info->scanner = NULL;
317 info->scan_error = SHE_NO_ERROR;
319 if(scan_info_home(info)) err = SHE_SCAN_ERROR;
321 return err;
325 bool set_scan_info_line(scan_info *info)
328 if(info->current == NULL) return true;
330 strcpy(info->input_line,info->current->text);
331 info->scanner = (info->input_line);
332 return scan(info);
336 // fetch next token
337 // **in scan string
338 // *out token
339 // return token type (STY_<> vars)
342 void init_scan_info(const char*in,scan_info *info){
344 strncpy(info->input_line,in,SCAN_SIZE);
346 info->input_line[SCAN_SIZE] = 0;
347 info->scanner=(const char*)info->input_line;
348 info->scan_error = SHE_NO_ERROR;
349 info->current = NULL;
350 info->line_no = 1;
352 scan(info);
356 bool scan(scan_info *info)
358 bool err = false;
359 int sym_code = SVO_NONE;
360 const char **in = &(info->scanner);
361 char tmp[SCAN_SIZE+1];
363 while((**in != 0) && (isspace(**in))) (*in)++;
365 if(isalpha(**in)){
367 scan_ident(in,info->token,SCAN_SIZE);
369 sym_code = token_to_id(info->token);
370 if(sym_code == SVO_NONE) sym_code = SVO_IDENT;
372 } else if(isdigit(**in)){
374 scan_number(in,info->token,SCAN_SIZE);
375 sym_code = SVO_NUMBER;
376 } else{
377 switch(**in){
378 case '#':
379 sym_code = SVO_END;
380 break;
381 case '>':
382 case '<':
383 case '=':
384 case '!':
386 scan_comp(in,info->token,SCAN_SIZE);
387 break;
389 case '"':
391 err = scan_string(info,SCAN_SIZE);
393 if(err != SHE_NO_ERROR){
394 parse_vars_in_string(info->token,tmp,SCAN_SIZE);
395 strncpy(info->token,tmp,SCAN_SIZE);
396 info->token[SCAN_SIZE] = 0;
399 sym_code = SVO_DQ_STRING;
400 break;
401 case '\'':
403 sym_code = SVO_SQ_STRING;
404 err =scan_string(info,SCAN_SIZE);
405 break;
406 case 0:
408 *(info->token) = 0;
409 sym_code = SVO_END;
410 break;
411 default:
412 info->token[0] = **in;
413 info->token[1] = 0;
414 (*in)++;
415 break;
418 if(sym_code == SVO_NONE) sym_code = token_to_id(info->token);
422 info->sym_code = sym_code;
424 return err;
427 void parse_vars_in_string(const char *string,char *out,int max_len)
429 const char *scan= string;
430 char buf[SCAN_SIZE + 1];
431 char *dest;
432 char *out_scan = out;
433 shell_value *value;
434 int out_len = 0;
435 int len_cnt;
436 int out_max_len= max_len;
437 int can_move;
438 char *text;
440 while((*scan != 0) && (*scan != '\'') && (out_max_len > 0)){
441 if(*scan == '$'){
442 scan++;
443 dest = buf;
444 len_cnt = SCAN_SIZE;
446 while ((*scan != 0) && (IS_IDENT_CHAR(*scan)) &&(len_cnt > 0)){
448 *dest = *scan;
449 dest++;
450 scan++;
451 len_cnt--;
455 *dest = 0;
456 value = get_value_by_name(buf);
458 if(value != NULL){
460 text = shell_value_to_char(value);
461 can_move = strlen(text);
463 if(can_move > out_max_len) can_move = out_max_len;
465 memcpy(out_scan,text,can_move);
466 out_max_len -= can_move;
467 out_scan += can_move;
469 free(text);
473 } else{
475 *out_scan = *scan;
476 out_len++;
477 out_scan++;
478 scan ++;
479 out_max_len--;
483 *out_scan= 0;
489 static int launch(int (*cmd)(int, char **), int argc, char **argv, char *r_in, char *r_out)
491 int saved_in;
492 int saved_out;
493 int new_in;
494 int new_out;
495 int retval= 0;
496 int err;
498 if(strcmp(r_in, "")!= 0) {
499 new_in = sys_open(r_in, STREAM_TYPE_ANY, 0);
500 if(new_in < 0) {
501 new_in = sys_create(r_in,STREAM_TYPE_FILE);
503 } else {
504 new_in = sys_dup(0);
506 if(new_in < 0) {
507 err = new_in;
508 goto err_1;
511 if(strcmp(r_out, "")!= 0) {
512 new_out = sys_open(r_out, STREAM_TYPE_ANY, 0);
513 if(new_out < 0){
514 new_out = sys_create(r_out,STREAM_TYPE_FILE);
516 } else {
517 new_out = sys_dup(1);
519 if(new_out < 0) {
520 err = new_out;
521 goto err_2;
525 saved_in = sys_dup(0);
526 saved_out= sys_dup(1);
528 sys_dup2(new_in, 0);
529 sys_dup2(new_out, 1);
530 sys_close(new_in);
531 sys_close(new_out);
533 retval= cmd(argc, argv);
535 sys_dup2(saved_in, 0);
536 sys_dup2(saved_out, 1);
537 sys_close(saved_in);
538 sys_close(saved_out);
540 return 0;
542 err_2:
543 sys_close(new_in);
544 err_1:
545 return err;
549 int shell_parse(const char *buf, int len)
551 int i;
552 bool found_command = false;
553 int argc;
554 char *argv[64];
555 char redirect_in[256];
556 char redirect_out[256];
557 cmd_handler_proc *handler = NULL;
558 int cnt;
559 int err;
561 // search for the command
562 argc = parse_line(buf, argv, 64, redirect_in, redirect_out);
564 if(argc == 0) return 0;
566 handler = &cmd_create_proc;
568 for(i=0; cmds[i].cmd_handler != NULL; i++) {
569 if(strcmp(cmds[i].cmd_text,argv[0]) == 0){
570 handler = cmds[i].cmd_handler;
571 break;
575 err = launch(handler, argc, argv, redirect_in, redirect_out);
577 for(cnt = 0;cnt <argc;cnt++) free(argv[cnt]);
579 return err;