1 /****************************************************************************
2 * Copyright (C) 2008 by Matteo Franchin *
3 * *
4 * This file is part of Box. *
5 * *
6 * Box is free software: you can redistribute it and/or modify it *
7 * under the terms of the GNU Lesser General Public License as published *
8 * by the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * Box 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 Lesser General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with Box. If not, see <http://www.gnu.org/licenses/>. *
18 ****************************************************************************/
19
20 /* buffer.c - aprile 2002
21 *
22 * Questo file contiene il codice necessario per gestire un buffer.
23 * Si possono inserire e togliere elementi senza preoccuparsi
24 * dei ridimensionamenti del buffer.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 /* De-commentare per includere i messaggi di debug */
32 /*#define DEBUG*/
33
34 #include "error.h"
35 #include "buffer.h"
36
37 /* Questa macro provvede ad allargare il buffer
38 * in modo che riesca a contenere n elementi
39 */
40 #define BUFF_EXPAND(buffer, n) \
41 if ( n > buffer->dim ) { \
42 if ( buffer->dim == 0 ) { \
43 for( buffer->dim = buffer->mindim; \
44 buffer->dim < n; buffer->dim *= 2); \
45 buffer->size = (buffer->dim) * buffer->elsize; \
46 buffer->ptr = malloc( buffer->size ); \
47 } else { \
48 for(; buffer->dim < n; buffer->dim *= 2); \
49 buffer->size = (buffer->dim)*buffer->elsize; \
50 buffer->ptr = realloc( buffer->ptr, buffer->size ); \
51 } \
52 if ( buffer->ptr == NULL ) { \
53 FATALMSG("buffer.c", "Memoria esaurita"); \
54 return 0; \
55 }\
56 }
57
58 /* Questa macro provvede a contrarre il buffer
59 * qualora sia vuoto per piu' di 3/4
60 * in modo tale che sia almeno mezzo pieno.
61 * n e' il numero di elementi del buffer.
62 */
63 #define BUFF_SHRINK(buffer, n) \
64 if (buffer->dim > buffer->mindim) { \
65 for(; 4*n < buffer->dim; buffer->dim /= 2); \
66 if (buffer->dim < buffer->mindim) \
67 buffer->dim = buffer->mindim; \
68 buffer->size = (buffer->dim)*buffer->elsize; \
69 buffer->ptr = realloc( buffer->ptr, buffer->size ); \
70 if ( buffer->ptr == NULL ) { \
71 ERRORMSG("buffer.c", "Problemi con realloc"); \
72 return 0; \
73 } \
74 }
75
76 /* NOME: buff_create
77 * DESCRIZIONE: Crea un buffer con:
78 * elsize = numero byte per elemento
79 * mindim = dimensione minima del buffer (in elementi)
80 * Restituisce 1 se tutto va bene, 0 in caso di errore.
81 * NOTA: buffer e' un puntatore ad una struttura di tipo
82 * buff (gia' precedentemente allocata).
83 */
buff_create(buff * buffer,short elsize,long mindim)84 int buff_create(buff *buffer, short elsize, long mindim) {
85 if (elsize<1 || mindim<1) {
86 ERRORMSG("buff_create", "Parametri errati");
87 buffer->id = 0;
88 return 0;
89 }
90
91 buffer->id = buffID;
92 buffer->ptr = NULL;
93 buffer->dim = 0;
94 buffer->size = 0;
95 buffer->numel = 0;
96 buffer->mindim = mindim;
97 buffer->elsize = elsize;
98
99 return 1;
100 }
101
buff_dup(buff * dest,buff * src)102 int buff_dup(buff *dest, buff *src) {
103 if (src->id != buffID) {
104 ERRORMSG("buff_recycle", "Buffer danneggiato");
105 return 0;
106 }
107
108 *dest = *src;
109 if (dest->size > 0 && dest->ptr != (void *) NULL) {
110 dest->ptr = (void *) malloc(dest->size);
111 (void) memcpy(dest->ptr, src->ptr, dest->size);
112 }
113 return 1;
114 }
115
116 /* NOME: buff_create
117 * DESCRIZIONE: Converte il buffer specificato, in un nuovo buffer
118 * con elementi di dimensione diversa (elsize).
119 * mindim = dimensione minima del buffer (in elementi)
120 * Restituisce 1 se tutto va bene, 0 in caso di errore.
121 * NOTA: Il buffer creato sara' vuoto.
122 */
buff_recycle(buff * buffer,short elsize,long mindim)123 int buff_recycle(buff *buffer, short elsize, long mindim) {
124 if ( (elsize<1) || (mindim<1) ) {
125 ERRORMSG("buff_recycle", "Parametri errati");
126 return 0;
127 }
128
129 if ( buffer->id != buffID ) {
130 ERRORMSG("buff_recycle", "Buffer danneggiato");
131 return 0;
132 }
133
134 /* Calcolo quanti elementi di dimensione elsize ci stanno nella zona
135 * allocata per il vecchio buffer
136 */
137 buffer->dim = buffer->size / elsize;
138 if ( buffer->dim < 1 ) {
139 /* Non c'e' memoria sufficiente:
140 * distruggo il vecchio buffer e ne creo uno nuovo!
141 */
142 free( buffer->ptr );
143 buffer->id = 0;
144
145 return buff_create(buffer, elsize, mindim);
146 }
147
148 buffer->numel = 0;
149 buffer->mindim = mindim;
150 buffer->elsize = elsize;
151 return 1;
152 }
153
154 /* NOME: buff_push
155 * DESCRIZIONE: Inserisce un elemento in coda nel buffer,
156 * preoccupandosi di reallocare la memoria se necessario.
157 * Restituisce 1 solo in caso di successo.
158 */
buff_push(buff * buffer,void * elem)159 int buff_push(buff *buffer, void *elem) {
160 void *tptr;
161 long tpos;
162
163 if (buffer->id == buffID) {
164 tpos = buffer->numel++ * buffer->elsize;
165
166 /* Controlla che il buffer non debba essere allargato */
167 BUFF_EXPAND(buffer, buffer->numel);
168
169 tptr = buffer->ptr + tpos;
170 memcpy(tptr, elem, buffer->elsize);
171
172 } else {
173 ERRORMSG("buff_push", "Buffer non inizializzato");
174 return 0;
175 }
176
177 return 1;
178 }
179
180 /* NOME: buff_mpush
181 * DESCRIZIONE: Inserisce pi elementi in coda nel buffer,
182 * preoccupandosi di reallocare la memoria se necessario.
183 * Restituisce 1 solo in caso di successo.
184 */
buff_mpush(buff * buffer,void * elem,long numel)185 int buff_mpush(buff *buffer, void *elem, long numel) {
186 void *tptr;
187 long tpos;
188
189 if (buffer->id == buffID) {
190 if (numel < 1) {
191 ERRORMSG("buff_mpush", "Parametri errati");
192 return 0;
193 }
194
195 tpos = buffer->numel * buffer->elsize;
196 buffer->numel += numel;
197
198 /* Controlla che il buffer non debba essere allargato */
199 BUFF_EXPAND(buffer, buffer->numel);
200
201 tptr = buffer->ptr + tpos;
202 memcpy(tptr, elem, numel*buffer->elsize);
203
204 } else {
205 ERRORMSG("buff_mpush", "Buffer non inizializzato");
206 return 0;
207 }
208
209 return 1;
210 }
211
212 /* NOME: buff_bigenough
213 * DESCRIZIONE: Se necessario allarga il buffer in modo che contenga
214 * numel elementi. Restituisce 1 in caso di successo.
215 */
buff_bigenough(buff * buffer,long numel)216 int buff_bigenough(buff *buffer, long numel) {
217 if (buffer->id == buffID) {
218 if (numel < 0) {
219 ERRORMSG("buff_bigenough", "Parametri errati");
220 return 0;
221 }
222
223 /* Controlla che il buffer non debba essere allargato */
224 BUFF_EXPAND(buffer, numel);
225
226 } else {
227 ERRORMSG("buff_bigenough", "Buffer non inizializzato");
228 return 0;
229 }
230
231 return 1;
232 }
233
234 /* NOME: buff_smallenough
235 * DESCRIZIONE: Se necessario riduce il buffer in modo che non sia
236 * troppo vuoto. Restituisce 1 in caso di successo.
237 */
buff_smallenough(buff * buffer,long numel)238 int buff_smallenough(buff *buffer, long numel) {
239 if (buffer->id == buffID) {
240 if (numel < 0) {
241 ERRORMSG("buff_smallenough", "Parametri errati");
242 return 0;
243 }
244
245 /* Controlla che il buffer non debba essere allargato */
246 BUFF_SHRINK(buffer, numel);
247
248 } else {
249 ERRORMSG("buff_smallenough", "Buffer non inizializzato");
250 return 0;
251 }
252
253 return 1;
254 }
255
256 /* NOME: buff_clear
257 * DESCRIZIONE: Svuota il buffer, riallocandolo se la sua dimensione
258 * supera la dimensione "di riposo".
259 * Restituisce 1 in caso di successo.
260 */
buff_clear(buff * buffer)261 int buff_clear(buff *buffer) {
262 if (buff_smallenough(buffer, 0))
263 buffer->numel = 0;
264 else
265 return 0;
266
267 return 1;
268 }
269
270 /* NOME: buff_free
271 * DESCRIZIONE: De-alloca il buffer, riportandolo alla condizione in cui
272 * buff_create lo aveva posto.
273 */
buff_free(buff * buffer)274 void buff_free(buff *buffer) {
275 if (buffer->id == buffID) {
276 free(buffer->ptr);
277 buffer->ptr = NULL;
278 buffer->dim = 0;
279 buffer->size = 0;
280 buffer->numel = 0;
281 }
282 }
283