1 /*
2  * Copyright (c) 2015-2017 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Jan Friesse (jfriesse@redhat.com)
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  * - Neither the name of the Red Hat, Inc. nor the names of its
19  *   contributors may be used to endorse or promote products derived from this
20  *   software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/types.h>
36 
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "dynar.h"
41 
42 void
dynar_init(struct dynar * array,size_t maximum_size)43 dynar_init(struct dynar *array, size_t maximum_size)
44 {
45 
46 	memset(array, 0, sizeof(*array));
47 	array->maximum_size = maximum_size;
48 }
49 
50 void
dynar_set_max_size(struct dynar * array,size_t maximum_size)51 dynar_set_max_size(struct dynar *array, size_t maximum_size)
52 {
53 
54 	array->maximum_size = maximum_size;
55 }
56 
57 int
dynar_set_size(struct dynar * array,size_t size)58 dynar_set_size(struct dynar *array, size_t size)
59 {
60 
61 	if (size > dynar_max_size(array)) {
62 		dynar_set_max_size(array, size);
63 	}
64 
65 	if (size > dynar_size(array)) {
66 		if (dynar_prealloc(array, size - dynar_size(array)) == -1) {
67 			return (-1);
68 		}
69 	}
70 
71 	array->size = size;
72 
73 	return (0);
74 }
75 
76 void
dynar_destroy(struct dynar * array)77 dynar_destroy(struct dynar *array)
78 {
79 
80 	free(array->data);
81 	dynar_init(array, array->maximum_size);
82 }
83 
84 void
dynar_clean(struct dynar * array)85 dynar_clean(struct dynar *array)
86 {
87 
88 	array->size = 0;
89 }
90 
91 size_t
dynar_size(const struct dynar * array)92 dynar_size(const struct dynar *array)
93 {
94 
95 	return (array->size);
96 }
97 
98 size_t
dynar_max_size(const struct dynar * array)99 dynar_max_size(const struct dynar *array)
100 {
101 
102 	return (array->maximum_size);
103 }
104 
105 char *
dynar_data(const struct dynar * array)106 dynar_data(const struct dynar *array)
107 {
108 
109 	return (array->data);
110 }
111 
112 static int
dynar_realloc(struct dynar * array,size_t new_array_size)113 dynar_realloc(struct dynar *array, size_t new_array_size)
114 {
115 	char *new_data;
116 
117 	if (new_array_size > array->maximum_size) {
118 		return (-1);
119 	}
120 
121 	new_data = realloc(array->data, new_array_size);
122 
123 	if (new_data == NULL) {
124 		return (-1);
125 	}
126 
127 	array->allocated = new_array_size;
128 	array->data = new_data;
129 
130 	return (0);
131 }
132 
133 int
dynar_prealloc(struct dynar * array,size_t size)134 dynar_prealloc(struct dynar *array, size_t size)
135 {
136 	size_t new_size;
137 
138 	if (array->size + size > array->maximum_size) {
139 		return (-1);
140 	}
141 
142 	if (array->size + size > array->allocated) {
143 		new_size = (array->allocated + size) * 2;
144 		if (new_size > array->maximum_size) {
145 			new_size = array->maximum_size;
146 		}
147 
148 		if (dynar_realloc(array, new_size) == -1) {
149 			return (-1);
150 		}
151 	}
152 
153 	return (0);
154 }
155 
156 int
dynar_cat(struct dynar * array,const void * src,size_t size)157 dynar_cat(struct dynar *array, const void *src, size_t size)
158 {
159 
160 	if (dynar_prealloc(array, size) != 0) {
161 		return (-1);
162 	}
163 
164 	memmove(array->data + array->size, src, size);
165 	array->size += size;
166 
167 	return (0);
168 }
169 
170 int
dynar_prepend(struct dynar * array,const void * src,size_t size)171 dynar_prepend(struct dynar *array, const void *src, size_t size)
172 {
173 
174 	if (dynar_prealloc(array, size) != 0) {
175 		return (-1);
176 	}
177 
178 	memmove(array->data + size, array->data, array->size);
179 	memmove(array->data, src, size);
180 	array->size += size;
181 
182 	return (0);
183 }
184