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