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