1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#include "sfhdr.h"
1N/A
1N/A/* Write data out to the file system
1N/A**
1N/A** Written by Kiem-Phong Vo.
1N/A*/
1N/A
1N/A#if __STD_C
1N/Assize_t sfwrite(Sfio_t* f, const Void_t* buf, size_t n)
1N/A#else
1N/Assize_t sfwrite(f,buf,n)
1N/ASfio_t* f; /* write to this stream. */
1N/AVoid_t* buf; /* buffer to be written. */
1N/Asize_t n; /* number of bytes. */
1N/A#endif
1N/A{
1N/A reg uchar *s, *begs, *next;
1N/A reg ssize_t w;
1N/A reg int local;
1N/A SFMTXDECL(f);
1N/A
1N/A SFMTXENTER(f, (ssize_t)(-1));
1N/A
1N/A GETLOCAL(f,local);
1N/A
1N/A if(!buf)
1N/A SFMTXRETURN(f, (ssize_t)(n == 0 ? 0 : -1) );
1N/A
1N/A /* release peek lock */
1N/A if(f->mode&SF_PEEK)
1N/A { if(!(f->mode&SF_WRITE) && (f->flags&SF_RDWR) != SF_RDWR)
1N/A SFMTXRETURN(f, (ssize_t)(-1));
1N/A
1N/A if((uchar*)buf != f->next &&
1N/A (!f->rsrv || f->rsrv->data != (uchar*)buf) )
1N/A SFMTXRETURN(f, (ssize_t)(-1));
1N/A
1N/A f->mode &= ~SF_PEEK;
1N/A
1N/A if(f->mode&SF_PKRD)
1N/A { /* read past peeked data */
1N/A char buf[16];
1N/A reg ssize_t r;
1N/A
1N/A for(w = n; w > 0; )
1N/A { if((r = w) > sizeof(buf))
1N/A r = sizeof(buf);
1N/A if((r = sysreadf(f->file,buf,r)) <= 0)
1N/A { n -= w;
1N/A break;
1N/A }
1N/A else w -= r;
1N/A }
1N/A
1N/A f->mode &= ~SF_PKRD;
1N/A f->endb = f->data + n;
1N/A f->here += n;
1N/A }
1N/A
1N/A if((f->mode&SF_READ) && f->proc)
1N/A f->next += n;
1N/A }
1N/A
1N/A s = begs = (uchar*)buf;
1N/A for(;; f->mode &= ~SF_LOCK)
1N/A { /* check stream mode */
1N/A if(SFMODE(f,local) != SF_WRITE && _sfmode(f,SF_WRITE,local) < 0 )
1N/A { w = s > begs ? s-begs : -1;
1N/A SFMTXRETURN(f,w);
1N/A }
1N/A
1N/A SFLOCK(f,local);
1N/A
1N/A w = f->endb - f->next;
1N/A
1N/A if(s == f->next) /* after sfreserve */
1N/A { if(w > (ssize_t)n)
1N/A w = (ssize_t)n;
1N/A f->next = (s += w);
1N/A n -= w;
1N/A break;
1N/A }
1N/A
1N/A /* attempt to create space in buffer */
1N/A if(w == 0 || ((f->flags&SF_WHOLE) && w < (ssize_t)n) )
1N/A { if(f->flags&SF_STRING) /* extend buffer */
1N/A { (void)SFWR(f, s, n-w, f->disc);
1N/A if((w = f->endb - f->next) < (ssize_t)n)
1N/A { if(!(f->flags&SF_STRING)) /* maybe sftmp */
1N/A { if(f->next > f->data)
1N/A goto fls_buf;
1N/A }
1N/A else if(w == 0)
1N/A break;
1N/A }
1N/A }
1N/A else if(f->next > f->data)
1N/A { fls_buf:
1N/A (void)SFFLSBUF(f, -1);
1N/A if((w = f->endb - f->next) < (ssize_t)n &&
1N/A (f->flags&SF_WHOLE) && f->next > f->data )
1N/A break;
1N/A }
1N/A }
1N/A
1N/A if(!(f->flags&SF_STRING) && f->next == f->data &&
1N/A (((f->flags&SF_WHOLE) && w <= n) || SFDIRECT(f,n)) )
1N/A { /* bypass buffering */
1N/A if((w = SFWR(f,s,n,f->disc)) <= 0 )
1N/A break;
1N/A }
1N/A else
1N/A { if(w > (ssize_t)n)
1N/A w = (ssize_t)n;
1N/A if(w <= 0) /* no forward progress possible */
1N/A break;
1N/A memmove(f->next, s, w);
1N/A f->next += w;
1N/A }
1N/A
1N/A s += w;
1N/A if((n -= w) <= 0)
1N/A break;
1N/A }
1N/A
1N/A /* always flush buffer for share streams */
1N/A if(f->extent < 0 && (f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC) )
1N/A (void)SFFLSBUF(f,-1);
1N/A
1N/A /* check to see if buffer should be flushed */
1N/A else if(n == 0 && (f->flags&SF_LINE) && !(f->flags&SF_STRING))
1N/A { if((ssize_t)(n = f->next-f->data) > (w = s-begs))
1N/A n = w;
1N/A if(n > 0 && n < HIFORLINE)
1N/A { for(next = f->next-1; n > 0; --n, --next)
1N/A { if(*next == '\n')
1N/A { n = HIFORLINE;
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A if(n >= HIFORLINE)
1N/A (void)SFFLSBUF(f,-1);
1N/A }
1N/A
1N/A SFOPEN(f,local);
1N/A
1N/A w = s-begs;
1N/A SFMTXRETURN(f,w);
1N/A}