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 */ 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 /* 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 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