1 /*
2 Simple buffer
3
4 Basic buffer manipulation routines. Taken from ELAPI code.
5
6 Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 - 2010
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21 #include <errno.h> /* for errors */
22 #include <stdlib.h> /* for free() */
23 #include <unistd.h> /* for write() */
24 #include <string.h> /* for memcpy() */
25
26 #include "simplebuffer.h"
27 #include "trace.h"
28
29 /* End line string */
30 #define ENDLNSTR "\n"
31
32 /* Function to free buffer */
simplebuffer_free(struct simplebuffer * data)33 void simplebuffer_free(struct simplebuffer *data)
34 {
35 TRACE_FLOW_ENTRY();
36
37 if (data) {
38 free(data->buffer);
39 free(data);
40 }
41
42 TRACE_FLOW_EXIT();
43 }
44
45 /* Allocate buffer structure */
simplebuffer_alloc(struct simplebuffer ** data)46 int simplebuffer_alloc(struct simplebuffer **data)
47 {
48 int error = EOK;
49
50 TRACE_FLOW_ENTRY();
51
52 if (!data) {
53 TRACE_ERROR_STRING("Invalid argument", "");
54 error = EINVAL;
55 }
56 else {
57 *data = (struct simplebuffer *)calloc(1,
58 sizeof(struct simplebuffer));
59 if (*data == NULL) {
60 TRACE_ERROR_STRING("Failed to allocate memory", "");
61 error = ENOMEM;
62 }
63 else error = EOK;
64 }
65
66 TRACE_FLOW_RETURN(error);
67 return error;
68 }
69
70
71 /* Grow buffer */
simplebuffer_grow(struct simplebuffer * data,uint32_t len,uint32_t block)72 int simplebuffer_grow(struct simplebuffer *data,
73 uint32_t len,
74 uint32_t block)
75 {
76 int error = EOK;
77 unsigned char *newbuf = NULL;
78
79 TRACE_FLOW_ENTRY();
80
81 TRACE_INFO_NUMBER("Current length: ", data->length);
82 TRACE_INFO_NUMBER("Current size: ", data->size);
83 TRACE_INFO_NUMBER("Length to have: ", len);
84 TRACE_INFO_NUMBER("Increment length: ", block);
85
86 /* Grow buffer if needed */
87 while (data->length + len >= data->size) {
88 newbuf = realloc(data->buffer, data->size + block);
89 if (newbuf == NULL) {
90 TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM);
91 return ENOMEM;
92 }
93 data->buffer = newbuf;
94 data->size += block;
95 TRACE_INFO_NUMBER("New size: ", data->size);
96 }
97
98 TRACE_INFO_NUMBER("Final size: ", data->size);
99 TRACE_FLOW_RETURN(error);
100 return error;
101 }
102
103 /* Function to add raw data to the end of the buffer.
104 * Terminating 0 is not counted in length but appended
105 * automatically.
106 */
simplebuffer_add_raw(struct simplebuffer * data,void * data_in,uint32_t len,uint32_t block)107 int simplebuffer_add_raw(struct simplebuffer *data,
108 void *data_in,
109 uint32_t len,
110 uint32_t block)
111 {
112
113 int error = EOK;
114 uint32_t size;
115
116 TRACE_FLOW_ENTRY();
117
118 size = len + 1;
119 error = simplebuffer_grow(data, size,
120 ((block > size) ? block : size));
121 if (error) {
122 TRACE_ERROR_NUMBER("Failed to grow buffer.", error);
123 return error;
124 }
125
126 memcpy(data->buffer + data->length, data_in, len);
127 data->length += len;
128 data->buffer[data->length] = '\0';
129
130 TRACE_FLOW_EXIT();
131 return error;
132 }
133
134 /* Function to add string to the end of the buffer. */
simplebuffer_add_str(struct simplebuffer * data,const char * str,uint32_t len,uint32_t block)135 int simplebuffer_add_str(struct simplebuffer *data,
136 const char *str,
137 uint32_t len,
138 uint32_t block)
139 {
140
141 int error = EOK;
142 uint32_t size;
143
144 TRACE_FLOW_ENTRY();
145
146 size = len + 1;
147 error = simplebuffer_grow(data, size,
148 ((block > size) ? block : size));
149 if (error) {
150 TRACE_ERROR_NUMBER("Failed to grow buffer.", error);
151 return error;
152 }
153
154 memcpy(data->buffer + data->length, str, len);
155 data->length += len;
156 data->buffer[data->length] = '\0';
157
158 TRACE_FLOW_EXIT();
159 return error;
160 }
161
162 /* Finction to add CR to the buffer */
simplebuffer_add_cr(struct simplebuffer * data)163 int simplebuffer_add_cr(struct simplebuffer *data)
164 {
165 int error = EOK;
166 char cr[] = ENDLNSTR;
167
168 TRACE_FLOW_ENTRY();
169
170 error = simplebuffer_add_raw(data,
171 (void *)cr,
172 sizeof(ENDLNSTR) - 1,
173 sizeof(ENDLNSTR));
174
175 TRACE_FLOW_RETURN(error);
176 return error;
177 }
178
179
180 /* Function to write data synchroniusly */
simplebuffer_write(int fd,struct simplebuffer * data,uint32_t * left)181 int simplebuffer_write(int fd, struct simplebuffer *data, uint32_t *left)
182 {
183 size_t res;
184 int error;
185
186 TRACE_FLOW_ENTRY();
187
188 /* Write given number of bytes to the socket */
189 res = write(fd,
190 data->buffer + (data->length - *left),
191 (size_t)(*left));
192
193 if (res == -1) {
194 error = errno;
195 TRACE_ERROR_NUMBER("Write failed.", error);
196 return error;
197 }
198
199 (*left) -= res;
200
201 TRACE_FLOW_EXIT();
202 return EOK;
203 }
204
205 /* Get buffer */
simplebuffer_get_buf(struct simplebuffer * data)206 const unsigned char *simplebuffer_get_buf(struct simplebuffer *data)
207 {
208 return data->buffer;
209 }
210
211 /* Get void buffer */
simplebuffer_get_vbuf(struct simplebuffer * data)212 void *simplebuffer_get_vbuf(struct simplebuffer *data)
213 {
214 return (void *)data->buffer;
215 }
216
217
218 /* Get length */
simplebuffer_get_len(struct simplebuffer * data)219 uint32_t simplebuffer_get_len(struct simplebuffer *data)
220 {
221 return data->length;
222 }
223