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