1 /* pool.c - create a file in memeory to write to
2 Copyright (C) 1996-2017 Paul Sheer
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307, USA.
18 */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include "stringtools.h"
25 #include "pool.h"
26 #include "mad.h"
27
28 #define min(x,y) ((x)<=(y)?(x):(y))
29
30 /* returns NULL on error */
31 #ifdef HAVE_MAD
mad_pool_init(char * file,int line)32 POOL *mad_pool_init (char *file, int line)
33 #else
34 POOL *pool_init (void)
35 #endif
36 {
37 POOL *p;
38 p = malloc (sizeof (POOL));
39 if (!p)
40 return 0;
41 #ifdef HAVE_MAD
42 p->current = p->start = mad_alloc (START_SIZE, file, line);
43 #else
44 p->current = p->start = malloc (START_SIZE);
45 #endif
46 if (!p->start)
47 return 0;
48 p->end = p->start + START_SIZE;
49 p->length = START_SIZE;
50 return p;
51 }
52
53 /* free's a pool except for the actual data which is returned */
54 /* result must be free'd by the caller even if the pool_length is zero */
pool_break(POOL * p)55 unsigned char *pool_break (POOL * p)
56 {
57 unsigned char *d;
58 d = p->start;
59 free (p);
60 return d;
61 }
62
63 /* free's a pool and all its data */
pool_free(POOL * p)64 void pool_free (POOL * p)
65 {
66 if (!p)
67 return;
68 if (p->start)
69 free (p->start);
70 free (p);
71 }
72
73 /* make space for a forthcoming write of l bytes. leaves current untouched */
74 #ifdef HAVE_MAD
mad_pool_advance(POOL * p,unsigned long l,char * file,int line)75 unsigned long mad_pool_advance (POOL * p, unsigned long l, char *file, int line)
76 #else
77 unsigned long pool_advance (POOL * p, unsigned long l)
78 #endif
79 {
80 if ((unsigned long) p->current + l > (unsigned long) p->end) {
81 unsigned char *t;
82 unsigned long old_length;
83 old_length = p->length;
84 do {
85 p->length *= 2;
86 p->end = p->start + p->length;
87 } while ((unsigned long) p->current + l > (unsigned long) p->end);
88 #ifdef HAVE_MAD
89 t = mad_alloc (p->length, file, line);
90 #else
91 t = malloc (p->length);
92 #endif
93 if (!t)
94 return 0;
95 memcpy (t, p->start, old_length);
96 p->current = t + (unsigned long) p->current - (unsigned long) p->start;
97 free (p->start);
98 p->start = t;
99 p->end = p->start + p->length;
100 }
101 return l;
102 }
103
104 /* returns the number of bytes written into p */
105 #ifdef HAVE_MAD
mad_pool_write(POOL * p,unsigned char * d,unsigned long l,char * file,int line)106 unsigned long mad_pool_write (POOL * p, unsigned char *d, unsigned long l, char *file, int line)
107 #else
108 unsigned long pool_write (POOL * p, unsigned char *d, unsigned long l)
109 #endif
110 {
111 unsigned long a;
112 #ifdef HAVE_MAD
113 a = mad_pool_advance (p, l, file, line);
114 #else
115 a = pool_advance (p, l);
116 #endif
117 memcpy (p->current, d, a);
118 p->current += a;
119 return a;
120 }
121
122 /* returns the number of bytes read into d */
pool_read(POOL * p,unsigned char * d,unsigned long l)123 unsigned long pool_read (POOL * p, unsigned char *d, unsigned long l)
124 {
125 unsigned long m;
126 m = min (l, (unsigned long) p->end - (unsigned long) p->current);
127 memcpy (d, p->current, m);
128 p->current += m;
129 return m;
130 }
131
132 /* sets the position in the pool */
pool_seek(POOL * p,unsigned long l)133 unsigned long pool_seek (POOL * p, unsigned long l)
134 {
135 unsigned long m;
136 m = min (l, p->length);
137 p->current = p->start + m;
138 return m;
139 }
140
141 /* used like sprintf */
pool_printf(POOL * p,const char * fmt,...)142 unsigned long pool_printf (POOL * p, const char *fmt,...)
143 {
144 unsigned long l;
145 va_list ap;
146 va_start (ap, fmt);
147 l = vfmtlen (fmt, ap) + 1;
148 va_end (ap);
149 if (pool_advance (p, l) != l)
150 return 0;
151 va_start (ap, fmt);
152 vsprintf ((char *) p->current, fmt, ap);
153 va_end (ap);
154 l = strlen ((char *) p->current);
155 p->current += l;
156 return l;
157 }
158
159 /* zero the char after the last char written/read */
pool_null(POOL * p)160 int pool_null (POOL * p)
161 {
162 if (pool_advance (p, 1) != 1)
163 return 0;
164 p->current[0] = 0;
165 return 1;
166 }
167
168 /* removes the last line from the length, and null-terminates */
pool_drop_last_line(POOL * p)169 void pool_drop_last_line (POOL * p)
170 {
171 char *q;
172 q = (char *) strrchr ((char *) pool_start (p), '\n');
173 if (!q)
174 pool_seek (p, 0);
175 else
176 pool_seek (p, (int) (q - (char *) pool_start (p)) + 1);
177 pool_null (p);
178 }
179
180