#include "sfhdr.h"
#if __STD_C
Void_t* sfreserve(reg Sfio_t* f, ssize_t size, int type)
#else
Void_t* sfreserve(f,size,type)
reg Sfio_t* f;
ssize_t size;
int type;
#endif
{
reg ssize_t n, sz;
reg Sfrsrv_t* rsrv;
reg Void_t* data;
reg int mode;
SFMTXSTART(f,NIL(Void_t*));
rsrv = NIL(Sfrsrv_t*);
_Sfi = f->val = -1;
if(type == SF_LASTR )
{ if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0)
{ rsrv->slen = 0;
_Sfi = f->val = n;
SFMTXRETURN(f, (Void_t*)rsrv->data);
}
else SFMTXRETURN(f, NIL(Void_t*));
}
if(type > 0 && !(type == SF_LOCKR || type == 1) )
SFMTXRETURN(f, NIL(Void_t*));
if((sz = size) == 0 && type != 0)
{
if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
SFMTXRETURN(f, NIL(Void_t*));
SFLOCK(f,0);
if((n = f->endb - f->next) < 0)
n = 0;
if(!f->data && type > 0)
rsrv = _sfrsrv(f,0);
goto done;
}
if(sz < 0)
sz = -sz;
for(;;)
{
if(!(mode = (f->flags&SF_READ)) )
mode = SF_WRITE;
if((int)f->mode != mode && _sfmode(f,mode,0) < 0)
{ n = -1;
goto done;
}
SFLOCK(f,0);
if((n = f->endb - f->next) < 0)
n = 0;
if(n > 0 && n >= sz)
break;
if(f->mode&SF_WRITE)
(void)SFFLSBUF(f, -1);
else if(type > 0 && f->extent < 0 && (f->flags&SF_SHARE) )
{ if(n == 0)
{ f->mode |= SF_RV;
(void)SFFILBUF(f, sz == 0 ? -1 : (sz-n) );
}
if((n = f->endb - f->next) < sz)
{ if(f->mode&SF_PKRD)
{ f->endb = f->endr = f->next;
f->mode &= ~SF_PKRD;
}
goto done;
}
}
else (void)SFFILBUF(f, sz == 0 ? -1 : (sz-n) );
if((n = f->endb - f->next) > 0)
break;
else if(n < 0)
n = 0;
if((f->mode&mode) != 0)
break;
}
if(n > 0 && n < sz && (f->mode&mode) != 0 )
{
if(f->flags&SF_STRING)
{ if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) )
{ (void)SFWR(f,f->next,sz,f->disc);
n = f->endb - f->next;
}
}
else if(f->mode&SF_WRITE)
{ if(type > 0 && (rsrv = _sfrsrv(f,sz)) )
n = sz;
}
else
{ if(type <= 0 && (rsrv = _sfrsrv(f,sz)) &&
(n = SFREAD(f,(Void_t*)rsrv->data,sz)) < sz)
rsrv->slen = -n;
}
}
done:
_Sfi = f->val = n;
SFOPEN(f,0);
if((sz > 0 && n < sz) || (n == 0 && type <= 0) )
SFMTXRETURN(f, NIL(Void_t*));
if((data = rsrv ? (Void_t*)rsrv->data : (Void_t*)f->next) )
{ if(type > 0)
{ f->mode |= SF_PEEK;
f->endr = f->endw = f->data;
}
else if(data == (Void_t*)f->next)
f->next += (size >= 0 ? size : n);
}
SFMTXRETURN(f, data);
}