快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
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的源码。