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_SYS_SELECT_H
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 "
249 "the Qore developers to implement an alternative to select() on this platform", fd, mname,
262 tv.tv_sec = timeout_ms / 1000;
263 tv.tv_usec = (timeout_ms % 1000) * 1000;
265 rc = read ? ::select(fd + 1, &sfs, 0, 0, &tv) : ::select(fd + 1, 0, &sfs, 0, &tv);
266 if (rc >= 0 || errno != EINTR)
271 xsink->
raiseException(
"FILE-SELECT-ERROR",
"select(2) returned an error in call to File::%s()", mname);
280 DLLLOCAL
bool isDataAvailableIntern(
int timeout_ms,
const char* mname,
ExceptionSink *xsink)
const {
281 return select(timeout_ms,
true, mname, xsink);
284 #ifdef HAVE_TERMIOS_H
285 DLLLOCAL
int setTerminalAttributes(
int action, QoreTermIOS* ios,
ExceptionSink* xsink)
const {
288 if (check_open(xsink))
291 return ios->set(fd, action, xsink);
294 DLLLOCAL
int getTerminalAttributes(QoreTermIOS* ios,
ExceptionSink* xsink)
const {
297 if (check_open(xsink))
300 return ios->get(fd, xsink);
305 DLLLOCAL
size_t read(
void *buf,
size_t bs)
const {
308 rc = ::read(fd, buf, bs);
310 if (rc >= 0 || errno != EINTR)
315 do_read_event_unlocked(rc, rc, bs);
321 DLLLOCAL
size_t write(
const void* buf,
size_t len,
ExceptionSink* xsink = 0)
const {
324 rc = ::write(fd, buf, len);
326 if (rc >= 0 || errno != EINTR)
331 do_write_event_unlocked(rc, rc, len);
332 else if (xsink && rc < 0)
333 xsink->
raiseErrnoException(
"FILE-WRITE-ERROR", errno,
"failed writing " QSD
" byte%s to File", len,
334 len == 1 ?
"" :
"s");
340 DLLLOCAL
int readChar()
const {
341 unsigned char ch = 0;
342 if (read(&ch, 1) != 1)
348 DLLLOCAL
int readUnicode(
int* n_len = 0)
const;
350 DLLLOCAL
qore_offset_t readData(
void* dest,
size_t limit,
int timeout_ms,
const char* mname,
353 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
355 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in "
356 "ReadOnlyFile::%s()", timeout_ms, mname);
362 rc = ::read(fd, dest, limit);
369 if (errno != EINTR) {
370 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file in ReadOnlyFile::%s()",
380 return q_read_string(xsink, size, charset, std::bind(&qore_qf_private::readData,
this, _1, _2, timeout_ms,
385 size_t bs = size > 0 && size < DEFAULT_FILE_BUFSIZE ? size : DEFAULT_FILE_BUFSIZE;
387 char* buf = (
char* )malloc(
sizeof(
char) * bs);
392 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
394 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in "
395 "ReadOnlyFile::%s()", timeout_ms, mname);
402 rc = ::read(fd, buf, bs);
406 if (errno != EINTR) {
407 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file after " QSD
" bytes "
408 "read in File::%s()", br, mname);
417 bbuf = (
char* )realloc(bbuf, br + rc + 1);
419 memcpy(bbuf + br, buf, rc);
422 do_read_event_unlocked(rc, br, size);
427 if (br >= (
size_t)size)
444 int rc = readLine(**str, incl_eol);
447 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
451 return rc == -1 ? 0 : str.release();
454 DLLLOCAL
int readLine(
QoreString& str,
bool incl_eol =
true) {
462 bool tty = (bool)isatty(fd);
466 while ((ch = readChar()) >= 0) {
481 lseek(fd, -1, SEEK_CUR);
500 DLLLOCAL
int readUntil(
char byte,
QoreString& str,
bool incl_byte =
true) {
510 while ((ch = readChar()) >= 0) {
528 int rc = readUntil(bytes, **str, incl_bytes);
531 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
535 return rc == -1 ? 0 : str.release();
538 DLLLOCAL
int readLineUnicode(
QoreString& str,
bool incl_eol =
true) {
546 bool tty = (bool)isatty(fd);
550 while ((ch = readUnicode()) >= 0) {
564 char c = str[str.
size() - 1];
570 ch = readUnicode(&len);
578 lseek(fd, -len, SEEK_CUR);
597 DLLLOCAL
int readUntilUnicode(
char byte,
QoreString& str,
bool incl_byte =
true) {
607 while ((ch = readUnicode()) >= 0) {
629 DLLLOCAL
int readUntilUnicode(
const char* bytes,
QoreString& str,
bool incl_bytes) {
642 while ((ch = readUnicode()) >= 0) {
656 if (ch == bytes[pos]) {
670 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
689 DLLLOCAL
int readUntil(
const char* bytes,
QoreString& str,
bool incl_bytes) {
691 return readUntil(bytes[0], str, incl_bytes);
705 while ((ch = readChar()) >= 0) {
711 if (c == bytes[pos]) {
725 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
743 DLLLOCAL
bool isTty()
const {
749 return (
bool)isatty(fd);
752 DLLLOCAL
int detachFd() {
767 DLLLOCAL
size_t getPos()
const {
773 return lseek(fd, 0, SEEK_CUR);
776 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_FILE)
const {
795 event_queue->deref(xsink);
799 event_data = with_data;
809 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
816 event_queue->deref(xsink);
817 event_queue =
nullptr;
821 DLLLOCAL
void do_open_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
828 event_queue->pushAndTakeRef(h);
832 DLLLOCAL
void do_opened_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
835 h->
setKeyValue(
"source", QORE_SOURCE_FILE,
nullptr);
841 event_queue->pushAndTakeRef(h);
845 DLLLOCAL
void do_close_event_unlocked()
const {
847 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
851 DLLLOCAL
void do_read_event_unlocked(
int bytes_read,
int total_read,
int bufsize)
const {
858 event_queue->pushAndTakeRef(h);
862 DLLLOCAL
void do_write_event_unlocked(
int bytes_written,
int total_written,
int bufsize)
const {
867 h->
setKeyValue(
"total_written", total_written,
nullptr);
868 h->
setKeyValue(
"total_to_write", bufsize,
nullptr);
869 event_queue->pushAndTakeRef(h);
876 if (check_read_open(xsink))
880 if (fstat(fd, &sbuf)) {
885 return stat_to_list(sbuf);
891 if (check_read_open(xsink))
895 if (fstat(fd, &sbuf)) {
900 return stat_to_hash(sbuf);
903 #ifdef Q_HAVE_STATVFS
907 if (check_read_open(xsink))
910 hashdecl statvfs vfs;
911 #ifdef HAVE_SYS_STATVFS_H
912 if (fstatvfs(fd, &vfs)) {
917 if (q_fstatvfs(filename.c_str(), &vfs)) {
923 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