xref: /titanic_50/usr/src/lib/libshell/common/sh/fcin.c (revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2009 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 
34 Fcin_t _Fcin = {0};
35 
36 /*
37  * open stream <f> for fast character input
38  */
39 int	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  */
76 int	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  */
114 int 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  */
131 void 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
142 extern void fcsave(Fcin_t *fp)
143 {
144 	*fp = _Fcin;
145 }
146 
147 #undef fcrestore
148 extern void fcrestore(Fcin_t *fp)
149 {
150 	_Fcin = *fp;
151 }
152 
153 struct Extra
154 {
155 	unsigned char	buff[2*MB_LEN_MAX];
156 	unsigned char	*next;
157 };
158 
159 int fcmbstate(const char *state, int *s, int *len)
160 {
161 	static struct Extra	extra;
162 	register int		i, c, n;
163 	if(_Fcin.fcleft)
164 	{
165 		if((c = mbsize(extra.next)) < 0)
166 			c = 1;
167 		if((_Fcin.fcleft -= c) <=0)
168 		{
169 			_Fcin.fcptr = (unsigned char*)fcfirst() - _Fcin.fcleft;
170 			_Fcin.fcleft = 0;
171 		}
172 		*len = c;
173 		if(c==1)
174 			*s = state[*extra.next++];
175 		else if(c==0)
176 			_Fcin.fcleft = 0;
177 		else
178 		{
179 			c = mbchar(extra.next);
180 			*s = state['a'];
181 		}
182 		return(c);
183 	}
184 	switch(*len = mbsize(_Fcin.fcptr))
185 	{
186 	    case -1:
187 		if(_Fcin._fcfile && (n=(_Fcin.fclast-_Fcin.fcptr)) < MB_LEN_MAX)
188 		{
189 			memcmp(extra.buff, _Fcin.fcptr, n);
190 			_Fcin.fcptr = _Fcin.fclast;
191 			for(i=n; i < MB_LEN_MAX+n; i++)
192 			{
193 				if((extra.buff[i] = fcgetc(c))==0)
194 					break;
195 			}
196 			_Fcin.fcleft = n;
197 			extra.next = extra.buff;
198 			return(fcmbstate(state,s,len));
199 		}
200 		*len = 1;
201 		/* fall through */
202 	    case 0:
203 	    case 1:
204 		*s = state[c=fcget()];
205 		break;
206 	    default:
207 		c = mbchar(_Fcin.fcptr);
208 		*s = state['a'];
209 	}
210 	return(c);
211 }
212 
213