Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1186 | savelij | 1 | /* dynstr.c */ |
2 | /*****************************************************************************/ |
||
3 | /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ |
||
4 | /* */ |
||
5 | /* AS-Port */ |
||
6 | /* */ |
||
7 | /* Handling of strings with dynamic allocation */ |
||
8 | /* */ |
||
9 | /*****************************************************************************/ |
||
10 | |||
11 | #include <stdio.h> |
||
12 | #include <string.h> |
||
13 | #include <stdlib.h> |
||
14 | #include <errno.h> |
||
15 | |||
16 | #include "dynstr.h" |
||
17 | |||
18 | static void check_dynamic(const as_dynstr_t *p_str) |
||
19 | { |
||
20 | if (!p_str->dynamic) |
||
21 | { |
||
22 | fprintf(stderr, "attemt to resize non-dynamic string\n"); |
||
23 | abort(); |
||
24 | } |
||
25 | } |
||
26 | |||
27 | /*!------------------------------------------------------------------------ |
||
28 | * \fn as_dynstr_ini(as_dynstr_t *p_str, size_t AllocLen) |
||
29 | * \brief initialize empty string with given capacity |
||
30 | * \param p_str string to initialize |
||
31 | * \param AllocLen initial alloc length |
||
32 | * ------------------------------------------------------------------------ */ |
||
33 | |||
34 | void as_dynstr_ini(as_dynstr_t *p_str, size_t ini_capacity) |
||
35 | { |
||
36 | p_str->p_str = ini_capacity ? (char*)malloc(ini_capacity) : NULL; |
||
37 | p_str->capacity = p_str->p_str ? ini_capacity : 0; |
||
38 | p_str->dynamic = !!p_str->p_str; |
||
39 | memset(p_str->p_str, 0, p_str->capacity); |
||
40 | } |
||
41 | |||
42 | /*!------------------------------------------------------------------------ |
||
43 | * \fn as_dynstr_ini_clone(as_dynstr_t *p_str, const as_dynstr_t *p_src) |
||
44 | * \brief initialize empty string from other string |
||
45 | * \param p_str string to initialize |
||
46 | * \param p_src string to clone |
||
47 | * ------------------------------------------------------------------------ */ |
||
48 | |||
49 | void as_dynstr_ini_clone(as_dynstr_t *p_str, const as_dynstr_t *p_src) |
||
50 | { |
||
51 | p_str->p_str = (char*)malloc(p_src->capacity); |
||
52 | if (p_str->p_str) |
||
53 | { |
||
54 | strcpy(p_str->p_str, p_src->p_str); |
||
55 | p_str->capacity = p_src->capacity; |
||
56 | p_str->dynamic = 1; |
||
57 | } |
||
58 | else |
||
59 | { |
||
60 | p_str->capacity = 0; |
||
61 | p_str->dynamic = 0; |
||
62 | } |
||
63 | } |
||
64 | |||
65 | /*!------------------------------------------------------------------------ |
||
66 | * \fn as_dynstr_ini_c_str(as_dynstr_t *p_str, const char *p_src) |
||
67 | * \brief initialize string from C string |
||
68 | * \param p_str string to initialize |
||
69 | * \param p_src init source |
||
70 | * ------------------------------------------------------------------------ */ |
||
71 | |||
72 | void as_dynstr_ini_c_str(as_dynstr_t *p_str, const char *p_src) |
||
73 | { |
||
74 | size_t capacity = as_dynstr_roundup_len(strlen(p_src)); |
||
75 | |||
76 | p_str->p_str = (char*)malloc(capacity); |
||
77 | if (p_str->p_str) |
||
78 | { |
||
79 | strcpy(p_str->p_str, p_src); |
||
80 | p_str->capacity = capacity; |
||
81 | p_str->dynamic = 1; |
||
82 | } |
||
83 | else |
||
84 | { |
||
85 | p_str->capacity = 0; |
||
86 | p_str->dynamic = 0; |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /*!------------------------------------------------------------------------ |
||
91 | * \fn as_dynstr_realloc(as_dynstr_t *p_str, size_t new_capacity) |
||
92 | * \brief shrink/grow string's capacity |
||
93 | * \param p_str string to adapt |
||
94 | * \param new_capacity new capacity |
||
95 | * \return 0 if success or error code |
||
96 | * ------------------------------------------------------------------------ */ |
||
97 | |||
98 | int as_dynstr_realloc(as_dynstr_t *p_str, size_t new_capacity) |
||
99 | { |
||
100 | char *p_new; |
||
101 | size_t old_capacity; |
||
102 | |||
103 | check_dynamic(p_str); |
||
104 | p_new = (char*)realloc(p_str->p_str, new_capacity); |
||
105 | old_capacity = p_str->capacity; |
||
106 | if (p_new) |
||
107 | { |
||
108 | p_str->p_str = p_new; |
||
109 | p_str->capacity = new_capacity; |
||
110 | if (new_capacity > old_capacity) |
||
111 | memset(p_str->p_str + old_capacity, 0, new_capacity - old_capacity); |
||
112 | else if (new_capacity > 0) |
||
113 | p_str->p_str[new_capacity - 1] = '\0'; |
||
114 | return 0; |
||
115 | } |
||
116 | else |
||
117 | return ENOMEM; |
||
118 | } |
||
119 | |||
120 | /*!------------------------------------------------------------------------ |
||
121 | * \fn as_dynstr_free(as_dynstr_t *p_str) |
||
122 | * \brief free/destroy string |
||
123 | * \param p_str string to handle |
||
124 | * ------------------------------------------------------------------------ */ |
||
125 | |||
126 | void as_dynstr_free(as_dynstr_t *p_str) |
||
127 | { |
||
128 | if (p_str->dynamic && p_str->p_str) |
||
129 | free(p_str->p_str); |
||
130 | p_str->p_str = NULL; |
||
131 | p_str->capacity = 0; |
||
132 | p_str->dynamic = 0; |
||
133 | } |
||
134 | |||
135 | /*!------------------------------------------------------------------------ |
||
136 | * \fn as_dynstr_copy(as_dynstr_t *p_dest, const as_dynstr_t *p_src) |
||
137 | * \brief set string from other string |
||
138 | * \param p_str string to set |
||
139 | * \param p_src init source |
||
140 | * \return actual # of characters copied |
||
141 | * ------------------------------------------------------------------------ */ |
||
142 | |||
143 | size_t as_dynstr_copy(as_dynstr_t *p_dest, const as_dynstr_t *p_src) |
||
144 | { |
||
145 | return as_dynstr_copy_c_str(p_dest, p_src->p_str); |
||
146 | } |
||
147 | |||
148 | /*!------------------------------------------------------------------------ |
||
149 | * \fn as_dynstr_copy_c_str(as_dynstr_t *p_dest, const char *p_src) |
||
150 | * \brief set string from C string |
||
151 | * \param p_str string to set |
||
152 | * \param p_src init source |
||
153 | * \return actual # of characters copied |
||
154 | * ------------------------------------------------------------------------ */ |
||
155 | |||
156 | size_t as_dynstr_copy_c_str(as_dynstr_t *p_dest, const char *p_src) |
||
157 | { |
||
158 | size_t len = strlen(p_src); |
||
159 | |||
160 | if ((len >= p_dest->capacity) && p_dest->dynamic) |
||
161 | as_dynstr_realloc(p_dest, as_dynstr_roundup_len(len)); |
||
162 | |||
163 | if (len >= p_dest->capacity) |
||
164 | len = p_dest->capacity - 1; |
||
165 | memcpy(p_dest->p_str, p_src, len); |
||
166 | p_dest->p_str[len] = '\0'; |
||
167 | return len; |
||
168 | } |
||
169 | |||
170 | /*!------------------------------------------------------------------------ |
||
171 | * \fn as_dynstr_append(as_dynstr_t *p_dest, const char *p_src, size_t src_len) |
||
172 | * \brief extend string |
||
173 | * \param p_dest string to extend |
||
174 | * \param p_src what to append |
||
175 | * \param src_len how much to append |
||
176 | * \return actual # of bytes transferred |
||
177 | * ------------------------------------------------------------------------ */ |
||
178 | |||
179 | size_t as_dynstr_append(as_dynstr_t *p_dest, const char *p_src, size_t src_len) |
||
180 | { |
||
181 | size_t dest_len = strlen(p_dest->p_str); |
||
182 | |||
183 | if ((dest_len + src_len + 1 > p_dest->capacity) && p_dest->dynamic) |
||
184 | as_dynstr_realloc(p_dest, as_dynstr_roundup_len(dest_len + src_len)); |
||
185 | if (src_len >= p_dest->capacity - dest_len) |
||
186 | src_len = p_dest->capacity - dest_len - 1; |
||
187 | memcpy(p_dest->p_str + dest_len, p_src, src_len); |
||
188 | p_dest->p_str[dest_len + src_len] = '\0'; |
||
189 | return src_len; |
||
190 | } |
||
191 | |||
192 | /*!------------------------------------------------------------------------ |
||
193 | * \fn as_dynstr_append_c_str(as_dynstr_t *p_dest, const char *p_src) |
||
194 | * \brief extend string |
||
195 | * \param p_dest string to extend |
||
196 | * \param p_src what to append |
||
197 | * \return actual # of bytes transferred |
||
198 | * ------------------------------------------------------------------------ */ |
||
199 | |||
200 | size_t as_dynstr_append_c_str(as_dynstr_t *p_dest, const char *p_src) |
||
201 | { |
||
202 | return as_dynstr_append(p_dest, p_src, strlen(p_src)); |
||
203 | } |
||
204 | |||
205 | /*!------------------------------------------------------------------------ |
||
206 | * \fn as_dynstr_dump_hex(FILE *p_file, const as_dynstr_t *p_str) |
||
207 | * \brief debug helper |
||
208 | * \param p_file where to dump |
||
209 | * \param p_str string to dump |
||
210 | * ------------------------------------------------------------------------ */ |
||
211 | |||
212 | void as_dynstr_dump_hex(FILE *p_file, const as_dynstr_t *p_str) |
||
213 | { |
||
214 | const char *p_run; |
||
215 | |||
216 | fprintf(p_file, "[%u]", (unsigned)p_str->capacity); |
||
217 | for (p_run = p_str->p_str; *p_run; p_run++) fprintf(p_file, " %02x", *p_run & 0xff); |
||
218 | fprintf(p_file, "\n"); |
||
219 | } |