]> code.delx.au - pulseaudio/blob - src/strbuf.c
cli protocol
[pulseaudio] / src / strbuf.c
1 #include <sys/types.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7
8 struct chunk {
9 struct chunk *next;
10 size_t length;
11 char text[];
12 };
13
14 struct strbuf {
15 size_t length;
16 struct chunk *head, *tail;
17 };
18
19 struct strbuf *strbuf_new(void) {
20 struct strbuf *sb = malloc(sizeof(struct strbuf));
21 assert(sb);
22 sb->length = 0;
23 sb->head = sb->tail = NULL;
24 return sb;
25 }
26
27 void strbuf_free(struct strbuf *sb) {
28 assert(sb);
29 while (sb->head) {
30 struct chunk *c = sb->head;
31 sb->head = sb->head->next;
32 free(c);
33 }
34
35 free(sb);
36 }
37
38 char *strbuf_tostring(struct strbuf *sb) {
39 char *t, *e;
40 struct chunk *c;
41 assert(sb);
42
43 t = malloc(sb->length+1);
44 assert(t);
45
46 e = t;
47 for (c = sb->head; c; c = c->next) {
48 memcpy(e, c->text, c->length);
49 e += c->length;
50 }
51
52 *e = 0;
53
54 return t;
55 }
56
57 char *strbuf_tostring_free(struct strbuf *sb) {
58 char *t;
59 assert(sb);
60 t = strbuf_tostring(sb);
61 strbuf_free(sb);
62 return t;
63 }
64
65 void strbuf_puts(struct strbuf *sb, const char *t) {
66 struct chunk *c;
67 size_t l;
68 assert(sb && t);
69
70 l = strlen(t);
71 c = malloc(sizeof(struct chunk)+l);
72 assert(c);
73
74 c->next = NULL;
75 c->length = l;
76 memcpy(c->text, t, l);
77
78 if (sb->tail) {
79 assert(sb->head);
80 sb->tail->next = c;
81 } else {
82 assert(!sb->head);
83 sb->head = c;
84 }
85
86 sb->tail = c;
87 sb->length += l;
88 }
89
90 int strbuf_printf(struct strbuf *sb, const char *format, ...) {
91 int r, size = 100;
92 struct chunk *c = NULL;
93
94 assert(sb);
95
96 for(;;) {
97 va_list ap;
98
99 c = realloc(c, sizeof(struct chunk)+size);
100 assert(c);
101
102 va_start(ap, format);
103 r = vsnprintf(c->text, size, format, ap);
104 va_end(ap);
105
106 if (r > -1 && r < size) {
107 c->length = r;
108 c->next = NULL;
109
110 if (sb->tail) {
111 assert(sb->head);
112 sb->tail->next = c;
113 } else {
114 assert(!sb->head);
115 sb->head = c;
116 }
117
118 sb->tail = c;
119 sb->length += r;
120
121 return r;
122 }
123
124 if (r > -1) /* glibc 2.1 */
125 size = r+1;
126 else /* glibc 2.0 */
127 size *= 2;
128 }
129 }