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"
48 #include <sys/types.h>
53 #elif defined HAVE_SELECT
54 #include <sys/select.h>
55 #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
58 #error no async I/O APIs available
61 #ifndef DEFAULT_FILE_BUFSIZE
62 #define DEFAULT_FILE_BUFSIZE 16384
65 hashdecl qore_qf_private {
68 bool special_file =
false;
72 Queue* event_queue =
nullptr;
76 bool event_data =
false;
78 DLLLOCAL qore_qf_private(
const QoreEncoding* cs) : charset(cs) {
81 DLLLOCAL ~qore_qf_private() {
88 DLLLOCAL
int close_intern(
bool detach =
false) {
98 do_close_event_unlocked();
108 DLLLOCAL
int redirect(qore_qf_private& file,
ExceptionSink* xsink) {
117 int rc = dup2(file.fd, fd);
122 filename = file.filename;
127 DLLLOCAL
int open_intern(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
135 if (!(flags & O_TEXT))
139 do_open_event_unlocked(fn, flags, mode, cs);
141 fd = ::open(fn, flags, mode);
145 do_opened_event_unlocked(fn, flags, mode, cs);
154 DLLLOCAL
int open(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
155 if (!fn || special_file)
159 return open_intern(fn, flags, mode, cs);
167 xsink->
raiseException(
"FILE-READ-ERROR",
"file has not been opened");
176 xsink->
raiseException(
"FILE-WRITE-ERROR",
"file has not been opened");
185 xsink->
raiseException(
"FILE-OPERATION-ERROR",
"file has not been opened");
189 DLLLOCAL
bool isOpen()
const {
193 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
ExceptionSink *xsink)
const {
196 if (check_read_open(xsink))
199 return isDataAvailableIntern(timeout_ms,
"isDataAvailable", xsink);
208 DLLLOCAL
int select(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
210 if (check_open(xsink))
213 #if defined HAVE_POLL
214 return poll_intern(timeout_ms, read, mname, xsink);
215 #elif defined HAVE_SELECT
216 return select_intern(timeout_ms, read, mname, xsink);
218 #error no async I/O operations supported
222 #if defined HAVE_POLL
223 DLLLOCAL
int poll_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
225 pollfd fds = {fd, (short)(read ? POLLIN : POLLOUT), 0};
227 rc = poll(&fds, 1, timeout_ms);
228 if (rc == -1 && errno == EINTR)
233 xsink->
raiseException(
"FILE-SELECT-ERROR",
"poll(2) returned an error in call to File::%s()", mname);
234 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
239 #elif defined HAVE_SELECT
240 DLLLOCAL
int select_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
241 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
246 if (fd >= FD_SETSIZE) {
248 xsink->
raiseException(
"FILE-SELECT-ERROR",
"fd is %d in call to File::%s() which is >= %d; contact the Qore developers to implement an alternative to select() on this platform", fd, mname, FD_SETSIZE);
260 tv.tv_sec = timeout_ms / 1000;
261 tv.tv_usec = (timeout_ms % 1000) * 1000;
263 rc = read ? ::select(fd + 1, &sfs, 0, 0, &tv) : ::select(fd + 1, 0, &sfs, 0, &tv);
264 if (rc >= 0 || errno != EINTR)
269 xsink->
raiseException(
"FILE-SELECT-ERROR",
"select(2) returned an error in call to File::%s()", mname);
278 DLLLOCAL
bool isDataAvailableIntern(
int timeout_ms,
const char* mname,
ExceptionSink *xsink)
const {
279 return select(timeout_ms,
true, mname, xsink);
282 #ifdef HAVE_TERMIOS_H
283 DLLLOCAL
int setTerminalAttributes(
int action, QoreTermIOS* ios,
ExceptionSink* xsink)
const {
286 if (check_open(xsink))
289 return ios->set(fd, action, xsink);
292 DLLLOCAL
int getTerminalAttributes(QoreTermIOS* ios,
ExceptionSink* xsink)
const {
295 if (check_open(xsink))
298 return ios->get(fd, xsink);
303 DLLLOCAL
size_t read(
void *buf,
size_t bs)
const {
306 rc = ::read(fd, buf, bs);
308 if (rc >= 0 || errno != EINTR)
313 do_read_event_unlocked(rc, rc, bs);
319 DLLLOCAL
size_t write(
const void* buf,
size_t len,
ExceptionSink* xsink = 0)
const {
322 rc = ::write(fd, buf, len);
324 if (rc >= 0 || errno != EINTR)
329 do_write_event_unlocked(rc, rc, len);
330 else if (xsink && rc < 0)
331 xsink->
raiseErrnoException(
"FILE-WRITE-ERROR", errno,
"failed writing " QSD
" byte%s to File", len, len == 1 ?
"" :
"s");
337 DLLLOCAL
int readChar()
const {
338 unsigned char ch = 0;
339 if (read(&ch, 1) != 1)
345 DLLLOCAL
int readUnicode(
int* n_len = 0)
const;
349 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
351 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
357 rc = ::read(fd, dest, limit);
361 if (errno != EINTR) {
362 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file in ReadOnlyFile::%s()", mname);
371 return q_read_string(xsink, size, charset, std::bind(&qore_qf_private::readData,
this, _1, _2, timeout_ms, mname, _3));
375 size_t bs = size > 0 && size < DEFAULT_FILE_BUFSIZE ? size : DEFAULT_FILE_BUFSIZE;
377 char* buf = (
char* )malloc(
sizeof(
char) * bs);
382 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
384 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
391 rc = ::read(fd, buf, bs);
395 if (errno != EINTR) {
396 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file after " QSD
" bytes read in File::%s()", br, mname);
405 bbuf = (
char* )realloc(bbuf, br + rc + 1);
407 memcpy(bbuf + br, buf, rc);
410 do_read_event_unlocked(rc, br, size);
415 if (br >= (
size_t)size)
432 int rc = readLine(**str, incl_eol);
435 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
439 return rc == -1 ? 0 : str.release();
442 DLLLOCAL
int readLine(
QoreString& str,
bool incl_eol =
true) {
450 bool tty = (bool)isatty(fd);
454 while ((ch = readChar()) >= 0) {
469 lseek(fd, -1, SEEK_CUR);
488 DLLLOCAL
int readUntil(
char byte,
QoreString& str,
bool incl_byte =
true) {
498 while ((ch = readChar()) >= 0) {
516 int rc = readUntil(bytes, **str, incl_bytes);
519 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
523 return rc == -1 ? 0 : str.release();
526 DLLLOCAL
int readLineUnicode(
QoreString& str,
bool incl_eol =
true) {
534 bool tty = (bool)isatty(fd);
538 while ((ch = readUnicode()) >= 0) {
552 char c = str[str.
size() - 1];
558 ch = readUnicode(&len);
566 lseek(fd, -len, SEEK_CUR);
585 DLLLOCAL
int readUntilUnicode(
char byte,
QoreString& str,
bool incl_byte =
true) {
595 while ((ch = readUnicode()) >= 0) {
617 DLLLOCAL
int readUntilUnicode(
const char* bytes,
QoreString& str,
bool incl_bytes) {
630 while ((ch = readUnicode()) >= 0) {
644 if (ch == bytes[pos]) {
658 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
677 DLLLOCAL
int readUntil(
const char* bytes,
QoreString& str,
bool incl_bytes) {
679 return readUntil(bytes[0], str, incl_bytes);
693 while ((ch = readChar()) >= 0) {
699 if (c == bytes[pos]) {
713 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
731 DLLLOCAL
bool isTty()
const {
737 return (
bool)isatty(fd);
740 DLLLOCAL
int detachFd() {
755 DLLLOCAL
size_t getPos()
const {
761 return lseek(fd, 0, SEEK_CUR);
764 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_FILE)
const {
783 event_queue->deref(xsink);
787 event_data = with_data;
797 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
804 event_queue->deref(xsink);
805 event_queue =
nullptr;
809 DLLLOCAL
void do_open_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
816 event_queue->pushAndTakeRef(h);
820 DLLLOCAL
void do_opened_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
823 h->
setKeyValue(
"source", QORE_SOURCE_FILE,
nullptr);
829 event_queue->pushAndTakeRef(h);
833 DLLLOCAL
void do_close_event_unlocked()
const {
835 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
839 DLLLOCAL
void do_read_event_unlocked(
int bytes_read,
int total_read,
int bufsize)
const {
846 event_queue->pushAndTakeRef(h);
850 DLLLOCAL
void do_write_event_unlocked(
int bytes_written,
int total_written,
int bufsize)
const {
855 h->
setKeyValue(
"total_written", total_written,
nullptr);
856 h->
setKeyValue(
"total_to_write", bufsize,
nullptr);
857 event_queue->pushAndTakeRef(h);
864 if (check_read_open(xsink))
868 if (fstat(fd, &sbuf)) {
873 return stat_to_list(sbuf);
879 if (check_read_open(xsink))
883 if (fstat(fd, &sbuf)) {
888 return stat_to_hash(sbuf);
891 #ifdef Q_HAVE_STATVFS
895 if (check_read_open(xsink))
898 hashdecl statvfs vfs;
899 #ifdef HAVE_SYS_STATVFS_H
900 if (fstatvfs(fd, &vfs)) {
905 if (q_fstatvfs(filename.c_str(), &vfs)) {
911 return statvfs_to_hash(vfs);
DLLEXPORT const QoreEncoding * QCS_UTF16
UTF-16 (only UTF-8 and UTF-16* are multi-byte encodings)
Definition: QoreEncoding.h:248
DLLEXPORT const QoreEncoding * QCS_UTF16LE
UTF-16LE (only UTF-8 and UTF-16* 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:48
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...
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
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
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 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)
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
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:275
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