Skip to content
Snippets Groups Projects
main.c 29.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			p = p_buf;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			n = 0;
    			continue;
    
    
    		case 0x17:				/* ^W - erase word	*/
    
    			p=delete_char(p_buf, p, &col, &n, plen);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			while ((n > 0) && (*p != ' ')) {
    
    				p=delete_char(p_buf, p, &col, &n, plen);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			}
    			continue;
    
    		case 0x08:				/* ^H  - backspace	*/
    		case 0x7F:				/* DEL - backspace	*/
    
    			p=delete_char(p_buf, p, &col, &n, plen);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			continue;
    
    		default:
    			/*
    			 * Must be a normal character then
    			 */
    			if (n < CFG_CBSIZE-2) {
    				if (c == '\t') {	/* expand TABs		*/
    
    #ifdef CONFIG_AUTO_COMPLETE
    					/* if auto completion triggered just continue */
    					*p = '\0';
    					if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
    
    						p = p_buf + n;	/* reset */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    					puts (tab_seq+(col&07));
    					col += 8 - (col&07);
    				} else {
    					++col;		/* echo input		*/
    					putc (c);
    				}
    				*p++ = c;
    				++n;
    			} else {			/* Buffer full		*/
    				putc ('\a');
    			}
    		}
    	}
    
    #endif /* CONFIG_CMDLINE_EDITING */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }
    
    /****************************************************************************/
    
    
    #ifndef CONFIG_CMDLINE_EDITING
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
    {
    	char *s;
    
    	if (*np == 0) {
    		return (p);
    	}
    
    	if (*(--p) == '\t') {			/* will retype the whole line	*/
    		while (*colp > plen) {
    			puts (erase_seq);
    			(*colp)--;
    		}
    		for (s=buffer; s<p; ++s) {
    			if (*s == '\t') {
    				puts (tab_seq+((*colp) & 07));
    				*colp += 8 - ((*colp) & 07);
    			} else {
    				++(*colp);
    				putc (*s);
    			}
    		}
    	} else {
    		puts (erase_seq);
    		(*colp)--;
    	}
    	(*np)--;
    	return (p);
    }
    
    #endif /* CONFIG_CMDLINE_EDITING */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    /****************************************************************************/
    
    int parse_line (char *line, char *argv[])
    {
    	int nargs = 0;
    
    #ifdef DEBUG_PARSER
    	printf ("parse_line: \"%s\"\n", line);
    #endif
    	while (nargs < CFG_MAXARGS) {
    
    		/* skip any white space */
    		while ((*line == ' ') || (*line == '\t')) {
    			++line;
    		}
    
    		if (*line == '\0') {	/* end of line, no more args	*/
    			argv[nargs] = NULL;
    #ifdef DEBUG_PARSER
    		printf ("parse_line: nargs=%d\n", nargs);
    #endif
    			return (nargs);
    		}
    
    		argv[nargs++] = line;	/* begin of argument string	*/
    
    		/* find end of string */
    		while (*line && (*line != ' ') && (*line != '\t')) {
    			++line;
    		}
    
    		if (*line == '\0') {	/* end of line, no more args	*/
    			argv[nargs] = NULL;
    #ifdef DEBUG_PARSER
    		printf ("parse_line: nargs=%d\n", nargs);
    #endif
    			return (nargs);
    		}
    
    		*line++ = '\0';		/* terminate current arg	 */
    	}
    
    	printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
    
    #ifdef DEBUG_PARSER
    	printf ("parse_line: nargs=%d\n", nargs);
    #endif
    	return (nargs);
    }
    
    /****************************************************************************/
    
    static void process_macros (const char *input, char *output)
    {
    	char c, prev;
    	const char *varname_start = NULL;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	int inputcnt = strlen (input);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	int outputcnt = CFG_CBSIZE;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	int state = 0;		/* 0 = waiting for '$'  */
    
    	/* 1 = waiting for '(' or '{' */
    	/* 2 = waiting for ')' or '}' */
    	/* 3 = waiting for '''  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #ifdef DEBUG_PARSER
    	char *output_start = output;
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
    		input);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	prev = '\0';		/* previous character   */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	while (inputcnt && outputcnt) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		c = *input++;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		inputcnt--;
    
    		if (state != 3) {
    			/* remove one level of escape characters */
    			if ((c == '\\') && (prev != '\\')) {
    				if (inputcnt-- == 0)
    					break;
    				prev = c;
    				c = *input++;
    			}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		switch (state) {
    		case 0:	/* Waiting for (unescaped) $    */
    			if ((c == '\'') && (prev != '\\')) {
    				state = 3;
    				break;
    			}
    			if ((c == '$') && (prev != '\\')) {
    				state++;
    			} else {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				*(output++) = c;
    				outputcnt--;
    			}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			break;
    		case 1:	/* Waiting for (        */
    			if (c == '(' || c == '{') {
    				state++;
    				varname_start = input;
    			} else {
    				state = 0;
    				*(output++) = '$';
    				outputcnt--;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				if (outputcnt) {
    					*(output++) = c;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    					outputcnt--;
    				}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			}
    			break;
    		case 2:	/* Waiting for )        */
    			if (c == ')' || c == '}') {
    				int i;
    				char envname[CFG_CBSIZE], *envval;
    				int envcnt = input - varname_start - 1;	/* Varname # of chars */
    
    				/* Get the varname */
    				for (i = 0; i < envcnt; i++) {
    					envname[i] = varname_start[i];
    				}
    				envname[i] = 0;
    
    				/* Get its value */
    				envval = getenv (envname);
    
    				/* Copy into the line if it exists */
    				if (envval != NULL)
    					while ((*envval) && outputcnt) {
    						*(output++) = *(envval++);
    						outputcnt--;
    					}
    				/* Look for another '$' */
    				state = 0;
    			}
    			break;
    		case 3:	/* Waiting for '        */
    			if ((c == '\'') && (prev != '\\')) {
    				state = 0;
    			} else {
    				*(output++) = c;
    				outputcnt--;
    			}
    			break;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		prev = c;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    	if (outputcnt)
    		*output = 0;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef DEBUG_PARSER
    	printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		strlen (output_start), output_start);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif
    }
    
    /****************************************************************************
     * returns:
     *	1  - command executed, repeatable
     *	0  - command executed but not repeatable, interrupted commands are
     *	     always considered not repeatable
     *	-1 - not executed (unrecognized, bootd recursion or too many args)
     *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
     *           considered unrecognized)
     *
     * WARNING:
     *
     * We must create a temporary copy of the command since the command we get
     * may be the result from getenv(), which returns a pointer directly to
     * the environment data, which may change magicly when the command we run
     * creates or modifies environment variables (like "bootp" does).
     */
    
    int run_command (const char *cmd, int flag)
    {
    	cmd_tbl_t *cmdtp;
    	char cmdbuf[CFG_CBSIZE];	/* working copy of cmd		*/
    	char *token;			/* start of token in cmdbuf	*/
    	char *sep;			/* end of token (separator) in cmdbuf */
    	char finaltoken[CFG_CBSIZE];
    	char *str = cmdbuf;
    	char *argv[CFG_MAXARGS + 1];	/* NULL terminated	*/
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	int repeatable = 1;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef DEBUG_PARSER
    	printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
    	puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */
    	puts ("\"\n");
    #endif
    
    	clear_ctrlc();		/* forget any previous Control C */
    
    	if (!cmd || !*cmd) {
    		return -1;	/* empty command */
    	}
    
    	if (strlen(cmd) >= CFG_CBSIZE) {
    		puts ("## Command too long!\n");
    		return -1;
    	}
    
    	strcpy (cmdbuf, cmd);
    
    	/* Process separators and check for invalid
    	 * repeatable commands
    	 */
    
    #ifdef DEBUG_PARSER
    	printf ("[PROCESS_SEPARATORS] %s\n", cmd);
    #endif
    	while (*str) {
    
    		/*
    		 * Find separator, or string end
    		 * Allow simple escape of ';' by writing "\;"
    		 */
    
    		for (inquotes = 0, sep = str; *sep; sep++) {
    			if ((*sep=='\'') &&
    			    (*(sep-1) != '\\'))
    				inquotes=!inquotes;
    
    			if (!inquotes &&
    			    (*sep == ';') &&	/* separator		*/
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			    ( sep != str) &&	/* past string start	*/
    			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
    				break;
    		}
    
    		/*
    		 * Limit the token to data between separators
    		 */
    		token = str;
    		if (*sep) {
    			str = sep + 1;	/* start of command for next pass */
    			*sep = '\0';
    		}
    		else
    			str = sep;	/* no more commands for next pass */
    #ifdef DEBUG_PARSER
    		printf ("token: \"%s\"\n", token);
    #endif
    
    		/* find macros in this token and replace them */
    		process_macros (token, finaltoken);
    
    		/* Extract arguments */
    
    		if ((argc = parse_line (finaltoken, argv)) == 0) {
    			rc = -1;	/* no command at all */
    			continue;
    		}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		/* Look up command in command table */
    		if ((cmdtp = find_cmd(argv[0])) == NULL) {
    			printf ("Unknown command '%s' - try 'help'\n", argv[0]);
    
    			rc = -1;	/* give up after bad command */
    			continue;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		}
    
    		/* found - check max args */
    		if (argc > cmdtp->maxargs) {
    			printf ("Usage:\n%s\n", cmdtp->usage);
    
    #if defined(CONFIG_CMD_BOOTD)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		/* avoid "bootd" recursion */
    		if (cmdtp->cmd == do_bootd) {
    #ifdef DEBUG_PARSER
    			printf ("[%s]\n", finaltoken);
    #endif
    			if (flag & CMD_FLAG_BOOTD) {
    
    				puts ("'bootd' recursion detected\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				flag |= CMD_FLAG_BOOTD;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		/* OK - call function to do the command */
    		if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		}
    
    		repeatable &= cmdtp->repeatable;
    
    		/* Did the user stop this? */
    		if (had_ctrlc ())
    
    			return -1;	/* if stopped then not repeatable */
    
    	return rc ? rc : repeatable;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }
    
    /****************************************************************************/
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
    {
    	int i;
    
    	if (argc < 2) {
    		printf ("Usage:\n%s\n", cmdtp->usage);
    		return 1;
    	}
    
    	for (i=1; i<argc; ++i) {
    
    		char *arg;
    
    		if ((arg = getenv (argv[i])) == NULL) {
    			printf ("## Error: \"%s\" not defined\n", argv[i]);
    			return 1;
    		}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #ifndef CFG_HUSH_PARSER
    
    		if (run_command (arg, flag) == -1)
    			return 1;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #else
    
    		if (parse_string_outer(arg,
    
    		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }