1 /*
2  * Copyright (C) 2002 2003 2005, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit 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 mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include <config.h>
23 #include "ringbuf.h"
24 #include <string.h>
25 
ringbuf_new(guint32 size)26 Ringbuf *ringbuf_new(guint32 size)
27 {
28      Ringbuf *r;
29 
30      r = g_malloc(sizeof(Ringbuf)+size);
31 
32      r->size = size;
33      r->start = r->end = 0;
34 
35      return r;
36 }
37 
ringbuf_free(Ringbuf * bufptr)38 void ringbuf_free(Ringbuf *bufptr)
39 {
40      g_free(bufptr);
41 }
42 
ringbuf_available(Ringbuf * buf)43 guint32 ringbuf_available(Ringbuf *buf)
44 {
45      guint32 start,end;
46 
47      start = buf->start;
48      end = buf->end;
49 
50      if (end >= start)
51 	  return end-start;
52      else
53 	  return buf->size+1 + end - start;
54 }
55 
ringbuf_freespace(Ringbuf * buf)56 guint32 ringbuf_freespace(Ringbuf *buf)
57 {
58      guint32 start,end;
59 
60      start = buf->start;
61      end = buf->end;
62 
63      if (start > end)
64 	  return start - end - 1;
65      else
66 	  return buf->size + start - end;
67 }
68 
ringbuf_drain(Ringbuf * buf)69 void ringbuf_drain(Ringbuf *buf)
70 {
71      buf->end = buf->start;
72 }
73 
ringbuf_isempty(Ringbuf * buf)74 gboolean ringbuf_isempty(Ringbuf *buf)
75 {
76      return (buf->end == buf->start);
77 }
78 
ringbuf_isfull(Ringbuf * buf)79 gboolean ringbuf_isfull(Ringbuf *buf)
80 {
81      guint32 start,end;
82 
83      start = buf->start;
84      end = buf->end;
85 
86      if (start == 0)
87 	  return (end == buf->size);
88      else
89 	  return (end == start-1);
90 }
91 
ringbuf_enqueue(Ringbuf * buf,gpointer data,guint32 datasize)92 guint32 ringbuf_enqueue(Ringbuf *buf, gpointer data, guint32 datasize)
93 {
94      guint32 blksize;
95      guint32 start,end;
96      guint32 bytes_done = 0;
97 
98      start = buf->start;
99      end = buf->end;
100 
101      if (end >= start) {
102 
103 	  if (start == 0)
104 	       blksize = MIN(datasize, buf->size - end);
105 	  else
106 	       blksize = MIN(datasize, 1+buf->size - end);
107 
108 	  if (blksize == 0) return 0;
109 	  memcpy( buf->data + end, data, blksize );
110 	  end += blksize;
111 	  if (end == 1+buf->size) {
112 	       end = 0;
113 	       bytes_done = blksize;
114 	       /* Fall through */
115 	  } else {
116 	       buf->end = end;
117 	       return blksize;
118 	  }
119      }
120 
121      blksize = MIN ( datasize-bytes_done, start - end - 1);
122 
123      if (blksize == 0) { buf->end = end; return bytes_done; }
124 
125      memcpy( buf->data + end,
126 	     G_STRUCT_MEMBER_P( data, bytes_done ), blksize);
127 
128      end += blksize;
129      bytes_done += blksize;
130 
131      buf->end = end;
132 
133      return bytes_done;
134 }
135 
ringbuf_enqueue_zeroes(Ringbuf * buf,guint32 count)136 guint32 ringbuf_enqueue_zeroes(Ringbuf *buf, guint32 count)
137 {
138      guint32 blksize;
139      guint32 start,end;
140      guint32 bytes_done = 0;
141 
142      start = buf->start;
143      end = buf->end;
144 
145      if (end >= start) {
146 
147 	  if (start == 0)
148 	       blksize = MIN(count, buf->size - end);
149 	  else
150 	       blksize = MIN(count, 1+buf->size - end);
151 
152 	  if (blksize == 0) return 0;
153 	  memset( buf->data + end, 0, blksize );
154 	  end += blksize;
155 	  if (end == 1+buf->size) {
156 	       end = 0;
157 	       bytes_done = blksize;
158 	       /* Fall through */
159 	  } else {
160 	       buf->end = end;
161 	       return blksize;
162 	  }
163      }
164 
165      blksize = MIN ( count-bytes_done, start - end - 1);
166 
167      if (blksize == 0) { buf->end = end; return bytes_done; }
168 
169      memset( buf->data + end, 0, blksize);
170 
171      end += blksize;
172      bytes_done += blksize;
173 
174      buf->end = end;
175 
176      return bytes_done;
177 }
178 
ringbuf_dequeue(Ringbuf * buf,gpointer data,guint32 datasize)179 guint32 ringbuf_dequeue(Ringbuf *buf, gpointer data, guint32 datasize)
180 {
181      guint32 blksize,start,end;
182      guint32 bytes_done = 0;
183 
184      start = buf->start;
185      end = buf->end;
186 
187      if (start > end) {
188 	  blksize = MIN ( datasize, buf->size+1 - start );
189 	  memcpy(data, buf->data+start, blksize);
190 	  start += blksize;
191 	  if (start == buf->size+1) {
192 	       start = 0;
193 	       bytes_done = blksize;
194 	       /* Fall through */
195 	  } else {
196 	       buf->start = start;
197 	       return blksize;
198 	  }
199      }
200 
201      blksize = MIN ( datasize - bytes_done, end - start );
202      if (blksize == 0) { buf->start=start; return bytes_done; }
203 
204      memcpy ( G_STRUCT_MEMBER_P(data,bytes_done), buf->data + start, blksize );
205 
206      start += blksize;
207      bytes_done += blksize;
208 
209      buf->start = start;
210 
211      return bytes_done;
212 }
213 
ringbuf_transfer(Ringbuf * source,Ringbuf * dest)214 guint32 ringbuf_transfer ( Ringbuf *source, Ringbuf *dest )
215 {
216      guint32 blksize;
217      guint32 dest_start,dest_end;
218      guint32 bytes_done = 0;
219 
220      dest_start = dest->start;
221      dest_end = dest->end;
222 
223      if (dest_end >= dest_start) {
224 
225 	  if (dest_start == 0)
226 	       blksize = dest->size - dest_end;
227 	  else
228 	       blksize = 1+dest->size - dest_end;
229 
230 	  if (blksize == 0) return 0;
231 	  blksize = ringbuf_dequeue(source, dest->data + dest_end, blksize);
232 	  dest_end += blksize;
233 	  if (dest_end == 1+dest->size) {
234 	       dest_end = 0;
235 	       bytes_done = blksize;
236 	       /* Fall through */
237 	  } else {
238 	       dest->end = dest_end;
239 	       return blksize;
240 	  }
241      }
242 
243      blksize = dest_start - dest_end - 1;
244 
245      if (blksize == 0) { dest->end = dest_end; return bytes_done; }
246 
247      blksize = ringbuf_dequeue(source, dest->data + dest_end, blksize);
248 
249      dest_end += blksize;
250      bytes_done += blksize;
251 
252      dest->end = dest_end;
253 
254      return bytes_done;
255 }
256 
257