|
使用 Options() 函数实现对 getopt() 函数的简单模拟,该函数接收形如 '-c' (一个破折号加一单字符)的命令行选项。该函数原型为:DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
下面分析该函数的代码和使用方法举例(Codes Come From WSP4)
代码如下:
[C++] 纯文本查看 复制代码
#include <stdarg.h>
#include <memory.h>
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
va_list pFlagList;
LPBOOL pFlag;
int iFlag = 0, iArg;
va_start (pFlagList, OptStr);
while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL && iFlag < (int)_tcslen (OptStr))
{
*pFlag = FALSE;
for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
*pFlag = wmemchr (argv [iArg], OptStr [iFlag], _tcslen (argv [iArg])) != NULL;
iFlag++;
}
va_end (pFlagList);
for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);
return iArg;
}
函数的命令参数显示指定的共有 3 个,分别是 argc, argv 和 OptStr ,其中 argc 和 argv 和 main() 中的一样,而 OptStr 是本程序所支持的命令选项的合集字符串。比如我们这个程序一共支持 3 个命令选项,如 -a, -m,-c ,那么 OptStr 就写成 "amc"。
从函数体中可以看到 "..." 部分只接收 BOOL 指针类型。
在 while() 循环的条件里,(pFlag = va_arg (pFlagList, LPBOOL)) 在每次循环时得到 "..." 中的一个参数,然后指向下一个,一直迭代直到遇到 NULL 为止。
在 for() 循环里,会遍历整个 argv 命令行选项,以查看是否遇到我们所支持的命令选项。从中可以看出,命令选项必须是以 '-' 破折号开始,并后接一个单字符的形式。因为是遍历整个命令行,所以像 -m 这样的命令选项写在命令行中的哪个位置都是没问题的。如果找到了支持的命令选项,则 wmemchr() 函数返回非 NULL(实际返回的是指向 OptStr 中选项字符所在的位置指针),所以 *pFlag 会被置为 1 。注意, pFlag 是指向 "..." 中的每次迭代到的参数的,*pFlag == 1 也就是对应的参数为 1,否则仍然为 0。这样 "..." 中的参数值就和命令选项对应起来。也就是说,当命令行中给出某个命令选项时,Options() 中的 "..." 参数列表里就有某一项对应的被置为 1 (这个参数在调用 Options() 的函数里另有他用)。
另外,iFlag 变量是对每一次循环的计数,也就是说你即使指定 "..." 里的参数的数目大于 OptStr 里给出的字符个数,那么由于 iFlag < (int)_tcslen (OptStr) 条件的限制,while() 循环在遍历完 OptStr() 的选项后也会结束循环。
最后一个 for() 循环用来查找第 1 个非命令选项的命令行参数,如果找到则返回该参数的位置。
下面是一个具体的示例:
[C++] 纯文本查看 复制代码
// setFileTime.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
DWORD Options (int argc, LPTSTR argv [], LPCTSTR OptStr, ...)
{
va_list pFlagList;
LPBOOL pFlag;
int iFlag = 0, iArg;
va_start (pFlagList, OptStr);
while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL && iFlag < (int)_tcslen (OptStr))
{
*pFlag = FALSE;
for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
*pFlag = wmemchr (argv [iArg], OptStr [iFlag], _tcslen (argv [iArg])) != NULL;
iFlag++;
}
va_end (pFlagList);
for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);
return iArg;
}
int _tmain(int argc, LPTSTR argv[])
{
FILETIME newFileTime;
LPFILETIME pAccessTime = NULL, pModifyTime = NULL;
HANDLE hFile;
BOOL setAccessTime, setModTime, NotCreateNew, maFlag;
DWORD createFlag;
int i, fileIndex;
fileIndex = Options (argc, argv, _T("amc"), &setAccessTime, &setModTime, &NotCreateNew, NULL);
maFlag = setAccessTime || setModTime;
createFlag = NotCreateNew ? OPEN_EXISTING : OPEN_ALWAYS;
for (i = fileIndex; i < argc; i++) {
hFile = CreateFile (argv[i], GENERIC_READ | GENERIC_WRITE, 0, NULL, createFlag, FILE_ATTRIBUTE_NORMAL, NULL);
GetSystemTimeAsFileTime(&newFileTime); /* 获取系统时间并转换为文件时间 */
if (setAccessTime || !maFlag)
pAccessTime = &newFileTime;
if (setModTime || !maFlag)
pModifyTime = &newFileTime;
SetFileTime(hFile, (LPFILETIME)NULL, pAccessTime, pModifyTime); /* 设置文件时间 */
}
return 0;
}
上面程序有几个功能:
1. 如果程序的当前目录下没有指定要操作的文件,那么运行程序接文件名参数,则会创建这个文件,这是因为此时 createFlag 为 OPEN_ALWASY 。如:
D:\WindowsAPP\setFileTime\Debug 的目录
2011/09/10 03:24 <DIR> .
2011/09/10 03:24 <DIR> ..
2011/09/10 02:44 315,080 setFileTime.ilk
2011/09/10 02:44 1,657,856 setFileTime.pdb
2011/09/10 02:44 29,184 touch.exe
3 个文件 2,002,120 字节
2 个目录 133,992,869,888 可用字节 运行下面命令后会生成一个名为 123.txt 的文件:D:\WindowsAPP\setFileTime\Debug>touch.exe 123.txt
D:\WindowsAPP\setFileTime\Debug>dir
驱动器 D 中的卷是 WinSoft
卷的序列号是 6EAB-3C0C
D:\WindowsAPP\setFileTime\Debug 的目录
2011/09/10 03:24 <DIR> .
2011/09/10 03:24 <DIR> ..
2011/09/10 03:24 0 123.txt
2011/09/10 02:44 315,080 setFileTime.ilk
2011/09/10 02:44 1,657,856 setFileTime.pdb
2011/09/10 02:44 29,184 touch.exe
4 个文件 2,002,120 字节
2 个目录 133,992,869,888 可用字节 如果 123.txt 文件已经存在,那么再运行一次时,程序会修改该文件的访问时间和修改时间:D:\WindowsAPP\setFileTime\Debug>touch.exe 123.txt
D:\WindowsAPP\setFileTime\Debug>dir 123.txt
驱动器 D 中的卷是 WinSoft
卷的序列号是 6EAB-3C0C
D:\WindowsAPP\setFileTime\Debug 的目录
2011/09/10 03:28 0 123.txt
1 个文件 0 字节
0 个目录 133,992,869,888 可用字节 这是因为,当不带任何命令选项时,setAccessTime, setModTime, NotCreateNew 3 个变量都会为 0;所以 createFlag 的值为 OPEN_ALWAYS,也就是”总是打开该文件“,那么此时 CreateFile() 执行是成功的,如果用 GetLastError() 来查看返回代码,那么会是 183 号的 ERROR_ALREADY_EXISTS,表示文件已存在。此时,在程序底下的两个 if 判断逻辑中,实际上通过 !maFlag 来强制要修改文件的访问时间和修改时间。
如果带 -c 命令选项,那么此时NotCreateNew 值为 1,则 createFlag 为 OPEN_EXISTING,如果打开一个已经存在的文件,那么仍然会修改其访问时间和修改时间。如果 -c 后接的文件名不存在,那么仅会提示找不到文件,如:D:\WindowsAPP\setFileTime\Debug>dir 1234.txt
驱动器 D 中的卷是 WinSoft
卷的序列号是 6EAB-3C0C
D:\WindowsAPP\setFileTime\Debug 的目录
找不到文件 而 -m 和 -a 选项分别明确指定要修改文件的修改时间和访问时间。 |
|