Remove Unixware and openserver support
[oweals/cde.git] / cde / programs / dtmail / libDtMail / Common / Buffer.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 libraries 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 /*
24  *+SNOTICE
25  *
26  *
27  *  $XConsortium: Buffer.C /main/6 1996/04/21 19:47:10 drk $
28  *
29  *  RESTRICTED CONFIDENTIAL INFORMATION:
30  *  
31  *  The information in this document is subject to special
32  *  restrictions in a confidential disclosure agreement between
33  *  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *  document outside HP, IBM, Sun, USL, SCO, or Univel without
35  *  Sun's specific written approval.  This document and all copies
36  *  and derivative works thereof must be returned or destroyed at
37  *  Sun's request.
38  *
39  *  Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
40  *
41  *+ENOTICE
42  */
43
44 #include <DtMail/Buffer.hh>
45
46 #include <string.h>
47 #ifdef __osf__
48 #include <stdlib.h>
49 #endif // __osf__
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <DtMail/Threads.hh>
53
54 const int Buffer::defaultchunksize = 16 * 1024;
55
56
57 // buffer.C -- implement buffer class
58
59
60 // initialization
61 void
62 BufferMemory::initBuffer(int chunksize)
63 {
64     _firstreader = NULL;
65     _firstchunk = NULL;
66     _lastchunk = NULL;
67     _totalsize = 0;
68     _chunksize = chunksize;
69
70     _mutex = MutexInit();
71 }
72
73 BufferMemory::BufferMemory()
74 {
75     initBuffer(defaultchunksize);
76 }
77
78 BufferMemory::BufferMemory(int chunksize)
79 {
80     initBuffer(chunksize);
81 }
82
83
84 BufferMemory::~BufferMemory()
85 {
86         MutexLock mutex(_mutex);
87
88         // free the data in the buffer
89         Chunk *c = _firstchunk;
90         while (c) {
91                 Chunk *next;
92
93                 next = c->_nextchunk;
94                 free(c->_buffer);
95                 free(c);
96                 c = next;
97         }
98
99
100         // disassociate us from all the readers
101         BufReaderMemory *r = _firstreader;
102         while (r) {
103                 r->_buffer = NULL;
104                 r = r->_nextreader;
105         }
106
107         // free the mutex
108         mutex.unlock_and_destroy();
109 }
110
111
112
113
114 Buffer::Buffer() { }
115 Buffer::~Buffer() { }
116 BufReader::~BufReader() { }
117
118
119 // buffer memory class functions
120 int
121 BufferMemory::appendData(const char *user_buffer, int length)
122 {
123     int numwritten = 0;
124     int numbytes;
125
126     MutexLock mutex(_mutex);
127
128     while (numwritten < length) {
129         if (! _lastchunk || _lastchunk->_chunksize <= _lastchunk->_currentend) {
130             // we need to get a new data chunk
131             if (newChunk(length - numwritten) < 0) {
132
133                 // we had an allocation error
134                 return (numwritten);
135             }
136         }
137
138         // number of free bytes in data chunk
139         numbytes = _lastchunk->_chunksize - _lastchunk->_currentend;
140
141         // don't write more than remaining bytes in user's request
142         if (numbytes > length - numwritten) {
143             numbytes = length - numwritten;
144         }
145
146         // do the copy
147         (void) memcpy(&_lastchunk->_buffer[_lastchunk->_currentend],
148                 user_buffer, numbytes);
149
150         // update the counters
151         numwritten += numbytes;
152         _totalsize += numbytes;
153         _lastchunk->_currentend += numbytes;
154         user_buffer += numbytes;
155
156     }
157
158     return (numwritten);
159 }
160
161
162 // add a new data chunk to the buffer
163 int
164 BufferMemory::newChunk(int size)
165 {
166     // make sure we get at least the default chunksize
167     if (size < _chunksize) size = _chunksize;
168
169     // allocate the data regions
170     Chunk *d = (Chunk *) malloc(sizeof (Chunk));
171     if (! d) return (-1);
172
173     d->_buffer = (char *) malloc(size);
174     if (! d->_buffer) {
175         free (d);
176         return (-1);
177     }
178
179     d->_chunksize = size;
180     d->_currentend = 0;
181
182     // now splice it into the list
183     // lock should already have been called
184
185     d->_nextchunk = NULL;
186     if (_firstchunk == NULL) _firstchunk = d;
187
188     if (_lastchunk) {
189         _lastchunk->_nextchunk = d;
190     }
191     _lastchunk = d;
192
193     return (0);
194 }
195
196
197 BufReader *
198 BufferMemory::getReader(void)
199 {
200     BufReader *r;
201
202     MutexLock mutex(_mutex);
203
204     r = new BufReaderMemory(this);
205
206     return (r);
207 }
208
209
210 unsigned long
211 BufferMemory::iterate(Buffer::CallBack callback, ...)
212 {
213     va_list va;
214     MutexLock mutex(_mutex);
215     Chunk *c;
216     unsigned long ret = 0;
217  
218     va_start(va, callback);
219  
220     // walk through the chunk list, calling the callback for each one
221     for (c = _firstchunk; c; c = c->_nextchunk) {
222
223         // don't bother with null length chunks
224         if (c->_currentend == 0) continue;
225
226         // do the callback
227         ret = (*callback)(c->_buffer, c->_currentend, va);
228
229         // check for problems
230         if (ret) break;
231     }
232     
233     va_end(va);
234  
235     return (ret);
236 }
237  
238
239
240
241 //------------- beginning of bufreader code
242
243 BufReader::BufReader() {}
244
245 BufReaderMemory::BufReaderMemory(BufferMemory *b)
246 {
247
248     MutexLock mutex(b->_mutex);
249
250     _buffer = b;
251     _nextreader = b->_firstreader;
252     _prevreader = NULL;
253
254     if (b->_firstreader) {
255         b->_firstreader->_prevreader = this;
256     }
257     b->_firstreader = this;
258
259     _currentoffset = 0;
260     _currentchunk = NULL;
261 }
262
263
264 int
265 BufferMemory::getSize()
266 {
267     return (_totalsize);
268 }
269
270
271 int
272 BufReaderMemory::getData(char *user_buffer, int length)
273 {
274     int numread = 0;
275     int numbytes;
276
277     if (! _buffer) {
278         // the buffer has already been freed
279         return (0);
280     }
281
282     MutexLock mutex(_buffer->_mutex);
283
284     // handle starup case
285     if (_currentchunk == NULL) {
286         _currentchunk = _buffer->_firstchunk;
287
288         // see if buffer is still empty
289         if (!_currentchunk) {
290             return (0);
291         }
292     }
293
294     do {
295         // space in buffer
296         numbytes = _currentchunk->_currentend - _currentoffset;
297
298         if (numbytes <= 0) {
299             // we are at the end of this data chunk
300             if (_currentchunk->_nextchunk == NULL) {
301                 // we are at the end of the valid data
302                 break;
303             }
304
305             // advance to the next chunk
306             _currentchunk = _currentchunk->_nextchunk;
307             _currentoffset = 0;
308
309         }
310
311         // don't read more than user requested
312         if (numbytes > length - numread) {
313                 numbytes = length - numread;
314         }
315
316         // copy the data
317         memcpy(user_buffer, &_currentchunk->_buffer[_currentoffset], numbytes);
318
319         // update all the pointers
320         numread += numbytes;
321         user_buffer += numbytes;
322         _currentoffset += numbytes;
323
324     } while (numread < length);
325
326     return (numread);
327 }
328
329
330 BufReaderMemory::~BufReaderMemory()
331 {
332
333     if (! _buffer) return;
334     MutexLock mutex(_buffer->_mutex);
335
336     // unlink us from the buffer's list
337     if (_nextreader) {
338         _nextreader->_prevreader = _prevreader;
339     }
340
341     if (_prevreader) {
342             _prevreader->_nextreader = _nextreader;
343     } else {
344         // ASSERT(_buffer->_firstreader == this);
345         _buffer->_firstreader = _nextreader;
346     }
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361