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);
306 rc = ::read(fd, buf, bs);
308 if (rc >= 0 || errno != EINTR)
313 do_read_event_unlocked(rc, rc, bs);
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 qore_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);
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() {
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);
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
DLLEXPORT bool empty() const
returns true if the string is empty, false if not
This is the hash or associative list container type in Qore, dynamically allocated only...
Definition: QoreHashNode.h:50
DLLEXPORT const QoreEncoding * QCS_UTF16
UTF-16 (only UTF-8 and UTF-16* are multi-byte encodings)
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
size_t qore_size_t
used for sizes (same range as a pointer)
Definition: common.h:73
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...
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:81
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack...
Definition: QoreThreadLock.h:128
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
DLLEXPORT qore_size_t strlen() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT const char * getCode() const
returns the string code (ex: "UTF-8") for the encoding
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
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
DLLEXPORT void terminate(qore_size_t size)
terminates the string at byte position "size", the string is reallocated if necessary ...
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
DLLEXPORT int concatUnicode(unsigned code, ExceptionSink *xsink)
append a character sequence from a unicode code point (returns 0 for OK, -1 for exception) ...
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:47
DLLEXPORT const QoreEncoding * QCS_UTF16LE
UTF-16LE (only UTF-8 and UTF-16* are multi-byte encodings)
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change ...
DLLEXPORT qore_size_t size() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values ...