1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 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 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #include "sfhdr.h" 23 24 /* Reserve a segment of data or buffer. 25 ** 26 ** Written by Kiem-Phong Vo. 27 */ 28 29 #if __STD_C 30 Void_t* sfreserve(Sfio_t* f, ssize_t size, int type) 31 #else 32 Void_t* sfreserve(f,size,type) 33 Sfio_t* f; /* file to peek */ 34 ssize_t size; /* size of peek */ 35 int type; /* LOCKR: lock stream, LASTR: last record */ 36 #endif 37 { 38 reg ssize_t n, now, sz, iosz; 39 reg Sfrsrv_t* rsrv; 40 reg Void_t* data; 41 reg int mode, local; 42 SFMTXDECL(f); 43 44 SFMTXENTER(f,NIL(Void_t*)); 45 46 sz = size < 0 ? -size : size; 47 48 /* see if we need to bias toward SF_WRITE instead of the default SF_READ */ 49 if(type < 0) 50 mode = 0; 51 else if((mode = type&SF_WRITE) ) 52 type &= ~SF_WRITE; 53 54 /* return the last record */ 55 if(type == SF_LASTR ) 56 { if((n = f->endb - f->next) > 0 && n == f->val ) 57 { data = (Void_t*)f->next; 58 f->next += n; 59 } 60 else if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0) 61 { rsrv->slen = 0; 62 _Sfi = f->val = n; 63 data = (Void_t*)rsrv->data; 64 } 65 else 66 { _Sfi = f->val = -1; 67 data = NIL(Void_t*); 68 } 69 70 SFMTXRETURN(f, data); 71 } 72 73 if(type > 0) 74 { if(type == 1 ) /* upward compatibility mode */ 75 type = SF_LOCKR; 76 else if(type != SF_LOCKR) 77 SFMTXRETURN(f, NIL(Void_t*)); 78 } 79 80 if(size == 0 && (type < 0 || type == SF_LOCKR) ) 81 { if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0) 82 SFMTXRETURN(f, NIL(Void_t*)); 83 84 SFLOCK(f,0); 85 if((n = f->endb - f->next) < 0) 86 n = 0; 87 88 goto done; 89 } 90 91 /* iterate until get to a stream that has data or buffer space */ 92 for(local = 0;; local = SF_LOCAL) 93 { _Sfi = f->val = -1; 94 95 if(!mode && !(mode = f->flags&SF_READ) ) 96 mode = SF_WRITE; 97 if((int)f->mode != mode && _sfmode(f,mode,local) < 0) 98 { SFOPEN(f,0); 99 SFMTXRETURN(f, NIL(Void_t*)); 100 } 101 102 SFLOCK(f,local); 103 104 if((n = now = f->endb - f->next) < 0) 105 n = 0; 106 if(n > 0 && n >= sz) /* all done */ 107 break; 108 109 /* set amount to perform IO */ 110 if(size == 0 || (f->mode&SF_WRITE)) 111 iosz = -1; 112 else if(size < 0 && n == 0 && f->push) /* maybe stack-pop */ 113 iosz = sz; /* so only get what is asked for */ 114 else 115 { iosz = sz - n; /* get enough to fulfill requirement */ 116 if(size < 0 && iosz < (f->size - n) ) 117 iosz = f->size - n; /* get as much as possible */ 118 if(iosz <= 0) /* nothing to do */ 119 break; 120 } 121 122 /* do a buffer refill or flush */ 123 now = n; 124 if(f->mode&SF_WRITE) 125 (void)SFFLSBUF(f, iosz); 126 else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) ) 127 { if(n == 0) /* peek-read only if there is no buffered data */ 128 { f->mode |= SF_RV; 129 (void)SFFILBUF(f, iosz ); 130 } 131 if((n = f->endb - f->next) < sz) 132 { if(f->mode&SF_PKRD) 133 { f->endb = f->endr = f->next; 134 f->mode &= ~SF_PKRD; 135 } 136 break; 137 } 138 } 139 else 140 { /* sfreserve(f,0,0) == sfread(f, sfreserve(f,-1,SF_LOCKR), 0) */ 141 if(size == 0 && type == 0) 142 f->mode |= SF_RV; 143 144 (void)SFFILBUF(f, iosz ); 145 } 146 147 if((n = f->endb - f->next) <= 0) 148 n = 0; 149 150 if(n >= sz) /* got it */ 151 break; 152 153 if(n == now || sferror(f) || sfeof(f)) /* no progress */ 154 break; 155 156 /* request was only to assess data availability */ 157 if(type == SF_LOCKR && size > 0 && n > 0 ) 158 break; 159 } 160 161 done: /* compute the buffer to be returned */ 162 data = NIL(Void_t*); 163 if(size == 0 || n == 0) 164 { if(n > 0) /* got data */ 165 data = (Void_t*)f->next; 166 else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) ) 167 data = (Void_t*)rsrv->data; 168 } 169 else if(n >= sz) /* got data */ 170 data = (Void_t*)f->next; 171 else if(f->flags&SF_STRING) /* try extending string buffer */ 172 { if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) ) 173 { (void)SFWR(f,f->next,sz,f->disc); 174 if((n = f->endb - f->next) >= sz ) 175 data = (Void_t*)f->next; 176 } 177 } 178 else if(f->mode&SF_WRITE) /* allocate side buffer */ 179 { if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) ) 180 data = (Void_t*)rsrv->data; 181 } 182 else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) ) 183 { if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */ 184 data = (Void_t*)rsrv->data; 185 else rsrv->slen = -n; 186 } 187 188 SFOPEN(f,0); 189 190 if(data) 191 { if(type == SF_LOCKR) 192 { f->mode |= SF_PEEK; 193 if((f->mode & SF_READ) && size == 0 && data != f->next) 194 f->mode |= SF_GETR; /* so sfread() will unlock */ 195 f->endr = f->endw = f->data; 196 } 197 else 198 { if(data == (Void_t*)f->next) 199 f->next += (size >= 0 ? size : n); 200 } 201 } 202 203 _Sfi = f->val = n; /* return true buffer size */ 204 205 SFMTXRETURN(f, data); 206 } 207