1 /* dstring.h */
2
3 #ifndef DSTRING_H
4 #define DSTRING_H
5
6
7 #include <stdarg.h>
8 #include <stddef.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "ngspice/memory.h"
12
13
14 /* Error codes */
15 #define DS_E_OK 0
16 #define DS_E_INVALID (-1)
17 #define DS_E_NO_MEMORY (-2)
18
19 /* Macros to create and initialize the most common type of dstring, which is
20 * one that uses the stack for the initial buffer and begins empty.
21 *
22 * Example:
23 *
24 * DS_CREATE(ds1, 50); // Creates dstring ds1 backed by 50 bytes of stack
25 * // memory and initialized to "".
26 * Note that each DS_CREATE macro must be on a separate line due to the use
27 * of the __LINE__ macro. Using __COUNTER__ in its place would resolve this
28 * issue, but __COUNTER__ is not part of the ANSI standard.
29 */
30 #undef DS_CONCAT
31 #undef DS_CONCAT2
32 #define DS_CONCAT2(a, b) a##b
33 #define DS_CONCAT(a, b) DS_CONCAT2(a, b)
34 #define DS_CREATE(ds_name, n) \
35 char DS_CONCAT(ds_buf___, __LINE__)[n]; \
36 DSTRING ds_name; \
37 ds_init(&ds_name, DS_CONCAT(ds_buf___, __LINE__), 0,\
38 sizeof DS_CONCAT(ds_buf___, __LINE__), ds_buf_type_stack)
39
40
41 /* Structure for maintaining a dynamic string */
42 typedef struct Dstring {
43 char *p_buf; /* Active data buffer */
44 size_t length; /* Number of characters in the string excluding the
45 * terminating NULL. */
46 size_t n_byte_alloc; /* Allocated size of current buffer */
47 char *p_stack_buf; /* address of stack-based buffer backing dstring
48 * or NULL if none */
49 size_t n_byte_stack_buf; /* size of stack_buffer or 0 if none */
50 } DSTRING, *DSTRINGPTR;
51
52
53 /* Enumeration defining buffer types used during initialization */
54 typedef enum ds_buf_type {
55 ds_buf_type_stack, /* Buffer allocated from stack */
56 ds_buf_type_heap /* Buffer allocated from heap */
57 } ds_buf_type_t;
58
59 /* Enumeration defining case conversion */
60 typedef enum ds_case {
61 ds_case_as_is, /* Leave characters as they are */
62 ds_case_lower, /* Losercase chars */
63 ds_case_upper /* Uppercase chars */
64 } ds_case_t;
65
66
67
68 /* General initialization */
69 int ds_init(DSTRING *p_ds, char *p_buf, size_t length_string,
70 size_t n_byte_buf, ds_buf_type_t type_buffer);
71
72 /* Free all memory used */
73 void ds_free(DSTRING *p_ds);
74
75
76 /* Concatenate string */
77 int ds_cat_str_case(DSTRING *p_ds, const char *sz, ds_case_t case_type);
ds_cat_str(DSTRING * p_ds,const char * sz)78 inline int ds_cat_str(DSTRING *p_ds, const char *sz)
79 {
80 return ds_cat_str_case(p_ds, sz, ds_case_as_is);
81 } /* end of function ds_cat_str */
82
83
84
85 /* Concatenate character */
86 int ds_cat_char_case(DSTRING *p_ds, char c, ds_case_t case_type);
ds_cat_char(DSTRING * p_ds,char c)87 inline int ds_cat_char(DSTRING *p_ds, char c)
88 {
89 return ds_cat_char_case(p_ds, c, ds_case_as_is);
90 } /* end of function ds_cat_char */
91
92
93
94 /* Concatenate another dstring */
95 int ds_cat_ds_case(DSTRING *p_ds_dst, const DSTRING *p_ds_src,
96 ds_case_t case_type);
ds_cat_ds(DSTRING * p_ds_dst,const DSTRING * p_ds_src)97 inline int ds_cat_ds(DSTRING *p_ds_dst, const DSTRING *p_ds_src)
98 {
99 return ds_cat_ds_case(p_ds_dst, p_ds_src, ds_case_as_is);
100 } /* end of function ds_cat_ds */
101
102
103
104 /* General concatenation of a memory buffer */
105 int ds_cat_mem_case(DSTRING *p_ds, const char *p_src, size_t n_char,
106 ds_case_t type_case);
ds_cat_mem(DSTRING * p_ds,const char * p_src,size_t n_char)107 inline int ds_cat_mem(DSTRING *p_ds, const char *p_src, size_t n_char)
108 {
109 return ds_cat_mem_case(p_ds, p_src, n_char, ds_case_as_is);
110 } /* end of function ds_cat_mem */
111
112
113
114 /* Ensure minimum internal buffer size */
115 int ds_reserve(DSTRING *p_ds, size_t n_byte_alloc_min);
116
117 /* Concatenate the result of a printf-style format */
118 int ds_cat_printf(DSTRING *p_ds, const char *sz_fmt, ...);
119
120 /* Concatenate the result of a printf-style format using va_list */
121 int ds_cat_vprintf(DSTRING *p_ds, const char *sz_fmt, va_list p_arg);
122
123 /* Reallocate/free to eliminate unused buffer space */
124 int ds_compact(DSTRING *p_ds);
125
126
127
128 /* This function sets the length of the buffer to some size less than
129 * the current allocated size
130 *
131 * Return codes
132 * DS_E_OK: length set OK
133 * DS_E_INVALID: length to large for current allocation
134 */
ds_set_length(DSTRING * p_ds,size_t length)135 inline int ds_set_length(DSTRING *p_ds, size_t length)
136 {
137 if (length >= p_ds->n_byte_alloc) {
138 return DS_E_INVALID;
139 }
140 p_ds->length = length;
141 p_ds->p_buf[p_ds->length] = '\0';
142 return DS_E_OK;
143 } /* end of function ds_set_length */
144
145
146
147 /* Sets the length of the data in the buffer to 0. It is equivalent to
148 * ds_set_length(p_ds, 0), except that the check for a valid length can
149 * be skipped since 0 is always valid. */
ds_clear(DSTRING * p_ds)150 inline void ds_clear(DSTRING *p_ds)
151 {
152 p_ds->length = 0;
153 p_ds->p_buf[0] = '\0';
154 } /* end of function ds_clear */
155
156
157
158 /* This function, if successful, returns an allocated buffer with the
159 * string to the caller and frees any other resources used by the DSTRING.
160 * If the buffer is not allocated and the DS_FREE_MOVE_OPT_FORCE_ALLOC
161 * option is not selected, NULL is returned.
162 *
163 * Parameters
164 * p_ds: Address of DSTRING to free
165 * opt: Bitwise options
166 * DS_FREE_MOVE_OPT_FORCE_ALLOC -- Force allocation in all cases.
167 * If fails, the DSTRING is unchanged.
168 * DS_FREE_MOVE_OPT_COMPACT -- Resize allocation to minimum size
169 * if one already exists.
170 *
171 * Return values
172 * The data string is returned as an allocation to be freed by the caller
173 * NULL is returned if either the allocation was stack-based and
174 * DS_FREE_MOVE_OPT_FORCE_ALLOC was not selected or if
175 * DS_FREE_MOVE_OPT_COMPACT or DS_FREE_MOVE_OPT_FORCE_ALLOC
176 * options were given and there was an allocation failure.
177 * In any case when NULL is returned, the DSTRING is unchanged
178 * on return.
179 *
180 * Remarks
181 * To force freeing of resources if this function fails, either it can
182 * be called again with no options or equivalently ds_free() can be used.
183 */
184 #define DS_FREE_MOVE_OPT_FORCE_ALLOC 1
185 #define DS_FREE_MOVE_OPT_COMPACT 2
ds_free_move(DSTRING * p_ds,unsigned int opt)186 inline char *ds_free_move(DSTRING *p_ds, unsigned int opt)
187 {
188 char * const p_buf_active = p_ds->p_buf;
189
190 /* If the buffer is from the stack, allocate if requested. Note that the
191 * compaction option is meaningless in this case since it is allocated
192 * to the minimum size required */
193 if (p_buf_active == p_ds->p_stack_buf) { /* not allocated */
194 if (opt & DS_FREE_MOVE_OPT_FORCE_ALLOC) {
195 /* Allocate to minimum size */
196 size_t n_byte_alloc = p_ds->length + 1;
197 char * const p_ret = TMALLOC(char, n_byte_alloc);
198 if (p_ret == (char *) NULL) {
199 return (char *) NULL;
200 }
201 return memcpy(p_ret, p_buf_active, n_byte_alloc);
202 }
203 return (char *) NULL;
204 }
205 /* Else allocated */
206 if (opt & DS_FREE_MOVE_OPT_COMPACT) {
207 /* Allocate to minimum size */
208 size_t n_byte_alloc = p_ds->length + 1;
209 char * const p_ret = TREALLOC(char, p_buf_active, n_byte_alloc);
210 if (p_ret == (char *) NULL) {
211 /* Realloc to smaller size somehow failed! */
212 return (char *) NULL;
213 }
214 return p_ret; /* Return resized allocation */
215 }
216 return p_buf_active; /* Return unchanged */
217 } /* end of function ds_free_move */
218
219
220
221 /* Returns the address of the buffer. The caller should never attempt
222 * to free the buffer. With care (not changing the length), it can
223 * be modified. */
ds_get_buf(DSTRING * p_ds)224 inline char *ds_get_buf(DSTRING *p_ds)
225 {
226 return p_ds->p_buf;
227 } /* end of function ds_get_buffer */
228
229
230
231 /* Returns the current dstring length */
ds_get_length(const DSTRING * p_ds)232 inline size_t ds_get_length(const DSTRING *p_ds)
233 {
234 return p_ds->length;
235 } /* end of function ds_get_length */
236
237
238
239 /* Returns the allocated dstring buffer size */
ds_get_buf_size(const DSTRING * p_ds)240 inline size_t ds_get_buf_size(const DSTRING *p_ds)
241 {
242 return p_ds->n_byte_alloc;
243 } /* end of function ds_get_buf_size */
244
245
246
247 #ifdef DSTRING_UNIT_TEST
248 #include <stdio.h>
249 int ds_test(FILE *fp);
250 #endif /* UNIT_TEST_DSTRING */
251
252 #endif /* include guard */
253