2 * Dynamic string library
4 * (C) 1992 Joseph H. Allen
6 * This file is part of JOE (Joe's Own Editor)
12 __IDSTRING(rcsid_vs_h, "$MirOS: contrib/code/jupp/vs.h,v 1.8 2017/12/02 17:00:52 tg Exp $");
19 * This is a dynamic string library which supports strings which automatically
20 * resize themselves when needed. The strings know their own size, so getting
21 * the length of a string is a fast operation and storing zeroes in the
22 * strings is permissable.
24 * The strings are stored in malloc blocks and have the following format:
26 * <bksize><length><string><zero>
28 * 'bksize' and 'length' are ints which give the size of the malloc block
29 * and the length of the string. A zero character always follows the string
30 * for compatibility with normal C zero-terminated strings. The zero is not
31 * counted in the string length.
33 * To further the compatibility with C strings, the address of a dynamic string
34 * is at <string> above, not at <bksize> (whose address is the start of the
35 * malloc block). Thus, dynamic strings can be passed as arguments to UNIX
36 * operating system functions and C library function, but they can not be freed
37 * with free()- a special function is provided in this library for freeing
40 * The primary dynamic string function is:
42 * char *vsncpy(char *d, int off, char *s, int len);
43 * Copy a block of characters at address 's' of
44 * length 'len' onto the dynamic string 'd' at
45 * offset 'off'. The dynamic string is expanded
46 * to handle any values of 'len' and 'off' which
47 * might be given. If 'off' is greater than the
48 * length of the string, SPACEs are placed in the
49 * gap. If 'd' is NULL, a string is created. If
50 * 'len' is 0, no copying or string expansion
53 * Three important macros are provided for helping with vsncpy():
55 * sc("Hello") Gives --> "Hello",sizeof("Hello")-1
56 * sz(s) Gives --> s,strlen(s)
57 * sv(d) Gives --> d,sLEN(d)
59 * These are used to build arguments for vsncpy(). Many functions
60 * can be created with combinations of sc/sz/sv with vsncpy:
62 * s=vsncpy(NULL,0,NULL,0); Create an empty dynamic string
64 * s=vsncpy(NULL,0,sc("Hello")); Create a dynamic string initialized
67 * d=vsncpy(NULL,0,sv(s)); Duplicate a dynamic string
69 * d=vsncpy(NULL,0,sz(s)); Convert a C string into a dynamic
72 * d=vsncpy(sv(d),sv(s)); Append dynamic string s onto d.
74 * d=vsncpy(sv(d),sc(".c")); Append a ".c" extension to d.
77 * These lesser functions are also provided:
79 * void vsrm(char *s); Free a string. Do nothing if 's' is NULL.
81 * int sLEN(char *s); Return the length of the string 's'. If 's'
84 * char *vstrunc(char *d,int len);
85 * Set the length of a string. Expand the string
86 * with blanks if necessary.
88 * char *vsensure(char *d,int len);
89 * Expand the malloc block for the string if
90 * necessary so that a string of 'len' chars can
93 * sLen(s)=10; Set the length indicator of the string to 10.
95 * char *vsins(char *d,int off,int len);
96 * Insert a gap into a string.
98 * char *vsdel(char *d,int off,int len);
99 * Delete characters from a string.
101 * Other function are provided as well. Look through the rest of the header
102 * file. The header file is kind of weird looking because it is intended to
103 * handle dynamic arrays of any type with only a few changes.
106 /* Functions and global variable you have to define. Replace these with
107 * macros or defines here if they are not to be actual functions
110 /* An element with name 'a' */
111 typedef unsigned char sELEMENT;
113 /* Duplicate an element */
114 /* sELEMENT sdup(); */
117 /* Delete an element */
118 /* sELEMENT sdel(); */
119 #define sdel(a) do {} while(0) /* effectively do nothing ;-) */
121 /* Compare a single element */
123 #define scmp(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
125 /* A blank element */
126 /* extern sELEMENT sblank; */
129 /* A termination element */
130 /* extern sELEMENT sterm; */
133 /************************/
134 /* Creation/Destruction */
135 /************************/
137 /* sELEMENT *vsmk(int len);
138 * Create a variable length array. Space for 'len' elements is preallocated.
140 sELEMENT *vsmk PARAMS((int len));
142 /* void vsrm(sELEMENT *vary);
143 * Free an array and everything which is in it. Does nothing if 'vary' is
146 void vsrm PARAMS((sELEMENT *vary));
148 /********************/
149 /* Space management */
150 /********************/
152 /* int sSIZ(sELEMENT *vary);
153 * int sSiz(sELEMENT *vary);
154 * Access size part of array. This int indicates the number of elements which
155 * can fit in the array before realloc needs to be called. It does not include
156 * the extra space needed for the terminator and the header.
158 * sSIZ returns 0 if you pass it 0. sSiz does not do this checking,
159 * but can be used as an lvalue.
161 #define sSIZ(a) ((a) ? *((int *)(a) - 2) : 0)
162 #define sSiz(a) (*((int *)(a) - 2))
164 /* int sLEN(sELEMENT *vary);
165 * int sLen(sELEMENT *vary);
166 * Access length part of array. This int indicates the number of elements
167 * currently in the array (not including the terminator). This should be
168 * used primarily for reading the size of the array. It can be used for
169 * setting the size of the array, but it must be used with care since it
170 * does not eliminate elements (if the size decreases) or make sure there's
171 * enough room (if the size increases). See vensure and vtrunc.
173 * sLEN return a length of zero if 'vary' is 0.
174 * sLen doesn't do this checking, but can be used as an lvalue
176 #define sLEN(a) ((a) ? *((int *)(a) - 1) : 0)
177 #define sLen(a) (*((int *)(a) - 1))
179 /* int slen(const sELEMENT *ary);
180 * Compute length of char or variable length array by searching for termination
181 * element. Returns 0 if 'vary' is 0.
183 int slen PARAMS((const sELEMENT *ary));
185 /* sELEMENT *vsensure(sELEMENT *vary, int len);
186 * Make sure there's enough space in the array for 'len' elements. Whenever
187 * vsensure reallocs the array, it allocates 25% more than the necessary
188 * minimum space in anticipation of future expansion. If 'vary' is 0,
189 * it creates a new array.
191 sELEMENT *vsensure PARAMS((sELEMENT *vary, int len));
193 /* sELEMENT *vstrunc(sELEMENT *vary, int len));
194 * Truncate array to indicated size. This zaps or expands with blank elements
195 * and sets the LEN() of the array. A new array is created if 'vary' is 0.
197 sELEMENT *vstrunc PARAMS((sELEMENT *vary, int len));
199 /************************************/
200 /* Function which write to an array */
201 /************************************/
203 /* sELEMENT *vsfill(sELEMENT *vary, int pos, sELEMENT el, int len);
204 * Set 'len' element of 'vary' beginning at 'pos' to duplications of 'el'.
205 * Ok, if pos/len are past end of array. If 'vary' is 0, a new array is
208 * This does not zap previous values. If you need that to happen, call
209 * vszap first. It does move the terminator around properly though.
211 sELEMENT *vsfill PARAMS((sELEMENT *vary, int pos, sELEMENT el, int len));
213 /* sELEMENT *vsncpy(sELEMENT *vary, int pos, const sELEMENT *array, int len));
214 * Copy 'len' elements from 'array' onto 'vary' beginning at position 'pos'.
215 * 'array' can be a normal char array since the length is passed seperately. The
216 * elements are copied, not duplicated. A new array is created if 'vary' is
217 * 0. This does not zap previous elements.
219 sELEMENT *vsncpy PARAMS((sELEMENT *vary, int pos, const sELEMENT *array, int len));
221 /* sELEMENT *vsndup(sELEMENT *vary, int pos, sELEMENT *array, int len));
222 * Duplicate 'len' elements from 'array' onto 'vary' beginning at position
223 * 'pos'. 'array' can be a char array since its length is passed seperately. A
224 * new array is created if 'vary' is 0.
226 sELEMENT *vsndup PARAMS((sELEMENT *vary, int pos, sELEMENT *array, int len));
228 /* sELEMENT *vsdup(sELEMENT *vary));
229 * Duplicate array. This is just a functionalized version of:
231 * vsndup(NULL, 0, vary, sLEN(vary));
233 * but since you need to be able to refer to this particular function by
234 * address often it's given here.
236 * (actually, there's bazillions of these simple combinations of the above
237 * functions and the macros of the next section. You'll probably want to make
238 * functionalized instances of the ones you use most often - especially since
239 * the macros aren't safe).
241 sELEMENT *vsdup PARAMS((sELEMENT *vary));
243 /* sELEMENT *vsset(sELEMENT *vary, int pos, sELEMENT element);
244 * Set an element in an array. Any value of 'pos' is valid. A new array
245 * is created if 'vary' is 0. The previous contents of the position is
246 * deleted. This does not duplicate 'element'. If you need 'element'
247 * duplicated, call: vsset(vary,pos,sdup(element));
249 sELEMENT *_vsset PARAMS((sELEMENT *vary, int pos, sELEMENT el));
251 #define vsset(v, p, el) \
252 (!(v) || (p) > sLen(v) || (p) >= sSiz(v) ? \
253 _vsset((v), (p), (el)) \
256 ((v)[(p) + 1] = 0, sLen(v) = (p) + 1, (v)[p] = (el), (v)) \
258 ((v)[p] = (el), (v)) \
262 /* sELEMENT *vsadd(sELEMENT *vary, sELEMENT element);
263 * Concatenate a single element to the end of 'vary'. A new array is created
264 * if 'vary' is 0. This does not duplicate element: call
265 * vsadd(vary,sdup(element)); If you need it duplicated.
267 #define vsadd(v, el) \
268 (!(v) || sLen(v) == sSiz(v) ? \
269 _vsset((v), sLEN(v), (el)) \
271 ((v)[sLen(v) + 1] = 0, (v)[sLen(v)] = (el), sLen(v) = sLen(v) + 1, (v)) \
274 /**************************************/
275 /* Functions which read from an array */
276 /**************************************/
278 /* These macros are used to generate the address/size pairs which get
279 * passed to the functions of the previous section.
282 /* { sELEMENT *, int } sv(sELEMENT *array);
283 * Return array, size pair. Uses sLEN to get size.
285 #define sv(a) (a), sLEN(a)
287 /* { sELEMENT *, int } sz(sELEMENT *array);
288 * Return array, size pair. Uses slen to get size.
290 #define sz(a) (a), slen(a)
292 /* { sELEMENT *, int } sc(sELEMENT *array);
293 * Return array, size pair. Uses 'sizeof' to get size.
295 #define sc(a) (unsigned char *)(a), (sizeof(a) / sizeof(sELEMENT) - 1)
297 /* { sELEMENT *, int } srest(sELEMENT *vary, int pos);
298 * Return array, size pair of rest of array beginning at pos. If
299 * pos is past end of array, gives size of 0.
301 #define srest(a, p) ((a) + (p)), (((p) > sLEN(a)) ? 0 : sLen(a) - (p))
303 /* { sELEMENT *, int } spart(sELEMENT *vary, int pos, int len);
304 * Return array,size pair of 'len' elements of array beginning with pos. If
305 * pos is past end of array, gives size of 0. If pos+len is past end of array,
306 * returns number of elements to end of array.
308 #define spart(a, p, l) \
309 ((a) + (p)), ((p) >= sLEN(a) ? 0 : ((p) + (l) > sLen(a) ? sLen(a) - (p) : (l)))
311 /* sELEMENT vsget(sELEMENT *vary, int pos);
312 * Get an element from an array. Any value of pos is valid; if it's past the
313 * end of the array or if 'vary' is 0, the terminator is returned. This
314 * does not make a duplicate of the returned element. If you want that, pass
315 * the return value of this to sdup.
317 #define vsget(a, p) ((p) >= sLEN(a) ? sterm : (a)[p])
319 /*************************/
320 /* Searching and Sorting */
321 /*************************/
323 /* int vsbsearch(const sELEMENT *ary, int len, sELEMENT element);
324 * Do a binary search on a sorted variable length or char array. Returns position
325 * of matching element or the position where the element should be if it was
326 * not found. (You should test with scmp to find out which).
328 * Hmm... this should really indicate whether or not the element was found.
330 int vsbsearch PARAMS((const sELEMENT *ary, int len, sELEMENT el));
332 /* int vscmpn(sELEMENT *a, int alen, sELEMENT *b, int blen);
334 * Compare two arrays using scmp. If 'a' > 'b', return 1. If 'a' == 'b',
335 * return 0. If 'a' < 'b', return -1. Longer strings are > shorter ones if
336 * their beginning match.
338 int vscmpn PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
340 /* int vscmp(sELEMENT *a, sELEMENT *b);
342 * Functionalized version of: vscmpn(sv(a), sv(b));
344 int vscmp PARAMS((sELEMENT *a, sELEMENT *b));
346 /* int vsscan(const sELEMENT *a, int alen, const sELEMENT *b, int blen);
347 * Find offset of first matching element in 'a' which matches any
348 * of the elements passed in 'b'. Array 'b' must be sorted.
350 * Hmm... this really needs to return what the found element is.
352 int vsscan PARAMS((const sELEMENT *a, int alen, const sELEMENT *b, int blen));
354 /* int vsspan(sELEMENT *a, int alen, sELEMENT *b, int blen);
355 * Find offset of first matching element in 'a' which does not match any
356 * of the elements passed in 'b'. Array 'b' must be sorted.
358 int vsspan PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));