]> code.delx.au - pulseaudio/blob - polyp/strbuf.c
introduce pa_xmalloc() and friends
[pulseaudio] / polyp / strbuf.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 <sys/types.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <xmalloc.h>
33
34 #include "strbuf.h"
35
36 struct chunk {
37 struct chunk *next;
38 size_t length;
39 char text[];
40 };
41
42 struct pa_strbuf {
43 size_t length;
44 struct chunk *head, *tail;
45 };
46
47 struct pa_strbuf *pa_strbuf_new(void) {
48 struct pa_strbuf *sb = pa_xmalloc(sizeof(struct pa_strbuf));
49 sb->length = 0;
50 sb->head = sb->tail = NULL;
51 return sb;
52 }
53
54 void pa_strbuf_free(struct pa_strbuf *sb) {
55 assert(sb);
56 while (sb->head) {
57 struct chunk *c = sb->head;
58 sb->head = sb->head->next;
59 pa_xfree(c);
60 }
61
62 pa_xfree(sb);
63 }
64
65 char *pa_strbuf_tostring(struct pa_strbuf *sb) {
66 char *t, *e;
67 struct chunk *c;
68 assert(sb);
69
70 t = pa_xmalloc(sb->length+1);
71
72 e = t;
73 for (c = sb->head; c; c = c->next) {
74 memcpy(e, c->text, c->length);
75 e += c->length;
76 }
77
78 *e = 0;
79
80 return t;
81 }
82
83 char *pa_strbuf_tostring_free(struct pa_strbuf *sb) {
84 char *t;
85 assert(sb);
86 t = pa_strbuf_tostring(sb);
87 pa_strbuf_free(sb);
88 return t;
89 }
90
91 void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) {
92 assert(sb && t);
93 pa_strbuf_putsn(sb, t, strlen(t));
94 }
95
96 void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) {
97 struct chunk *c;
98 assert(sb && t);
99
100 if (!l)
101 return;
102
103 c = pa_xmalloc(sizeof(struct chunk)+l);
104
105 c->next = NULL;
106 c->length = l;
107 memcpy(c->text, t, l);
108
109 if (sb->tail) {
110 assert(sb->head);
111 sb->tail->next = c;
112 } else {
113 assert(!sb->head);
114 sb->head = c;
115 }
116
117 sb->tail = c;
118 sb->length += l;
119 }
120
121 /* The following is based on an example from the GNU libc documentation */
122
123 int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) {
124 int r, size = 100;
125 struct chunk *c = NULL;
126
127 assert(sb);
128
129 for(;;) {
130 va_list ap;
131
132 c = pa_xrealloc(c, sizeof(struct chunk)+size);
133
134 va_start(ap, format);
135 r = vsnprintf(c->text, size, format, ap);
136 va_end(ap);
137
138 if (r > -1 && r < size) {
139 c->length = r;
140 c->next = NULL;
141
142 if (sb->tail) {
143 assert(sb->head);
144 sb->tail->next = c;
145 } else {
146 assert(!sb->head);
147 sb->head = c;
148 }
149
150 sb->tail = c;
151 sb->length += r;
152
153 return r;
154 }
155
156 if (r > -1) /* glibc 2.1 */
157 size = r+1;
158 else /* glibc 2.0 */
159 size *= 2;
160 }
161 }