nand_base: We have to ignore the -EUCLEAN error
[barebox-mini2440.git] / common / parser.c
blobc43d7ca176a9e154945653f41d294ed48b9c3a22
1 #include <common.h>
2 #include <command.h>
3 #include <environment.h>
5 static int parse_line (char *line, char *argv[])
7 int nargs = 0;
9 #ifdef DEBUG_PARSER
10 printf ("parse_line: \"%s\"\n", line);
11 #endif
12 while (nargs < CONFIG_MAXARGS) {
14 /* skip any white space */
15 while ((*line == ' ') || (*line == '\t')) {
16 ++line;
19 if (*line == '\0') { /* end of line, no more args */
20 argv[nargs] = NULL;
21 #ifdef DEBUG_PARSER
22 printf ("parse_line: nargs=%d\n", nargs);
23 #endif
24 return (nargs);
27 argv[nargs++] = line; /* begin of argument string */
29 /* find end of string */
30 while (*line && (*line != ' ') && (*line != '\t')) {
31 ++line;
34 if (*line == '\0') { /* end of line, no more args */
35 argv[nargs] = NULL;
36 #ifdef DEBUG_PARSER
37 printf ("parse_line: nargs=%d\n", nargs);
38 #endif
39 return (nargs);
42 *line++ = '\0'; /* terminate current arg */
45 printf ("** Too many args (max. %d) **\n", CONFIG_MAXARGS);
47 #ifdef DEBUG_PARSER
48 printf ("parse_line: nargs=%d\n", nargs);
49 #endif
50 return (nargs);
53 static void process_macros (const char *input, char *output)
55 char c, prev;
56 const char *varname_start = NULL;
57 int inputcnt = strlen (input);
58 int outputcnt = CONFIG_CBSIZE;
59 int state = 0; /* 0 = waiting for '$' */
61 /* 1 = waiting for '(' or '{' */
62 /* 2 = waiting for ')' or '}' */
63 /* 3 = waiting for ''' */
64 #ifdef DEBUG_PARSER
65 char *output_start = output;
67 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
68 input);
69 #endif
71 prev = '\0'; /* previous character */
73 while (inputcnt && outputcnt) {
74 c = *input++;
75 inputcnt--;
77 if (state != 3) {
78 /* remove one level of escape characters */
79 if ((c == '\\') && (prev != '\\')) {
80 if (inputcnt-- == 0)
81 break;
82 prev = c;
83 c = *input++;
87 switch (state) {
88 case 0: /* Waiting for (unescaped) $ */
89 if ((c == '\'') && (prev != '\\')) {
90 state = 3;
91 break;
93 if ((c == '$') && (prev != '\\')) {
94 state++;
95 } else {
96 *(output++) = c;
97 outputcnt--;
99 break;
100 case 1: /* Waiting for ( */
101 if (c == '(' || c == '{') {
102 state++;
103 varname_start = input;
104 } else {
105 state = 0;
106 *(output++) = '$';
107 outputcnt--;
109 if (outputcnt) {
110 *(output++) = c;
111 outputcnt--;
114 break;
115 case 2: /* Waiting for ) */
116 if (c == ')' || c == '}') {
117 int i;
118 char envname[CONFIG_CBSIZE];
119 const char *envval;
120 int envcnt = input - varname_start - 1; /* Varname # of chars */
122 /* Get the varname */
123 for (i = 0; i < envcnt; i++) {
124 envname[i] = varname_start[i];
126 envname[i] = 0;
128 /* Get its value */
129 envval = getenv (envname);
131 /* Copy into the line if it exists */
132 if (envval != NULL)
133 while ((*envval) && outputcnt) {
134 *(output++) = *(envval++);
135 outputcnt--;
137 /* Look for another '$' */
138 state = 0;
140 break;
141 case 3: /* Waiting for ' */
142 if ((c == '\'') && (prev != '\\')) {
143 state = 0;
144 } else {
145 *(output++) = c;
146 outputcnt--;
148 break;
150 prev = c;
153 if (outputcnt)
154 *output = 0;
156 #ifdef DEBUG_PARSER
157 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
158 strlen (output_start), output_start);
159 #endif
162 /****************************************************************************
163 * returns:
164 * 0 - command executed
165 * -1 - not executed (unrecognized, bootd recursion or too many args)
166 * (If cmd is NULL or "" or longer than CONFIG_CBSIZE-1 it is
167 * considered unrecognized)
169 * WARNING:
171 * We must create a temporary copy of the command since the command we get
172 * may be the result from getenv(), which returns a pointer directly to
173 * the environment data, which may change magicly when the command we run
174 * creates or modifies environment variables (like "bootp" does).
177 int run_command (const char *cmd, int flag)
179 cmd_tbl_t *cmdtp;
180 char cmdbuf[CONFIG_CBSIZE]; /* working copy of cmd */
181 char *token; /* start of token in cmdbuf */
182 char *sep; /* end of token (separator) in cmdbuf */
183 char finaltoken[CONFIG_CBSIZE];
184 char *str = cmdbuf;
185 char *argv[CONFIG_MAXARGS + 1]; /* NULL terminated */
186 int argc, inquotes;
187 int rc = 0;
189 #ifdef DEBUG_PARSER
190 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
191 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
192 puts ("\"\n");
193 #endif
195 if (!cmd || !*cmd) {
196 return -1; /* empty command */
199 if (strlen(cmd) >= CONFIG_CBSIZE) {
200 puts ("## Command too long!\n");
201 return -1;
204 strcpy (cmdbuf, cmd);
206 /* Process separators and check for invalid
207 * repeatable commands
210 #ifdef DEBUG_PARSER
211 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
212 #endif
213 while (*str) {
216 * Find separator, or string end
217 * Allow simple escape of ';' by writing "\;"
219 for (inquotes = 0, sep = str; *sep; sep++) {
220 if ((*sep=='\'') &&
221 (*(sep-1) != '\\'))
222 inquotes=!inquotes;
224 if (!inquotes &&
225 (*sep == ';') && /* separator */
226 ( sep != str) && /* past string start */
227 (*(sep-1) != '\\')) /* and NOT escaped */
228 break;
232 * Limit the token to data between separators
234 token = str;
235 if (*sep) {
236 str = sep + 1; /* start of command for next pass */
237 *sep = '\0';
239 else
240 str = sep; /* no more commands for next pass */
241 #ifdef DEBUG_PARSER
242 printf ("token: \"%s\"\n", token);
243 #endif
245 /* find macros in this token and replace them */
246 process_macros (token, finaltoken);
248 /* Extract arguments */
249 if ((argc = parse_line (finaltoken, argv)) == 0) {
250 rc = -1; /* no command at all */
251 continue;
254 /* Look up command in command table */
255 if ((cmdtp = find_cmd(argv[0])) == NULL) {
256 printf ("Unknown command '%s' - try 'help'\n", argv[0]);
257 rc = -1; /* give up after bad command */
258 continue;
261 /* found - check max args */
262 if (argc > cmdtp->maxargs) {
263 printf ("Usage:\n%s\n", cmdtp->usage);
264 rc = -1;
265 continue;
268 /* OK - call function to do the command */
269 if ((cmdtp->cmd) (cmdtp, argc, argv) != 0)
270 rc = -1;
273 return rc;
276 static char console_buffer[CONFIG_CBSIZE]; /* console I/O buffer */
278 int run_shell(void)
280 static char lastcommand[CONFIG_CBSIZE] = { 0, };
281 int len;
282 int rc = 1;
283 int flag;
284 for (;;) {
285 len = readline (CONFIG_PROMPT, console_buffer, CONFIG_CBSIZE);
287 flag = 0; /* assume no special flags for now */
288 if (len > 0)
289 strcpy (lastcommand, console_buffer);
291 if (len == -1)
292 puts ("<INTERRUPT>\n");
293 else
294 rc = run_command (lastcommand, flag);
296 if (rc <= 0) {
297 /* invalid command or not repeatable, forget it */
298 lastcommand[0] = 0;
301 return 0;