5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1998 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 /* Optimized buffer managing routines. These are short inline functions. */
29 SilcBuffer is very simple and easy to use, yet you can do to the
30 buffer almost anything you want with its method functions. The buffer
31 is constructed of four different data sections that in whole creates
32 the allocated data area. Following short description of the fields
37 True length of the buffer. This is set at the allocation of the
38 buffer and it should not be touched after that. This field should
39 be considered read-only.
43 Length of the currently valid data area. Tells the length of the
44 data at the buffer. This is set to zero at the allocation of the
45 buffer and should not be updated by hand. Method functions of the
46 buffer automatically updates this field. However, it is not
47 read-only field and can be updated manually if necessary.
51 Head of the allocated buffer. This is the start of the allocated
52 data area and remains as same throughout the lifetime of the buffer.
53 However, the end of the head area or the start of the currently valid
54 data area is variable.
56 --------------------------------
57 | head | data | tail |
58 --------------------------------
61 Current head section in the buffer is sb->data - sb->head.
65 Currently valid data area. This is the start of the currently valid
66 main data area. The data area is variable in all directions.
68 --------------------------------
69 | head | data | tail |
70 --------------------------------
73 Current valid data area in the buffer is sb->tail - sb->data.
77 Tail of the buffer. This is the end of the currently valid data area
78 or start of the tail area. The start of the tail area is variable.
80 --------------------------------
81 | head | data | tail |
82 --------------------------------
85 Current tail section in the buffer is sb->end - sb->tail.
89 End of the allocated buffer. This is the end of the allocated data
90 area and remains as same throughout the lifetime of the buffer.
91 Usually this field is not needed except when checking the size
94 --------------------------------
95 | head | data | tail |
96 --------------------------------
99 Length of the entire buffer is (ie. truelen) sb->end - sb->head.
101 Currently valid data area is considered to be the main data area in
102 the buffer. However, the entire buffer is of course valid data and can
103 be used as such. Usually head section of the buffer includes different
104 kind of headers or similiar. Data section includes the main data of
105 the buffer. Tail section can be seen as a reserve space of the data
106 section. Tail section can be pulled towards end thus the data section
109 This buffer scheme is based on Linux kernel's Socket Buffer, the
110 idea were taken directly from there and credits should go there.
121 } *SilcBuffer, SilcBufferStruct;
125 /* Returns the true length of the buffer. This is used to pull
126 the buffer area to the end of the buffer. */
127 #define SILC_BUFFER_END(x) ((x)->end - (x)->head)
129 /* Inline functions */
132 SilcBuffer silc_buffer_alloc(uint32 len)
136 /* Allocate new SilcBuffer */
137 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
139 /* Allocate the actual data area */
140 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
142 /* Set pointers to the new buffer */
146 sb->end = sb->head + sb->truelen;
151 /* Free's a SilcBuffer */
154 void silc_buffer_free(SilcBuffer sb)
157 memset(sb->head, 'F', sb->truelen);
163 /* Sets the `data' and `data_len' to the buffer pointer sent as argument.
164 The data area is automatically set to the `data_len'. This function
165 can be used to set the data to static buffer without needing any
166 memory allocations. The `data' will not be copied to the buffer. */
169 void silc_buffer_set(SilcBuffer sb, unsigned char *data, uint32 data_len)
171 sb->data = sb->head = data;
172 sb->tail = sb->end = data + data_len;
173 sb->len = sb->truelen = data_len;
176 /* Pulls current data area towards end. The length of the currently
177 valid data area is also decremented. Returns pointer to the data
181 ---------------------------------
182 | head | data | tail |
183 ---------------------------------
185 Pulls the start of the data area.
187 ---------------------------------
188 | head | data | tail |
189 ---------------------------------
194 unsigned char *silc_buffer_pull(SilcBuffer sb, uint32 len)
196 unsigned char *old_data = sb->data;
199 assert(len <= (uint32)(sb->tail - sb->data));
208 /* Pushes current data area towards beginning. Length of the currently
209 valid data area is also incremented. Returns a pointer to the
210 data area before pushing.
213 ---------------------------------
214 | head | data | tail |
215 ---------------------------------
217 Pushes the start of the data area.
219 ---------------------------------
220 | head | data | tail |
221 ---------------------------------
226 unsigned char *silc_buffer_push(SilcBuffer sb, uint32 len)
228 unsigned char *old_data = sb->data;
231 assert((sb->data - len) >= sb->head);
240 /* Pulls current tail section towards end. Length of the current valid
241 data area is also incremented. Returns a pointer to the data area
245 ---------------------------------
246 | head | data | tail |
247 ---------------------------------
249 Pulls the start of the tail section.
251 ---------------------------------
252 | head | data | tail |
253 ---------------------------------
258 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, uint32 len)
260 unsigned char *old_tail = sb->tail;
263 assert((uint32)(sb->end - sb->tail) >= len);
272 /* Pushes current tail section towards beginning. Length of the current
273 valid data area is also decremented. Returns a pointer to the
274 tail section before pushing.
277 ---------------------------------
278 | head | data | tail |
279 ---------------------------------
281 Pushes the start of the tail section.
283 ---------------------------------
284 | head | data | tail |
285 ---------------------------------
290 unsigned char *silc_buffer_push_tail(SilcBuffer sb, uint32 len)
292 unsigned char *old_tail = sb->tail;
295 assert((sb->tail - len) >= sb->data);
304 /* Puts data at the head of the buffer. Returns pointer to the copied
308 ---------------------------------
309 | head | data | tail |
310 ---------------------------------
312 Puts data to the head section.
316 unsigned char *silc_buffer_put_head(SilcBuffer sb,
317 const unsigned char *data,
321 assert((uint32)(sb->data - sb->head) >= len);
323 return (unsigned char *)memcpy(sb->head, data, len);
326 /* Puts data at the start of the valid data area. Returns a pointer
327 to the copied data area.
330 ---------------------------------
331 | head | data | tail |
332 ---------------------------------
334 Puts data to the data section.
338 unsigned char *silc_buffer_put(SilcBuffer sb,
339 const unsigned char *data,
343 assert((uint32)(sb->tail - sb->data) >= len);
345 return (unsigned char *)memcpy(sb->data, data, len);
348 /* Puts data at the tail of the buffer. Returns pointer to the copied
352 ---------------------------------
353 | head | data | tail |
354 ---------------------------------
356 Puts data to the tail section.
360 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
361 const unsigned char *data,
365 assert((uint32)(sb->end - sb->tail) >= len);
367 return (unsigned char *)memcpy(sb->tail, data, len);