QU_open()
user-redefinable#include <quintus/quintus.h> QP_stream *QU_open(stream_option, system_option, error_number) QP_stream *stream_option; char *system_option; int *error_number;
The embedding function for creating a
stream opened through open/[3,4]
or QP_fopen()
.
Creates a stream and returns the QP_stream
pointer for that
stream.
stream_option specifies the options for the stream to be created.
system_option specifies the system-dependent stream option
specified in the option of system(
option)
in open/4
. If there
is no system-dependent option, the system_option
field is the
empty string, ""
.
The functionality of QU_open()
is illustrated in these steps
open/4
uses to create a Prolog stream:
QU_stream_param()
.
open/4
.
QU_open()
with the stream options resulted in the previous two
steps to create the stream.
QU_open()
through QP_register_stream()
.
QU_open()
to the Prolog
representation of the stream through stream_code/2
.
The process required to implement QU_open()
is similar to implementing
a customized Prolog stream. (see fli-ios-cps). There
are only a few differences.
QU_open()
, so QU_open()
does not need to call
QU_stream_param()
.
QU_open()
may need to parse system_option
string to recognize the option specified in that string. Notice that
the core Prolog system itself does not make use of any information
specified in system_option. It simply takes the string specified
in open/4
and passes it to QU_open()
without any alteration.
QU_open()
does not need to register the stream it creates. The
caller of QU_open()
will register it.
Implementation of QU_fdopen()
is similar to QU_open()
except that the
file stream is already opened and the opened file descriptor is
passed through the parameter file_des.
If any error occurs during the creation of
the stream, QP_NULL_STREAM
is returned and the error code
for the error condition is set in the third parameter,
error_number. The error code could be any of the host operating
system error numbers, QP error numbers or a user-defined error number.
QU_fdopen()
requires an addition parameter, file_des,
which is the opened file descriptor for the stream to be created.
The following is the source code for an implementation
of QU_open()
function and QU_fdopen()
function in C.
#include <fcntl.h> #include <errno.h> #include <sys/file.h> #include <sys/types.h> #include <sys/stat.h> #ifndef L_SET #define L_SET 0 #endif #ifndef L_INCR #define L_INCR 1 #endif #ifndef L_XTND #define L_XTND 2 #endif #include <quintus/quintus.h> extern char *ttyname();
QP_stream * QU_fdopen(option, sys_option, error_num, file_des) QP_stream *option; char *sys_option; int *error_num, file_des; { QP_stream *stream; extern long lseek(); extern QP_stream *QU_tty_open(), *QU_text_open(), *QU_raw_open(); if (sys_option && *sys_option != '\0') { *error_num = QP_E_SYS_OPTION; return QP_NULL_STREAM; } *error_num = 0; if (option->format == QP_FMT_UNKNOWN) { if (option->line_border==QP_NOLB && option->trim==0) option->format = QP_VAR_LEN; /* binary file */ else option->format = QP_DELIM_LF; }
switch (option->mode) { case QP_READ: case QP_WRITE: option->magic.byteno = 0; if (option->seek_type != QP_SEEK_ERROR) { struct stat statbuf; if (fstat(file_des, &statbuf) == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG) if ((option->magic.byteno = lseek(file_des,0L,L_INCR))==-1) { *error_num = errno; return QP_NULL_STREAM; } } break; case QP_APPEND: if ((option->magic.byteno = lseek(file_des,0L,L_XTND)) == -1) { *error_num = errno; return QP_NULL_STREAM; } break; default: *error_num = QP_E_BAD_MODE; return QP_NULL_STREAM; }
switch (option->format) { case QP_DELIM_TTY: stream = QU_tty_open(option, error_num, file_des); break; case QP_DELIM_LF: stream = QU_text_open(option, error_num, file_des); break; case QP_VAR_LEN: stream = QU_raw_open(option, error_num, file_des); break; default: *error_num = QP_E_BAD_FORMAT; return QP_NULL_STREAM; } return stream; }
QP_stream * QU_open(option, sys_option, error_num) QP_stream *option; char *sys_option; /* not useful in this version */ int *error_num; { QP_stream *stream; int fd; char *filename; struct stat statbuf; *error_num = 0; if (! (filename = option->filename)) { *error_num = QP_E_FILENAME; return QP_NULL_STREAM; } switch (option->mode) { case QP_READ: fd = open(filename, O_RDONLY, 0000); break; case QP_WRITE: fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); break; case QP_APPEND: fd = open(filename, O_WRONLY|O_CREAT, 0666); break; default: *error_num = QP_E_BAD_MODE; return QP_NULL_STREAM; }
if (fstat(fd, &statbuf) == 0) { if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { (void) close(fd); *error_num = QP_E_DIRECTORY; return QP_NULL_STREAM; } } if (fd < 0) { *error_num = errno; return QP_NULL_STREAM; } if (option->format == QP_DELIM_TTY && !(isatty(fd)) ) { *error_num = QP_E_BAD_FORMAT; (void) close(fd); return QP_NULL_STREAM; } if ((stream=QU_fdopen(option, sys_option, error_num, fd)) == QP_NULL_STREAM) { (void) close(fd); return QP_NULL_STREAM; } if (stream->format == QP_DELIM_TTY) { char *tty_id; if (! (tty_id = ttyname(fd)) ) tty_id = "/PROLOG DEFAULT TTYS"; (void) QP_add_tty(stream, tty_id); } return stream; }
The following is the source code for the implementation of
QU_tty_open()
in C. QU_tty_open()
is called in the
QU_fdopen()
source code listed above. (QU_text_open()
and
QU_raw_open()
are also called in QU_fdopen()
. The source code for
these two functions is not listed here, but they are shipped with
Quintus Prolog.)
#include <fcntl.h> #include <errno.h> #include <quintus/quintus.h> extern char *QP_malloc(); #define Min_Buffer_Size 4 struct TtyStream { QP_stream qpinfo; int fd; unsigned char buffer[Min_Buffer_Size]; }; #define CoerceTtyStream(x) ((struct TtyStream *)(x)) static int tty_read(stream, bufptr, sizeptr) QP_stream *stream; unsigned char **bufptr; size_t *sizeptr; { int n; extern int errno; register struct TtyStream *u = CoerceTtyStream(stream); n = read(u->fd, (char*)u->buffer, (int)u->qpinfo.max_reclen); if (n > 0) { *bufptr = u->buffer; *sizeptr = n; if (u->buffer[n-1] == '\n') return QP_FULL; else return QP_PART; } else if (n == 0) { *sizeptr = 0; return QP_EOF; } else { u->qpinfo.errno = errno; return QP_ERROR; } }
static int tty_write(stream, bufptr, sizeptr) QP_stream *stream; unsigned char **bufptr; size_t *sizeptr; { struct TtyStream *u = CoerceTtyStream(stream); int n, len=(int) *sizeptr; char *buf = (char *) *bufptr; if (len==0) { /* be sure to set *sizeptr and *bufptr */ *sizeptr = u->qpinfo.max_reclen; *bufptr = u->buffer; return QP_SUCCESS; } while ((n = write(u->fd, buf, len)) > 0 && n < len) { buf += n; len -= n; } if (n >= 0) { *sizeptr = u->qpinfo.max_reclen; *bufptr = u->buffer; return QP_SUCCESS; } else { u->qpinfo.errno = errno; return QP_ERROR; } }
static int tty_close(stream) QP_stream *stream; { struct TtyStream *u = CoerceTtyStream(stream); int fd = u->fd; QP_free(stream); if (close(fd) < 0) return QP_ERROR; return QP_SUCCESS; }
QP_stream * QU_tty_open(option, error_num, fd) register QP_stream *option; int *error_num, fd; { struct TtyStream *stream; if (option->seek_type != QP_SEEK_ERROR) { *error_num = QP_E_SEEK_TYPE; return QP_NULL_STREAM; } stream = (struct TtyStream *) QP_malloc(sizeof(*stream) + ((option->max_reclen <= Min_Buffer_Size) ? 0 : option->max_reclen - Min_Buffer_Size) ); stream->qpinfo = *option; QP_prepare_stream(&stream->qpinfo, stream->buffer); stream->fd = fd; stream->qpinfo.close = tty_close; if (option->mode != QP_READ) { stream->qpinfo.write = stream->qpinfo.flush = tty_write; } else stream->qpinfo.read = tty_read; return (QP_stream *) stream; }
open/4
, QU_fdopen()
fli-ios