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