1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 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 */
fcfopen(register Sfio_t * f)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 */
fcfill(void)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 */
fcclose(void)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 */
fcnotify(void (* fun)(Sfio_t *,const char *,int,void *),void * context)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
fcsave(Fcin_t * fp)142 extern void fcsave(Fcin_t *fp)
143 {
144 *fp = _Fcin;
145 }
146
147 #undef fcrestore
fcrestore(Fcin_t * fp)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
fcmbstate(const char * state,int * s,int * len)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 memcpy(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