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 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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 /* 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
159 struct Extra
160 {
161 unsigned char buff[2*MB_LEN_MAX];
162 unsigned char *next;
163 };
164
_fcmbget(short * len)165 int _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