当boot从终端读取一行输入后,该怎么解释执行呢,怎么判断一条命令什么时候结束,用户输入的是一条命令还是多条命令?
下面是boot中的部分重要代码片段:
int boot_docommands(char *buf)
{
queue_t cmdqueue;
ui_command_t *cmd;
int status = CMD_ERR_BLANK;
int term;
q_init(&cmdqueue);
while ((cmd = cmd_readcommand(&buf))) {
q_enqueue(&cmdqueue,(queue_t *) cmd);
}
while ((cmd = (ui_command_t *) q_deqnext(&(cmdqueue)))) {
if (env_getenv("CMD_ECHO"))
printf("{CMD} <%s>\n", cmd->ptr);
status = ui_docommand(cmd->ptr);
term = cmd->term;
KFREE(cmd);
if (status == CMD_ERR_BLANK) continue;
/*
* And causes us to stop at the first failure.
*/
if ((term == CMD_TERM_AND) && (status != 0)) break;
/*
* OR causes us to stop at the first success.
*/
if ((term == CMD_TERM_OR) && (status == 0)) break;
/*
* Neither AND nor OR causes us to keep chugging away.
*/
}
return status;
}
ui_command_t *cmd_readcommand(char **pptr)
{
char *ptr = *pptr;
int insquote = FALSE;
int indquote = FALSE;
ui_command_t *cmd;
int term = CMD_TERM_EOL;
int termlen = 0;
while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) ptr++;
*pptr = ptr;
if (!*ptr) return NULL;
while (*ptr) {
if (!insquote && !indquote) {
if ((*ptr == ';') || (*ptr == '\n')) {
term = CMD_TERM_SEMI;
termlen = 1;
break;
}
if ((*ptr == '&') && (*(ptr+1) == '&')) {
term = CMD_TERM_AND;
termlen = 2;
break;
}
if ((*ptr == '|') && (*(ptr+1) == '|')) {
term = CMD_TERM_OR;
termlen = 2;
break;
}
}
if (*ptr == '\'') {
insquote = !insquote;
ptr++;
continue;
}
if (!insquote) {
if (*ptr == '"') {
indquote = !indquote;
ptr++;
continue;
}
}
if (!insquote && (*ptr == '\\')) {
ptr++; /* skip the backslash */
if (*ptr) ptr++; /* skip escaped char */
continue;
}
ptr++;
}
ptr += termlen;
cmd = (ui_command_t *) KMALLOC((sizeof(ui_cmdline_t) + (ptr-*pptr) - termlen + 1),0);
memcpy((char *)(cmd+1),*pptr,ptr-*pptr-termlen);
cmd->ptr= (char *) (cmd+1);
cmd->term = term;
cmd->ptr[ptr-*pptr-termlen] = 0;
*pptr = ptr;
return cmd;
}
insquote表示处在单引号中,indquote表示处在双引号中
1. 首先考虑没有单引号和双引号的情况:
碰到下列字符表示一条命令的结束:
- 碰到';'或'\n'字符
- 碰到两个&&
- 碰到两个||
2. 只有单引号的情况:
单引号不能嵌套,因为单引号左边跟右边是同一个字符,因此嵌套深度不知道是该加一还是减一。单引号中可以包含任何字符,包括双引号,反斜杠\,但任何字符都看做普通字符,直到碰到下一个单引号(跟在转义字符之后的单引号也算),单引号才算结束。
3. 只有双引号的情况:
双引号也不能嵌套,原因跟单引号一样,左右部分相同。双引号中支持转义字符,因此碰到\" 双引号不算结束。
4. 单引号中包含双引号:
这种情况较简单,因为单引号中的都看做普通字符
5. 双引号中包含单引号:
双引号中可以包含单引号,碰到单引号后当做特殊字符来处理,直到碰到下一个单引号结束,其他情况跟只有双引号一样。
另外注意组合命令的处理,&& 只有当前面一条命令执行成功才执行后面的命令, ||表示前面的命令执行失败了才执行后面的命令。