annotate src/circbuffer.c @ 13967:99b9b58b19dd

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