注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

anqiang专栏

不要问细节是怎么搞的,源码说明一切

 
 
 

日志

 
 

PType源码解读之---输入输出流架构  

2010-07-22 14:04:55|  分类: PType |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

作为一个包,它至少应该提供上层的输入输出流功能。PType也实现了一套输入输出流的接口,它们的类继承关系如下:

Iobase->instm->(inmemory, infile, infliter)

Iobase->outstm->(outmemory, outfile, outfliter)

其中,iobase类定义了基本的输入输出操作,instm类定义了一个抽象的输入流操作集合,outstm类定义了一个抽象的输出流操作集合。其它的如inmemoryinfileoutmemory, outfile之类的它们是对输入输出流类的特殊化。

这里给出piobase.cxx文件的部分注释:

/*

 *

 *  C++ Portable Types Library (PTypes)

 *  Version 2.1.1  Released 27-Jun-2007

 *

 *  Copyright (C) 2001-2007 Hovik Melikyan

 *

 *  http://www.melikyan.com/ptypes/

 *

 */

 

#include <errno.h>

#include <limits.h>

 

#ifdef WIN32

#  include <windows.h>

#else

#  include <signal.h>

#  include <unistd.h>

#endif

 

#include "pstreams.h"

 

 

PTYPES_BEGIN

 

 

/*

 

Known UNIX error codes:

 

EPERM         1          Not owner

ENOENT        2          No such file or directory

ESRCH         3          No such process

EINTR         4          Interrupted system call

EIO           5          I/O error

ENXIO         6          No such device or address

E2BIG         7          Argument list too long

ENOEXEC       8          Exec format error

EBADF         9          Bad file number

ECHILD       10          No spawned processes

EAGAIN       11          No more processes; not enough memory; maximum nesting level reached

ENOMEM       12          Not enough memory

EACCES       13          Permission denied

EFAULT       14          Bad address

ENOTBLK      15          Block device required

EBUSY        16          Mount device busy

EEXIST       17          File exists

EXDEV        18          Cross-device link

ENODEV       19          No such device

ENOTDIR      20          Not a directory

EISDIR       21          Is a directory

EINVAL       22          Invalid argument

ENFILE       23          File table overflow

EMFILE       24          Too many open files

ENOTTY       25          Not a teletype

ETXTBSY      26          Text file busy

EFBIG        27          File too large

ENOSPC       28          No space left on device

ESPIPE       29          Illegal seek

EROFS        30          Read-only file system

EMLINK       31          Too many links

EPIPE        32          Broken pipe

EDOM         33          Math argument

ERANGE       34          Result too large

EUCLEAN      35          File system needs cleaning

EDEADLK      36          Resource deadlock would occur

EDEADLOCK    36          Resource deadlock would occur

 

*/

 

 

#ifndef WIN32

 

static class _io_init

{

public:

    _io_init();

} _io_init_inst;

 

 

_io_init::_io_init()

{

    // We don't like broken pipes. PTypes will throw an exception instead.

    signal(SIGPIPE, SIG_IGN);

}

 

#endif

 

 

//获得当前程序异常

int ptdecl unixerrno()

{

#ifdef WIN32

//将在windows下抛出的异常转换成unix类型的异常

    switch(GetLastError())

    {

    case ERROR_FILE_NOT_FOUND:

    case ERROR_PATH_NOT_FOUND:      return ENOENT;

    case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;

    case ERROR_ACCESS_DENIED:

    case ERROR_SHARING_VIOLATION:   return EACCES;

    case ERROR_INVALID_HANDLE:      return EBADF;

    case ERROR_NOT_ENOUGH_MEMORY:

    case ERROR_OUTOFMEMORY:         return ENOMEM;

    case ERROR_INVALID_DRIVE:       return ENODEV;

    case ERROR_WRITE_PROTECT:       return EROFS;

    case ERROR_FILE_EXISTS:         return EEXIST;

    case ERROR_BROKEN_PIPE:         return EPIPE;

    case ERROR_DISK_FULL:           return ENOSPC;

    case ERROR_SEEK_ON_DEVICE:      return ESPIPE;

    default: return EIO;

    }

#else

    return errno;

#endif

}

 

 

//

// This function gives error messages for most frequently occurring

// IO errors. If the function returns NULL a generic message

// can be given, e.g. "I/O error". See also iobase::get_errormsg()

//

//将异常代码与异常信息串联起来

const char* ptdecl unixerrmsg(int code)

{

    switch(code)

    {

    case EBADF:  return "Invalid file descriptor";

    case ESPIPE: return "Can not seek on this device";

    case ENOENT: return "No such file or directory";

    case EMFILE: return "Too many open files";

    case EACCES: return "Access denied";

    case ENOMEM: return "Not enough memory";

    case ENODEV: return "No such device";

    case EROFS:  return "Read-only file system";

    case EEXIST: return "File already exists";

    case ENOSPC: return "Disk full";

    case EPIPE:  return "Broken pipe";

    case EFBIG:  return "File too large";

    default: return nil;

    }

}

 

//estream的构造函数

estream::estream(iobase* ierrstm, int icode, const char* imsg)

    : exception(imsg), code(icode), errstm(ierrstm) {}

 

 

estream::estream(iobase* ierrstm, int icode, const string& imsg)

    : exception(imsg), code(icode), errstm(ierrstm) {}

 

//estream的析构函数

estream::~estream() {}

 

//默认的buf大小

int defbufsize = 8192;

int stmbalance = 0;

 

//iobase的构造函数

iobase::iobase(int ibufsize)

    : component(), active(false), cancelled(false), eof(true),

      handle(invhandle), abspos(0), bufsize(0), bufdata(nil), bufpos(0), bufend(0),

      stmerrno(0), deferrormsg(), status(IO_CREATED), onstatus(nil)

