1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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(reg Sfio_t* f, ssize_t size, int type) 31 #else 32 Void_t* sfreserve(f,size,type) 33 reg 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 43 SFMTXSTART(f,NIL(Void_t*)); 44 45 sz = size < 0 ? -size : size; 46 47 /* see if we need to bias toward SF_WRITE instead of the default SF_READ */ 48 if(type < 0) 49 mode = 0; 50 else if((mode = type&SF_WRITE) ) 51 type &= ~SF_WRITE; 52 53 /* return the last record */ 54 if(type == SF_LASTR ) 55 { if((n = f->endb - f->next) > 0 && n == f->val ) 56 { data = (Void_t*)f->next; 57 f->next += n; 58 } 59 else if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0) 60 { rsrv->slen = 0; 61 _Sfi = f->val = n; 62 data = (Void_t*)rsrv->data; 63 } 64 else 65 { _Sfi = f->val = -1; 66 data = NIL(Void_t*); 67 } 68 69 SFMTXRETURN(f, data); 70 } 71 72 if(type > 0) 73 { if(type == 1 ) /* upward compatibility mode */ 74 type = SF_LOCKR; 75 else if(type != SF_LOCKR) 76 SFMTXRETURN(f, NIL(Void_t*)); 77 } 78 79 if(size == 0 && (type < 0 || type == SF_LOCKR) ) 80 { if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0) 81 SFMTXRETURN(f, NIL(Void_t*)); 82 83 SFLOCK(f,0); 84 if((n = f->endb - f->next) < 0) 85 n = 0; 86 87 goto done; 88 } 89 90 /* iterate until get to a stream that has data or buffer space */ 91 for(local = 0;; local = SF_LOCAL) 92 { _Sfi = f->val = -1; 93 94 if(!mode && !(mode = f->flags&SF_READ) ) 95 mode = SF_WRITE; 96 if((int)f->mode != mode && _sfmode(f,mode,local) < 0) 97 { SFOPEN(f,0); 98 SFMTXRETURN(f, NIL(Void_t*)); 99 } 100 101 SFLOCK(f,local); 102 103 if((n = now = f->endb - f->next) < 0) 104 n = 0; 105 if(n > 0 && n >= sz) /* all done */ 106 break; 107 108 /* amount to perform IO */ 109 if(size == 0 || (f->mode&SF_WRITE) ) 110 iosz = -1; 111 else 112 { iosz = sz - n; 113 if(type != SF_LOCKR && size < 0 && iosz < (f->size - n) ) 114 iosz = f->size - n; 115 if(iosz <= 0) 116 break; 117 } 118 119 /* do a buffer refill or flush */ 120 now = n; 121 if(f->mode&SF_WRITE) 122 (void)SFFLSBUF(f, iosz); 123 else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) ) 124 { if(n == 0) /* peek-read only if there is no buffered data */ 125 { f->mode |= SF_RV; 126 (void)SFFILBUF(f, iosz ); 127 } 128 if((n = f->endb - f->next) < sz) 129 { if(f->mode&SF_PKRD) 130 { f->endb = f->endr = f->next; 131 f->mode &= ~SF_PKRD; 132 } 133 break; 134 } 135 } 136 else (void)SFFILBUF(f, iosz ); 137 138 if((n = f->endb - f->next) <= 0) 139 n = 0; 140 141 if(n >= sz) /* got it */ 142 break; 143 144 if(n == now || sferror(f) || sfeof(f)) /* no progress */ 145 break; 146 147 /* request was only to assess data availability */ 148 if(type == SF_LOCKR && size > 0 && n > 0 ) 149 break; 150 } 151 152 done: /* compute the buffer to be returned */ 153 data = NIL(Void_t*); 154 if(size == 0 || n == 0) 155 { if(n > 0) /* got data */ 156 data = (Void_t*)f->next; 157 else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) ) 158 data = (Void_t*)rsrv->data; 159 } 160 else if(n >= sz) /* got data */ 161 data = (Void_t*)f->next; 162 else if(f->flags&SF_STRING) /* try extending string buffer */ 163 { if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) ) 164 { (void)SFWR(f,f->next,sz,f->disc); 165 if((n = f->endb - f->next) >= sz ) 166 data = (Void_t*)f->next; 167 } 168 } 169 else if(f->mode&SF_WRITE) /* allocate side buffer */ 170 { if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) ) 171 data = (Void_t*)rsrv->data; 172 } 173 else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) ) 174 { if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */ 175 data = (Void_t*)rsrv->data; 176 else rsrv->slen = -n; 177 } 178 179 SFOPEN(f,0); 180 181 if(data) 182 { if(type == SF_LOCKR) 183 { f->mode |= SF_PEEK; 184 if((f->mode & SF_READ) && size == 0 && data != f->next) 185 f->mode |= SF_GETR; /* so sfread() will unlock */ 186 f->endr = f->endw = f->data; 187 } 188 else 189 { if(data == (Void_t*)f->next) 190 f->next += (size >= 0 ? size : n); 191 } 192 } 193 194 _Sfi = f->val = n; /* return true buffer size */ 195 196 SFMTXRETURN(f, data); 197 } 198