diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
commit | 3950ffe2a485479f6561c27364d3d7df5a21d124 (patch) | |
tree | 468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/sfio/sfwrite.c | |
download | ksh-upstream.tar.gz |
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/sfio/sfwrite.c')
-rw-r--r-- | src/lib/libast/sfio/sfwrite.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/lib/libast/sfio/sfwrite.c b/src/lib/libast/sfio/sfwrite.c new file mode 100644 index 0000000..170c863 --- /dev/null +++ b/src/lib/libast/sfio/sfwrite.c @@ -0,0 +1,171 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#include "sfhdr.h" + +/* Write data out to the file system +** +** Written by Kiem-Phong Vo. +*/ + +#if __STD_C +ssize_t sfwrite(Sfio_t* f, const Void_t* buf, size_t n) +#else +ssize_t sfwrite(f,buf,n) +Sfio_t* f; /* write to this stream. */ +Void_t* buf; /* buffer to be written. */ +size_t n; /* number of bytes. */ +#endif +{ + reg uchar *s, *begs, *next; + reg ssize_t w; + reg int local; + SFMTXDECL(f); + + SFMTXENTER(f, (ssize_t)(-1)); + + GETLOCAL(f,local); + + if(!buf) + SFMTXRETURN(f, (ssize_t)(n == 0 ? 0 : -1) ); + + /* release peek lock */ + if(f->mode&SF_PEEK) + { if(!(f->mode&SF_WRITE) && (f->flags&SF_RDWR) != SF_RDWR) + SFMTXRETURN(f, (ssize_t)(-1)); + + if((uchar*)buf != f->next && + (!f->rsrv || f->rsrv->data != (uchar*)buf) ) + SFMTXRETURN(f, (ssize_t)(-1)); + + f->mode &= ~SF_PEEK; + + if(f->mode&SF_PKRD) + { /* read past peeked data */ + char buf[16]; + reg ssize_t r; + + for(w = n; w > 0; ) + { if((r = w) > sizeof(buf)) + r = sizeof(buf); + if((r = sysreadf(f->file,buf,r)) <= 0) + { n -= w; + break; + } + else w -= r; + } + + f->mode &= ~SF_PKRD; + f->endb = f->data + n; + f->here += n; + } + + if((f->mode&SF_READ) && f->proc) + f->next += n; + } + + s = begs = (uchar*)buf; + for(;; f->mode &= ~SF_LOCK) + { /* check stream mode */ + if(SFMODE(f,local) != SF_WRITE && _sfmode(f,SF_WRITE,local) < 0 ) + { w = s > begs ? s-begs : -1; + SFMTXRETURN(f,w); + } + + SFLOCK(f,local); + + w = f->endb - f->next; + + if(s == f->next) /* after sfreserve */ + { if(w > (ssize_t)n) + w = (ssize_t)n; + f->next = (s += w); + n -= w; + break; + } + + /* attempt to create space in buffer */ + if(w == 0 || ((f->flags&SF_WHOLE) && w < (ssize_t)n) ) + { if(f->flags&SF_STRING) /* extend buffer */ + { (void)SFWR(f, s, n-w, f->disc); + if((w = f->endb - f->next) < (ssize_t)n) + { if(!(f->flags&SF_STRING)) /* maybe sftmp */ + { if(f->next > f->data) + goto fls_buf; + } + else if(w == 0) + break; + } + } + else if(f->next > f->data) + { fls_buf: + (void)SFFLSBUF(f, -1); + if((w = f->endb - f->next) < (ssize_t)n && + (f->flags&SF_WHOLE) && f->next > f->data ) + break; + } + } + + if(!(f->flags&SF_STRING) && f->next == f->data && + (((f->flags&SF_WHOLE) && w <= n) || SFDIRECT(f,n)) ) + { /* bypass buffering */ + if((w = SFWR(f,s,n,f->disc)) <= 0 ) + break; + } + else + { if(w > (ssize_t)n) + w = (ssize_t)n; + if(w <= 0) /* no forward progress possible */ + break; + memmove(f->next, s, w); + f->next += w; + } + + s += w; + if((n -= w) <= 0) + break; + } + + /* always flush buffer for share streams */ + if(f->extent < 0 && (f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC) ) + (void)SFFLSBUF(f,-1); + + /* check to see if buffer should be flushed */ + else if(n == 0 && (f->flags&SF_LINE) && !(f->flags&SF_STRING)) + { if((ssize_t)(n = f->next-f->data) > (w = s-begs)) + n = w; + if(n > 0 && n < HIFORLINE) + { for(next = f->next-1; n > 0; --n, --next) + { if(*next == '\n') + { n = HIFORLINE; + break; + } + } + } + if(n >= HIFORLINE) + (void)SFFLSBUF(f,-1); + } + + SFOPEN(f,local); + + w = s-begs; + SFMTXRETURN(f,w); +} |