2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: sfmode.c /main/3 1995/11/01 18:30:58 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
31 * Copyright (c) 1995 AT&T Corp. *
32 * All Rights Reserved *
34 * This software is licensed by AT&T Corp. *
35 * under the terms and conditions of the license in *
36 * http://www.research.att.com/orgs/ssr/book/reuse *
38 * This software was created by the *
39 * Software Engineering Research Department *
40 * AT&T Bell Laboratories *
42 * For further information contact *
43 * gsf@research.att.com *
45 ***************************************************************/
47 static char* Version = "\n@(#)sfio (AT&T Bell Laboratories) 05/09/95\0\n";
53 /* Switch the given stream to a desired mode
55 ** Written by Kiem-Phong Vo (06/27/90)
59 static void _sfcleanup(void)
61 static void _sfcleanup()
71 /* unbuffer all write streams so that any new output
72 from other atexit functions will be done immediately.
73 This can be inefficient for applications that do lots of
74 output at the end but it's correct.
76 for(p = &_Sfpool; p; p = p->next)
77 { for(n = 0; n < p->n_sf; ++n)
79 if(SFFROZEN(f) || (f->flags&SF_STRING) )
82 pool = f->mode&SF_POOL;
84 if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
85 (void)_sfmode(f,SF_WRITE,0);
86 if((f->mode&SF_WRITE) && f->next == f->data)
87 sfsetbuf(f,NIL(Void_t*),0);
92 /* set this so that no more buffering is allowed */
96 /* put into discrete pool */
109 { _Sfcleanup = _sfcleanup;
110 (void)atexit(_sfcleanup);
114 p = f->pool = &_Sfpool;
116 if(p->n_sf >= p->s_sf)
117 { if(p->s_sf == 0) /* initialize pool array */
118 { p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
121 else /* allocate a larger array */
122 { n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
123 if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
126 /* move old array to new one */
127 memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
128 if(p->sf != p->array)
129 free((Void_t*)p->sf);
136 /* always add at end of array because if this was done during some sort
137 of walk thru all streams, we'll want the new stream to be seen.
139 p->sf[p->n_sf++] = f;
143 /* to create auxiliary buffer for large sfgetr() or sfrsrv() */
145 static Sfrsrv_t* _Sfrsrv;
148 Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg int size)
150 Sfrsrv_t* _sfrsrv(f,size)
152 reg int size; /* closing if size < 0 */
155 reg Sfrsrv_t *last, *frs;
157 for(last = NIL(Sfrsrv_t*), frs = _Sfrsrv; frs; last = frs, frs = frs->next)
161 { /* unhook it from current position */
163 last->next = frs->next;
164 else _Sfrsrv = frs->next;
167 if(size < 0) /* closing stream */
170 return NIL(Sfrsrv_t*);
173 /* inserting, make buffer if nothing yet */
174 size = ((size + SF_RSRV-1)/SF_RSRV)*SF_RSRV;
175 if(!frs || size > frs->size)
176 { if(!(last = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
181 memcpy((char*)last,(char*)frs,
182 sizeof(Sfrsrv_t)+frs->slen);
199 return size >= 0 ? frs : NIL(Sfrsrv_t*);
203 /* to keep track of process or unseekable read/write streams */
206 struct _sfp_* next; /* link list */
207 int pid; /* process id */
208 Sfio_t* sf; /* stream associated with */
209 uchar* rdata; /* read data being cached */
210 int ndata; /* size of cached data */
211 int size; /* buffer size */
212 int file; /* saved file descriptor */
214 static Sfpopen_t* _Sfprocess;
217 _sfpopen(reg Sfio_t* f, int fd, int pid)
225 reg Sfpopen_t* p = (Sfpopen_t*)Version; /* shut up unuse warning */
227 for(p = _Sfprocess; p; p = p->next)
231 if(!(p = (Sfpopen_t*)malloc(sizeof(Sfpopen_t))) )
234 f->flags |= SF_PROCESS;
238 p->size = p->ndata = 0;
239 p->rdata = NIL(uchar*);
241 p->next = _Sfprocess;
248 _sfpclose(reg Sfio_t* f)
251 reg Sfio_t* f; /* stream to close */
254 reg Sfpopen_t *last, *p;
258 { /* before exec-ing, close all pipe ends */
259 for(p = _Sfprocess; p; p = p->next)
267 /* find the associated process structure */
268 for(last = NIL(Sfpopen_t*), p = _Sfprocess; p ; last = p, p = p->next)
274 f->flags &= ~SF_PROCESS;
276 { f->flags |= SF_PROCESS;
280 /* delete from process table */
282 last->next = p->next;
283 else _Sfprocess = p->next;
285 free((char*)p->rdata);
292 /* close the associated streams */
296 /* wait for process termination */
300 while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR);
306 return (pid == -1 ? -1 : status);
310 static _sfpmode(Sfio_t* f, int type)
312 static _sfpmode(f,type)
316 { reg Sfpopen_t *last, *p;
318 /* find the associated process structure. We must be careful here
319 with respect to a stacked stream since it takes on the identity
322 for(last = NIL(Sfpopen_t*), p = _Sfprocess; p; last = p, p = p->next)
323 if((f->push ? f->push : f) == p->sf)
328 /* move-to-front heuristic */
330 { last->next = p->next;
331 p->next = _Sfprocess;
336 { /* save unread data */
337 p->ndata = f->endb-f->next;
338 if(p->ndata > p->size)
340 free((char*)p->rdata);
341 if((p->rdata = (uchar*)malloc(p->ndata)) )
349 memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
353 { /* restore read data */
354 if(p->ndata > f->size) /* may lose data!!! */
357 { memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
358 f->endb = f->data+p->ndata;
363 /* switch file descriptor */
374 void _sfswap(Sfio_t* f1, Sfio_t* f2, int stack)
376 void _sfswap(f1, f2, stack)
382 reg Sfrsrv_t *r, *r1, *r2;
383 reg Sfpopen_t *p, *p1, *p2;
385 /* switch sfreserve or sfgetr identifier */
386 r1 = r2 = NIL(Sfrsrv_t*);
387 for(r = _Sfrsrv; r; r = r->next)
398 /* if called from sfstack, we already did this */
400 { /* and for sfpopen buffer */
401 p1 = p2 = NIL(Sfpopen_t*);
402 for(p = _Sfprocess; p; p = p->next)
416 _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
418 _sfmode(f, wanted, local)
419 reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */
420 reg int wanted; /* desired mode */
421 reg int local; /* a local call */
428 if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
434 { f->mode &= ~SF_GETR;
435 f->next[-1] = f->getr;
438 if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
441 if(f->disc == _Sfudisc && wanted == SF_WRITE &&
442 sfclose((*_Sfstack)(f,NIL(Sfile_t*))) < 0 )
448 { /* move to head of pool */
449 if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
458 /* buffer initialization */
462 if(!f->pool && _sfsetpool(f) < 0)
470 if(wanted != (f->mode&SF_RDWR) && !(f->flags&wanted) )
473 if((f->flags&SF_STRING) && f->size >= 0 && f->data)
474 { f->mode &= ~SF_INIT;
475 f->extent = (f->flags&(SF_READ|SF_BOTH)) ? f->size : 0;
477 f->endb = f->data + f->size;
478 f->next = f->endr = f->endw = f->data;
481 else f->endw = f->endb;
485 (void)SFSETBUF(f,(char*)f->data,f->size);
486 f->flags |= (n&SF_MALLOC);
490 if(wanted == SFMODE(f,1))
495 case SF_WRITE: /* switching to SF_READ */
496 if(wanted == 0 || wanted == SF_WRITE)
498 if(!(f->flags&SF_READ) )
500 else if(f->flags&SF_STRING)
502 f->endb = f->data+f->extent;
508 if(f->next > f->data && SFFLSBUF(f,-1) < 0)
514 f->size = sizeof(f->tiny);
516 f->next = f->endr = f->endw = f->endb = f->data;
517 f->mode = SF_READ|SF_LOCK;
519 /* restore saved read data for coprocess */
520 if((f->flags&SF_PROCESS) && _sfpmode(f,wanted) < 0)
525 case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
526 if(wanted != SF_WRITE)
527 { /* just reset the pointers */
528 f->mode = SF_READ|SF_LOCK;
530 /* see if must go with new physical location */
531 if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
532 (addr = SFSK(f,0L,1,f->disc)) != f->here)
535 if((f->flags&SF_MMAP) && f->data)
536 { munmap((caddr_t)f->data,f->endb-f->data);
537 f->data = NIL(uchar*);
540 f->endb = f->endr = f->endw = f->next = f->data;
544 { addr = f->here + (f->endb - f->next);
545 if(SFSK(f,addr,0,f->disc) < 0)
554 case SF_READ: /* switching to SF_WRITE */
555 if(wanted != SF_WRITE)
557 else if(!(f->flags&SF_WRITE))
559 else if(f->flags&SF_STRING)
560 { f->endb = f->data+f->size;
561 f->mode = SF_WRITE|SF_LOCK;
565 /* save unread data before switching mode */
566 if((f->flags&SF_PROCESS) && _sfpmode(f,wanted) < 0)
569 /* reset buffer and seek pointer */
570 if(!(f->mode&SF_SYNCED) )
571 { n = f->endb - f->next;
572 if(f->extent >= 0 && (n > 0 || (f->data && (f->flags&SF_MMAP))) )
573 { /* reset file pointer */
575 if(SFSK(f,addr,0,f->disc) < 0)
581 f->mode = SF_WRITE|SF_LOCK;
585 { (void)munmap((caddr_t)f->data,f->endb-f->data);
586 f->endb = f->endr = f->endw =
587 f->next = f->data = NIL(uchar*);
589 (void)SFSETBUF(f,(char*)f->tiny,-1);
592 if(f->data == f->tiny)
593 { f->endb = f->data = f->next = NIL(uchar*);
596 else f->endb = (f->next = f->data) + f->size;
600 default: /* unknown case */
603 { if((wanted &= SF_RDWR) == 0)
604 wanted = f->flags&SF_RDWR;
605 (*_Sfnotify)(f,wanted,f->file);