{

       //如果给定的缓存大小小于0,则为其设定一个默认缓存大小

    if (ibufsize < 0)

        bufsize = defbufsize;

    else

        bufsize = ibufsize;

}

 

//iobase的析构函数

iobase::~iobase()

{

}

 

 

void iobase::bufalloc()

{

    if (bufdata != nil)

        fatal(CRIT_FIRST + 13, "(ptypes internal) invalid buffer allocation");

   

    //申请一块儿内存

    bufdata = (char*)memalloc(bufsize);

}

 

 

void iobase::buffree()

{

    //重置缓存标示

    bufclear();

    //释放缓存

    memfree(bufdata);

    bufdata = 0;

}

 

//现在控件的状态

void iobase::chstat(int newstat)

{

    status = newstat;

    if (onstatus != nil)

        (*onstatus)(this, newstat);

}

 

//

void iobase::errstminactive()

{

    error(EIO, "Stream inactive");

}

 

 

void iobase::errbufrequired()

{

    fatal(CRIT_FIRST + 11, "Internal: buffer required");

}

 

 

int iobase::convertoffset(large offs)

{

    if (offs < 0 || offs > INT_MAX)

        error(EFBIG, "File offset value too large");

    return (int)offs;

}

 

//打开的过程

/**

 * 1. 关闭设备

 * 2. 重置设备的状态为正在打开中

 * 3. 设置一些必要状态

 * 4. 申请缓存

 * 5. 实施打开操作

 * 6. 重置设备的状态为已打开

**/

void iobase::open()

{

    cancel();

    chstat(IO_OPENING);

    abspos = 0;

    cancelled = false;

    eof = false;

    stmerrno = 0;

    clear(deferrormsg);

    active = true;

    stmbalance++;

              //分配缓存

    bufalloc();

    //实施打开操作

    doopen();

    //重置设备状态为已打开

    chstat(IO_OPENED);

}

 

//关闭的过程

/**

 * 1. 如果缓存中还有数据,执行flush操作

 * 2. 执行关闭操作

 * 3. 释放缓存

 * 4. 设置一些状态值

 * 5. 设置设备当前状态为已关闭

**/

void iobase::close()

{

    if (!active)

        return;

    stmbalance--;

    try

    {

        if (bufdata != 0 && !cancelled)

            flush();

        doclose();

    }

    catch(estream* e)

    {

        delete e;

    }

    buffree();

    active = false;

    eof = true;

    chstat(IO_CLOSED);

}

 

//cancel做了关闭操作

void iobase::cancel()

{

    cancelled = true;

    close();

}

 

//在一定模式下进行seek操作

large iobase::seekx(large newpos, ioseekmode mode)

{

    if (!active)

        errstminactive();

    flush();

    large ret = doseek(newpos, mode);

    if (ret < 0)

        error(ESPIPE, "Seek failed");

    bufclear();

    eof = false;

    abspos = ret;

    return ret;

}

 

//flush没有做任何工作

void iobase::flush()

{

}

 

//seek操作,windows下和linux下采取不同的API

large iobase::doseek(large newpos, ioseekmode mode)

{

    if (handle == invhandle)

    {

        error(ESPIPE, "Can't seek on this device");

        return -1;

    }

#ifdef WIN32

    static int wmode[3] = {FILE_BEGIN, FILE_CURRENT, FILE_END};

    LARGE_INTEGER li;

    li.QuadPart = newpos;

    li.LowPart = SetFilePointer(HANDLE(handle), li.LowPart, &li.HighPart, wmode[mode]);

    if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)

        return -1;

    return li.QuadPart;

#else

    static int umode[3] = {SEEK_SET, SEEK_CUR, SEEK_END};

    return lseek(handle, newpos, umode[mode]);

#endif

}

 

//doclose操作

void iobase::doclose()

{

#ifdef WIN32

    CloseHandle(HANDLE(pexchange(&handle, invhandle)));

#else

    ::close(pexchange(&handle, invhandle));

#endif

}

 

//

void iobase::set_active(bool newval)

{

    if (newval != active)

        if (newval)

            open();

        else

            close();

}

 

//改变buf的大小,stream在激活状态时,不应该改变buf的大小,因为此时的buf是已经申请得到的

//这个改变后的buf大小会在新一次的stream打开过程中被使用到

void iobase::set_bufsize(int newval)

{

    if (active)

        fatal(CRIT_FIRST + 12, "Cannot change buffer size while stream is active");

    if (newval < 0)

        bufsize = defbufsize;

    else

        bufsize = newval;

       

}

 

 

string iobase::get_errstmname()

{

    return get_streamname();

}

 

 

const char* iobase::uerrmsg(int code)

{

    return unixerrmsg(code);

}

 

 

int iobase::uerrno()

{

    return unixerrno();

}

 

 

string iobase::get_errormsg()

{

    string s = uerrmsg(stmerrno);

    if (isempty(s))

        s = deferrormsg;

    if (pos('[', s) >= 0 && *(pconst(s) + length(s) - 1) == ']')

        return s;

    string e = get_errstmname();

    if (isempty(e))

        return s;

    return s + " [" + e + ']';

}

 

 

#ifdef _MSC_VER

// disable "unreachable code" warning for throw (known compiler bug)

#  pragma warning (disable: 4702)

#endif

 

void iobase::error(int code, const char* defmsg)

{

    eof = true;

    stmerrno = code;

    deferrormsg = defmsg;

    throw new estream(this, code, get_errormsg());

}

 

 

PTYPES_END

  评论这张
 
阅读(917)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017