Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfmode.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: sfmode.c /main/3 1995/11/01 18:30:58 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
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        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46 #include        "sfhdr.h"
47 static char*    Version = "\n@(#)sfio (AT&T Bell Laboratories) 05/09/95\0\n";
48
49 #if _PACKAGE_ast
50 #include <wait.h>
51 #endif
52
53 /*      Switch the given stream to a desired mode
54 **
55 **      Written by Kiem-Phong Vo (06/27/90)
56 */
57
58 #if __STD_C
59 static void _sfcleanup(void)
60 #else
61 static void _sfcleanup()
62 #endif
63 {
64         reg Sfpool_t*   p;
65         reg Sfio_t*     f;
66         reg int         n;
67         reg int         pool;
68
69         sfsync(NIL(Sfio_t*));
70
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.
75         */
76         for(p = &_Sfpool; p; p = p->next)
77         {       for(n = 0; n < p->n_sf; ++n)
78                 {       f = p->sf[n];
79                         if(SFFROZEN(f) || (f->flags&SF_STRING) )
80                                 continue;
81
82                         pool = f->mode&SF_POOL;
83                         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);
88                         f->mode |= pool;
89                 }
90         }
91
92         /* set this so that no more buffering is allowed */
93         _Sfexiting = 1001;
94 }
95
96 /* put into discrete pool */
97 #if __STD_C
98 _sfsetpool(Sfio_t* f)
99 #else
100 _sfsetpool(f)
101 Sfio_t* f;
102 #endif
103 {
104         reg Sfpool_t*   p;
105         reg Sfio_t**    array;
106         reg int         n;
107
108         if(!_Sfcleanup)
109         {       _Sfcleanup = _sfcleanup;
110                 (void)atexit(_sfcleanup);
111         }
112
113         if(!(p = f->pool) )
114                 p = f->pool = &_Sfpool;
115
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]);
119                         p->sf = p->array;
120                 }
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*))) )
124                                 return -1;
125
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);
130
131                         p->sf = array;
132                         p->s_sf = n;
133                 }
134         }
135
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.
138         */
139         p->sf[p->n_sf++] = f;
140         return 0;
141 }
142
143 /* to create auxiliary buffer for large sfgetr() or sfrsrv() */
144 #define SF_RSRV 128
145 static Sfrsrv_t*        _Sfrsrv;
146
147 #if __STD_C
148 Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg int size)
149 #else
150 Sfrsrv_t* _sfrsrv(f,size)
151 reg Sfio_t*     f;
152 reg int         size;   /* closing if size < 0 */
153 #endif
154 {
155         reg Sfrsrv_t    *last, *frs;
156
157         for(last = NIL(Sfrsrv_t*), frs = _Sfrsrv; frs; last = frs, frs = frs->next)
158                 if(frs->sf == f)
159                         break;
160         if(frs)
161         {       /* unhook it from current position */
162                 if(last)
163                         last->next = frs->next;
164                 else    _Sfrsrv = frs->next;
165         }
166
167         if(size < 0)    /* closing stream */
168         {       if(frs)
169                         free((char*)frs);
170                 return NIL(Sfrsrv_t*);
171         }
172
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))))
177                         size = -1;
178                 else
179                 {       if(frs)
180                         {       if(frs->slen > 0)
181                                         memcpy((char*)last,(char*)frs,
182                                                 sizeof(Sfrsrv_t)+frs->slen);
183                                 free((char*)frs);
184                         }
185                         frs = last;
186                         frs->size = size;
187                         frs->slen = 0;
188                 }
189         }
190
191         if(frs)
192         {       if(size > 0)
193                         frs->slen = 0;
194                 frs->sf = f;
195                 frs->next = _Sfrsrv;
196                 _Sfrsrv = frs;
197         }
198
199         return size >= 0 ? frs : NIL(Sfrsrv_t*);
200 }
201
202
203 /* to keep track of process or unseekable read/write streams */
204 typedef struct _sfp_
205 {
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        */
213 } Sfpopen_t;
214 static Sfpopen_t*       _Sfprocess;
215
216 #if __STD_C
217 _sfpopen(reg Sfio_t* f, int fd, int pid)
218 #else
219 _sfpopen(f, fd, pid)
220 reg Sfio_t*     f;
221 int             fd;
222 int             pid;
223 #endif
224 {
225         reg Sfpopen_t* p = (Sfpopen_t*)Version; /* shut up unuse warning */
226
227         for(p = _Sfprocess; p; p = p->next)
228                 if(p->sf == f)
229                         return 0;
230
231         if(!(p = (Sfpopen_t*)malloc(sizeof(Sfpopen_t))) )
232                 return -1;
233
234         f->flags |= SF_PROCESS;
235
236         p->pid = pid;
237         p->sf = f;
238         p->size = p->ndata = 0;
239         p->rdata = NIL(uchar*);
240         p->file = fd;
241         p->next = _Sfprocess;
242         _Sfprocess = p;
243
244         return 0;
245 }
246
247 #if __STD_C
248 _sfpclose(reg Sfio_t* f)
249 #else
250 _sfpclose(f)
251 reg Sfio_t*     f;      /* stream to close */
252 #endif
253 {
254         reg Sfpopen_t   *last, *p;
255         int             pid, status;
256
257         if(!f)
258         {       /* before exec-ing, close all pipe ends */
259                 for(p = _Sfprocess; p; p = p->next)
260                 {       if(p->file >= 0)
261                                 CLOSE(p->file);
262                         CLOSE(p->sf->file);
263                 }
264                 return 0;
265         }
266
267         /* find the associated process structure */
268         for(last = NIL(Sfpopen_t*), p = _Sfprocess; p ; last = p, p = p->next)
269                 if(f == p->sf)
270                         break;
271         if(!p)
272                 return -1;
273
274         f->flags &= ~SF_PROCESS;
275         if(sfclose(f) < 0)
276         {       f->flags |= SF_PROCESS;
277                 return -1;
278         }
279
280         /* delete from process table */
281         if(last)
282                 last->next = p->next;
283         else    _Sfprocess = p->next;
284         if(p->rdata)
285                 free((char*)p->rdata);
286
287         if(p->pid < 0)
288         {       free((char*)p);
289                 return 0;
290         }
291
292         /* close the associated streams */
293         if(p->file >= 0)
294                 CLOSE(p->file);
295
296         /* wait for process termination */
297 #if _PACKAGE_ast
298         sigcritical(1);
299 #endif
300         while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR);
301 #if _PACKAGE_ast
302         sigcritical(0);
303 #endif
304
305         free((char*)p);
306         return (pid == -1 ? -1 : status);
307 }
308
309 #if __STD_C
310 static _sfpmode(Sfio_t* f, int type)
311 #else
312 static _sfpmode(f,type)
313 Sfio_t* f;
314 int     type;
315 #endif
316 {       reg Sfpopen_t   *last, *p;
317
318         /* find the associated process structure. We must be careful here
319            with respect to a stacked stream since it takes on the identity
320            of the stack base.
321         */
322         for(last = NIL(Sfpopen_t*), p = _Sfprocess; p; last = p, p = p->next)
323                 if((f->push ? f->push : f) == p->sf)
324                         break;
325         if(!p)
326                 return -1;
327
328         /* move-to-front heuristic */
329         if(last)
330         {       last->next = p->next;
331                 p->next = _Sfprocess;
332                 _Sfprocess = p;
333         }
334
335         if(type == SF_WRITE)
336         {       /* save unread data */
337                 p->ndata = f->endb-f->next;
338                 if(p->ndata > p->size)
339                 {       if(p->rdata)
340                                 free((char*)p->rdata);
341                         if((p->rdata = (uchar*)malloc(p->ndata)) )
342                                 p->size = p->ndata;
343                         else
344                         {       p->size = 0;
345                                 return -1;
346                         }
347                 }
348                 if(p->ndata > 0)
349                         memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
350                 f->endb = f->data;
351         }
352         else
353         {       /* restore read data */
354                 if(p->ndata > f->size)  /* may lose data!!! */
355                         p->ndata = f->size;
356                 if(p->ndata > 0)
357                 {       memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
358                         f->endb = f->data+p->ndata;
359                         p->ndata = 0;
360                 }
361         }
362
363         /* switch file descriptor */
364         if(p->pid >= 0)
365         {       type = f->file;
366                 f->file = p->file;
367                 p->file = type;
368         }
369
370         return 0;
371 }
372
373 #if __STD_C
374 void _sfswap(Sfio_t* f1, Sfio_t* f2, int stack)
375 #else
376 void _sfswap(f1, f2, stack)
377 Sfio_t* f1;
378 Sfio_t* f2;
379 int     stack;
380 #endif
381 {
382         reg Sfrsrv_t    *r, *r1, *r2;
383         reg Sfpopen_t   *p, *p1, *p2;
384
385         /* switch sfreserve or sfgetr identifier */
386         r1 = r2 = NIL(Sfrsrv_t*);
387         for(r = _Sfrsrv; r; r = r->next)
388         {       if(r->sf == f1)
389                         r1 = r;
390                 if(r->sf == f2)
391                         r2 = r;
392         }
393         if(r1)
394                 r1->sf = f2;
395         if(r2)
396                 r2->sf = f1;
397
398         /* if called from sfstack, we already did this */
399         if(!stack)
400         {       /* and for sfpopen buffer */
401                 p1 = p2 = NIL(Sfpopen_t*);
402                 for(p = _Sfprocess; p; p = p->next)
403                 {       if(p->sf == f1)
404                                 p1 = p;
405                         if(p->sf == f2)
406                                 p2 = p;
407                 }
408                 if(p1)
409                         p1->sf = f2;
410                 if(p2)
411                         p2->sf = f1;
412         }
413 }
414
415 #if __STD_C
416 _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
417 #else
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 */
422 #endif
423 {
424         reg int         n;
425         reg long        addr;
426         reg int         rv = 0;
427
428         if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
429         {       local = 1;
430                 goto err_notify;
431         }
432
433         if(f->mode&SF_GETR)
434         {       f->mode &= ~SF_GETR;
435                 f->next[-1] = f->getr;
436         }
437
438         if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
439                 (*_Sfstdio)(f);
440
441         if(f->disc == _Sfudisc && wanted == SF_WRITE &&
442            sfclose((*_Sfstack)(f,NIL(Sfile_t*))) < 0 )
443         {       local = 1;
444                 goto err_notify;
445         }
446
447         if(f->mode&SF_POOL)
448         {       /* move to head of pool */
449                 if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
450                 {       local = 1;
451                         goto err_notify;
452                 }
453                 f->mode &= ~SF_POOL;
454         }
455
456         SFLOCK(f,local);
457
458         /* buffer initialization */
459         wanted &= SF_RDWR;
460         if(f->mode&SF_INIT)
461         {       
462                 if(!f->pool && _sfsetpool(f) < 0)
463                 {       rv = -1;
464                         goto done;
465                 }
466
467                 if(wanted == 0)
468                         goto done;
469
470                 if(wanted != (f->mode&SF_RDWR) && !(f->flags&wanted) )
471                         goto err_notify;
472
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;
476                         f->here = 0;
477                         f->endb = f->data + f->size;
478                         f->next = f->endr = f->endw = f->data;
479                         if(f->mode&SF_READ)
480                                 f->endr = f->endb;
481                         else    f->endw = f->endb;
482                 }
483                 else
484                 {       n = f->flags;
485                         (void)SFSETBUF(f,(char*)f->data,f->size);
486                         f->flags |= (n&SF_MALLOC);
487                 }
488         }
489
490         if(wanted == SFMODE(f,1))
491                 goto done;
492
493         switch(SFMODE(f,1))
494         {
495         case SF_WRITE: /* switching to SF_READ */
496                 if(wanted == 0 || wanted == SF_WRITE)
497                         break;
498                 if(!(f->flags&SF_READ) )
499                         goto err_notify;
500                 else if(f->flags&SF_STRING)
501                 {       SFSTRSIZE(f);
502                         f->endb = f->data+f->extent;
503                         f->mode = SF_READ;
504                         break;
505                 }
506
507                 /* reset buffer */
508                 if(f->next > f->data && SFFLSBUF(f,-1) < 0)
509                         goto err_notify;
510
511                 if(f->size == 0)
512                 {       /* unbuffered */
513                         f->data = f->tiny;
514                         f->size = sizeof(f->tiny);
515                 }
516                 f->next = f->endr = f->endw = f->endb = f->data;
517                 f->mode = SF_READ|SF_LOCK;
518
519                 /* restore saved read data for coprocess */
520                 if((f->flags&SF_PROCESS) && _sfpmode(f,wanted) < 0)
521                         goto err_notify;
522
523                 break;
524
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;
529
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)
533                         {
534 #ifdef MAP_TYPE
535                                 if((f->flags&SF_MMAP) && f->data)
536                                 {       munmap((caddr_t)f->data,f->endb-f->data);
537                                         f->data = NIL(uchar*);
538                                 }
539 #endif
540                                 f->endb = f->endr = f->endw = f->next = f->data;
541                                 f->here = addr;
542                         }
543                         else
544                         {       addr = f->here + (f->endb - f->next);
545                                 if(SFSK(f,addr,0,f->disc) < 0)
546                                         goto err_notify;
547                                 f->here = addr;
548                         }
549
550                         break;
551                 }
552                 /* fall thru */
553
554         case SF_READ: /* switching to SF_WRITE */
555                 if(wanted != SF_WRITE)
556                         break;
557                 else if(!(f->flags&SF_WRITE))
558                         goto err_notify;
559                 else if(f->flags&SF_STRING)
560                 {       f->endb = f->data+f->size;
561                         f->mode = SF_WRITE|SF_LOCK;
562                         break;
563                 }
564
565                 /* save unread data before switching mode */
566                 if((f->flags&SF_PROCESS) && _sfpmode(f,wanted) < 0)
567                         goto err_notify;
568
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 */
574                                 addr = f->here - n;
575                                 if(SFSK(f,addr,0,f->disc) < 0)
576                                         goto err_notify;
577                                 f->here = addr;
578                         }
579                 }
580
581                 f->mode = SF_WRITE|SF_LOCK;
582 #ifdef MAP_TYPE
583                 if(f->flags&SF_MMAP)
584                 {       if(f->data)
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*);
588                         }
589                         (void)SFSETBUF(f,(char*)f->tiny,-1);
590                 }
591 #endif
592                 if(f->data == f->tiny)
593                 {       f->endb = f->data = f->next = NIL(uchar*);
594                         f->size = 0;
595                 }
596                 else    f->endb = (f->next = f->data) + f->size;
597
598                 break;
599
600         default: /* unknown case */
601         err_notify:
602                 if(_Sfnotify)
603                 {       if((wanted &= SF_RDWR) == 0)
604                                 wanted = f->flags&SF_RDWR;
605                         (*_Sfnotify)(f,wanted,f->file);
606                 }
607                 rv = -1;
608                 break;
609         }
610
611 done:
612         SFOPEN(f,local);
613         return rv;
614 }