gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

piobase.cxx (8167B)


      1 /*
      2  *
      3  *  C++ Portable Types Library (PTypes)
      4  *  Version 2.1.1  Released 27-Jun-2007
      5  *
      6  *  Copyright (C) 2001-2007 Hovik Melikyan
      7  *
      8  *  http://www.melikyan.com/ptypes/
      9  *
     10  */
     11 
     12 #include <errno.h>
     13 #include <limits.h>
     14 
     15 #ifdef WIN32
     16 #  include <windows.h>
     17 #else
     18 #  include <signal.h>
     19 #  include <unistd.h>
     20 #endif
     21 
     22 #include "pstreams.h"
     23 
     24 
     25 namespace ptypes {
     26 
     27 
     28 /*
     29 
     30 Known UNIX error codes:
     31 
     32 EPERM         1          Not owner
     33 ENOENT        2          No such file or directory
     34 ESRCH         3          No such process
     35 EINTR         4          Interrupted system call
     36 EIO           5          I/O error
     37 ENXIO         6          No such device or address
     38 E2BIG         7          Argument list too long
     39 ENOEXEC       8          Exec format error
     40 EBADF         9          Bad file number
     41 ECHILD       10          No spawned processes
     42 EAGAIN       11          No more processes; not enough memory; maximum nesting level reached
     43 ENOMEM       12          Not enough memory
     44 EACCES       13          Permission denied
     45 EFAULT       14          Bad address
     46 ENOTBLK      15          Block device required
     47 EBUSY        16          Mount device busy
     48 EEXIST       17          File exists
     49 EXDEV        18          Cross-device link
     50 ENODEV       19          No such device
     51 ENOTDIR      20          Not a directory
     52 EISDIR       21          Is a directory
     53 EINVAL       22          Invalid argument
     54 ENFILE       23          File table overflow
     55 EMFILE       24          Too many open files
     56 ENOTTY       25          Not a teletype
     57 ETXTBSY      26          Text file busy
     58 EFBIG        27          File too large
     59 ENOSPC       28          No space left on device
     60 ESPIPE       29          Illegal seek
     61 EROFS        30          Read-only file system
     62 EMLINK       31          Too many links
     63 EPIPE        32          Broken pipe
     64 EDOM         33          Math argument
     65 ERANGE       34          Result too large
     66 EUCLEAN      35          File system needs cleaning
     67 EDEADLK      36          Resource deadlock would occur
     68 EDEADLOCK    36          Resource deadlock would occur
     69 
     70 */
     71 
     72 
     73 #ifndef WIN32
     74 
     75 static class _io_init
     76 {
     77 public:
     78     _io_init();
     79 } _io_init_inst;
     80 
     81 
     82 _io_init::_io_init()
     83 {
     84     // We don't like broken pipes. PTypes will throw an exception instead.
     85     signal(SIGPIPE, SIG_IGN);
     86 }
     87 
     88 #endif
     89 
     90 
     91 
     92 int ptdecl unixerrno() 
     93 {
     94 #ifdef WIN32
     95     switch(GetLastError()) 
     96     {
     97     case ERROR_FILE_NOT_FOUND:
     98     case ERROR_PATH_NOT_FOUND:      return ENOENT;
     99     case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
    100     case ERROR_ACCESS_DENIED:
    101     case ERROR_SHARING_VIOLATION:   return EACCES;
    102     case ERROR_INVALID_HANDLE:      return EBADF;
    103     case ERROR_NOT_ENOUGH_MEMORY:
    104     case ERROR_OUTOFMEMORY:         return ENOMEM;
    105     case ERROR_INVALID_DRIVE:       return ENODEV;
    106     case ERROR_WRITE_PROTECT:       return EROFS;
    107     case ERROR_FILE_EXISTS:         return EEXIST;
    108     case ERROR_BROKEN_PIPE:         return EPIPE;
    109     case ERROR_DISK_FULL:           return ENOSPC;
    110     case ERROR_SEEK_ON_DEVICE:      return ESPIPE;
    111     default: return EIO;
    112     }
    113 #else
    114     return errno;
    115 #endif
    116 }
    117 
    118 
    119 //
    120 // This function gives error messages for most frequently occurring 
    121 // IO errors. If the function returns NULL a generic message
    122 // can be given, e.g. "I/O error". See also iobase::get_errormsg()
    123 //
    124 
    125 const char* ptdecl unixerrmsg(int code)
    126 {
    127     switch(code) 
    128     {
    129     case EBADF:  return "Invalid file descriptor";
    130     case ESPIPE: return "Can not seek on this device";
    131     case ENOENT: return "No such file or directory";
    132     case EMFILE: return "Too many open files";
    133     case EACCES: return "Access denied";
    134     case ENOMEM: return "Not enough memory";
    135     case ENODEV: return "No such device";
    136     case EROFS:  return "Read-only file system";
    137     case EEXIST: return "File already exists";
    138     case ENOSPC: return "Disk full";
    139     case EPIPE:  return "Broken pipe";
    140     case EFBIG:  return "File too large";
    141     default: return nil;
    142     }
    143 }
    144 
    145 
    146 estream::estream(iobase* ierrstm, int icode, const char* imsg)
    147     : exception(imsg), code(icode), errstm(ierrstm) {}
    148 
    149 
    150 estream::estream(iobase* ierrstm, int icode, const string& imsg)
    151     : exception(imsg), code(icode), errstm(ierrstm) {}
    152 
    153 
    154 estream::~estream() {}
    155 
    156 
    157 int defbufsize = 8192;
    158 int stmbalance = 0;
    159 
    160 iobase::iobase(int ibufsize)
    161     : component(), active(false), cancelled(false), eof(true), 
    162       handle(invhandle), abspos(0), bufsize(0), bufdata(nil), bufpos(0), bufend(0),
    163       stmerrno(0), deferrormsg(), status(IO_CREATED), onstatus(nil) 
    164 {
    165     if (ibufsize < 0)
    166         bufsize = defbufsize;
    167     else
    168         bufsize = ibufsize;
    169 }
    170 
    171 
    172 iobase::~iobase() 
    173 {
    174 }
    175 
    176 
    177 void iobase::bufalloc() 
    178 {
    179     if (bufdata != nil)
    180         fatal(CRIT_FIRST + 13, "(ptypes internal) invalid buffer allocation");
    181     bufdata = (char*)memalloc(bufsize);
    182 }
    183 
    184 
    185 void iobase::buffree() 
    186 {
    187     bufclear();
    188     memfree(bufdata);
    189     bufdata = 0;
    190 }
    191 
    192 
    193 void iobase::chstat(int newstat) 
    194 {
    195     status = newstat;
    196     if (onstatus != nil)
    197         (*onstatus)(this, newstat);
    198 }
    199 
    200 
    201 void iobase::errstminactive() 
    202 {
    203     error(EIO, "Stream inactive");
    204 }
    205 
    206 
    207 void iobase::errbufrequired()
    208 {
    209     fatal(CRIT_FIRST + 11, "Internal: buffer required");
    210 }
    211 
    212 
    213 int iobase::convertoffset(large offs)
    214 {
    215     if (offs < 0 || offs > INT_MAX)
    216         error(EFBIG, "File offset value too large");
    217     return (int)offs;
    218 }
    219 
    220 
    221 void iobase::open() 
    222 {
    223     cancel();
    224     chstat(IO_OPENING);
    225     abspos = 0;
    226     cancelled = false;
    227     eof = false;
    228     stmerrno = 0;
    229     clear(deferrormsg);
    230     active = true;
    231     stmbalance++;
    232     bufalloc();
    233     doopen();
    234     chstat(IO_OPENED);
    235 }
    236 
    237 
    238 void iobase::close() 
    239 {
    240     if (!active)
    241         return;
    242     stmbalance--;
    243     try 
    244     {
    245         if (bufdata != 0 && !cancelled)
    246             flush();
    247         doclose();
    248     }
    249     catch(estream* e) 
    250     {
    251         delete e;
    252     }
    253     buffree();
    254     active = false;
    255     eof = true;
    256     chstat(IO_CLOSED);
    257 }
    258 
    259 
    260 void iobase::cancel() 
    261 {
    262     cancelled = true;
    263     close();
    264 }
    265 
    266 
    267 large iobase::seekx(large newpos, ioseekmode mode) 
    268 {
    269     if (!active)
    270         errstminactive();
    271     flush();
    272     large ret = doseek(newpos, mode);
    273     if (ret < 0)
    274         error(ESPIPE, "Seek failed");
    275     bufclear();
    276     eof = false;
    277     abspos = ret;
    278     return ret;
    279 }
    280 
    281 
    282 void iobase::flush() 
    283 {
    284 }
    285 
    286 
    287 large iobase::doseek(large newpos, ioseekmode mode)
    288 {
    289     if (handle == invhandle)
    290     {
    291         error(ESPIPE, "Can't seek on this device");
    292         return -1;
    293     }
    294 #ifdef WIN32
    295     static int wmode[3] = {FILE_BEGIN, FILE_CURRENT, FILE_END};
    296     LARGE_INTEGER li;
    297     li.QuadPart = newpos;
    298     li.LowPart = SetFilePointer(HANDLE(handle), li.LowPart, &li.HighPart, wmode[mode]);
    299     if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
    300         return -1;
    301     return li.QuadPart;
    302 #else
    303     static int umode[3] = {SEEK_SET, SEEK_CUR, SEEK_END};
    304     return lseek(handle, newpos, umode[mode]);
    305 #endif
    306 }
    307 
    308 
    309 void iobase::doclose()
    310 {
    311 #ifdef WIN32
    312     CloseHandle(HANDLE(pexchange(&handle, invhandle)));
    313 #else
    314     ::close(pexchange(&handle, invhandle));
    315 #endif
    316 }
    317 
    318 
    319 void iobase::set_active(bool newval) 
    320 {
    321     if (newval != active)
    322 	{
    323         if (newval)
    324             open();
    325         else
    326             close();
    327 	}
    328 }
    329 
    330 
    331 void iobase::set_bufsize(int newval) 
    332 {
    333     if (active)
    334         fatal(CRIT_FIRST + 12, "Cannot change buffer size while stream is active");
    335     if (newval < 0)
    336         bufsize = defbufsize;
    337     else
    338         bufsize = newval;
    339 }
    340 
    341 
    342 string iobase::get_errstmname() 
    343 {
    344     return get_streamname();
    345 }
    346 
    347 
    348 const char* iobase::uerrmsg(int code)
    349 {
    350     return unixerrmsg(code);
    351 }
    352 
    353 
    354 int iobase::uerrno()
    355 {
    356     return unixerrno();
    357 }
    358 
    359 
    360 string iobase::get_errormsg() 
    361 {
    362     string s = uerrmsg(stmerrno);
    363     if (isempty(s))
    364         s = deferrormsg;
    365     if (pos('[', s) >= 0 && *(pconst(s) + length(s) - 1) == ']')
    366         return s;
    367     string e = get_errstmname();
    368     if (isempty(e))
    369         return s;
    370     return s + " [" + e + ']';
    371 }
    372 
    373 
    374 #ifdef _MSC_VER
    375 // disable "unreachable code" warning for throw (known compiler bug)
    376 #  pragma warning (disable: 4702)
    377 #endif
    378 
    379 void iobase::error(int code, const char* defmsg) 
    380 {
    381     eof = true;
    382     stmerrno = code;
    383     deferrormsg = defmsg;
    384     throw new estream(this, code, get_errormsg());
    385 }
    386 
    387 
    388 }