QU_open() user-redefinable

Synopsis

     #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.

Description

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:

  1. Set up the default stream options through QU_stream_param().
  2. Changes the stream options obtained in the previous step based on the options specified in open/4.
  3. Calls QU_open() with the stream options resulted in the previous two steps to create the stream.
  4. Register the stream created by QU_open() through QP_register_stream().
  5. Converts the stream pointer returned by 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.

  1. The stream options are specified as a parameter in a call to QU_open(), so QU_open() does not need to call QU_stream_param().
  2. 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.
  3. 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.

Return Value

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.

Examples

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;
         }
     

See Also

open/4, QU_fdopen() fli-ios