Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1858073
  • 博文数量: 473
  • 博客积分: 13997
  • 博客等级: 上将
  • 技术积分: 5953
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 11:52
文章分类

全部博文(473)

文章存档

2014年(8)

2013年(38)

2012年(95)

2011年(181)

2010年(151)

分类: LINUX

2012-02-11 12:13:26

common/main.c:

/****************************************************************************

 * 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 */

    int argc, inquotes;

    int repeatable = 1;

    int rc = 0;

 

#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);  /*备份command*/

 

    /* Process separators and check for invalid

     * repeatable commands

     */

 

#ifdef DEBUG_PARSER

    printf ("[PROCESS_SEPARATORS] %s/n", cmd);

#endif

    while (*str) { /*看前面的定义,str指向cmdbuf */

 

        /*

         * Find separator, or string end

         * Allow simple escape of ';' by writing "/;"

         */

        /*下面这个for是对u-boot的特殊语法的解析,这里就不分析了*/

        for (inquotes = 0, sep = str; *sep; sep++) {

            if ((*sep=='/'') &&

                (*(sep-1) != '//'))

                inquotes=!inquotes;

 

            if (!inquotes &&

                (*sep == ';') &&   /* separator       */

                ( 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 */

        argc = parse_line (finaltoken, argv); /*获取参数*/

 

        /* Look up command in command table */

        if ((cmdtp = find_cmd(argv[0])) == NULL) {  /*获取对应的command*/

            printf ("Unknown command '%s' - try 'help'/n", argv[0]);

            rc = -1;    /* give up after bad command */

            continue;

        }

 

        /* found - check max args */

        if (argc > cmdtp->maxargs) {  /*检测command语法是否正确*/

            printf ("Usage:/n%s/n", cmdtp->usage);

            rc = -1;

            continue;

        }

 

#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)

        /* 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");

                rc = -1;

                continue;

            }

            else

                flag |= CMD_FLAG_BOOTD;

        }

#endif  /* CFG_CMD_BOOTD */

 

        /* OK - call function to do the command */

        if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {  /*执行具体的command*/

            rc = -1;

        }

 

        repeatable &= cmdtp->repeatable;

 

        /* Did the user stop this? */

        if (had_ctrlc ())

            return 0;   /* if stopped then not repeatable */

    }

 

    return rc ? rc : repeatable;

}

这个函数主要是对用户输入的命令进行语法分析,从中获取命令,参数等信息,并查找一张系统保存的命令表,找到该命令对应的处理函数。并调用它来处理这个命令。

下面先详细分析这张系统的命令表是如何生成的,接着在以一个命令为例,来结束整篇文章。

 

首先看的是命令表中存的每个命令的属性

 include/command.h:

    struct cmd_tbl_s {

    char        *name;      /* Command Name        */

    int     maxargs;    /* maximum number of arguments */

    int     repeatable; /* autorepeat allowed?     */

                   /* Implementation function */

    int     (*cmd)(struct cmd_tbl_s *, int, int, char *[]);

    char        *usage;     /* Usage message   (short) */

#ifdef  CFG_LONGHELP

    char        *help;      /* Help  message   (long)  */

#endif

#ifdef CONFIG_AUTO_COMPLETE

    /* do auto completion on the arguments */

    int     (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);

#endif

};

这个就不解释了,英文的已经很详细了。

 

接着看如何定义命令:

include/command.h:

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

 

#ifdef  CFG_LONGHELP

 

/*每个命令就用这个宏来定义,并加进系统命令表中*/

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

/*它定义一个command变量,并把它放入".u_boot_cmd"节中*/

#else   /* no long help info */

 

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}

 

#endif  /* CFG_LONGHELP */

最后看定义command的示例:

common/command.c:

U_BOOT_CMD(

    version,    1,      1,  do_version,   

    "version - print monitor version/n",

    NULL

);

这定义了一个名字为versioncommand, 对应的函数为do_version, 也就是说如果用户输入命令:versionu-boot将执行do_version函数。

至于为什么要用这种方式来定义一个命令列表,大家可以看一下这个文件:

doc/README.commands:

**** Behinde the scene ******

 

The structure created is named with a special prefix (__u_boot_cmd_)

and placed by the linker in a special section.

 

This makes it possible for the final link to extract all commands

compiled into any object code and construct a static array so the

command can be found in an array starting at __u_boot_cmd_start.

 

If a new board is defined do not forget to define the command section

by writing in u-boot.lds ($(TOPDIR)/board/boardname/u-boot.lds) these

3 lines:

 

    __u_boot_cmd_start = .;

    .u_boot_cmd : { *(.u_boot_cmd) }

    __u_boot_cmd_end = .;

 

呵呵, __u_boot_cmd_start就是命令表的首地址,__u_boot_cmd_end就是结束地址, 而程序中就是靠这两个变量来从命令表中查询命令的。

懂了这些东西之后,我们也就知道了怎么去添加我们自定义的命令了。同时我们也可以去查看u-boot下提供了哪些命令了。
阅读(5935) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~