Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfmove.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: sfmove.c /main/3 1995/11/01 18:31:10 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46 #include        "sfhdr.h"
47
48 /*      Move data from one stream to another.
49 **      This code is written so that it'll work even in the presence
50 **      of stacking streams, pool, and discipline.
51 **      If you must change it, be gentle.
52 **
53 **      Written by Kiem-Phong Vo (12/07/90)
54 */
55
56 #if __STD_C
57 long sfmove(Sfio_t* fr, Sfio_t* fw, long n, reg int rc)
58 #else
59 long sfmove(fr,fw,n,rc)
60 Sfio_t* fr;     /* moving data from this stream */
61 Sfio_t* fw;     /* moving data to this stream */
62 long            n;      /* number of bytes/records to move. <0 for unbounded move */
63 reg int         rc;     /* record separator */
64 #endif
65 {
66         reg uchar       *cp, *next;
67         reg int         r, w;
68         reg uchar       *endb;
69         reg int         direct;
70         reg long        n_move;
71         uchar           *rbuf = NIL(uchar*);
72         int             rsize = 0;
73         reg int         frsize;
74
75         if(!fr)
76                 return 0;
77         frsize = fr->size;
78
79         for(n_move = 0; n != 0; )
80         {       /* get the streams into the right mode */
81                 if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
82                         goto done;
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
98                 /* about to move all, set map to a large amount */
99                 if(n < 0 && (fr->flags&SF_MMAP))
100                         fr->size = fr->size*SF_NMAP;
101
102                 /* try reading a block of data */
103                 direct = 0;
104                 if((r = fr->endb - (next = fr->next)) <= 0)
105                 {       /* amount of data remained to be read */
106                         if((w = n > SF_MAXINT ? SF_MAXINT : (int)n) < 0)
107                         {       if(fr->extent < 0)
108                                         w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
109                                 else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
110                                         w = SF_NMAP*SF_PAGE;
111                                 else    w = (int)(fr->extent-fr->here);
112                         }
113
114                         /* use a decent buffer for data transfer but make sure
115                            that if we overread, the left over can be retrieved
116                         */
117                         if(!(fr->flags&(SF_MMAP|SF_STRING)) &&
118                            (n < 0 || fr->extent >= 0L) )
119                         {       reg int maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE);
120
121                                 /* direct transfer to a seekable write stream */
122                                 if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) )
123                                 {       w = fw->endb - (next = fw->next);
124                                         direct = SF_WRITE;
125                                 }
126                                 else if(w > fr->size && maxw > fr->size)
127                                 {       /* making our own buffer */
128                                         if(w >= maxw)
129                                                 w = maxw;
130                                         else    w = ((w+fr->size-1)/fr->size)*fr->size;
131                                         if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
132                                                 rsize = w;
133                                         if(rbuf)
134                                         {       next = rbuf;
135                                                 w = rsize;
136                                                 direct = SF_STRING;
137                                         }
138                                 }
139                         }
140
141                         if(!direct)
142                         {       /* make sure we don't read too far ahead */
143                                 if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) )
144                                 {       if(rc >= 0)
145                                         {       /* try peeking a large buffer */
146                                                 fr->mode |= SF_RV;
147                                                 if((r = SFFILBUF(fr,-1)) > 0)
148                                                         goto done_filbuf;
149                                                 else /* get a single record */
150                                                 {       fr->getr = rc;
151                                                         fr->mode |= SF_RC;
152                                                         r = -1;
153                                                 }
154                                         }
155                                         else if((long)(r = fr->size) > n)
156                                                 r = (int)n;
157                                 }
158                                 else    r = -1;
159                                 if((r = SFFILBUF(fr,r)) <= 0)
160                                         break;
161                         done_filbuf:
162                                 next = fr->next;
163                         }
164                         else
165                         {       /* actual amount to be read */
166                                 if(rc < 0 && n > 0 && n < w)
167                                         w = (int)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(rc < 0)
180                 {       if(n > 0)
181                         {       if(r > n)
182                                         r = (int)n;
183                                 n -= r;
184                         }
185                         n_move += r;
186                         cp = next+r;
187                 }
188                 else
189                 {       /* count records */
190                         reg int rdwr = (fr->flags&(SF_BOTH|SF_MALLOC|SF_MMAP));
191
192                         if(rdwr)
193                         {       w = endb[-1];
194                                 endb[-1] = rc;
195                         }
196                         else    w = 0;
197                         for(cp = next; cp < endb; )
198                         {       /* find the line extent */
199                                 if(rdwr)
200                                         while(*cp++ != rc)
201                                                 ;
202                                 else    while(r-- && *cp++ != rc)
203                                                 ;
204                                 if(cp < endb || w == rc)
205                                 {       n_move += 1;
206                                         if(n > 0 && (n -= 1) == 0)
207                                                 break;
208                                 }
209                         }
210                         if(rdwr)
211                                 endb[-1] = w;
212                         r = cp-next;
213                         if(fr->mode&SF_PKRD)
214                         {       /* advance the read point by proper amount */
215                                 fr->mode &= ~SF_PKRD;
216                                 (void)read(fr->file,(Void_t*)next,r);
217                                 fr->here += r;
218                                 if(!direct)
219                                         fr->endb = cp;
220                                 else    endb = cp;
221                         }
222                 }
223
224                 if(!direct)
225                         fr->next += r;
226                 else if((w = endb-cp) > 0)
227                 {       /* move left-over to read stream */
228                         if(w > fr->size)
229                                 w = fr->size;
230                         memcpy((Void_t*)fr->data,(Void_t*)cp,w);
231                         fr->endb = fr->data+w;
232                         if((w = endb - (cp+w)) > 0)
233                                 (void)SFSK(fr,(long)(-w),1,fr->disc);
234                 }
235
236                 if(fw)
237                 {       if(direct == SF_WRITE)
238                                 fw->next += r;
239                         else if(r <= (fw->endb-fw->next) )
240                         {       memcpy((Void_t*)fw->next,(Void_t*)next,r);
241                                 fw->next += r;
242                         }
243                         else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
244                         {       /* a write error happened */
245                                 if(w > 0)
246                                 {       r -= w;
247                                         if(rc < 0)
248                                                 n_move -= r;
249                                 }
250                                 if(fr->extent >= 0L)
251                                         (void)SFSEEK(fr,(long)(-r),1);
252                                 break;
253                         }
254                 }
255
256         again:
257                 SFOPEN(fr,0);
258                 if(fw)
259                         SFOPEN(fw,0);
260         }
261
262 done:
263         if(n < 0 && (fr->flags&SF_MMAP) )
264                 fr->size = frsize;
265
266         if(rbuf)
267                 free((char*)rbuf);
268
269         SFOPEN(fr,0);
270         if(fw)
271                 SFOPEN(fw,0);
272
273         return n_move;
274 }