X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Flib%2Fstd%2Fcbits%2FfilePutc.lc;h=cf9ffe1213986923282247e8a75d5d8ef362dc2a;hb=967cc47f37cb93a5e2b6df7822c9a646f0428247;hp=980aa63e507d5ed725828b7d4451ee6ca2dedf8d;hpb=f3211cf9a67d44e99c44ef81190b9d7b50ef2872;p=ghc-hetmet.git diff --git a/ghc/lib/std/cbits/filePutc.lc b/ghc/lib/std/cbits/filePutc.lc index 980aa63..cf9ffe1 100644 --- a/ghc/lib/std/cbits/filePutc.lc +++ b/ghc/lib/std/cbits/filePutc.lc @@ -9,24 +9,79 @@ #include "stgio.h" #include "error.h" +#define TERMINATE_LINE(x) ((x) == '\n') + StgInt -filePutc(fp, c) -StgForeignObj fp; -StgInt c; +filePutc(ptr, c) +StgForeignObj ptr; +StgChar c; { - int rc; + IOFileObject* fo = (IOFileObject*)ptr; + int rc = 0; + + /* What filePutc needs to do: + + - if there's no buffering => write it out. + - if the buffer is line-buffered + write out buffer (+char), iff buffer would be full afterwards || + new char is the newline character + add to buffer , otherwise + - if the buffer is fully-buffered + write out buffer (+char), iff adding char fills up buffer. + add char to buffer, otherwise. + + In the cases where a file is buffered, the invariant is that operations + that fill up a buffer also flushes them. A consequence of this here, is + that we're guaranteed to be passed a buffer with space for (at least) + the one char we're adding. - /* Try to write a character */ - while ((rc = putc((int) c, (FILE *) fp)) == EOF && errno == EINTR) - clearerr((FILE *) fp); + Supporting RW objects adds yet another twist, since we have to make + sure that if such objects have been read from just previously, we + flush(i.e., empty) the buffer first. (We could be smarter about this, + but aren't!) + + */ + + if ( FILEOBJ_READABLE(fo) && FILEOBJ_JUST_READ(fo) ) { + rc = flushReadBuffer(ptr); + if (rc<0) return rc; + } - if (rc == EOF) { + fo->flags = (fo->flags & ~FILEOBJ_RW_READ) | FILEOBJ_RW_WRITE; + + /* check whether we can just add it to the buffer.. */ + if ( FILEOBJ_UNBUFFERED(fo) ) { + ; + } else { + /* We're buffered, add it to the pack */ + ((char*)fo->buf)[fo->bufWPtr] = (char)c; + fo->bufWPtr++; + /* If the buffer filled up as a result, *or* + the added character terminated a line + => flush. + */ + if ( FILEOBJ_BUFFER_FULL(fo) || + (FILEOBJ_LINEBUFFERED(fo) && TERMINATE_LINE(c)) ) { + rc = writeBuffer(ptr, fo->bufWPtr); + /* Undo the write if we're blocking..*/ + if (rc == FILEOBJ_BLOCKED_WRITE ) fo->bufWPtr--; + } + return rc; + } + + if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady(ptr,0) != 1 ) + return FILEOBJ_BLOCKED_WRITE; + + /* Unbuffered, write the character directly. */ + while ((rc = write(fo->fd, &c, 1)) == 0 && errno == EINTR) ; + + if (rc == 0) { cvtErrno(); stdErrno(); return -1; } - return 0; + } \end{code}