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