designing an interface for FILE*

36 views
Skip to first unread message

luserdroog

unread,
Nov 3, 2016, 6:11:29 PM11/3/16
to xpost-discuss
Initial post
led to POSIX fmemopen() to avoid using a tempfile for string input to
the interpreter.

But I still need another interface over the postscript filetype objects to support filtered files, initially for `eexec`.

luserdroog

unread,
Nov 4, 2016, 2:11:56 AM11/4/16
to xpost-discuss
So currently we have these functions for files, in xpost_file.h:

Xpost_Object xpost_file_cons(Xpost_Memory_File *mem, /*@NULL@*/ const FILE *fp);
/**
 * @brief Read a byte from FILE*.
 */
int xpost_file_getc(FILE *in);
/**
 * @brief Open and construct a file object given filename and mode.
 */
int xpost_file_open(Xpost_Memory_File *mem, char *fn, char *mode, Xpost_Object *retval);
/**
 * @brief Return the FILE* from the file object.
 */
FILE *xpost_file_get_file_pointer(Xpost_Memory_File *mem, Xpost_Object f);
/**
 * @brief Get the status of the file object.
 */
int xpost_file_get_status(Xpost_Memory_File *mem, Xpost_Object f);
/**
 * @brief Return number of bytes available to read.
 */
int xpost_file_get_bytes_available(Xpost_Memory_File *mem, Xpost_Object f, int *retval);
/**
 * @brief Close the file and deallocate the descriptor in VM.
 */
int xpost_file_close(Xpost_Memory_File *mem, Xpost_Object f);
/**
 * @brief Read a byte from file object.
 */
Xpost_Object xpost_file_read_byte(Xpost_Memory_File *mem, Xpost_Object f);
/**
 * @brief Write a byte to a file object.
 */
int xpost_file_write_byte(Xpost_Memory_File *mem, Xpost_Object f, Xpost_Object b);
/**
 

Now the problem is the "escape valve" function which gives the real FILE*.

functions in xpost_op_file.c and xpost_op_token.c use this to do these things to files:

fputc()
fread()
fwrite()
fflush()
__fpurge()
fungetc()
ftell()
fseek()

read and write can be factored down to getc and putc, but all the rest will need interfacing, I fear.

luserdroog

unread,
Nov 8, 2016, 3:17:20 AM11/8/16
to xpost-discuss
Here's half of it. Added the extensible interfaced file type and the implementation for regular files to support the existing functionality. The other half will be the rest of the operator functions (which are also a mess). But I need to rest up now. :)

diff --git a/src/lib/xpost_file.c b/src/lib/xpost_file.c
index 15a2877..d6967f2 100644
--- a/src/lib/xpost_file.c
+++ b/src/lib/xpost_file.c
@@ -58,6 +58,10 @@ void *alloca (size_t);
 # endif
 #endif
 
+#ifndef _WIN32
+# include <stdio_ext.h> /* __fpurge */
+#endif
+
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
@@ -118,13 +122,58 @@ f_tmpfile(void)
 # define f_tmpfile tmpfile
 #endif
 
