程序代码:
<_open.c>
/***
*FILE *_openfile(filename, mode, shflag, stream) - 通过模式字符串和共享标志打开一个文件.
*
*目的:
* 解析字符串, 查看是否恰当的有 {rwa} 中的一个, 至多一个 '+',
* 至多一个 {tb}, 至多一个 {cn}, 至多一个 {SR}, 至多一个 'T', 至多一个 'D'.
* 通过shflag的结果.
* 如果权限允许的话以恰当的方式打开一个文件. 直到第一次io操作不分配缓冲区。
* 只建议在库内使用。
*
*进入:
* char *filename - 要打开的文件
* char *mode - 打开模式
* int shflag - 文件的共享标志
* FILE *stream - 使用文件的流
*
*退出:
* 配置流的参数, 引用系统文件的管理 通过流的调用。
* 返回 流 或 NULL
*
*Exceptions:
*
*******************************************************************************/
FILE * __cdecl __topenfile (
const _TSCHAR *filename,
REG3 const _TSCHAR *mode,
int shflag,
FILE *str
)
{
int modeflag;
int streamflag = _commode; //设置默认的流状态模式为未指派 int _commode = 0;
int commodeset = 0;
int scanset = 0;
int whileflag;
int filedes;
FILE *stream;
BOOL encodingFlag = FALSE;
_ASSERTE(filename != NULL);
_ASSERTE(mode != NULL);
_ASSERTE(str != NULL); //检验参数
/*解析用户的打开模式配置下面两处的参数。
(1) modeflag - 系统调用标志词
(2) streamflag - 流句柄标志词. */
/* 去掉前端的空格 */
while (*mode == _T(' '))
{
++mode; //说明 fopen 第二个参数前面可以有空格出现。
}
/* 第一个字符必须是 'r', 'w', 或 'a'. */
switch (*mode) { //modeflag 的参数在 <fcntl.h> 中 , streamflag 的参数在 <stdio.h> 中
case _T('r'):
modeflag = _O_RDONLY; //文件只读
streamflag |= _IOREAD; //流可读
break;
case _T('w'):
modeflag = _O_WRONLY | _O_CREAT | _O_TRUNC; //文件只写 | 文件可创建 | 文件清空 (根据后面的字符不同,含义可变)
streamflag |= _IOWRT; //流可写
break;
case _T('a'):
modeflag = _O_WRONLY | _O_CREAT | _O_APPEND; //文件只写 | 文件可创建 | 文件末尾添加
streamflag |= _IOWRT; //流可写
break;
default:
_VALIDATE_RETURN(("Invalid file open mode",0), EINVAL, NULL);
}
/* 下面接可能有三组选项的模式字符:
(1) A single '+' character,
(2) One of 't' and 'b' and
(3) One of 'c' and 'n'.
*/
//标准C中只规定了 b 和 + 所以只考虑这两种情况。
whileflag=1; //这个变量保证每个字符只能出现一次。
while(*++mode && whileflag)
switch(*mode) {
case _T(' '): //跳过空格
/* skip spaces */
break;
case _T('+'):
if (modeflag & _O_RDWR) //如果包含可读可写的标志位,说明 + 已经出现过了,停止解析。
whileflag=0;
else {
modeflag |= _O_RDWR; //设置可读可写的标志位,清除读 或 写的标志位。
modeflag &= ~(_O_RDONLY | _O_WRONLY);
streamflag |= _IORW;
streamflag &= ~(_IOREAD | _IOWRT);
}
break;
case _T('b'): //设置二进制文件的标志位。
if (modeflag & (_O_TEXT | _O_BINARY))
whileflag=0;
else
modeflag |= _O_BINARY;
break;
//下面的忽略
case _T('t'):
if (modeflag & (_O_TEXT | _O_BINARY))
whileflag=0;
else
modeflag |= _O_TEXT;
break;
case _T('c'):
if (commodeset)
whileflag=0;
else {
commodeset = 1;
streamflag |= _IOCOMMIT;
}
break;
case _T('n'):
if (commodeset)
whileflag=0;
else {
commodeset = 1;
streamflag &= ~_IOCOMMIT;
}
break;
case _T('S'):
if (scanset)
whileflag=0;
else {
scanset = 1;
modeflag |= _O_SEQUENTIAL;
}
break;
case _T('R'):
if (scanset)
whileflag=0;
else {
scanset = 1;
modeflag |= _O_RANDOM;
}
break;
case _T('T'):
if (modeflag & _O_SHORT_LIVED)
whileflag=0;
else
modeflag |= _O_SHORT_LIVED;
break;
case _T('D'):
if (modeflag & _O_TEMPORARY)
whileflag=0;
else
modeflag |= _O_TEMPORARY;
break;
case _T('N'):
modeflag |= _O_NOINHERIT;
break;
case _T(','):
encodingFlag = TRUE;
whileflag = 0;
break;
default:
_VALIDATE_RETURN(("Invalid file open mode",0), EINVAL, NULL);
}
if (encodingFlag)
{//这部分忽略
static const _TSCHAR ccsField[] = _T("ccs");
static const _TSCHAR utf8encoding[] = _T("UTF-8");
static const _TSCHAR utf16encoding[] = _T("UTF-16LE");
static const _TSCHAR unicodeencoding[] = _T("UNICODE");
/* Skip spaces */
while (*mode == _T(' '))
{
++mode;
}
/*
* The length that we want to compare is numbers of elements in
* csField -1 since this number also contains NULL terminator
*/
if (_tcsncmp(ccsField, mode, (_countof(ccsField))-1) != 0)
_VALIDATE_RETURN(("Invalid file open mode",0), EINVAL, NULL);
mode += _countof(ccsField)-1;
/* Skip spaces */
while (*mode == _T(' '))
{
++mode;
}
/* Look for '=' */
if (*mode != _T('='))
{
_VALIDATE_RETURN(("Invalid file open mode",0), EINVAL, NULL);
}
++mode;
/* Skip spaces */
while (*mode == _T(' '))
{
++mode;
}
if (_tcsnicmp(mode, utf8encoding, _countof(utf8encoding) - 1) == 0){
mode += _countof(utf8encoding)-1;
modeflag |= _O_U8TEXT;
}
else if (_tcsnicmp(mode, utf16encoding, _countof(utf16encoding) - 1) == 0) {
mode += _countof(utf16encoding)-1;
modeflag |= _O_U16TEXT;
}
else if (_tcsnicmp(mode, unicodeencoding, _countof(unicodeencoding) - 1) == 0) {
mode += _countof(unicodeencoding)-1;
modeflag |= _O_WTEXT;
}
else
_VALIDATE_RETURN(("Invalid file open mode",0), EINVAL, NULL);
}
/* Skip trailing spaces */
while (*mode == _T(' ')) //掉过空格
{
++mode;
}
_VALIDATE_RETURN( (*mode == _T('\0')), EINVAL, NULL); //保证 mode 中除了标准要求的没有其他别的字符了。
/* 尝试打开文件. 注意如果没有b 或t, 就使用默认的文件模式. */
if (_tsopen_s(&filedes, filename, modeflag, shflag, _S_IREAD | _S_IWRITE) != 0) //打开文件的具体操作。成功返回0,失败返回-1.会返回文件描述符filedes
return(NULL);
/*配置流的基本信息 */
#ifndef CRTDLL
_cflush++; /* 促使 库 每次终止 程序(步骤) */ //这个变量不清楚是干什么的,猜测和关闭程序时要关闭所有的文件这步操作有关。
#endif /* CRTDLL */
/* Init pointers */
stream = str; //赋值给返回值
stream->_flag = streamflag; //设置流的状态标志参数
stream->_cnt = 0; //没弄清的参数
stream->_tmpfname = stream->_base = stream->_ptr = NULL; //一堆指针置为空
stream->_file = filedes; //文件的文件描述符
return(stream); //返回
}
下面接着 _tsopen_s(...)
求指点 求意见 求笼罩。。。。