32#ifndef _QORE_INTERN_QORE_QF_PRIVATE_H
33#define _QORE_INTERN_QORE_QF_PRIVATE_H
35#include "qore/intern/QC_Queue.h"
37#include "qore/intern/QC_TermIOS.h"
40#include "qore/intern/StringReaderHelper.h"
41#include "qore/AbstractPollState.h"
54#elif defined HAVE_SYS_SELECT_H
55#include <sys/select.h>
56#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
59#error no async I/O APIs available
62#ifndef DEFAULT_FILE_BUFSIZE
63#define DEFAULT_FILE_BUFSIZE 16384
66hashdecl qore_qf_private {
69 bool special_file =
false;
73 Queue* event_queue =
nullptr;
77 bool event_data =
false;
78 bool in_non_block =
false;
80 DLLLOCAL qore_qf_private(
const QoreEncoding* cs) : charset(cs) {
83 DLLLOCAL ~qore_qf_private() {
90 DLLLOCAL
int close_intern(
bool detach =
false) {
100 do_close_event_unlocked();
110 DLLLOCAL
int redirect(qore_qf_private& file,
ExceptionSink* xsink) {
116 if (checkNonBlock(xsink)) {
121 if (file.checkNonBlock(xsink)) {
126 int rc = dup2(file.fd, fd);
131 filename = file.filename;
136 DLLLOCAL
int open_intern(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
144 if (!(flags & O_TEXT))
148 do_open_event_unlocked(fn, flags, mode, cs);
150 fd = ::open(fn, flags, mode);
154 do_opened_event_unlocked(fn, flags, mode, cs);
163 DLLLOCAL
int open(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
164 if (!fn || special_file)
168 return open_intern(fn, flags, mode, cs);
177 xsink->
raiseException(
"FILE-READ-ERROR",
"file has not been opened");
187 xsink->
raiseException(
"FILE-WRITE-ERROR",
"file has not been opened");
197 xsink->
raiseException(
"FILE-OPERATION-ERROR",
"file has not been opened");
201 DLLLOCAL
bool isOpen()
const {
205 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
ExceptionSink *xsink)
const {
207 if (checkNonBlock(xsink)) {
211 if (checkReadOpen(xsink))
214 return isDataAvailableIntern(timeout_ms,
"isDataAvailable", xsink);
223 DLLLOCAL
int select(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
225 if (checkOpen(xsink))
229 return poll_intern(timeout_ms, read, mname, xsink);
230#elif defined HAVE_SELECT
231 return select_intern(timeout_ms, read, mname, xsink);
233#error no async I/O operations supported
238 DLLLOCAL
int poll_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
240 pollfd fds = {fd, (short)(read ? POLLIN : POLLOUT), 0};
242 rc = poll(&fds, 1, timeout_ms);
243 if (rc == -1 && errno == EINTR)
248 xsink->
raiseException(
"FILE-SELECT-ERROR",
"poll(2) returned an error in call to File::%s()", mname);
249 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
254#elif defined HAVE_SELECT
255 DLLLOCAL
int select_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
256#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
261 if (fd >= FD_SETSIZE) {
263 xsink->
raiseException(
"FILE-SELECT-ERROR",
"fd is %d in call to File::%s() which is >= %d; contact "
264 "the Qore developers to implement an alternative to select() on this platform", fd, mname,
277 tv.tv_sec = timeout_ms / 1000;
278 tv.tv_usec = (timeout_ms % 1000) * 1000;
280 rc = read ? ::select(fd + 1, &sfs, 0, 0, &tv) : ::select(fd + 1, 0, &sfs, 0, &tv);
281 if (rc >= 0 || errno != EINTR)
286 xsink->
raiseException(
"FILE-SELECT-ERROR",
"select(2) returned an error in call to File::%s()", mname);
295 DLLLOCAL
bool isDataAvailableIntern(
int timeout_ms,
const char* mname,
ExceptionSink *xsink)
const {
296 return select(timeout_ms,
true, mname, xsink);
300 DLLLOCAL
int setTerminalAttributes(
int action, QoreTermIOS* ios,
ExceptionSink* xsink)
const {
302 if (checkNonBlock(xsink)) {
306 if (checkOpen(xsink))
309 return ios->set(fd, action, xsink);
312 DLLLOCAL
int getTerminalAttributes(QoreTermIOS* ios,
ExceptionSink* xsink)
const {
314 if (checkNonBlock(xsink)) {
318 if (checkOpen(xsink))
321 return ios->get(fd, xsink);
326 DLLLOCAL ssize_t readCheck(
ExceptionSink* xsink,
void* buf,
size_t bs)
const {
327 if (checkNonBlock(xsink)) {
331 if (checkReadOpen(xsink)) {
335 return read(buf, bs);
339 DLLLOCAL ssize_t read(
void* buf,
size_t bs)
const {
345 rc = ::read(fd, buf, bs);
347 if (rc >= 0 || errno != EINTR)
352 do_read_event_unlocked(rc, rc, bs);
358 DLLLOCAL ssize_t writeCheck(
const void* buf,
size_t len,
ExceptionSink* xsink)
const {
359 if (checkNonBlock(xsink)) {
363 if (checkWriteOpen(xsink)) {
367 return write(buf, len, xsink);
371 DLLLOCAL ssize_t write(
const void* buf,
size_t len,
ExceptionSink* xsink = 0)
const {
377 rc = ::write(fd, buf, len);
379 if (rc >= 0 || errno != EINTR)
384 do_write_event_unlocked(rc, rc, len);
385 }
else if (xsink && rc < 0) {
386 xsink->
raiseErrnoException(
"FILE-WRITE-ERROR", errno,
"failed writing " QSD
" byte%s to File", len,
387 len == 1 ?
"" :
"s");
394 DLLLOCAL
int readChar()
const {
395 unsigned char ch = 0;
396 if (read(&ch, 1) != 1)
402 DLLLOCAL
int readUnicode(
int* n_len = 0)
const;
404 DLLLOCAL
qore_offset_t readData(
void* dest,
size_t limit,
int timeout_ms,
const char* mname,
407 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
409 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in "
410 "ReadOnlyFile::%s()", timeout_ms, mname);
416 rc = ::read(fd, dest, limit);
423 if (errno != EINTR) {
424 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file in ReadOnlyFile::%s()",
434 return q_read_string(xsink, size, charset, std::bind(&qore_qf_private::readData,
this, _1, _2, timeout_ms,
439 size_t bs = size > 0 && size < DEFAULT_FILE_BUFSIZE ? size : DEFAULT_FILE_BUFSIZE;
441 char* buf = (
char* )malloc(
sizeof(
char) * bs);
446 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
448 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in "
449 "ReadOnlyFile::%s()", timeout_ms, mname);
456 rc = ::read(fd, buf, bs);
460 if (errno != EINTR) {
461 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file after " QSD
" bytes "
462 "read in File::%s()", br, mname);
471 bbuf = (
char* )realloc(bbuf, br + rc + 1);
473 memcpy(bbuf + br, buf, rc);
476 do_read_event_unlocked(rc, br, size);
481 if (br >= (
size_t)size)
498 int rc = readLine(**str, incl_eol);
501 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
505 return rc == -1 ? 0 : str.release();
508 DLLLOCAL
int readLine(
QoreString& str,
bool incl_eol =
true) {
512 assert(!in_non_block);
517 bool tty = (bool)isatty(fd);
521 while ((ch = readChar()) >= 0) {
536 lseek(fd, -1, SEEK_CUR);
555 DLLLOCAL
int readUntil(
char byte,
QoreString& str,
bool incl_byte =
true) {
559 assert(!in_non_block);
566 while ((ch = readChar()) >= 0) {
584 int rc = readUntil(bytes, **str, incl_bytes);
587 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
591 return rc == -1 ? 0 : str.release();
594 DLLLOCAL
int readLineUnicode(
QoreString& str,
bool incl_eol =
true) {
598 assert(!in_non_block);
603 bool tty = (bool)isatty(fd);
607 while ((ch = readUnicode()) >= 0) {
621 char c = str[str.
size() - 1];
627 ch = readUnicode(&len);
635 lseek(fd, -len, SEEK_CUR);
654 DLLLOCAL
int readUntilUnicode(
char byte,
QoreString& str,
bool incl_byte =
true) {
658 assert(!in_non_block);
665 while ((ch = readUnicode()) >= 0) {
687 DLLLOCAL
int readUntilUnicode(
const char* bytes,
QoreString& str,
bool incl_bytes) {
691 assert(!in_non_block);
701 while ((ch = readUnicode()) >= 0) {
715 if (ch == bytes[pos]) {
729 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
748 DLLLOCAL
int readUntil(
const char* bytes,
QoreString& str,
bool incl_bytes) {
750 return readUntil(bytes[0], str, incl_bytes);
755 assert(!in_non_block);
765 while ((ch = readChar()) >= 0) {
771 if (c == bytes[pos]) {
785 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
803 DLLLOCAL
bool isTty()
const {
805 assert(!in_non_block);
810 return (
bool)isatty(fd);
813 DLLLOCAL
int detachFd() {
815 assert(!in_non_block);
829 DLLLOCAL
size_t getPos()
const {
831 assert(!in_non_block);
836 return lseek(fd, 0, SEEK_CUR);
839 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_FILE)
const {
858 event_queue->deref(xsink);
862 event_data = with_data;
872 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
879 event_queue->deref(xsink);
880 event_queue =
nullptr;
884 DLLLOCAL
void do_open_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
891 event_queue->pushAndTakeRef(h);
895 DLLLOCAL
void do_opened_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
898 h->
setKeyValue(
"source", QORE_SOURCE_FILE,
nullptr);
904 event_queue->pushAndTakeRef(h);
908 DLLLOCAL
void do_close_event_unlocked()
const {
910 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
914 DLLLOCAL
void do_read_event_unlocked(
int bytes_read,
int total_read,
int bufsize)
const {
921 event_queue->pushAndTakeRef(h);
925 DLLLOCAL
void do_write_event_unlocked(
int bytes_written,
int total_written,
int bufsize)
const {
930 h->
setKeyValue(
"total_written", total_written,
nullptr);
931 h->
setKeyValue(
"total_to_write", bufsize,
nullptr);
932 event_queue->pushAndTakeRef(h);
938 if (checkNonBlock(xsink)) {
942 if (checkReadOpen(xsink))
946 if (fstat(fd, &sbuf)) {
951 return stat_to_list(sbuf);
956 if (checkNonBlock(xsink)) {
960 if (checkReadOpen(xsink))
964 if (fstat(fd, &sbuf)) {
969 return stat_to_hash(sbuf);
975 if (checkNonBlock(xsink)) {
979 if (checkReadOpen(xsink))
982 hashdecl statvfs vfs;
983#ifdef HAVE_SYS_STATVFS_H
984 if (fstatvfs(fd, &vfs)) {
989 if (q_fstatvfs(filename.c_str(), &vfs)) {
995 return statvfs_to_hash(vfs);
999 DLLLOCAL AbstractPollState* startRead(
ExceptionSink* xsink, ssize_t bytes);
1002 DLLLOCAL
int setNonBlockingIo(
bool non_blocking,
ExceptionSink* xsink);
1010 xsink->
raiseException(
"FILE-NON-BLOCK-ERROR",
"a non-blocking operation is currently in progress");
1018 DLLLOCAL
int setNonBlock(
ExceptionSink* xsink,
bool do_io =
true) {
1022 if (!checkNonBlock(xsink) && (!do_io || !setNonBlockingIo(
true, xsink))) {
1023 in_non_block =
true;
1035 setNonBlockingIo(
false, xsink);
1036 in_non_block =
false;
DLLEXPORT const QoreEncoding * QCS_UTF16
UTF-16 (only UTF-* are multi-byte encodings)
Definition: QoreEncoding.h:248
DLLEXPORT const QoreEncoding * QCS_UTF16LE
UTF-16LE (only UTF-* are multi-byte encodings)
Definition: QoreEncoding.h:250
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack,...
Definition: QoreThreadLock.h:136
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
DLLEXPORT AbstractQoreNode * raiseErrnoException(const char *err, int en, const char *fmt,...)
appends a Qore-language exception to the list and appends the result of strerror(errno) to the descri...
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
DLLEXPORT const char * getCode() const
returns the string code (ex: "UTF-8") for the encoding
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:60
DLLEXPORT void clear()
unconditionally set the QoreValue to QoreNothingNode (does not dereference any possible contained Abs...
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT size_t strlen() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change
DLLEXPORT void terminate(size_t size)
terminates the string at byte position "size", the string is reallocated if necessary
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
DLLEXPORT size_t size() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT bool empty() const
returns true if the string is empty, false if not
DLLEXPORT int concatUnicode(unsigned code, ExceptionSink *xsink)
append a character sequence from a unicode code point (returns 0 for OK, -1 for exception)
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
DLLLOCAL int trylock()
attempts to acquire the mutex and returns the status immediately; does not block
Definition: QoreThreadLock.h:101
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:276
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself