1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*d6f391efSAndy Fiddaman * Copyright (c) 1985-2013 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6b30d1939SAndy Fiddaman * Eclipse Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10b30d1939SAndy Fiddaman * http://www.eclipse.org/org/documents/epl-v10.html *
11b30d1939SAndy Fiddaman * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17*d6f391efSAndy Fiddaman * Glenn Fowler <glenn.s.fowler@gmail.com> *
18*d6f391efSAndy Fiddaman * David Korn <dgkorn@gmail.com> *
19*d6f391efSAndy Fiddaman * Phong Vo <phongvo@gmail.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include "sfhdr.h"
23da2e3ebdSchin
24da2e3ebdSchin /* Move data from one stream to another.
25da2e3ebdSchin ** This code is written so that it'll work even in the presence
26da2e3ebdSchin ** of stacking streams, pool, and discipline.
27da2e3ebdSchin ** If you must change it, be gentle.
28da2e3ebdSchin **
29da2e3ebdSchin ** Written by Kiem-Phong Vo.
30da2e3ebdSchin */
31da2e3ebdSchin #define MAX_SSIZE ((ssize_t)((~((size_t)0)) >> 1))
32da2e3ebdSchin
33da2e3ebdSchin #if __STD_C
sfmove(Sfio_t * fr,Sfio_t * fw,Sfoff_t n,reg int rc)34da2e3ebdSchin Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, reg int rc)
35da2e3ebdSchin #else
36da2e3ebdSchin Sfoff_t sfmove(fr,fw,n,rc)
37da2e3ebdSchin Sfio_t* fr; /* moving data from this stream */
38da2e3ebdSchin Sfio_t* fw; /* moving data to this stream */
39da2e3ebdSchin Sfoff_t n; /* number of bytes/records to move. <0 for unbounded move */
40da2e3ebdSchin reg int rc; /* record separator */
41da2e3ebdSchin #endif
42da2e3ebdSchin {
43da2e3ebdSchin reg uchar *cp, *next;
44da2e3ebdSchin reg ssize_t r, w;
45da2e3ebdSchin reg uchar *endb;
46da2e3ebdSchin reg int direct;
47da2e3ebdSchin Sfoff_t n_move, sk, cur;
48da2e3ebdSchin uchar *rbuf = NIL(uchar*);
49da2e3ebdSchin ssize_t rsize = 0;
50b30d1939SAndy Fiddaman SFMTXDECL(fr); /* declare a shadow stream variable for from stream */
51b30d1939SAndy Fiddaman SFMTXDECL2(fw); /* declare a shadow stream variable for to stream */
52da2e3ebdSchin
537c2fbfb3SApril Chin SFMTXENTER(fr, (Sfoff_t)0);
54da2e3ebdSchin if(fw)
557c2fbfb3SApril Chin SFMTXBEGIN2(fw, (Sfoff_t)0);
56da2e3ebdSchin
57da2e3ebdSchin for(n_move = 0; n != 0; )
58da2e3ebdSchin {
59da2e3ebdSchin if(rc >= 0) /* moving records, let sfgetr() deal with record reading */
60da2e3ebdSchin { if(!(cp = (uchar*)sfgetr(fr,rc,0)) )
61da2e3ebdSchin n = 0;
62da2e3ebdSchin else
63da2e3ebdSchin { r = sfvalue(fr);
64da2e3ebdSchin if(fw && (w = SFWRITE(fw, cp, r)) != r)
65da2e3ebdSchin { if(fr->extent >= 0 )
66da2e3ebdSchin (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
67da2e3ebdSchin if(fw->extent >= 0 && w > 0)
68da2e3ebdSchin (void)SFSEEK(fw,(Sfoff_t)(-w),SEEK_CUR);
69da2e3ebdSchin n = 0;
70da2e3ebdSchin }
71da2e3ebdSchin else
72da2e3ebdSchin { n_move += 1;
73da2e3ebdSchin if(n > 0)
74da2e3ebdSchin n -= 1;
75da2e3ebdSchin }
76da2e3ebdSchin }
77da2e3ebdSchin continue;
78da2e3ebdSchin }
79da2e3ebdSchin
80da2e3ebdSchin /* get the streams into the right mode */
81da2e3ebdSchin if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
82da2e3ebdSchin break;
83da2e3ebdSchin
84da2e3ebdSchin SFLOCK(fr,0);
85da2e3ebdSchin
86da2e3ebdSchin /* flush the write buffer as necessary to make room */
87da2e3ebdSchin if(fw)
88da2e3ebdSchin { if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 )
89da2e3ebdSchin break;
90da2e3ebdSchin SFLOCK(fw,0);
91da2e3ebdSchin if(fw->next >= fw->endb ||
92da2e3ebdSchin (fw->next > fw->data && fr->extent < 0 &&
93da2e3ebdSchin (fw->extent < 0 || (fw->flags&SF_SHARE)) ) )
94da2e3ebdSchin if(SFFLSBUF(fw,-1) < 0 )
95da2e3ebdSchin break;
96da2e3ebdSchin }
97da2e3ebdSchin else if((cur = SFSEEK(fr, (Sfoff_t)0, SEEK_CUR)) >= 0 )
98da2e3ebdSchin { sk = n > 0 ? SFSEEK(fr, n, SEEK_CUR) : SFSEEK(fr, 0, SEEK_END);
99da2e3ebdSchin if(sk > cur) /* safe to skip over data in current stream */
100da2e3ebdSchin { n_move += sk - cur;
101da2e3ebdSchin if(n > 0)
102da2e3ebdSchin n -= sk - cur;
103da2e3ebdSchin continue;
104da2e3ebdSchin }
105da2e3ebdSchin /* else: stream unstacking may happen below */
106da2e3ebdSchin }
107da2e3ebdSchin
108da2e3ebdSchin /* about to move all, set map to a large amount */
109da2e3ebdSchin if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) )
110da2e3ebdSchin { SFMVSET(fr);
111da2e3ebdSchin fr->bits |= SF_SEQUENTIAL; /* sequentially access data */
112da2e3ebdSchin }
113da2e3ebdSchin
114da2e3ebdSchin /* try reading a block of data */
115da2e3ebdSchin direct = 0;
116*d6f391efSAndy Fiddaman if(fr->rsrv && (r = -fr->rsrv->slen) > 0)
117*d6f391efSAndy Fiddaman { fr->rsrv->slen = 0;
118*d6f391efSAndy Fiddaman next = fr->rsrv->data;
119*d6f391efSAndy Fiddaman }
120*d6f391efSAndy Fiddaman else if((r = fr->endb - (next = fr->next)) <= 0)
121da2e3ebdSchin { /* amount of data remained to be read */
122da2e3ebdSchin if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0)
123da2e3ebdSchin { if(fr->extent < 0)
124da2e3ebdSchin w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
125da2e3ebdSchin else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
126da2e3ebdSchin w = SF_NMAP*SF_PAGE;
127da2e3ebdSchin else w = (ssize_t)(fr->extent-fr->here);
128da2e3ebdSchin }
129da2e3ebdSchin
130da2e3ebdSchin /* use a decent buffer for data transfer but make sure
131da2e3ebdSchin that if we overread, the left over can be retrieved
132da2e3ebdSchin */
133da2e3ebdSchin if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) &&
134da2e3ebdSchin (n < 0 || fr->extent >= 0) )
135da2e3ebdSchin { reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE);
136da2e3ebdSchin
137da2e3ebdSchin /* direct transfer to a seekable write stream */
138da2e3ebdSchin if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) )
139da2e3ebdSchin { w = fw->endb - (next = fw->next);
140da2e3ebdSchin direct = SF_WRITE;
141da2e3ebdSchin }
142da2e3ebdSchin else if(w > fr->size && maxw > fr->size)
143da2e3ebdSchin { /* making our own buffer */
144da2e3ebdSchin if(w >= maxw)
145da2e3ebdSchin w = maxw;
146da2e3ebdSchin else w = ((w+fr->size-1)/fr->size)*fr->size;
147da2e3ebdSchin if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
148da2e3ebdSchin rsize = w;
149da2e3ebdSchin if(rbuf)
150da2e3ebdSchin { next = rbuf;
151da2e3ebdSchin w = rsize;
152da2e3ebdSchin direct = SF_STRING;
153da2e3ebdSchin }
154da2e3ebdSchin }
155da2e3ebdSchin }
156da2e3ebdSchin
157da2e3ebdSchin if(!direct)
158da2e3ebdSchin { /* make sure we don't read too far ahead */
159da2e3ebdSchin if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) )
160da2e3ebdSchin { if((Sfoff_t)(r = fr->size) > n)
161da2e3ebdSchin r = (ssize_t)n;
162da2e3ebdSchin }
163da2e3ebdSchin else r = -1;
164da2e3ebdSchin if((r = SFFILBUF(fr,r)) <= 0)
165da2e3ebdSchin break;
166da2e3ebdSchin next = fr->next;
167da2e3ebdSchin }
168da2e3ebdSchin else
169da2e3ebdSchin { /* actual amount to be read */
170da2e3ebdSchin if(n > 0 && n < w)
171da2e3ebdSchin w = (ssize_t)n;
172da2e3ebdSchin
173da2e3ebdSchin if((r = SFRD(fr,next,w,fr->disc)) > 0)
174da2e3ebdSchin fr->next = fr->endb = fr->endr = fr->data;
175da2e3ebdSchin else if(r == 0)
176da2e3ebdSchin break; /* eof */
177da2e3ebdSchin else goto again; /* popped stack */
178da2e3ebdSchin }
179da2e3ebdSchin }
180da2e3ebdSchin
181da2e3ebdSchin /* compute the extent of data to be moved */
182da2e3ebdSchin endb = next+r;
183da2e3ebdSchin if(n > 0)
184da2e3ebdSchin { if(r > n)
185da2e3ebdSchin r = (ssize_t)n;
186da2e3ebdSchin n -= r;
187da2e3ebdSchin }
188da2e3ebdSchin n_move += r;
189da2e3ebdSchin cp = next+r;
190da2e3ebdSchin
191da2e3ebdSchin if(!direct)
192da2e3ebdSchin fr->next += r;
193da2e3ebdSchin else if((w = endb-cp) > 0)
194da2e3ebdSchin { /* move left-over to read stream */
195da2e3ebdSchin if(w > fr->size)
196da2e3ebdSchin w = fr->size;
197da2e3ebdSchin memcpy((Void_t*)fr->data,(Void_t*)cp,w);
198da2e3ebdSchin fr->endb = fr->data+w;
199da2e3ebdSchin if((w = endb - (cp+w)) > 0)
200da2e3ebdSchin (void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc);
201da2e3ebdSchin }
202da2e3ebdSchin
203da2e3ebdSchin if(fw)
204da2e3ebdSchin { if(direct == SF_WRITE)
205da2e3ebdSchin fw->next += r;
206da2e3ebdSchin else if(r <= (fw->endb-fw->next) )
207da2e3ebdSchin { memcpy((Void_t*)fw->next,(Void_t*)next,r);
208da2e3ebdSchin fw->next += r;
209da2e3ebdSchin }
210da2e3ebdSchin else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
211da2e3ebdSchin { /* a write error happened */
212da2e3ebdSchin if(w > 0)
213da2e3ebdSchin { r -= w;
214da2e3ebdSchin n_move -= r;
215da2e3ebdSchin }
216da2e3ebdSchin if(fr->extent >= 0)
217da2e3ebdSchin (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
218da2e3ebdSchin break;
219da2e3ebdSchin }
220da2e3ebdSchin }
221da2e3ebdSchin
222da2e3ebdSchin again:
223da2e3ebdSchin SFOPEN(fr,0);
224da2e3ebdSchin if(fw)
225da2e3ebdSchin SFOPEN(fw,0);
226da2e3ebdSchin }
227da2e3ebdSchin
228da2e3ebdSchin if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE))
229da2e3ebdSchin { /* back to normal access mode */
230da2e3ebdSchin SFMVUNSET(fr);
231da2e3ebdSchin if((fr->bits&SF_SEQUENTIAL) && (fr->data))
232da2e3ebdSchin SFMMSEQOFF(fr,fr->data,fr->endb-fr->data);
233da2e3ebdSchin fr->bits &= ~SF_SEQUENTIAL;
234da2e3ebdSchin }
235da2e3ebdSchin
236da2e3ebdSchin if(rbuf)
237da2e3ebdSchin free(rbuf);
238da2e3ebdSchin
239da2e3ebdSchin if(fw)
240da2e3ebdSchin { SFOPEN(fw,0);
2417c2fbfb3SApril Chin SFMTXEND2(fw);
242da2e3ebdSchin }
243da2e3ebdSchin
2447c2fbfb3SApril Chin SFOPEN(fr,0);
245da2e3ebdSchin SFMTXRETURN(fr, n_move);
246da2e3ebdSchin }
247