diff options
Diffstat (limited to 'filepopen.cpp')
-rw-r--r-- | filepopen.cpp | 1191 |
1 files changed, 1191 insertions, 0 deletions
diff --git a/filepopen.cpp b/filepopen.cpp new file mode 100644 index 0000000..afcd184 --- /dev/null +++ b/filepopen.cpp @@ -0,0 +1,1191 @@ +// filepopen.cpp +// Revision 6-feb-2005 + +#include "file.h" + +#include "blassic.h" +#include "error.h" +#include "showerror.h" +#include "sysvar.h" +#include "util.h" +using util::to_string; + +#include "trace.h" + +#include <iostream> +using std::cerr; +using std::endl; + +#ifndef BLASSIC_USE_WINDOWS + +#include <stdio.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> + +// Suggested in autoconf manual. +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(star_val) ((unsigned) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + + +#include <fcntl.h> +#include <sys/poll.h> + +#else + +#include <windows.h> +#undef min +#undef max + +#endif + +// para strerror (errno) +#include <string.h> +#include <errno.h> + +#include <assert.h> + +#define ASSERT assert + +namespace blassic { + +namespace file { + +//*********************************************** +// BlFilePopen +//*********************************************** + +class BlFilePopen : public BlFile { +protected: + virtual char getcharfrombuffer ()= 0; + virtual void outstring (const std::string & str)= 0; + virtual void outchar (char c)= 0; + bool forread; + bool forwrite; + bool witherr; +public: + BlFilePopen (OpenMode nmode); + bool isfile () const { return true; } + virtual void closein ()= 0; + virtual void closeout ()= 0; + virtual bool eof ()= 0; + void flush (); + virtual void endline ()= 0; + virtual std::string read (size_t n)= 0; + virtual void getline (std::string & str, bool endline= true)= 0; + virtual bool poll ()= 0; +}; + +BlFilePopen::BlFilePopen (OpenMode nmode) : + BlFile (nmode) +{ + if (nmode & Input) + forread= true; + if (nmode & Output) + forwrite= true; + if (nmode & WithErr) + witherr= true; + const OpenMode checkmode= OpenMode (Input | Output | WithErr); + if ( (nmode | checkmode) != checkmode) + throw ErrFileMode; +} + +void BlFilePopen::flush () +{ +} + +#ifdef BLASSIC_USE_WINDOWS + +//*********************************************** +// Auxiliary functions and classes for windows +//*********************************************** + +namespace { + +class ProtectHandle { +public: + ProtectHandle () : + handle (INVALID_HANDLE_VALUE) + { } + ProtectHandle (HANDLE handle) : + handle (handle) + { } + ~ProtectHandle () + { + close (); + } + void reset (HANDLE newhandle) + { + close (); + handle= newhandle; + } + void close () + { + if (handle != INVALID_HANDLE_VALUE) + { + CloseHandle (handle); + handle= INVALID_HANDLE_VALUE; + } + } + void release () + { + handle= INVALID_HANDLE_VALUE; + } +private: + HANDLE handle; +}; + +std::string makecommand (const std::string & str) +{ + const char * comspec= getenv ("COMSPEC"); + if (comspec == NULL) + comspec= "C:\\COMMAND.COM"; + std::string command= comspec; + command+= " /C "; + command+= str; + return command; +} + +void create_pipe (HANDLE & hread, HANDLE & hwrite) +{ + if (CreatePipe (& hread, & hwrite, NULL, 0) == 0) + { + showlasterror ("CreatePipe failed"); + throw ErrFunctionCall; + } +} + +HANDLE duplicate_inherit (HANDLE handle, HANDLE current) +{ + HANDLE newhandle; + if (DuplicateHandle (current, handle, + current, & newhandle, + 0, + TRUE, // Inherited + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS) == 0) + { + showlasterror ("DuplicateHandle hread failed"); + throw ErrFunctionCall; + } + return newhandle; +} + +HANDLE createnull () +{ + SECURITY_ATTRIBUTES sec; + sec.nLength= sizeof sec; + sec.lpSecurityDescriptor= NULL; + sec.bInheritHandle= TRUE; + + const HANDLE hnull= CreateFile ("NUL", + GENERIC_READ | GENERIC_WRITE, + 0, + & sec, // Inheritable. + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hnull == INVALID_HANDLE_VALUE) + { + showlasterror ("Error creating /dev/null handle"); + throw ErrOperatingSystem; + } + return hnull; +} + +void launchchild (const std::string & str, + bool forread, bool forwrite, bool witherr, + HANDLE & hreadpipe, HANDLE & hwritepipe, HANDLE & childprocess) +{ + TRACEFUNC (tr, "launchchild"); + + const std::string command= makecommand (str); + + HANDLE current= GetCurrentProcess (); + const HANDLE hnull= createnull (); + ProtectHandle prnull (hnull); + + STARTUPINFO start; + start.cb= sizeof start; + GetStartupInfo (& start); + start.dwFlags= STARTF_USESTDHANDLES; + start.hStdInput= hnull; + start.hStdOutput= hnull; + start.hStdError= hnull; + DWORD creationflags= 0; + + HANDLE hwritechild; + ProtectHandle prreadpipe; + ProtectHandle prwritechild; + if (forread) + { + TRMESSAGE (tr, "Creating pipe input"); + + HANDLE hwrite; + create_pipe (hreadpipe, hwrite); + prreadpipe.reset (hreadpipe); + hwritechild= duplicate_inherit (hwrite, current); + prwritechild.reset (hwritechild); + start.hStdOutput= hwritechild; + if (witherr) + start.hStdError= hwritechild; + } + HANDLE hreadchild; + ProtectHandle prwritepipe; + ProtectHandle prreadchild; + if (forwrite) + { + TRMESSAGE (tr, "Creating pipe output"); + + // In Windows 95 or 98 detach the process from the + // actual console, without that the parent process + // gets blocked. + // Now seems inneccessary, and conflicts with + // bidirectional mode. + #if 0 + { + OSVERSIONINFO osv; + osv.dwOSVersionInfoSize= sizeof (OSVERSIONINFO); + GetVersionEx (& osv); + if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + creationflags|= DETACHED_PROCESS; + } + #endif + + HANDLE hread; + create_pipe (hread, hwritepipe); + prwritepipe.reset (hwritepipe); + hreadchild= duplicate_inherit (hread, current); + prreadchild.reset (hreadchild); + start.hStdInput= hreadchild; + } + + TRMESSAGE (tr, "Creating pipe process"); + + PROCESS_INFORMATION procinfo; + if (CreateProcess ( + NULL, (char *) command.c_str (), + NULL, NULL, + TRUE, // Inherit handles + creationflags, + NULL, NULL, & start, & procinfo) == 0) + { + showlasterror ( ("CreateProcess " + command + + " failed in POPEN").c_str () ); + throw ErrFunctionCall; + } + + // No need to close here the child handles, ProtectHandle + // takes care of him. + + // Release protection of the parent handles. + prreadpipe.release (); + prwritepipe.release (); + + childprocess= procinfo.hProcess; + CloseHandle (procinfo.hThread); +} + +class CriticalSection { +public: + CriticalSection () + { + InitializeCriticalSection (& object); + } + ~CriticalSection () + { + DeleteCriticalSection (& object); + } + CriticalSection (const CriticalSection &); // Forbidden + void operator= (const CriticalSection &); // Forbidden + void enter () + { + EnterCriticalSection (& object); + } + void leave () + { + LeaveCriticalSection (& object); + } +private: + CRITICAL_SECTION object; +}; + +class CriticalLock { +public: + CriticalLock (CriticalSection & crit) : + crit (crit) + { + crit.enter (); + } + ~CriticalLock () + { + crit.leave (); + } +private: + CriticalSection & crit; +}; + +class Event +{ +public: + Event () + { + hevent= CreateEvent ( + NULL, // Default security + FALSE, // Automatic + FALSE, // Initially not signaled + NULL // Without name + ); + if (hevent == NULL) + { + showlasterror (); + throw ErrOperatingSystem; + } + } + ~Event () + { + CloseHandle (hevent); + } + void wait () + { + WaitForSingleObject (hevent, INFINITE); + } + void set () + { + SetEvent (hevent); + } + void reset () + { + ResetEvent (hevent); + } +private: + HANDLE hevent; +}; + +} // namespace + +//*********************************************** +// BlFilePopenWindows +//*********************************************** + +class BlFilePopenWindows : public BlFilePopen { +public: + BlFilePopenWindows (const std::string & str, OpenMode mode); + ~BlFilePopenWindows (); + void closein (); + void closeout (); + bool eof (); + void endline (); + std::string read (size_t n); + void getline (std::string & str, bool endline= true); + bool poll (); +private: + static const size_t bufsize= 4096; + char buffer [bufsize]; + size_t bufpos, bufread; + void readbuffer (); + char getcharfrombuffer (); + + void read_in_thread (); + + void outstring (const std::string & str); + void outchar (char c); + + CriticalSection critical; + Event canread; + bool nowreading; + Event hasread; + HANDLE hreadpipe, hwritepipe; + HANDLE hprocess; + HANDLE hreadthread; + bool finishthread; + bool error_reading; + bool eof_found; + + friend DWORD WINAPI thread_popen_read (LPVOID param); + friend class ProtectThread; +}; + +class ProtectThread { +public: + ProtectThread (BlFilePopenWindows & popen) : + popen (popen), + released (false) + { } + ~ProtectThread () + { + if (! released && popen.hreadthread != NULL) + { + popen.finishthread= true; + ResumeThread (popen.hreadthread); + CloseHandle (popen.hreadthread); + } + } + void release () + { + released= true; + } +private: + BlFilePopenWindows & popen; + bool released; +}; + +DWORD WINAPI thread_popen_read (LPVOID param) +{ + BlFilePopenWindows & popen= * + reinterpret_cast <BlFilePopenWindows *> (param); + if (popen.finishthread) + return 0; + + try + { + popen.read_in_thread (); + } + catch (...) + { + popen.error_reading= true; + popen.nowreading= false; + popen.hasread.set (); + } + + return 0; +} + +BlFilePopenWindows::BlFilePopenWindows + (const std::string & str, OpenMode nmode) : + BlFilePopen (nmode) +{ + TRACEFUNC (tr, "BlFilePopenWindows::BlFilePopenWindows"); + + hprocess= INVALID_HANDLE_VALUE; + hreadpipe= INVALID_HANDLE_VALUE; + hwritepipe= INVALID_HANDLE_VALUE; + hreadthread= NULL; + nowreading= false; + finishthread= false; + error_reading= false; + eof_found= false; + + if (forread) + { + DWORD idthread; + hreadthread= CreateThread (NULL, 1024, + thread_popen_read, this, + CREATE_SUSPENDED, & idthread); + if (hreadthread == NULL) + { + showlasterror (); + throw ErrOperatingSystem; + } + } + ProtectThread protect (* this); + launchchild (str, forread, forwrite, witherr, + hreadpipe, hwritepipe, hprocess); + if (forread) + { + ResumeThread (hreadthread); + nowreading= true; + canread.set (); + } + protect.release (); +} + +BlFilePopenWindows::~BlFilePopenWindows () +{ + TRACEFUNC (tr, "BlFilePopenWindows::~BlFilePopenWindows"); + + // This is to workaround errors in C++ Builder. + if (hprocess == INVALID_HANDLE_VALUE) + return; + + if (hreadthread != NULL) + { + finishthread= true; + CloseHandle (hreadthread); + hreadthread= NULL; + nowreading= true; + hasread.reset (); + canread.set (); + } + // Close the pipe before wait for termination, + // the child process can be waiting for + // input. + //CloseHandle (hpipe); + if (hreadpipe != INVALID_HANDLE_VALUE) + CloseHandle (hreadpipe); + if (hwritepipe != INVALID_HANDLE_VALUE) + CloseHandle (hwritepipe); + + WaitForSingleObject (hprocess, INFINITE); + DWORD exitcode; + BOOL r= GetExitCodeProcess (hprocess, & exitcode); + if (r == 0) + { + showlasterror (); + } + CloseHandle (hprocess); + if (r == 0) + { + throw ErrOperatingSystem; + } + TRMESSAGE (tr, "Exit code: " + to_string (exitcode) ); + sysvar::set (sysvar::ShellResult, + static_cast <BlChar> (exitcode & 0xFF) ); +} + +char BlFilePopenWindows::getcharfrombuffer () +{ + { + CriticalLock lock (critical); + if (bufpos < bufread) + return buffer [bufpos++]; + } + + if (error_reading) + throw ErrOperatingSystem; + if (eof_found) + return 0; + + readbuffer (); + hasread.wait (); + + if (error_reading) + throw ErrOperatingSystem; + if (eof_found) + return 0; + + return buffer [bufpos++]; +} + +void BlFilePopenWindows::closein () +{ + TRACEFUNC (tr, "BlFilePopenWindows::closein"); + + if (! getmode () & Input) + throw ErrFileMode; + finishthread= true; + CloseHandle (hreadpipe); + hreadpipe= INVALID_HANDLE_VALUE; + + critical.enter (); + nowreading= true; + hasread.reset (); + canread.set (); + critical.leave (); + + CloseHandle (hreadthread); + hreadthread= INVALID_HANDLE_VALUE; +} + +void BlFilePopenWindows::closeout () +{ + TRACEFUNC (tr, "BlFilePopenWindows::closeout"); + + if (! getmode () & Output) + throw ErrFileMode; + CloseHandle (hwritepipe); + hwritepipe= INVALID_HANDLE_VALUE; +} + +bool BlFilePopenWindows::eof () +{ + TRACEFUNC (tr, "BlFilePopenWindows::eof"); + + if (! getmode () & Input) + throw ErrFileMode; + + { + CriticalLock lock (critical); + if (bufpos < bufread) + return false; + } + + readbuffer (); + hasread.wait (); + + if (error_reading) + throw ErrOperatingSystem; + if (!eof_found) + { + ASSERT (bufpos < bufread); + } + return eof_found; +} + +void BlFilePopenWindows::endline () +{ + outstring ("\r\n"); +} + +std::string BlFilePopenWindows::read (size_t n) +{ + if (! getmode () & Input) + throw ErrFileMode; + + std::string str; + for (size_t i= 0; i < n; ++i) + { + char c= getcharfrombuffer (); + if (c == 0 && eof_found) + break; + str+= c; + } + return str; +} + +void BlFilePopenWindows::getline (std::string & str, bool) +{ + TRACEFUNC (tr, "BlFilePopenWindows::getline"); + + if (! getmode () & Input) + throw ErrFileMode; + + str= std::string (); + char c; + while ( (c= getcharfrombuffer () ) != '\r' && c != '\n') + { + if (c == 0) + { + if (eof_found) + { + if (str.empty () ) + throw ErrPastEof; + else + break; + } + } + else + str+= c; + } + + if (c == '\r') + getcharfrombuffer (); +} + +void BlFilePopenWindows::readbuffer () +{ + if (finishthread | error_reading | eof_found) + return; + CriticalLock lock (critical); + if (nowreading) + return; + nowreading= true; + hasread.reset (); + canread.set (); +} + +void BlFilePopenWindows::read_in_thread () +{ + do + { + canread.wait (); + if (finishthread) + break; + if (hreadpipe == INVALID_HANDLE_VALUE) + break; + DWORD bytesread= 0; + if (ReadFile (hreadpipe, buffer, bufsize, & bytesread, NULL) == 0) + { + DWORD r= GetLastError (); + if (r != ERROR_BROKEN_PIPE) + { + error_reading= true; + } + else + { + eof_found= true; + } + + CriticalLock lock (critical); + nowreading= false; + } + else + { + CriticalLock lock (critical); + if (bytesread == 0) + { + // This is not supposed to happen + // in an anonymous pipe. + error_reading= true; + } + bufpos= 0; + bufread= bytesread; + nowreading= false; + } + hasread.set (); + } while (! error_reading & ! eof_found & ! finishthread); +} + +void BlFilePopenWindows::outstring (const std::string & str) +{ + TRACEFUNC (tr, "BlFilePopenWindows::outstring"); + + if (! getmode () & Output) + throw ErrFileMode; + + const char * to= str.data (); + std::string::size_type l= str.size (); + DWORD written; + //WriteFile (hpipe, to, l, & written, NULL); + if (WriteFile (hwritepipe, to, l, & written, NULL) == 0) + { + showlasterror (); + throw ErrOperatingSystem; + } +} + +void BlFilePopenWindows::outchar (char c) +{ + if (! getmode () & Output) + throw ErrFileMode; + + DWORD written; + //WriteFile (hpipe, & c, 1, & written, NULL); + if (WriteFile (hwritepipe, & c, 1, & written, NULL) == 0) + { + showlasterror (); + throw ErrOperatingSystem; + } +} + +bool BlFilePopenWindows::poll () +{ + if (! getmode () & Input) + throw ErrFileMode; + + { + CriticalLock lock (critical); + if (bufpos < bufread) + return true; + } + + readbuffer (); + + return false; +} + +#else +// No Windows + +//*********************************************** +// Auxiliary functions and classes for unix +//*********************************************** + +namespace { + +class ProtectHandle { +public: + ProtectHandle (int handle) : + handle (handle) + { } + ~ProtectHandle () + { + close (); + } + void close () + { + if (handle != -1) + { + ::close (handle); + handle= -1; + } + } + void release () + { + handle= -1; + } +private: + int handle; +}; + +void exec_command (const std::string & str) +{ + const char * strShell= getenv ("SHELL"); + if (! strShell) + strShell= "/bin/sh"; + + execlp (strShell, strShell, "-c", + str.c_str (), (char *) 0); + + // If something fails: + exit (127); +} + +void createpipe (int & hread, int & hwrite) +{ + int handlepair [2]; + if (pipe (handlepair) != 0) + { + showlasterror ("Creating pipe"); + throw ErrOperatingSystem; + } + hread= handlepair [0]; + hwrite= handlepair [1]; +} + +void duporfail (int oldfd, int newfd) +{ + if (dup2 (oldfd, newfd) == -1) + exit (127); +} + +void stdtonull () +{ + int newstd= open ("/dev/null", O_RDWR); + if (newstd == -1) + exit (127); + duporfail (newstd, STDIN_FILENO); + duporfail (newstd, STDOUT_FILENO); + duporfail (newstd, STDERR_FILENO); + close (newstd); +} + +void launchchild (const std::string & str, + bool forread, bool forwrite, bool witherr, + int & readhandle, int & writehandle, pid_t & childpid) +{ + TRACEFUNC (tr, "launchchild"); + + if (! forread && ! forwrite) + { + ASSERT (false); + throw ErrBlassicInternal; + } + + int writechild= -1; + if (forread) + createpipe (readhandle, writechild); + ProtectHandle prrhandle (readhandle); + ProtectHandle prwchild (writechild); + + int readchild= -1; + if (forwrite) + createpipe (readchild, writehandle); + ProtectHandle prwhandle (writehandle); + ProtectHandle prrchild (readchild); + + childpid= fork (); + switch (childpid) + { + case pid_t (-1): + // Fork has failed. + showlasterror (); + throw ErrOperatingSystem; + case pid_t (0): + // Child process. + // No need to take care of handles in case of fail + // here, the process will be terminated. + stdtonull (); + if (forread) + { + prrhandle.close (); + duporfail (writechild, STDOUT_FILENO); + if (witherr) + duporfail (writechild, STDERR_FILENO); + prwchild.close (); + } + if (forwrite) + { + prwhandle.close (); + duporfail (readchild, STDIN_FILENO); + prrchild.close (); + } + exec_command (str); + break; // To avoid warnings. + default: + // Parent process. + if (forread) + { + prwchild.close (); + prrhandle.release (); + } + if (forwrite) + { + prrchild.close (); + prwhandle.release (); + } + } +} + +} // namespace + +//*********************************************** +// BlFilePopenUnix +//*********************************************** + +class BlFilePopenUnix : public BlFilePopen { +public: + BlFilePopenUnix (const std::string & str, OpenMode mode); + ~BlFilePopenUnix (); + void closein (); + void closeout (); + bool eof (); + void endline (); + std::string read (size_t n); + void getline (std::string & str, bool endline= true); + bool poll (); +private: + static const size_t bufsize= 4096; + char buffer [bufsize]; + size_t bufpos, bufread; + void readbuffer (); + char getcharfrombuffer (); + size_t do_readbuffer (char * buffer, size_t bytes); + + void closeread (); + void closewrite (); + void outstring (const std::string & str); + void outchar (char c); + + int readhandle; + int writehandle; + pid_t childpid; +}; + +BlFilePopenUnix::BlFilePopenUnix + (const std::string & str, OpenMode nmode) : + BlFilePopen (nmode) +{ + TRACEFUNC (tr, "BlFilePopenUnix::BlFilePopenUnix"); + TRMESSAGE (tr, str); + + readhandle= -1; + writehandle= -1; + childpid= -1; + + launchchild (str, forread, forwrite, witherr, + readhandle, writehandle, childpid); +} + +BlFilePopenUnix::~BlFilePopenUnix () +{ + TRACEFUNC (tr, "BlFilePopenUnix::~BlFilePopenUnix"); + + // First close the pipes, the child can be waiting for input. + closeread (); + closewrite (); + + int status; + if (waitpid (childpid, & status, 0) == -1 || ! WIFEXITED (status) ) + { + showlasterror (); + throw ErrOperatingSystem; + } + TRMESSAGE (tr, "Exit code: " + to_string (WEXITSTATUS (status) ) ); + sysvar::set (sysvar::ShellResult, WEXITSTATUS (status) ); +} + +char BlFilePopenUnix::getcharfrombuffer () +{ + if (bufpos >= bufread) + { + readbuffer (); + if (bufread == 0) + return '\0'; + } + return buffer [bufpos++]; +} + +void BlFilePopenUnix::closein () +{ + TRACEFUNC (tr, "BlFilePopenUnix::closein"); + + if (! getmode () & Input) + throw ErrFileMode; + + closeread (); +} + +void BlFilePopenUnix::closeout () +{ + TRACEFUNC (tr, "BlFilePopenUnix::closeout"); + + if (! getmode () & Output) + throw ErrFileMode; + + closewrite (); +} + +bool BlFilePopenUnix::eof () +{ + TRACEFUNC (tr, "BlFilePopenUnix::eof"); + + if (! getmode () & Input) + throw ErrFileMode; + + if (bufpos < bufread) + return false; + readbuffer (); + return bufread == 0; +} + +void BlFilePopenUnix::endline () +{ + outchar ('\n'); +} + +std::string BlFilePopenUnix::read (size_t n) +{ + if (! getmode () & Input) + throw ErrFileMode; + + std::string str; + for (size_t i= 0; i < n; ++i) + { + char c= getcharfrombuffer (); + if (c == '\0') + { + if (eof () ) + break; + else + str+= c; + } + else + str+= c; + } + return str; +} + +void BlFilePopenUnix::getline (std::string & str, bool) +{ + TRACEFUNC (tr, "BlFilePopenUnix::getline"); + + if (! getmode () & Input) + throw ErrFileMode; + + str= std::string (); + char c; + while ( (c= getcharfrombuffer () ) != '\r' && c != '\n') + { + if (c == '\0') + { + if (eof () ) + { + if (str.empty () ) + throw ErrPastEof; + else + break; + } + else + break; + } + else + str+= c; + } +} + +void BlFilePopenUnix::closeread () +{ + if (readhandle != -1) + { + close (readhandle); + readhandle= -1; + } +} + +void BlFilePopenUnix::closewrite () +{ + if (writehandle != -1) + { + close (writehandle); + writehandle= -1; + } +} + +void BlFilePopenUnix::readbuffer () +{ + bufpos= 0; + bufread= do_readbuffer (buffer, bufsize); +} + +size_t BlFilePopenUnix::do_readbuffer (char * buffer, size_t bytes) +{ + TRACEFUNC (tr, "BlFilePopenUnix::do_readbuffer"); + + size_t bytesread= ::read (readhandle, buffer, bytes); + if (bytesread == size_t (-1) ) + bytesread= 0; + return bytesread; +} + +void BlFilePopenUnix::outstring (const std::string & str) +{ + TRACEFUNC (tr, "BlFilePopenUnix::outstring"); + + if (! getmode () & Output) + throw ErrFileMode; + + const char * to= str.data (); + std::string::size_type l= str.size (); + if (write (writehandle, to, l) == -1) + { + showlasterror (); + throw ErrOperatingSystem; + } +} + +void BlFilePopenUnix::outchar (char c) +{ + if (! getmode () & Output) + throw ErrFileMode; + + if (write (writehandle, & c, 1) == -1) + { + showlasterror (); + throw ErrOperatingSystem; + } +} + +bool BlFilePopenUnix::poll () +{ + TRACEFUNC (tr, "BlFilePopenUnix::poll"); + + if (! getmode () & Input) + throw ErrFileMode; + struct pollfd data [1]; + data [0].fd= readhandle; + data [0].events= POLLIN | POLLPRI; + switch (::poll (data, 1, 0) ) + { + case 0: + return false; + case 1: + return true; + default: + showlasterror (); + throw ErrOperatingSystem; + } +} + +#endif +// Windows or unix + +//*********************************************** +// newBlFilePopen +//*********************************************** + +BlFile * newBlFilePopen (const std::string & name, OpenMode mode) +{ + #ifdef BLASSIC_USE_WINDOWS + + return new BlFilePopenWindows (name, mode); + + #else + + return new BlFilePopenUnix (name, mode); + + #endif +} + +} // namespace file + +} // namespace blassic + +// End of filepopen.cpp |