1/*
2 * buffer.c -- generic memory buffer .
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9
10#include "config.h"
11#include <stdlib.h>
12#include <stdio.h>
13
14#include "buffer.h"
15
16static void
17buffer_cleanup(void *arg)
18{
19	buffer_type *buffer = (buffer_type *) arg;
20	assert(!buffer->_fixed);
21	free(buffer->_data);
22}
23
24buffer_type *
25buffer_create(region_type *region, size_t capacity)
26{
27	buffer_type *buffer
28		= (buffer_type *) region_alloc(region, sizeof(buffer_type));
29	if (!buffer)
30		return NULL;
31
32	buffer->_data = (uint8_t *) xalloc(capacity);
33	buffer->_position = 0;
34	buffer->_limit = buffer->_capacity = capacity;
35	buffer->_fixed = 0;
36	buffer_invariant(buffer);
37
38	region_add_cleanup(region, buffer_cleanup, buffer);
39
40	return buffer;
41}
42
43void
44buffer_create_from(buffer_type *buffer, void *data, size_t size)
45{
46	assert(data);
47
48	buffer->_position = 0;
49	buffer->_limit = buffer->_capacity = size;
50	buffer->_data = (uint8_t *) data;
51	buffer->_fixed = 1;
52
53	buffer_invariant(buffer);
54}
55
56void
57buffer_clear(buffer_type *buffer)
58{
59	buffer_invariant(buffer);
60
61	buffer->_position = 0;
62	buffer->_limit = buffer->_capacity;
63}
64
65void
66buffer_flip(buffer_type *buffer)
67{
68	buffer_invariant(buffer);
69
70	buffer->_limit = buffer->_position;
71	buffer->_position = 0;
72}
73
74void
75buffer_rewind(buffer_type *buffer)
76{
77	buffer_invariant(buffer);
78
79	buffer->_position = 0;
80}
81
82void
83buffer_set_capacity(buffer_type *buffer, size_t capacity)
84{
85	buffer_invariant(buffer);
86	assert(buffer->_position <= capacity);
87	buffer->_data = (uint8_t *) xrealloc(buffer->_data, capacity);
88	buffer->_limit = buffer->_capacity = capacity;
89}
90
91void
92buffer_reserve(buffer_type *buffer, size_t amount)
93{
94	buffer_invariant(buffer);
95	assert(!buffer->_fixed);
96	if (buffer->_capacity < buffer->_position + amount) {
97		size_t new_capacity = buffer->_capacity * 3 / 2;
98		if (new_capacity < buffer->_position + amount) {
99			new_capacity = buffer->_position + amount;
100		}
101		buffer_set_capacity(buffer, new_capacity);
102	}
103	buffer->_limit = buffer->_capacity;
104}
105
106int
107buffer_printf(buffer_type *buffer, const char *format, ...)
108{
109	va_list args;
110	int written;
111	size_t remaining;
112
113	buffer_invariant(buffer);
114	assert(buffer->_limit == buffer->_capacity);
115
116	remaining = buffer_remaining(buffer);
117	va_start(args, format);
118	written = vsnprintf((char *) buffer_current(buffer), remaining,
119			    format, args);
120	va_end(args);
121	if (written >= 0 && (size_t) written >= remaining) {
122		buffer_reserve(buffer, written + 1);
123		va_start(args, format);
124		written = vsnprintf((char *) buffer_current(buffer),
125				    buffer_remaining(buffer),
126				    format, args);
127		va_end(args);
128	}
129	buffer->_position += written;
130	return written;
131}
132