ls带来的困惑

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

 

本文适用于

Cygwin checkout-2008-09-28

vs2008

 

欢迎转载,但请保留作者信息

 

继日前在vs2008下编译成功bash-4之后,开始编译linux下的基本应用程序。先瞄准的目标是CoreUtils-7.6,因为这个包里面含有linux的常用命令,包括cp, ls这样再熟悉不过的东西。

先编译的是ls,洋洋洒洒4000多行的程序,有点出乎意料。不过更出乎意料的是当使用命令:

ls *.exe

进行调试的时候,居然发现这个时候传递给main函数的argc值不是期望的2,而是随文件个数变化的值!argv参数里面也不是“*.exe”,而是列出了当前目录下的所有exe文件!

真让人怀疑当初的C语言是不是白学了。

cygwin的代码,发现在它初始化的时候有一个相关的处理:

         PWCHAR wline = GetCommandLineW ();

         size_t size = sys_wcstombs (NULL, 0, wline);

         char *line = (char *) alloca (size);

         sys_wcstombs (line, size, wline);

 

         /* Scan the command line and build argv.  Expand wildcards if not

         called from another cygwin process. */

         build_argv (line, __cyg_argv, __cyg_argc,

              NOTSTATE (myself, PID_CYGPARENT) && allow_glob);

 

         /* Convert argv[0] to posix rules if it's currently blatantly

         win32 style. */

         if ((strchr (__cyg_argv[0], ':')) || (strchr (__cyg_argv[0], '//')))

         {

              char *new_argv0 = (char *) cyg_malloc (NT_MAX_PATH);

              cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, __cyg_argv[0],

                   new_argv0, NT_MAX_PATH);

              __cyg_argv[0] = (char *) cyg_realloc (new_argv0, strlen (new_argv0) + 1);

         }

这里将根据windows传递进来的命令行构建__argc__argv这两个全局变量,然后将可执行文件的文件名转换为posix路径,比如传递进来的可执行文件名f:/etools/debug/bin/ls.exe,经过转换就变成了/bin/ls,这也是在main函数的argv[0]中看到的字符串。

取得argv的关键操作由build_argv函数完成,看看:

/* Build argv, argc from string passed from Windows.  */

 

static void __stdcall

build_argv (char *cmd, char **&argv, int &argc, int winshell)

{

     int argvlen = 0;

     int nesting = 0;       // monitor "nesting" from insert_file

 

     argc = 0;

     argvlen = 0;

     argv = NULL;

 

     /* Scan command line until there is nothing left. */

     while (*cmd)

     {

         /* Ignore spaces */

         if (issep (*cmd))

         {

              cmd++;

              continue;

         }

 

         /* Found the beginning of an argument. */

         char *word = cmd;

         char *sawquote = NULL;

         while (*cmd)

         {

              if (*cmd != '"' && (!winshell || *cmd != '/''))

                   cmd++;        // Skip over this character

              else

                   /* Skip over characters until the closing quote */

              {

                   sawquote = cmd;

                   cmd = quoted (cmd, winshell && argc > 0);

              }

              if (issep (*cmd))  // End of argument if space

                   break;

         }

         if (*cmd)

              *cmd++ = '/0';         // Terminate `word'

 

         /* Possibly look for @file construction assuming that this isn't

         the very first argument and the @ wasn't quoted */

         if (argc && sawquote != word && *word == '@')

         {

              if (++nesting > MAX_AT_FILE_LEVEL)

                   api_fatal ("Too many levels of nesting for %s", word);

              if (insert_file (word, cmd))

                   continue;          // There's new stuff in cmd now

         }

 

         /* See if we need to allocate more space for argv */

         if (argc >= argvlen)

         {

              argvlen = argc + 10;

              argv = (char **) cyg_realloc (argv, (1 + argvlen) * sizeof (argv[0]));

         }

 

         /* Add word to argv file after (optional) wildcard expansion. */

         if (!winshell || !argc || !globify (word, argv, argc, argvlen))

         {

              debug_printf ("argv[%d] = '%s'", argc, word);

              argv[argc++] = word;

         }

     }

 

     argv[argc] = NULL;

 

     debug_printf ("argc %d", argc);

}

注意这一行:

         /* Add word to argv file after (optional) wildcard expansion. */

         if (!winshell || !argc || !globify (word, argv, argc, argvlen))

正是通过globify函数,argv得以对*号这样的通配符进行扩展。

/* Perform a glob on word if it contains wildcard characters.

Also quote every character between quotes to force cyg_glob to

treat the characters literally. */

static int __stdcall

globify (char *word, char **&argv, int &argc, int &argvlen)

{

     if (*word != '~' && strpbrk (word, "?*[/"/'(){}") == NULL)

         return 0;

…………….

}

这个函数较长,有兴趣的可以自己看cygwin的源码。

 

 

 

你可能感兴趣的:(ls带来的困惑)