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