packaging: Bump to 1.17
[platform/upstream/ofono.git] / gatchat / ringbuffer.c
1 /*
2  *
3  *  AT chat library with GLib integration
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include <glib.h>
29
30 #include "ringbuffer.h"
31
32 #define MAX_SIZE 262144
33
34 struct ring_buffer {
35         unsigned char *buffer;
36         unsigned int size;
37         unsigned int mask;
38         unsigned int in;
39         unsigned int out;
40 };
41
42 struct ring_buffer *ring_buffer_new(unsigned int size)
43 {
44         unsigned int real_size = 1;
45         struct ring_buffer *buffer;
46
47         /* Find the next power of two for size */
48         while (real_size < size && real_size < MAX_SIZE)
49                 real_size = real_size << 1;
50
51         if (real_size > MAX_SIZE)
52                 return NULL;
53
54         buffer = g_slice_new(struct ring_buffer);
55         if (buffer == NULL)
56                 return NULL;
57
58         buffer->buffer = g_slice_alloc(real_size);
59         if (buffer->buffer == NULL) {
60                 g_free(buffer);
61                 return NULL;
62         }
63
64         buffer->size = real_size;
65         buffer->mask = real_size - 1;
66         buffer->in = 0;
67         buffer->out = 0;
68
69         return buffer;
70 }
71
72 int ring_buffer_write(struct ring_buffer *buf, const void *data,
73                         unsigned int len)
74 {
75         unsigned int end;
76         unsigned int offset;
77         const unsigned char *d = data; /* Needed to satisfy non-gcc compilers */
78
79         /* Determine how much we can actually write */
80         len = MIN(len, buf->size - buf->in + buf->out);
81
82         /* Determine how much to write before wrapping */
83         offset = buf->in & buf->mask;
84         end = MIN(len, buf->size - offset);
85         memcpy(buf->buffer+offset, d, end);
86
87         /* Now put the remainder on the beginning of the buffer */
88         memcpy(buf->buffer, d + end, len - end);
89
90         buf->in += len;
91
92         return len;
93 }
94
95 unsigned char *ring_buffer_write_ptr(struct ring_buffer *buf,
96                                         unsigned int offset)
97 {
98         return buf->buffer + ((buf->in + offset) & buf->mask);
99 }
100
101 int ring_buffer_avail_no_wrap(struct ring_buffer *buf)
102 {
103         unsigned int offset = buf->in & buf->mask;
104         unsigned int len = buf->size - buf->in + buf->out;
105
106         return MIN(len, buf->size - offset);
107 }
108
109 int ring_buffer_write_advance(struct ring_buffer *buf, unsigned int len)
110 {
111         len = MIN(len, buf->size - buf->in + buf->out);
112         buf->in += len;
113
114         return len;
115 }
116
117 int ring_buffer_read(struct ring_buffer *buf, void *data, unsigned int len)
118 {
119         unsigned int end;
120         unsigned int offset;
121         unsigned char *d = data;
122
123         len = MIN(len, buf->in - buf->out);
124
125         /* Grab data from buffer starting at offset until the end */
126         offset = buf->out & buf->mask;
127         end = MIN(len, buf->size - offset);
128         memcpy(d, buf->buffer + offset, end);
129
130         /* Now grab remainder from the beginning */
131         memcpy(d + end, buf->buffer, len - end);
132
133         buf->out += len;
134
135         if (buf->out == buf->in)
136                 buf->out = buf->in = 0;
137
138         return len;
139 }
140
141 int ring_buffer_drain(struct ring_buffer *buf, unsigned int len)
142 {
143         len = MIN(len, buf->in - buf->out);
144
145         buf->out += len;
146
147         if (buf->out == buf->in)
148                 buf->out = buf->in = 0;
149
150         return len;
151 }
152
153 int ring_buffer_len_no_wrap(struct ring_buffer *buf)
154 {
155         unsigned int offset = buf->out & buf->mask;
156         unsigned int len = buf->in - buf->out;
157
158         return MIN(len, buf->size - offset);
159 }
160
161 unsigned char *ring_buffer_read_ptr(struct ring_buffer *buf,
162                                         unsigned int offset)
163 {
164         return buf->buffer + ((buf->out + offset) & buf->mask);
165 }
166
167 int ring_buffer_len(struct ring_buffer *buf)
168 {
169         if (buf == NULL)
170                 return -1;
171
172         return buf->in - buf->out;
173 }
174
175 void ring_buffer_reset(struct ring_buffer *buf)
176 {
177         if (buf == NULL)
178                 return;
179
180         buf->in = 0;
181         buf->out = 0;
182 }
183
184 int ring_buffer_avail(struct ring_buffer *buf)
185 {
186         if (buf == NULL)
187                 return -1;
188
189         return buf->size - buf->in + buf->out;
190 }
191
192 int ring_buffer_capacity(struct ring_buffer *buf)
193 {
194         if (buf == NULL)
195                 return -1;
196
197         return buf->size;
198 }
199
200 void ring_buffer_free(struct ring_buffer *buf)
201 {
202         if (buf == NULL)
203                 return;
204
205         g_slice_free1(buf->size, buf->buffer);
206         g_slice_free1(sizeof(struct ring_buffer), buf);
207 }