Skip to content
Snippets Groups Projects
main.c 29.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    			while (col > plen) {
    				puts (erase_seq);
    				--col;
    			}
    
    			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 < CONFIG_SYS_CBSIZE-2) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				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');
    			}
    		}
    	}
    
    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);
    }
    
    /****************************************************************************/
    
    int parse_line (char *line, char *argv[])
    {
    	int nargs = 0;
    
    #ifdef DEBUG_PARSER
    	printf ("parse_line: \"%s\"\n", line);
    #endif
    
    	while (nargs < CONFIG_SYS_MAXARGS) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		/* skip any white space */
    
    		while (isblank(*line))
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			++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 && !isblank(*line))
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			++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", CONFIG_SYS_MAXARGS);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef DEBUG_PARSER
    	printf ("parse_line: nargs=%d\n", nargs);
    #endif
    	return (nargs);
    }
    
    /****************************************************************************/
    
    
    #ifndef CONFIG_SYS_HUSH_PARSER
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    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);
    
    	int outputcnt = CONFIG_SYS_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[CONFIG_SYS_CBSIZE], *envval;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				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 CONFIG_SYS_CBSIZE-1 it is
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *           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).
     */
    
    static int builtin_run_command(const char *cmd, int flag)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
    	char cmdbuf[CONFIG_SYS_CBSIZE];	/* working copy of cmd		*/
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	char *token;			/* start of token in cmdbuf	*/
    	char *sep;			/* end of token (separator) in cmdbuf */
    
    	char finaltoken[CONFIG_SYS_CBSIZE];
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	char *str = cmdbuf;
    
    	char *argv[CONFIG_SYS_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) >= CONFIG_SYS_CBSIZE) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		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
    
    
    		if (cmd_process(flag, argc, argv, &repeatable))
    			rc = -1;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		/* 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
    
    
    /*
     * Run a command using the selected parser.
     *
     * @param cmd	Command to run
     * @param flag	Execution flags (CMD_FLAG_...)
     * @return 0 on success, or != 0 on error.
     */
    int run_command(const char *cmd, int flag)
    {
    #ifndef CONFIG_SYS_HUSH_PARSER
    	/*
    	 * builtin_run_command can return 0 or 1 for success, so clean up
    	 * its result.
    	 */
    	if (builtin_run_command(cmd, flag) == -1)
    		return 1;
    
    	return 0;
    #else
    	return parse_string_outer(cmd,
    			FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
    #endif
    }
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    /****************************************************************************/
    
    
    int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    	int i;
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	for (i=1; i<argc; ++i) {
    
    		char *arg;
    
    		if ((arg = getenv (argv[i])) == NULL) {
    			printf ("## Error: \"%s\" not defined\n", argv[i]);
    			return 1;
    		}
    
    		if (run_command(arg, flag) != 0)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }