[project @ 2000-08-07 23:37:19 by qrczak]
[ghc-hetmet.git] / ghc / lib / std / cbits / fileGetc.c
index 9c7b33f..810ee4c 100644 (file)
@@ -1,36 +1,93 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: fileGetc.c,v 1.1 1998/04/10 10:54:22 simonm Exp $
+ * $Id: fileGetc.c,v 1.6 2000/01/18 12:41:03 simonmar Exp $
  *
  * hGetChar Runtime Support
  */
 
 #include "Rts.h"
 #include "stgio.h"
-#include "error.h"
 
+#define EOT 4
+
+/* Pre-condition: only ever called on a readable fileObject */
 StgInt
-fileGetc(StgAddr fp)
+fileGetc(StgForeignPtr ptr)
 {
-    int c;
+    IOFileObject* fo = (IOFileObject*)ptr;
+    int rc=0;
+    unsigned char c;
+    
+#if 0
+    fprintf(stderr, "fgc: %d %d %d\n", fo->bufRPtr, fo->bufWPtr, fo->flags);
+#endif
+    /*
+      fileGetc does the following:
+       - if the input is buffered, try fetch the char from buffer.
+       - failing that,
+    
+          - if the input stream is 'connected' to an output stream,
+           flush it before requesting any input.
+         - if unbuffered, read in one character.
+         - if line-buffered, read in one line, returning the first.
+         - if block-buffered, fill up block, returning the first.
+    */
 
-    if (feof((FILE *)fp)) {
-       ghc_errtype = ERR_EOF;
-       ghc_errstr = "";
-       return EOF;
+    if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
+        rc = flushBuffer(ptr);
+       if (rc < 0) return rc;
     }
 
-    /* Try to read a character */
-    while ((c = getc((FILE *)fp)) == EOF && errno == EINTR)
-       clearerr((FILE *)fp);
+    fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
 
-    if (feof((FILE *)fp)) {
+    if ( FILEOBJ_IS_EOF(fo) ) {
        ghc_errtype = ERR_EOF;
        ghc_errstr = "";
-    } else if (c == EOF) {
-       cvtErrno();
-       stdErrno();
+       return -1;
+    }
+
+    if ( FILEOBJ_BUFFER_EMPTY(fo) ) {
+       ;
+    } else if ( FILEOBJ_UNBUFFERED(fo) && !FILEOBJ_HAS_PUSHBACKS(fo) ) {
+       ;
+    } else if ( FILEOBJ_UNBUFFERED(fo) ) { /* Unbuffered stream has pushbacks, retrieve them */
+          c=((unsigned char*)(fo->buf))[fo->bufRPtr++];
+         return (int)c;
+    } else {
+          c=((unsigned char*)(fo->buf))[fo->bufRPtr];
+          fo->bufRPtr++;
+         return (int)c;
+    }
+    
+    /* Nothing in the buffer, go out and fetch a byte for our customer,
+       filling up the buffer if needs be.
+    */
+    if ( FILEOBJ_UNBUFFERED(fo) ) {
+       return (readChar(ptr));
+    } else if ( FILEOBJ_LINEBUFFERED(fo) ) {
+
+        /* if input stream is connect to an output stream, flush it first */
+        if ( fo->connectedTo != NULL   &&
+             fo->connectedTo->fd != -1 &&
+            (fo->connectedTo->flags & FILEOBJ_WRITE)  ) {
+           rc = flushFile((StgForeignPtr)fo->connectedTo);
+        }
+        if (rc < 0) return rc;
+
+       rc = fill_up_line_buffer(fo);
+       if (rc < 0) return rc;
+
+        c=((unsigned char*)(fo->buf))[fo->bufRPtr];
+        fo->bufRPtr++;
+        return (int)c;
+
+    } else { /* Fully-buffered */
+        rc = readBlock(ptr);
+       if (rc < 0) return rc;
+  
+        c=((unsigned char*)(fo->buf))[fo->bufRPtr];
+        fo->bufRPtr++;
+        return (int)c;
     }
-    return c;
 }