]> code.delx.au - pulseaudio/blob - polyp/ioline.c
dfa92ab732833737742733bf0424225518b3c71a
[pulseaudio] / polyp / ioline.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "ioline.h"
33 #include "xmalloc.h"
34
35 #define BUFFER_LIMIT (64*1024)
36 #define READ_SIZE (1024)
37
38 struct pa_ioline {
39 struct pa_iochannel *io;
40 int dead;
41
42 char *wbuf;
43 size_t wbuf_length, wbuf_index, wbuf_valid_length;
44
45 char *rbuf;
46 size_t rbuf_length, rbuf_index, rbuf_valid_length;
47
48 void (*callback)(struct pa_ioline*io, const char *s, void *userdata);
49 void *userdata;
50 };
51
52 static void io_callback(struct pa_iochannel*io, void *userdata);
53 static int do_write(struct pa_ioline *l);
54
55 struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) {
56 struct pa_ioline *l;
57 assert(io);
58
59 l = pa_xmalloc(sizeof(struct pa_ioline));
60 l->io = io;
61 l->dead = 0;
62
63 l->wbuf = NULL;
64 l->wbuf_length = l->wbuf_index = l->wbuf_valid_length = 0;
65
66 l->rbuf = NULL;
67 l->rbuf_length = l->rbuf_index = l->rbuf_valid_length = 0;
68
69 l->callback = NULL;
70 l->userdata = NULL;
71
72 pa_iochannel_set_callback(io, io_callback, l);
73
74 return l;
75 }
76
77 void pa_ioline_free(struct pa_ioline *l) {
78 assert(l);
79 pa_iochannel_free(l->io);
80 pa_xfree(l->wbuf);
81 pa_xfree(l->rbuf);
82 pa_xfree(l);
83 }
84
85 void pa_ioline_puts(struct pa_ioline *l, const char *c) {
86 size_t len;
87 assert(l && c);
88
89 len = strlen(c);
90 if (len > BUFFER_LIMIT - l->wbuf_valid_length)
91 len = BUFFER_LIMIT - l->wbuf_valid_length;
92
93 if (!len)
94 return;
95
96 if (len > l->wbuf_length - l->wbuf_valid_length) {
97 size_t n = l->wbuf_valid_length+len;
98 char *new = pa_xmalloc(n);
99 if (l->wbuf) {
100 memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
101 pa_xfree(l->wbuf);
102 }
103 l->wbuf = new;
104 l->wbuf_length = n;
105 l->wbuf_index = 0;
106 } else if (len > l->wbuf_length - l->wbuf_valid_length - l->wbuf_index) {
107 memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
108 l->wbuf_index = 0;
109 }
110
111 memcpy(l->wbuf+l->wbuf_index+l->wbuf_valid_length, c, len);
112 l->wbuf_valid_length += len;
113
114 do_write(l);
115 }
116
117 void pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) {
118 assert(l && callback);
119 l->callback = callback;
120 l->userdata = userdata;
121 }
122
123 static int do_read(struct pa_ioline *l) {
124 ssize_t r;
125 size_t m, len;
126 char *e;
127 assert(l);
128
129 if (!pa_iochannel_is_readable(l->io))
130 return 0;
131
132 len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
133
134 if (len < READ_SIZE) {
135 size_t n = l->rbuf_valid_length+READ_SIZE;
136
137 if (n >= BUFFER_LIMIT)
138 n = BUFFER_LIMIT;
139
140 if (l->rbuf_length >= n) {
141 if (l->rbuf_valid_length)
142 memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
143 } else {
144 char *new = pa_xmalloc(n);
145 if (l->rbuf_valid_length)
146 memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
147 pa_xfree(l->rbuf);
148 l->rbuf = new;
149 l->rbuf_length = n;
150 }
151
152 l->rbuf_index = 0;
153 }
154
155 len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
156
157 if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0)
158 return -1;
159
160 e = memchr(l->rbuf+l->rbuf_index+l->rbuf_valid_length, '\n', r);
161 l->rbuf_valid_length += r;
162
163 if (!e &&l->rbuf_valid_length >= BUFFER_LIMIT)
164 e = l->rbuf+BUFFER_LIMIT-1;
165
166 if (e) {
167 char *p;
168
169 *e = 0;
170
171 p = l->rbuf+l->rbuf_index;
172 m = strlen(p);
173
174 l->rbuf_index += m+1;
175 l->rbuf_valid_length -= m+1;
176
177 if (l->rbuf_valid_length == 0)
178 l->rbuf_index = 0;
179
180 if (l->callback)
181 l->callback(l, p, l->userdata);
182 }
183
184 return 0;
185 }
186
187 static int do_write(struct pa_ioline *l) {
188 ssize_t r;
189 assert(l);
190
191 if (!l->wbuf_valid_length || !pa_iochannel_is_writable(l->io))
192 return 0;
193
194 if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0)
195 return -1;
196
197 l->wbuf_valid_length -= r;
198 if (l->wbuf_valid_length == 0)
199 l->wbuf_index = 0;
200
201 return 0;
202 }
203
204 static void io_callback(struct pa_iochannel*io, void *userdata) {
205 struct pa_ioline *l = userdata;
206 assert(io && l);
207
208 if (!l->dead && do_write(l) < 0)
209 goto fail;
210
211 if (!l->dead && do_read(l) < 0)
212 goto fail;
213
214 return;
215
216 fail:
217 l->dead = 1;
218 if (l->callback)
219 l->callback(l, NULL, l->userdata);
220 }