14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfhdr.h"
234887Schin
244887Schin /* Function to handle io exceptions.
254887Schin ** Written by Kiem-Phong Vo
264887Schin */
274887Schin
284887Schin #if __STD_C
_sfexcept(Sfio_t * f,int type,ssize_t io,Sfdisc_t * disc)294887Schin int _sfexcept(Sfio_t* f, int type, ssize_t io, Sfdisc_t* disc)
304887Schin #else
314887Schin int _sfexcept(f,type,io,disc)
324887Schin Sfio_t* f; /* stream where the exception happened */
334887Schin int type; /* io type that was performed */
344887Schin ssize_t io; /* the io return value that indicated exception */
354887Schin Sfdisc_t* disc; /* discipline in use */
364887Schin #endif
374887Schin {
384887Schin reg int ev, local, lock;
394887Schin reg ssize_t size;
404887Schin reg uchar* data;
418462SApril.Chin@Sun.COM SFMTXDECL(f);
424887Schin
438462SApril.Chin@Sun.COM SFMTXENTER(f,-1);
444887Schin
454887Schin GETLOCAL(f,local);
464887Schin lock = f->mode&SF_LOCK;
474887Schin
484887Schin if(local && io <= 0)
494887Schin f->flags |= io < 0 ? SF_ERROR : SF_EOF;
504887Schin
514887Schin if(disc && disc->exceptf)
524887Schin { /* let the stream be generally accessible for this duration */
534887Schin if(local && lock)
544887Schin SFOPEN(f,0);
554887Schin
564887Schin /* so that exception handler knows what we are asking for */
574887Schin _Sfi = f->val = io;
584887Schin ev = (*(disc->exceptf))(f,type,&io,disc);
594887Schin
604887Schin /* relock if necessary */
614887Schin if(local && lock)
624887Schin SFLOCK(f,0);
634887Schin
644887Schin if(io > 0 && !(f->flags&SF_STRING) )
654887Schin SFMTXRETURN(f, ev);
664887Schin if(ev < 0)
674887Schin SFMTXRETURN(f, SF_EDONE);
684887Schin if(ev > 0)
694887Schin SFMTXRETURN(f, SF_EDISC);
704887Schin }
714887Schin
724887Schin if(f->flags&SF_STRING)
734887Schin { if(type == SF_READ)
744887Schin goto chk_stack;
754887Schin else if(type != SF_WRITE && type != SF_SEEK)
764887Schin SFMTXRETURN(f, SF_EDONE);
774887Schin if(local && io >= 0)
784887Schin { if(f->size >= 0 && !(f->flags&SF_MALLOC))
794887Schin goto chk_stack;
804887Schin /* extend buffer */
814887Schin if((size = f->size) < 0)
824887Schin size = 0;
834887Schin if((io -= size) <= 0)
844887Schin io = SF_GRAIN;
854887Schin size = ((size+io+SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
864887Schin if(f->size > 0)
874887Schin data = (uchar*)realloc((char*)f->data,size);
884887Schin else data = (uchar*)malloc(size);
894887Schin if(!data)
904887Schin goto chk_stack;
914887Schin f->endb = data + size;
924887Schin f->next = data + (f->next - f->data);
934887Schin f->endr = f->endw = f->data = data;
944887Schin f->size = size;
954887Schin }
964887Schin SFMTXRETURN(f, SF_EDISC);
974887Schin }
984887Schin
994887Schin if(errno == EINTR)
1004887Schin { if(_Sfexiting || (f->bits&SF_ENDING) || /* stop being a hero */
1014887Schin (f->flags&SF_IOINTR) ) /* application requests to return */
1024887Schin SFMTXRETURN(f, SF_EDONE);
1034887Schin
1044887Schin /* a normal interrupt, we can continue */
1054887Schin errno = 0;
1064887Schin f->flags &= ~(SF_EOF|SF_ERROR);
1074887Schin SFMTXRETURN(f, SF_ECONT);
1084887Schin }
1094887Schin
1104887Schin chk_stack:
1114887Schin if(local && f->push &&
1124887Schin ((type == SF_READ && f->next >= f->endb) ||
1134887Schin (type == SF_WRITE && f->next <= f->data)))
1144887Schin { /* pop the stack */
1154887Schin reg Sfio_t *pf;
1164887Schin
1174887Schin if(lock)
1184887Schin SFOPEN(f,0);
1194887Schin
1204887Schin /* pop and close */
1214887Schin pf = (*_Sfstack)(f,NIL(Sfio_t*));
1224887Schin if((ev = sfclose(pf)) < 0) /* can't close, restack */
1234887Schin (*_Sfstack)(f,pf);
1244887Schin
1254887Schin if(lock)
1264887Schin SFLOCK(f,0);
1274887Schin
1284887Schin ev = ev < 0 ? SF_EDONE : SF_ESTACK;
1294887Schin }
1304887Schin else ev = SF_EDONE;
1314887Schin
1324887Schin SFMTXRETURN(f, ev);
1334887Schin }
134