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