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* 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 34Fcin_t _Fcin = {0}; 35 36/* 37 * open stream <f> for fast character input 38 */ 39int 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 */ 76int 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 */ 114int 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 */ 131void 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 142extern void fcsave(Fcin_t *fp) 143{ 144 *fp = _Fcin; 145} 146 147#undef fcrestore 148extern 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 159struct Extra 160{ 161 unsigned char buff[2*MB_LEN_MAX]; 162 unsigned char *next; 163}; 164 165int _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