-/* interface fgetc
-   in preparation for more elaborate cross-platform non-blocking mechanisms
-cf. http://stackoverflow.com/questions/20428616/how-to-handle-window-events-while-waiting-for-terminal-input
-and http://stackoverflow.com/questions/25506324/how-to-do-pollstdin-or-selectstdin-when-stdin-is-a-windows-console
-   */
-int xpost_file_getc(FILE *in){
-    return fgetc(in);
+int disk_readch(Xpost_File file){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return fgetc(df->file);
+}
+
+int disk_writech(Xpost_File file, int c){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return fputc(c, df->file);
+}
+
+int disk_close(Xpost_File file){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    int ret = fclose(df->file);
+    return df->file = NULL, ret;
+}
+
+int disk_flush(Xpost_File file){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return fflush(df->file);
+}
+
+int disk_purge(Xpost_File file){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return __fpurge(df->file);
+}
+
+int disk_unreadch(Xpost_File file, int c){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return ungetc(c, df->file);
+}
+
+long disk_tell(Xpost_File file){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return ftell(df->file);
+}
+
+int disk_seek(Xpost_File file, long offset){
+    Xpost_DiskFile df = (Xpost_DiskFile) file;
+    return fseek(df->file, offset, SEEK_SET);
+}
+
+Xpost_File_Methods disk_methods = &(struct Xpost_File_Methods){
+    disk_readch, disk_writech, disk_close, disk_flush, disk_purge, disk_unreadch, disktell, diskseek
+};
+
+Xpost_File xpost_diskfile_open(FILE *fp){
+    Xpost_DiskFile df = malloc(sizeof *df);
+    if (df) {
+        df->methods = disk_methods;
+        df->file = fp;
+    }
+    return (Xpost_File)df;
 }
 
 /* filetype objects use a slightly different interpretation
@@ -152,19 +201,21 @@ Xpost_Object xpost_file_cons(Xpost_Memory_File *mem,
     Xpost_Object f;
     unsigned int ent;
     int ret;
+    Xpost_File df;
 
 #ifdef DEBUG_FILE
     printf("xpost_file_cons %p\n", fp);
 #endif
     f.tag = filetype /*| (XPOST_OBJECT_TAG_ACCESS_UNLIMITED << XPOST_OBJECT_TAG_DATA_FLAG_ACCESS_OFFSET)*/;
+    df = xpost_diskfile_open(fp);
     /* xpost_memory_table_alloc(mem, sizeof(FILE *), 0, &f.mark_.padw); */
-    if (!xpost_memory_table_alloc(mem, sizeof(FILE *), filetype, &ent))
+    if (!xpost_memory_table_alloc(mem, sizeof df, filetype, &ent))
     {
         XPOST_LOG_ERR("cannot allocate file record");
         return invalid;
     }
     f.mark_.padw = ent;
-    ret = xpost_memory_put(mem, f.mark_.padw, 0, sizeof(FILE *), &fp);
+    ret = xpost_memory_put(mem, f.mark_.padw, 0, sizeof df, &df);
     if (!ret)
     {
         XPOST_LOG_ERR("cannot save FILE* in VM");
@@ -384,13 +435,13 @@ int xpost_file_open(Xpost_Memory_File *mem,
 /* adapter:
            FILE* <- filetype object
    yield the FILE* from a filetype object */
-FILE *xpost_file_get_file_pointer(Xpost_Memory_File *mem,
+Xpost_File xpost_file_get_file_pointer(Xpost_Memory_File *mem,
                                   Xpost_Object f)
 {
-    FILE *fp;
+    Xpost_File fp;
     int ret;
 
-    ret = xpost_memory_get(mem, f.mark_.padw, 0, sizeof(FILE *), &fp);
+    ret = xpost_memory_get(mem, f.mark_.padw, 0, sizeof fp, &fp);
     if (!ret)
     {
         return NULL;
@@ -405,6 +456,7 @@ int xpost_file_get_status(Xpost_Memory_File *mem,
     return xpost_file_get_file_pointer(mem, f) != NULL;
 }
 
+//FIXME assumes DiskFile subtype
 /* call fstat. */

 int xpost_file_get_bytes_available(Xpost_Memory_File *mem,
                                    Xpost_Object f,
@@ -415,7 +467,7 @@ int xpost_file_get_bytes_available(Xpost_Memory_File *mem,
     struct stat sb;
     long sz, pos;
 
-    fp = xpost_file_get_file_pointer(mem, f);
+    fp = (*(Xpost_DiskFile)xpost_file_get_file_pointer(mem, f))->file;
     if (!fp) return ioerror;
     ret = fstat(fileno(fp), &sb);
     if (ret != 0)
@@ -437,10 +489,10 @@ int xpost_file_get_bytes_available(Xpost_Memory_File *mem,
 
 /* close the file,
    NULL the FILE*. */
-int xpost_file_close(Xpost_Memory_File *mem,
+int xpost_file_object_close(Xpost_Memory_File *mem,
                      Xpost_Object f)
 {
-    FILE *fp;
+    Xpost_File fp;
     int ret;
 
     fp = xpost_file_get_file_pointer(mem, f);
@@ -451,9 +503,9 @@ int xpost_file_close(Xpost_Memory_File *mem,
         if (fp == stdin || fp == stdout || fp == stderr) /* do NOT close standard files */
             return 0;
 
-        fclose(fp);
+        xpost_file_close(fp);
         fp = NULL;
-        ret = xpost_memory_put(mem, f.mark_.padw, 0, sizeof(FILE *), &fp);
+        ret = xpost_memory_put(mem, f.mark_.padw, 0, sizeof fp, &fp);
         if (!ret)
         {
             XPOST_LOG_ERR("cannot write NULL over FILE* in VM");
@@ -487,7 +539,7 @@ int xpost_file_write_byte(Xpost_Memory_File *mem,
     {
         return ioerror;
     }
-    if (fputc(b.int_.val, xpost_file_get_file_pointer(mem, f)) == EOF)
+    if (xpost_file_putc(xpost_file_get_file_pointer(mem, f), b.int_.val) == EOF)
     {
         return ioerror;
     }
diff --git a/src/lib/xpost_file.h b/src/lib/xpost_file.h
index dcfc894..9d5ff80 100644
--- a/src/lib/xpost_file.h
+++ b/src/lib/xpost_file.h
@@ -43,18 +43,83 @@
 
 /*
    a filetype object uses .mark_.padw to store the ent
-   for the FILE *
+   for the Xpost_File pointer
    */
 
+typedef struct Xpost_File_Methods {
+    int (*readch)(Xpost_File);
+    int (*writech)(Xpost_File, int);
+    int (*close)(Xpost_File *);
+    int (*flush)(Xpost_File);
+    int (*purge)(Xpost_File);
+    int (*unreadch)(Xpost_File, int);
+    long (*tell)(Xpost_File);
+    int (*seek)(Xpost_File, long);
+} *Xpost_File_Methods;
+
+typedef struct Xpost_DiskFile {
+    Xpost_File_Methods methods;
+    FILE *file;
+} *Xpost_DiskFile;
+
+typedef struct Xpost_File {
+    Xpost_File_Methods methods;
+} *Xpost_File;
+
+/* interface fgetc
+   in preparation for more elaborate cross-platform non-blocking mechanisms
+cf. http://stackoverflow.com/questions/20428616/how-to-handle-window-events-while-waiting-for-terminal-input
+and http://stackoverflow.com/questions/25506324/how-to-do-pollstdin-or-selectstdin-when-stdin-is-a-windows-console
+   */
 /**
- * @brief Construct a file object given a FILE*.
+ * @brief Read a byte from an Xpost_File abstraction.
  */
-Xpost_Object xpost_file_cons(Xpost_Memory_File *mem, /*@NULL@*/ const FILE *fp);
+static inline
+int xpost_file_getc(Xpost_File in){
+    return in->methods->readch(in);
+}
+
+static inline
+int xpost_file_putc(Xpost_File out, int c){
+    return out->methods->writech(out, c);
+}
+
+static inline
+int xpost_file_close(Xpost_File f){
+    return f->methods->close(f);
+}
+
+static inline
+int xpost_file_flush(Xpost_File f){
+    return f->methods->flush(f);
+}
+
+static inline
+void xpost_file_purge(Xpost_File f){
+    return f->methods->purge(f);
+}
+
+static inline
+int xpost_file_ungetc(Xpost_File in, int c){
+    return f->methods->unreadch(in, c);
+}
+
+static inline
+long xpost_file_tell(Xpost_File f){
+    return f->methods->tell(f);
+}
+
+static inline
+int xpost_file_seek(Xpost_File f, long offset){
+    return f->methods->seek(f, offset);
+}
+
 
 /**
- * @brief Read a byte from FILE*.
+ * @brief Construct a file object given a FILE*.
  */
-int xpost_file_getc(FILE *in);
+Xpost_Object xpost_file_cons(Xpost_Memory_File *mem, /*@NULL@*/ const FILE *fp);
+

 
 /**
  * @brief Open and construct a file object given filename and mode.
@@ -64,7 +129,7 @@ int xpost_file_open(Xpost_Memory_File *mem, char *fn, char *mode, Xpost_Object *

 /**
  * @brief Return the FILE* from the file object.
  */
-FILE *xpost_file_get_file_pointer(Xpost_Memory_File *mem, Xpost_Object f);
+Xpost_File xpost_file_get_file_pointer(Xpost_Memory_File *mem, Xpost_Object f);

 
 /**
  * @brief Get the status of the file object.
@@ -79,7 +144,7 @@ int xpost_file_get_bytes_available(Xpost_Memory_File *mem, Xpost_Object f, int *

 /**
  * @brief Close the file and deallocate the descriptor in VM.
  */
-int xpost_file_close(Xpost_Memory_File *mem, Xpost_Object f);
+int xpost_file_object_close(Xpost_Memory_File *mem, Xpost_Object f);

 
 /**
  * @brief Read a byte from file object.
diff --git a/src/lib/xpost_op_file.c b/src/lib/xpost_op_file.c
index 313bd43..bf97646 100644
--- a/src/lib/xpost_op_file.c
+++ b/src/lib/xpost_op_file.c
@@ -131,7 +131,7 @@ int xpost_op_file_closefile (Xpost_Context *ctx,
                              Xpost_Object f)
 {
     int ret;
-    ret = xpost_file_close(ctx->lo, f);
+    ret = xpost_file_object_close(ctx->lo, f);
     if (ret)
         return ret;
     return 0;
 
Reply all
Reply to author
Forward
0 new messages