1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Joyent, Inc.
14  */
15 
16 #ifndef _LIBCUSTR_H
17 #define	_LIBCUSTR_H
18 
19 #include <stdarg.h>
20 #include <sys/types.h>
21 
22 /* dynamic string utilities */
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 typedef struct custr custr_t;
29 typedef struct custr_alloc_ops custr_alloc_ops_t;
30 typedef struct custr_alloc custr_alloc_t;
31 
32 /*
33  * A custom allocator instance.  To use a custom allocator, the user provides
34  * the memory for a given custr_alloc_t and calls custr_alloc_init() with the
35  * address of the instance to initialize it.  custr_alloc_init() will invoke
36  * the init op (if defined) with any additional arguments.  The user can then
37  * save any desired state for the allocator instance in cua_arg.  If a
38  * custom allocator instance needs to do any cleanup after it's no longer
39  * needed, it should also define the fini op and invoke custr_alloc_fini() to
40  * do the cleanup.
41  */
42 #define	CUSTR_VERSION 1
43 struct custr_alloc {
44 	uint_t			cua_version;
45 	const custr_alloc_ops_t	*cua_ops;
46 	void			*cua_arg;
47 };
48 
49 struct custr_alloc_ops {
50 	/*
51 	 * Optional allocator constructor.  Returns 0 on success, -1
52 	 * on failure (and should set errno on failure).
53 	 */
54 	int (*custr_ao_init)(custr_alloc_t *, va_list);
55 	/*
56 	 * Optional allocator destructor.
57 	 */
58 	void (*custr_ao_fini)(custr_alloc_t *);
59 	/*
60 	 * Returns at least size_t bytes of allocated memory, or NULL.
61 	 * It should also set errno on failure.
62 	 */
63 	void *(*custr_ao_alloc)(custr_alloc_t *, size_t);
64 	/*
65 	 * Free the memory previously allocated with custr_ao_alloc.
66 	 */
67 	void (*custr_ao_free)(custr_alloc_t *, void *, size_t);
68 };
69 
70 /*
71  * Initializes a custr allocator.  custr_alloc_t->cua_version should be set to
72  * CUSTR_VERSION prior to calling custr_alloc_init().  Both the custr_ao_alloc
73  * and custr_ao_free functions must be defined in custr_alloc_ops_t (the
74  * init and fini functions are both optional).  If an init function is
75  * provided, it will be called with a va_list parameter initialized to
76  * point to any arguments after the custr_alloc_ops_t * argument.
77  *
78  * If cua_version is not CUSTR_VERSION, or if the custr_ao_alloc or
79  * custr_ao_free functions are missing, -1 is returned and errno is set to
80  * EINVAL.  If an init function was given and it fails (returns -1 -- see
81  * the struct custr_alloc_ops definition aboive), -1 is returned and any
82  * value of errno set by the init function is left unchanged.
83  *
84  * On success, 0 is returned.
85  */
86 int custr_alloc_init(custr_alloc_t *, const custr_alloc_ops_t *, ...);
87 
88 /*
89  * If a fini function was given in the custr_alloc_init() call that initalized
90  * the given custr_alloc_t instance, it is called to perform any custom
91  * cleanup needed.
92  */
93 void custr_alloc_fini(custr_alloc_t *);
94 
95 /*
96  * Allocate and free a "custr_t" dynamic string object.  Returns 0 on success
97  * and -1 otherwise.
98  */
99 int custr_alloc(custr_t **);
100 int custr_xalloc(custr_t **, custr_alloc_t *);
101 void custr_free(custr_t *);
102 
103 /*
104  * Allocate a "custr_t" dynamic string object that operates on a fixed external
105  * buffer.
106  */
107 int custr_alloc_buf(custr_t **, void *, size_t);
108 
109 /*
110  * Like custr_alloc_buf(), except the given allocator is used to allocate
111  * the custr_t * instance (but still uses a fixed external buffer for the
112  * string contents).
113  */
114 int custr_xalloc_buf(custr_t **, void *, size_t, custr_alloc_t *);
115 
116 /*
117  * Append a single character, or a NUL-terminated string of characters, to a
118  * dynamic string.  Returns 0 on success and -1 otherwise.  The dynamic string
119  * will be unmodified if the function returns -1.
120  */
121 int custr_appendc(custr_t *, char);
122 int custr_append(custr_t *, const char *);
123 
124 /*
125  * Append a format string and arguments as though the contents were being parsed
126  * through snprintf. Returns 0 on success and -1 otherwise.  The dynamic string
127  * will be unmodified if the function returns -1.
128  */
129 int custr_append_printf(custr_t *, const char *, ...);
130 int custr_append_vprintf(custr_t *, const char *, va_list);
131 
132 /*
133  * Determine the length in bytes, not including the NUL terminator, of the
134  * dynamic string.
135  */
136 size_t custr_len(custr_t *);
137 
138 /*
139  * Clear the contents of a dynamic string.  Does not free the underlying
140  * memory.
141  */
142 void custr_reset(custr_t *);
143 
144 /*
145  * custr_remove(cus, idx, len)
146  *
147  * Remove len bytes from cus, starting at idx.
148  *
149  * Returns 0 on success or -1 on failure.  On failure, errno will be set to:
150  *	EINVAL	Either the idx or len parameter is invalid
151  *
152  */
153 int custr_remove(custr_t *, size_t, size_t);
154 
155 /*
156  * custr_rremove(cus, idx, len)
157  *
158  * Remove len bytes from cus, starting at idx relative to the end of cus.
159  * That is, 0 = last byte of cus, 1 = second to last byte of cus, ...).
160  * The direction of removal is always towards the end of the string.  I.e.
161  * 'custr_rremove(cus, 1, 2)' removes the last two bytes of cus.
162  *
163  * Returns 0 on success or -1 on failure.  On failure, errno will be set to:
164  *	EINVAL	Either the idx or len parameter is invalid
165  *
166  */
167 int custr_rremove(custr_t *, size_t, size_t);
168 
169 /*
170  * custr_trunc(cus, idx)
171  *
172  * Truncate cus starting at idx.
173  *
174  * Returns 0 on success or -1 on failure.  On failure, errno is set to:
175  *	EINVAL	The idx value was invalid.
176  */
177 int custr_trunc(custr_t *, size_t);
178 
179 /*
180  * custr_rtrunc(cus, idx)
181  *
182  * Truncate cus starting at idx relative to the end of cus (similar to how
183  * the idx paramter is treated with custr_rremove()).
184  *
185  * Returns 0 on success or -1 on failure.  On failure, errno is set to:
186  *	EINVAL	The idx value was invalid.
187  */
188 int custr_rtrunc(custr_t *, size_t);
189 
190 /*
191  * Retrieve a const pointer to a NUL-terminated string version of the contents
192  * of the dynamic string.  Storage for this string should not be freed, and
193  * the pointer will be invalidated by any mutations to the dynamic string.
194  */
195 const char *custr_cstr(custr_t *str);
196 
197 #ifdef __cplusplus
198 }
199 #endif
200 
201 #endif /* _LIBCUSTR_H */
202