dtmail: Further Coverity fixes
[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     va_end(va);
241  
242     return (ret);
243 }
244  
245
246
247
248 //------------- beginning of bufreader code
249
250 BufReader::BufReader() {}
251
252 BufReaderMemory::BufReaderMemory(BufferMemory *b)
253 {
254
255     MutexLock mutex(b->_mutex);
256
257     _buffer = b;
258     _nextreader = b->_firstreader;
259     _prevreader = NULL;
260
261     if (b->_firstreader) {
262         b->_firstreader->_prevreader = this;
263     }
264     b->_firstreader = this;
265
266     _currentoffset = 0;
267     _currentchunk = NULL;
268 }
269
270
271 int
272 BufferMemory::getSize()
273 {
274     return (_totalsize);
275 }
276
277
278 int
279 BufReaderMemory::getData(char *user_buffer, int length)
280 {
281     int numread = 0;
282     int numbytes;
283
284     if (! _buffer) {
285         // the buffer has already been freed
286         return (0);
287     }
288
289     MutexLock mutex(_buffer->_mutex);
290
291     // handle starup case
292     if (_currentchunk == NULL) {
293         _currentchunk = _buffer->_firstchunk;
294
295         // see if buffer is still empty
296         if (!_currentchunk) {
297             return (0);
298         }
299     }
300
301     do {
302         // space in buffer
303         numbytes = _currentchunk->_currentend - _currentoffset;
304
305         if (numbytes <= 0) {
306             // we are at the end of this data chunk
307             if (_currentchunk->_nextchunk == NULL) {
308                 // we are at the end of the valid data
309                 break;
310             }
311
312             // advance to the next chunk
313             _currentchunk = _currentchunk->_nextchunk;
314             _currentoffset = 0;
315
316         }
317
318         // don't read more than user requested
319         if (numbytes > length - numread) {
320                 numbytes = length - numread;
321         }
322
323         // copy the data
324         memcpy(user_buffer, &_currentchunk->_buffer[_currentoffset], numbytes);
325
326         // update all the pointers
327         numread += numbytes;
328         user_buffer += numbytes;
329         _currentoffset += numbytes;
330
331     } while (numread < length);
332
333     return (numread);
334 }
335
336
337 BufReaderMemory::~BufReaderMemory()
338 {
339
340     if (! _buffer) return;
341     MutexLock mutex(_buffer->_mutex);
342
343     // unlink us from the buffer's list
344     if (_nextreader) {
345         _nextreader->_prevreader = _prevreader;
346     }
347
348     if (_prevreader) {
349             _prevreader->_nextreader = _nextreader;
350     } else {
351         // ASSERT(_buffer->_firstreader == this);
352         _buffer->_firstreader = _nextreader;
353     }
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368