update from MirBSD CVS
[alioth/jupp.git] / vs.h
1 /*
2  *      Dynamic string library
3  *      Copyright
4  *              (C) 1992 Joseph H. Allen
5  *
6  *      This file is part of JOE (Joe's Own Editor)
7  */
8 #ifndef _JOE_VS_H
9 #define _JOE_VS_H 1
10
11 #ifdef EXTERN
12 __IDSTRING(rcsid_vs_h, "$MirOS: contrib/code/jupp/vs.h,v 1.8 2017/12/02 17:00:52 tg Exp $");
13 #endif
14
15 #include <string.h>
16
17 /***
18  *
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.
23  *
24  * The strings are stored in malloc blocks and have the following format:
25  *
26  *   <bksize><length><string><zero>
27  *
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.
32  *
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
38  * dynamic strings.
39  *
40  * The primary dynamic string function is:
41  *
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
51  *                              occurs.
52  *
53  * Three important macros are provided for helping with vsncpy():
54  *
55  * sc("Hello")   Gives -->  "Hello",sizeof("Hello")-1
56  * sz(s)         Gives -->  s,strlen(s)
57  * sv(d)         Gives -->  d,sLEN(d)
58  *
59  * These are used to build arguments for vsncpy().  Many functions
60  * can be created with combinations of sc/sz/sv with vsncpy:
61  *
62  *    s=vsncpy(NULL,0,NULL,0);          Create an empty dynamic string
63  *
64  *    s=vsncpy(NULL,0,sc("Hello"));     Create a dynamic string initialized
65  *                                      with "Hello"
66  *
67  *    d=vsncpy(NULL,0,sv(s));           Duplicate a dynamic string
68  *
69  *    d=vsncpy(NULL,0,sz(s));           Convert a C string into a dynamic
70  *                                      string.
71  *
72  *    d=vsncpy(sv(d),sv(s));            Append dynamic string s onto d.
73  *
74  *    d=vsncpy(sv(d),sc(".c"));         Append a ".c" extension to d.
75  *
76  *
77  * These lesser functions are also provided:
78  *
79  * void vsrm(char *s);          Free a string.  Do nothing if 's' is NULL.
80  *
81  * int sLEN(char *s);           Return the length of the string 's'.  If 's'
82  *                              is NULL, return 0.
83  *
84  * char *vstrunc(char *d,int len);
85  *                              Set the length of a string.  Expand the string
86  *                              with blanks if necessary.
87  *
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
91  *                              fit in it.
92  *
93  * sLen(s)=10;                  Set the length indicator of the string to 10.
94  *
95  * char *vsins(char *d,int off,int len);
96  *                              Insert a gap into a string.
97  *
98  * char *vsdel(char *d,int off,int len);
99  *                              Delete characters from a string.
100  *
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.
104  */
105
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
108  */
109
110 /* An element with name 'a' */
111 typedef unsigned char sELEMENT;
112
113 /* Duplicate an element */
114 /* sELEMENT sdup(); */
115 #define sdup(a) (a)
116
117 /* Delete an element */
118 /* sELEMENT sdel(); */
119 #define sdel(a) do {} while(0)          /* effectively do nothing ;-) */
120
121 /* Compare a single element */
122 /* int scmp(); */
123 #define scmp(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
124
125 /* A blank element */
126 /* extern sELEMENT sblank; */
127 #define sblank ' '
128
129 /* A termination element */
130 /* extern sELEMENT sterm; */
131 #define sterm '\0'
132
133 /************************/
134 /* Creation/Destruction */
135 /************************/
136
137 /* sELEMENT *vsmk(int len);
138  * Create a variable length array.  Space for 'len' elements is preallocated.
139  */
140 sELEMENT *vsmk PARAMS((int len));
141
142 /* void vsrm(sELEMENT *vary);
143  * Free an array and everything which is in it.  Does nothing if 'vary' is
144  * 0.
145  */
146 void vsrm PARAMS((sELEMENT *vary));
147
148 /********************/
149 /* Space management */
150 /********************/
151
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.
157  *
158  * sSIZ returns 0 if you pass it 0.  sSiz does not do this checking,
159  * but can be used as an lvalue.
160  */
161 #define sSIZ(a) ((a) ? *((int *)(a) - 2) : 0)
162 #define sSiz(a) (*((int *)(a) - 2))
163
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.
172  *
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
175  */
176 #define sLEN(a) ((a) ? *((int *)(a) - 1) : 0)
177 #define sLen(a) (*((int *)(a) - 1))
178
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.
182  */
183 int slen PARAMS((const sELEMENT *ary));
184
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.
190  */
191 sELEMENT *vsensure PARAMS((sELEMENT *vary, int len));
192
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.
196  */
197 sELEMENT *vstrunc PARAMS((sELEMENT *vary, int len));
198
199 /************************************/
200 /* Function which write to an array */
201 /************************************/
202
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
206  * created.
207  *
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.
210  */
211 sELEMENT *vsfill PARAMS((sELEMENT *vary, int pos, sELEMENT el, int len));
212
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.
218  */
219 sELEMENT *vsncpy PARAMS((sELEMENT *vary, int pos, const sELEMENT *array, int len));
220
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.
225  */
226 sELEMENT *vsndup PARAMS((sELEMENT *vary, int pos, sELEMENT *array, int len));
227
228 /* sELEMENT *vsdup(sELEMENT *vary));
229  * Duplicate array.  This is just a functionalized version of:
230  *
231  *   vsndup(NULL, 0, vary, sLEN(vary));
232  *
233  * but since you need to be able to refer to this particular function by
234  * address often it's given here.
235  *
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).
240  */
241 sELEMENT *vsdup PARAMS((sELEMENT *vary));
242
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));
248  */
249 sELEMENT *_vsset PARAMS((sELEMENT *vary, int pos, sELEMENT el));
250
251 #define vsset(v, p, el)  \
252  (!(v) || (p) > sLen(v) || (p) >= sSiz(v) ?  \
253   _vsset((v), (p), (el)) \
254  : \
255   ((p) == sLen(v) ? \
256    ((v)[(p) + 1] = 0, sLen(v) = (p) + 1, (v)[p] = (el), (v)) \
257   : \
258    ((v)[p] = (el), (v)) \
259   ) \
260  )
261
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.
266  */
267 #define vsadd(v, el) \
268  (!(v) || sLen(v) == sSiz(v) ? \
269   _vsset((v), sLEN(v), (el)) \
270  : \
271   ((v)[sLen(v) + 1] = 0, (v)[sLen(v)] = (el), sLen(v) = sLen(v) + 1, (v)) \
272  )
273
274 /**************************************/
275 /* Functions which read from an array */
276 /**************************************/
277
278 /* These macros are used to generate the address/size pairs which get
279  * passed to the functions of the previous section.
280  */
281
282 /* { sELEMENT *, int } sv(sELEMENT *array);
283  * Return array, size pair.  Uses sLEN to get size.
284  */
285 #define sv(a) (a), sLEN(a)
286
287 /* { sELEMENT *, int } sz(sELEMENT *array);
288  * Return array, size pair.  Uses slen to get size.
289  */
290 #define sz(a) (a), slen(a)
291
292 /* { sELEMENT *, int } sc(sELEMENT *array);
293  * Return array, size pair.  Uses 'sizeof' to get size.
294  */
295 #define sc(a) (unsigned char *)(a), (sizeof(a) / sizeof(sELEMENT) - 1)
296
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.
300  */
301 #define srest(a, p) ((a) + (p)), (((p) > sLEN(a)) ? 0 : sLen(a) - (p))
302
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.
307  */
308 #define spart(a, p, l) \
309  ((a) + (p)), ((p) >= sLEN(a) ? 0 : ((p) + (l) > sLen(a) ? sLen(a) - (p) : (l)))
310
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.
316  */
317 #define vsget(a, p) ((p) >= sLEN(a) ? sterm : (a)[p])
318
319 /*************************/
320 /* Searching and Sorting */
321 /*************************/
322
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).
327  *
328  * Hmm... this should really indicate whether or not the element was found.
329  */
330 int vsbsearch PARAMS((const sELEMENT *ary, int len, sELEMENT el));
331
332 /* int vscmpn(sELEMENT *a, int alen, sELEMENT *b, int blen);
333  *
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.
337  */
338 int vscmpn PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
339
340 /* int vscmp(sELEMENT *a, sELEMENT *b);
341  *
342  * Functionalized version of: vscmpn(sv(a), sv(b));
343  */
344 int vscmp PARAMS((sELEMENT *a, sELEMENT *b));
345
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.
349  *
350  * Hmm... this really needs to return what the found element is.
351  */
352 int vsscan PARAMS((const sELEMENT *a, int alen, const sELEMENT *b, int blen));
353
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.
357  */
358 int vsspan PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
359 #endif