1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  *   Routines to implement fast character input
23*4887Schin  *
24*4887Schin  *   David Korn
25*4887Schin  *   AT&T Labs
26*4887Schin  *
27*4887Schin  */
28*4887Schin 
29*4887Schin #include	<ast.h>
30*4887Schin #include	<sfio.h>
31*4887Schin #include	<error.h>
32*4887Schin #include	<fcin.h>
33*4887Schin 
34*4887Schin Fcin_t _Fcin = {0};
35*4887Schin 
36*4887Schin /*
37*4887Schin  * open stream <f> for fast character input
38*4887Schin  */
39*4887Schin int	fcfopen(register Sfio_t* f)
40*4887Schin {
41*4887Schin 	register int	n;
42*4887Schin 	char		*buff;
43*4887Schin 	Fcin_t		save;
44*4887Schin 	errno = 0;
45*4887Schin 	_Fcin.fcbuff = _Fcin.fcptr;
46*4887Schin 	_Fcin._fcfile = f;
47*4887Schin 	fcsave(&save);
48*4887Schin 	if(!(buff=(char*)sfreserve(f,SF_UNBOUND,SF_LOCKR)))
49*4887Schin 	{
50*4887Schin 		fcrestore(&save);
51*4887Schin 		_Fcin.fcchar = 0;
52*4887Schin 		_Fcin.fcptr = _Fcin.fcbuff = &_Fcin.fcchar;
53*4887Schin 		_Fcin.fclast = 0;
54*4887Schin 		_Fcin._fcfile = (Sfio_t*)0;
55*4887Schin 		return(EOF);
56*4887Schin 	}
57*4887Schin 	n = sfvalue(f);
58*4887Schin 	fcrestore(&save);
59*4887Schin 	sfread(f,buff,0);
60*4887Schin 	_Fcin.fcoff = sftell(f);;
61*4887Schin 	buff = (char*)sfreserve(f,SF_UNBOUND,SF_LOCKR);
62*4887Schin 	_Fcin.fclast = (_Fcin.fcptr=_Fcin.fcbuff=(unsigned char*)buff)+n;
63*4887Schin 	if(sffileno(f) >= 0)
64*4887Schin 		*_Fcin.fclast = 0;
65*4887Schin 	return(n);
66*4887Schin }
67*4887Schin 
68*4887Schin 
69*4887Schin /*
70*4887Schin  * With _Fcin.fcptr>_Fcin.fcbuff, the stream pointer is advanced and
71*4887Schin  * If _Fcin.fclast!=0, performs an sfreserve() for the next buffer.
72*4887Schin  * If a notify function has been set, it is called
73*4887Schin  * If last is non-zero, and the stream is a file, 0 is returned when
74*4887Schin  * the previous character is a 0 byte.
75*4887Schin  */
76*4887Schin int	fcfill(void)
77*4887Schin {
78*4887Schin 	register int		n;
79*4887Schin 	register Sfio_t	*f;
80*4887Schin 	register unsigned char	*last=_Fcin.fclast, *ptr=_Fcin.fcptr;
81*4887Schin 	if(!(f=fcfile()))
82*4887Schin 	{
83*4887Schin 		/* see whether pointer has passed null byte */
84*4887Schin 		if(ptr>_Fcin.fcbuff && *--ptr==0)
85*4887Schin 			_Fcin.fcptr=ptr;
86*4887Schin 		else
87*4887Schin 			_Fcin.fcoff = 0;
88*4887Schin 		return(0);
89*4887Schin 	}
90*4887Schin 	if(last)
91*4887Schin 	{
92*4887Schin 		if( ptr<last && ptr>_Fcin.fcbuff && *(ptr-1)==0)
93*4887Schin 			return(0);
94*4887Schin 		if(_Fcin.fcchar)
95*4887Schin 			*last = _Fcin.fcchar;
96*4887Schin 		if(ptr > last)
97*4887Schin 			_Fcin.fcptr = ptr = last;
98*4887Schin 	}
99*4887Schin 	if((n = ptr-_Fcin.fcbuff) && _Fcin.fcfun)
100*4887Schin 		(*_Fcin.fcfun)(f,(const char*)_Fcin.fcbuff,n);
101*4887Schin 	sfread(f, (char*)_Fcin.fcbuff, n);
102*4887Schin 	_Fcin.fcoff +=n;
103*4887Schin 	_Fcin._fcfile = 0;
104*4887Schin 	if(!last)
105*4887Schin 		return(0);
106*4887Schin 	else if(fcfopen(f) < 0)
107*4887Schin 		return(EOF);
108*4887Schin 	return(*_Fcin.fcptr++);
109*4887Schin }
110*4887Schin 
111*4887Schin /*
112*4887Schin  * Synchronize and close the current stream
113*4887Schin  */
114*4887Schin int fcclose(void)
115*4887Schin {
116*4887Schin 	register unsigned char *ptr;
117*4887Schin 	if(_Fcin.fclast==0)
118*4887Schin 		return(0);
119*4887Schin 	if((ptr=_Fcin.fcptr)>_Fcin.fcbuff && *(ptr-1)==0)
120*4887Schin 		_Fcin.fcptr--;
121*4887Schin 	if(_Fcin.fcchar)
122*4887Schin 		*_Fcin.fclast = _Fcin.fcchar;
123*4887Schin 	_Fcin.fclast = 0;
124*4887Schin 	_Fcin.fcleft = 0;
125*4887Schin 	return(fcfill());
126*4887Schin }
127*4887Schin 
128*4887Schin /*
129*4887Schin  * Set the notify function that is called for each fcfill()
130*4887Schin  */
131*4887Schin void fcnotify(void (*fun)(Sfio_t*,const char*,int))
132*4887Schin {
133*4887Schin 	_Fcin.fcfun = fun;
134*4887Schin }
135*4887Schin 
136*4887Schin #ifdef __EXPORT__
137*4887Schin #   define extern __EXPORT__
138*4887Schin #endif
139*4887Schin 
140*4887Schin #undef fcsave
141*4887Schin extern void fcsave(Fcin_t *fp)
142*4887Schin {
143*4887Schin 	*fp = _Fcin;
144*4887Schin }
145*4887Schin 
146*4887Schin #undef fcrestore
147*4887Schin extern void fcrestore(Fcin_t *fp)
148*4887Schin {
149*4887Schin 	_Fcin = *fp;
150*4887Schin }
151*4887Schin 
152*4887Schin struct Extra
153*4887Schin {
154*4887Schin 	unsigned char	buff[2*MB_LEN_MAX];
155*4887Schin 	unsigned char	*next;
156*4887Schin };
157*4887Schin 
158*4887Schin int fcmbstate(const char *state, int *s, int *len)
159*4887Schin {
160*4887Schin 	static struct Extra	extra;
161*4887Schin 	register int		i, c, n;
162*4887Schin 	if(_Fcin.fcleft)
163*4887Schin 	{
164*4887Schin 		if((c = mbsize(extra.next)) < 0)
165*4887Schin 			c = 1;
166*4887Schin 		if((_Fcin.fcleft -= c) <=0)
167*4887Schin 		{
168*4887Schin 			_Fcin.fcptr = (unsigned char*)fcfirst() - _Fcin.fcleft;
169*4887Schin 			_Fcin.fcleft = 0;
170*4887Schin 		}
171*4887Schin 		*len = c;
172*4887Schin 		if(c==1)
173*4887Schin 			*s = state[*extra.next++];
174*4887Schin 		else if(c==0)
175*4887Schin 			_Fcin.fcleft = 0;
176*4887Schin 		else
177*4887Schin 		{
178*4887Schin 			c = mbchar(extra.next);
179*4887Schin 			*s = state['a'];
180*4887Schin 		}
181*4887Schin 		return(c);
182*4887Schin 	}
183*4887Schin 	switch(*len = mbsize(_Fcin.fcptr))
184*4887Schin 	{
185*4887Schin 	    case -1:
186*4887Schin 		if(_Fcin._fcfile && (n=(_Fcin.fclast-_Fcin.fcptr)) < MB_LEN_MAX)
187*4887Schin 		{
188*4887Schin 			memcmp(extra.buff, _Fcin.fcptr, n);
189*4887Schin 			_Fcin.fcptr = _Fcin.fclast;
190*4887Schin 			for(i=n; i < MB_LEN_MAX+n; i++)
191*4887Schin 			{
192*4887Schin 				if((extra.buff[i] = fcgetc(c))==0)
193*4887Schin 					break;
194*4887Schin 			}
195*4887Schin 			_Fcin.fcleft = n;
196*4887Schin 			extra.next = extra.buff;
197*4887Schin 			return(fcmbstate(state,s,len));
198*4887Schin 		}
199*4887Schin 		*len = 1;
200*4887Schin 		/* fall through */
201*4887Schin 	    case 0:
202*4887Schin 	    case 1:
203*4887Schin 		*s = state[c=fcget()];
204*4887Schin 		break;
205*4887Schin 	    default:
206*4887Schin 		c = mbchar(_Fcin.fcptr);
207*4887Schin 		*s = state['a'];
208*4887Schin 	}
209*4887Schin 	return(c);
210*4887Schin }
211*4887Schin 
212