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