2
static char* Version = "\n@(#)sfio (AT&T Labs - kpv) 2001-02-01\0\n";
4
/* Functions to set a given stream to some desired mode
6
** Written by Kiem-Phong Vo.
9
** 06/27/1990 (first version)
18
** 08/01/1998 (extended formatting)
19
** 09/09/1999 (thread-safe)
20
** 02/01/2001 (adaptive buffering)
23
/* the below is for protecting the application from SIGPIPE */
27
#define Sfsignal_f Sig_handler_t
30
typedef void(* Sfsignal_f)_ARG_((int));
32
static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */
34
/* done at exiting time */
36
static void _sfcleanup(void)
38
static void _sfcleanup()
46
f = (Sfio_t*)Version; /* shut compiler warning */
48
/* set this so that no more buffering is allowed for write streams */
53
for(p = &_Sfpool; p; p = p->next)
54
{ for(n = 0; n < p->n_sf; ++n)
55
{ if(!(f = p->sf[n]) || SFFROZEN(f) )
61
/* let application know that we are leaving */
62
(void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*));
64
if(f->flags&SF_STRING)
67
/* from now on, write streams are unbuffered */
68
pool = f->mode&SF_POOL;
70
if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
71
(void)_sfmode(f,SF_WRITE,1);
72
if(((f->bits&SF_MMAP) && f->data) ||
73
((f->mode&SF_WRITE) && f->next == f->data) )
74
(void)SFSETBUF(f,NIL(Void_t*),0);
83
/* put into discrete pool */
85
int _sfsetpool(Sfio_t* f)
96
{ _Sfcleanup = _sfcleanup;
97
(void)atexit(_sfcleanup);
101
p = f->pool = &_Sfpool;
107
if(p->n_sf >= p->s_sf)
108
{ if(p->s_sf == 0) /* initialize pool array */
109
{ p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
112
else /* allocate a larger array */
113
{ n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
114
if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
117
/* move old array to new one */
118
memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
119
if(p->sf != p->array)
120
free((Void_t*)p->sf);
127
/* always add at end of array because if this was done during some sort
128
of walk thru all streams, we'll want the new stream to be seen.
130
p->sf[p->n_sf++] = f;
134
POOLMTXRETURN(p, rv);
137
/* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
139
Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
141
Sfrsrv_t* _sfrsrv(f,size)
148
/* make buffer if nothing yet */
149
size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
150
if(!(rsrv = f->rsrv) || size > rsrv->size)
151
{ if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
156
memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
168
return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
173
static void ignoresig(int sig)
175
static void ignoresig(sig)
179
signal(sig, ignoresig);
184
int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
186
int _sfpopen(f, fd, pid, stdio)
190
int stdio; /* stdio popen() does not reset SIGPIPE handler */
198
if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
202
p->size = p->ndata = 0;
203
p->rdata = NIL(uchar*);
205
p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
207
#ifdef SIGPIPE /* protect from broken pipe signal */
209
{ Sfsignal_f handler;
212
if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
213
handler != ignoresig)
214
signal(SIGPIPE, handler); /* honor user handler */
216
vtmtxunlock(_Sfmutex);
224
int _sfpclose(reg Sfio_t* f)
227
reg Sfio_t* f; /* stream to close */
235
f->proc = NIL(Sfproc_t*);
243
{ /* close the associated stream */
247
/* wait for process termination */
251
while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
261
if(p->sigp && (_Sfsigp -= 1) <= 0)
262
{ Sfsignal_f handler;
263
if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
264
handler != ignoresig)
265
signal(SIGPIPE,handler); /* honor user handler */
268
vtmtxunlock(_Sfmutex);
277
static int _sfpmode(Sfio_t* f, int type)
279
static int _sfpmode(f,type)
290
{ /* save unread data */
291
p->ndata = f->endb-f->next;
292
if(p->ndata > p->size)
294
free((char*)p->rdata);
295
if((p->rdata = (uchar*)malloc(p->ndata)) )
303
memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
307
{ /* restore read data */
308
if(p->ndata > f->size) /* may lose data!!! */
311
{ memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
312
f->endb = f->data+p->ndata;
317
/* switch file descriptor */
328
int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
330
int _sfmode(f, wanted, local)
331
reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */
332
reg int wanted; /* desired mode */
333
reg int local; /* a local call */
340
SFONCE(); /* initialize mutexes */
342
if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
343
{ if(local || !f->disc || !f->disc->exceptf)
349
{ if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
351
if((!local && SFFROZEN(f)) ||
352
(!(f->flags&SF_STRING) && f->file < 0) )
364
{ f->mode &= ~SF_GETR;
366
if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
367
{ /* turn off mmap to avoid page faulting */
368
sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
374
{ f->next[-1] = f->getr;
379
if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
382
if(f->disc == _Sfudisc && wanted == SF_WRITE &&
383
sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
389
{ /* move to head of pool */
390
if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
399
/* buffer initialization */
403
if(!f->pool && _sfsetpool(f) < 0)
411
if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
414
if((f->flags&SF_STRING) && f->size >= 0 && f->data)
415
{ f->mode &= ~SF_INIT;
416
f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
419
f->endb = f->data + f->size;
420
f->next = f->endr = f->endw = f->data;
423
else f->endw = f->endb;
427
(void)SFSETBUF(f,f->data,f->size);
428
f->flags |= (n&SF_MALLOC);
432
if(wanted == (int)SFMODE(f,1))
437
case SF_WRITE: /* switching to SF_READ */
438
if(wanted == 0 || wanted == SF_WRITE)
440
if(!(f->flags&SF_READ) )
442
else if(f->flags&SF_STRING)
444
f->endb = f->data+f->extent;
450
if(f->next > f->data && SFFLSBUF(f,-1) < 0)
456
f->size = sizeof(f->tiny);
458
f->next = f->endr = f->endw = f->endb = f->data;
459
f->mode = SF_READ|SF_LOCK;
461
/* restore saved read data for coprocess */
462
if(f->proc && _sfpmode(f,wanted) < 0)
467
case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
468
if(wanted != SF_WRITE)
469
{ /* just reset the pointers */
470
f->mode = SF_READ|SF_LOCK;
472
/* see if must go with new physical location */
473
if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
474
(addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
477
if((f->bits&SF_MMAP) && f->data)
478
{ SFMUNMAP(f,f->data,f->endb-f->data);
479
f->data = NIL(uchar*);
482
f->endb = f->endr = f->endw = f->next = f->data;
486
{ addr = f->here + (f->endb - f->next);
487
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
496
case SF_READ: /* switching to SF_WRITE */
497
if(wanted != SF_WRITE)
499
else if(!(f->flags&SF_WRITE))
501
else if(f->flags&SF_STRING)
502
{ f->endb = f->data+f->size;
503
f->mode = SF_WRITE|SF_LOCK;
507
/* save unread data before switching mode */
508
if(f->proc && _sfpmode(f,wanted) < 0)
511
/* reset buffer and seek pointer */
512
if(!(f->mode&SF_SYNCED) )
513
{ n = f->endb - f->next;
514
if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
515
{ /* reset file pointer */
517
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
523
f->mode = SF_WRITE|SF_LOCK;
527
SFMUNMAP(f,f->data,f->endb-f->data);
528
(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
531
if(f->data == f->tiny)
532
{ f->endb = f->data = f->next = NIL(uchar*);
535
else f->endb = (f->next = f->data) + f->size;
539
default: /* unknown case */
541
if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
544
/* set errno for operations that access wrong stream type */
545
if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
548
if(_Sfnotify) /* notify application of the error */
549
(*_Sfnotify)(f,wanted,f->file);