13951
|
1 /*
|
|
2 * @file circbuffer.h Buffer Utility Functions
|
|
3 * @ingroup core
|
|
4 *
|
|
5 * Gaim is the legal property of its developers, whose names are too numerous
|
|
6 * to list here. Please refer to the COPYRIGHT file distributed with this
|
|
7 * source distribution.
|
|
8 *
|
|
9 * This program is free software; you can redistribute it and/or modify
|
|
10 * it under the terms of the GNU General Public License as published by
|
|
11 * the Free Software Foundation; either version 2 of the License, or
|
|
12 * (at your option) any later version.
|
|
13 *
|
|
14 * This program is distributed in the hope that it will be useful,
|
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 * GNU General Public License for more details.
|
|
18 *
|
|
19 * You should have received a copy of the GNU General Public License
|
|
20 * along with this program; if not, write to the Free Software
|
|
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
22 */
|
|
23 #include "internal.h"
|
|
24
|
|
25 #include "circbuffer.h"
|
|
26
|
|
27 #define DEFAULT_BUF_SIZE 256
|
|
28
|
|
29 GaimCircBuffer *
|
|
30 gaim_circ_buffer_new(gsize growsize) {
|
|
31 GaimCircBuffer *buf = g_new0(GaimCircBuffer, 1);
|
|
32 buf->growsize = growsize ? growsize : DEFAULT_BUF_SIZE;
|
|
33 return buf;
|
|
34 }
|
|
35
|
|
36 void gaim_circ_buffer_destroy(GaimCircBuffer *buf) {
|
|
37 g_return_if_fail(buf);
|
|
38 g_free(buf->buffer);
|
|
39 g_free(buf);
|
|
40 }
|
|
41
|
|
42 static void grow_circ_buffer(GaimCircBuffer *buf, gsize len) {
|
|
43 int in_offset = 0, out_offset = 0;
|
|
44 int start_buflen = buf->buflen;
|
|
45
|
|
46 while ((buf->buflen - buf->bufused) < len)
|
|
47 buf->buflen += buf->growsize;
|
|
48
|
|
49 if (buf->inptr != NULL) {
|
|
50 in_offset = buf->inptr - buf->buffer;
|
|
51 out_offset = buf->outptr - buf->buffer;
|
|
52 }
|
|
53 buf->buffer = g_realloc(buf->buffer, buf->buflen);
|
|
54
|
|
55 /* adjust the fill and remove pointer locations */
|
|
56 if (buf->inptr == NULL) {
|
|
57 buf->inptr = buf->outptr = buf->buffer;
|
|
58 } else {
|
|
59 buf->inptr = buf->buffer + in_offset;
|
|
60 buf->outptr = buf->buffer + out_offset;
|
|
61 }
|
|
62
|
|
63 /* If the fill pointer is wrapped to before the remove
|
|
64 * pointer, we need to shift the data */
|
|
65 if (in_offset < out_offset) {
|
|
66 int shift_n = MIN(buf->buflen - start_buflen,
|
|
67 in_offset);
|
|
68 memcpy(buf->buffer + start_buflen, buf->buffer,
|
|
69 shift_n);
|
|
70
|
|
71 /* If we couldn't fit the wrapped read buffer
|
|
72 * at the end */
|
|
73 if (shift_n < in_offset) {
|
|
74 memmove(buf->buffer,
|
|
75 buf->buffer + shift_n,
|
|
76 in_offset - shift_n);
|
|
77 buf->inptr = buf->buffer +
|
|
78 (in_offset - shift_n);
|
|
79 } else {
|
|
80 buf->inptr = buf->buffer +
|
|
81 start_buflen + in_offset;
|
|
82 }
|
|
83 }
|
|
84 }
|
|
85
|
|
86 void gaim_circ_buffer_append(GaimCircBuffer *buf, gconstpointer src, gsize len) {
|
|
87
|
|
88 int len_stored;
|
|
89
|
|
90 /* Grow the buffer, if necessary */
|
|
91 if ((buf->buflen - buf->bufused) < len)
|
|
92 grow_circ_buffer(buf, len);
|
|
93
|
|
94 /* If there is not enough room to copy all of src before hitting
|
|
95 * the end of the buffer then we will need to do two copies.
|
|
96 * One copy from inptr to the end of the buffer, and the
|
|
97 * second copy from the start of the buffer to the end of src. */
|
|
98 if (buf->inptr >= buf->outptr)
|
|
99 len_stored = MIN(len, buf->buflen
|
|
100 - (buf->inptr - buf->buffer));
|
|
101 else
|
|
102 len_stored = len;
|
|
103
|
|
104 memcpy(buf->inptr, src, len_stored);
|
|
105
|
|
106 if (len_stored < len) {
|
|
107 memcpy(buf->buffer, src + len_stored, len - len_stored);
|
|
108 buf->inptr = buf->buffer + (len - len_stored);
|
|
109 } else if ((buf->buffer - buf->inptr) == len_stored) {
|
|
110 buf->inptr = buf->buffer;
|
|
111 } else {
|
|
112 buf->inptr += len_stored;
|
|
113 }
|
|
114
|
|
115 buf->bufused += len;
|
|
116 }
|
|
117
|
|
118 gsize gaim_circ_buffer_get_max_read(GaimCircBuffer *buf) {
|
|
119 int max_read;
|
|
120
|
|
121 if (buf->bufused == 0)
|
|
122 max_read = 0;
|
|
123 else if ((buf->outptr - buf->inptr) >= 0)
|
|
124 max_read = buf->buflen - (buf->outptr - buf->buffer);
|
|
125 else
|
|
126 max_read = buf->inptr - buf->outptr;
|
|
127
|
|
128 return max_read;
|
|
129 }
|
|
130
|
|
131 gboolean gaim_circ_buffer_mark_read(GaimCircBuffer *buf, gsize len) {
|
|
132 g_return_val_if_fail(gaim_circ_buffer_get_max_read(buf) >= len, FALSE);
|
|
133
|
|
134 buf->outptr += len;
|
|
135 buf->bufused -= len;
|
|
136 /* wrap to the start if we're at the end */
|
|
137 if ((buf->outptr - buf->buffer) == buf->buflen)
|
|
138 buf->outptr = buf->buffer;
|
|
139
|
|
140 return TRUE;
|
|
141 }
|
|
142
|