1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 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 { if((iosz = f->push->endb - f->push->next) == 0) 114 iosz = f->push->size; 115 if(iosz < sz) 116 iosz = sz; /* so only get what is asked for */ 117 } 118 else 119 { iosz = sz - n; /* get enough to fulfill requirement */ 120 if(size < 0 && iosz < (f->size - n) ) 121 iosz = f->size - n; /* get as much as possible */ 122 if(iosz <= 0) /* nothing to do */ 123 break; 124 } 125 126 /* do a buffer refill or flush */ 127 now = n; 128 if(f->mode&SF_WRITE) 129 (void)SFFLSBUF(f, iosz); 130 else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) ) 131 { if(n == 0) /* peek-read only if there is no buffered data */ 132 { f->mode |= SF_RV; 133 (void)SFFILBUF(f, iosz ); 134 } 135 if((n = f->endb - f->next) < sz) 136 { if(f->mode&SF_PKRD) 137 { f->endb = f->endr = f->next; 138 f->mode &= ~SF_PKRD; 139 } 140 break; 141 } 142 } 143 else 144 { /* sfreserve(f,0,0) == sfread(f, sfreserve(f,-1,SF_LOCKR), 0) */ 145 if(size == 0 && type == 0) 146 f->mode |= SF_RV; 147 148 (void)SFFILBUF(f, iosz ); 149 } 150 151 if((n = f->endb - f->next) <= 0) 152 n = 0; 153 154 if(n >= sz) /* got it */ 155 break; 156 157 if(n == now || sferror(f) || sfeof(f)) /* no progress */ 158 break; 159 160 /* request was only to assess data availability */ 161 if(type == SF_LOCKR && size > 0 && n > 0 ) 162 break; 163 } 164 165 done: /* compute the buffer to be returned */ 166 data = NIL(Void_t*); 167 if(size == 0 || n == 0) 168 { if(n > 0) /* got data */ 169 data = (Void_t*)f->next; 170 else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) ) 171 data = (Void_t*)rsrv->data; 172 } 173 else if(n >= sz) /* got data */ 174 data = (Void_t*)f->next; 175 else if(f->flags&SF_STRING) /* try extending string buffer */ 176 { if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) ) 177 { (void)SFWR(f,f->next,sz,f->disc); 178 if((n = f->endb - f->next) >= sz ) 179 data = (Void_t*)f->next; 180 } 181 } 182 else if(f->mode&SF_WRITE) /* allocate side buffer */ 183 { if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) ) 184 data = (Void_t*)rsrv->data; 185 } 186 else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) ) 187 { if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */ 188 data = (Void_t*)rsrv->data; 189 else rsrv->slen = -n; 190 } 191 192 SFOPEN(f,0); 193 194 if(data) 195 { if(type == SF_LOCKR) 196 { f->mode |= SF_PEEK; 197 if((f->mode & SF_READ) && size == 0 && data != f->next) 198 f->mode |= SF_GETR; /* so sfread() will unlock */ 199 f->endr = f->endw = f->data; 200 } 201 else 202 { if(data == (Void_t*)f->next) 203 f->next += (size >= 0 ? size : n); 204 } 205 } 206 207 _Sfi = f->val = n; /* return true buffer size */ 208 209 SFMTXRETURN(f, data); 210 } 211