~mirabilos/jupp/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/*
 *	Dynamic string library
 *	Copyright
 *		(C) 1992 Joseph H. Allen
 *
 *	This file is part of JOE (Joe's Own Editor)
 */
#ifndef JUPP_VS_H
#define JUPP_VS_H

#ifdef EXTERN
__IDSTRING(rcsid_vs_h, "$MirOS: contrib/code/jupp/vs.h,v 1.13 2020/04/07 11:56:42 tg Exp $");
#endif

#include <string.h>

/***
 *
 * This is a dynamic string library which supports strings which automatically
 * resize themselves when needed.  The strings know their own size, so getting
 * the length of a string is a fast operation and storing zeroes in the
 * strings is permissable.
 *
 * The strings are stored in malloc blocks and have the following format:
 *
 *   <bksize><length><string><zero>
 *
 * 'bksize' and 'length' are ints which give the size of the malloc block
 * and the length of the string.  A zero character always follows the string
 * for compatibility with normal C zero-terminated strings.  The zero is not
 * counted in the string length.
 *
 * To further the compatibility with C strings, the address of a dynamic string
 * is at <string> above, not at <bksize> (whose address is the start of the
 * malloc block).  Thus, dynamic strings can be passed as arguments to UNIX
 * operating system functions and C library function, but they can not be freed
 * with free()- a special function is provided in this library for freeing
 * dynamic strings.
 *
 * The primary dynamic string function is:
 *
 * char *vsncpy(char *d, int off, char *s, int len);
 *                              Copy a block of characters at address 's' of
 *				length 'len' onto the dynamic string 'd' at
 *				offset 'off'.  The dynamic string is expanded
 *				to handle any values of 'len' and 'off' which
 *				might be given.  If 'off' is greater than the
 *				length of the string, SPACEs are placed in the
 *				gap.  If 'd' is NULL, a string is created.  If
 *				'len' is 0, no copying or string expansion
 *				occurs.
 *
 * Three important macros are provided for helping with vsncpy():
 *
 * sc("Hello")   Gives -->  "Hello",sizeof("Hello")-1
 * sz(s)         Gives -->  s,strlen(s)
 * sv(d)         Gives -->  d,sLEN(d)
 *
 * These are used to build arguments for vsncpy().  Many functions
 * can be created with combinations of sc/sz/sv with vsncpy:
 *
 *    s=vsncpy(NULL,0,NULL,0);		Create an empty dynamic string
 *
 *    s=vsncpy(NULL,0,sc("Hello"));	Create a dynamic string initialized
 *					with "Hello"
 *
 *    d=vsncpy(NULL,0,sv(s));		Duplicate a dynamic string
 *
 *    d=vsncpy(NULL,0,sz(s));		Convert a C string into a dynamic
 *                                      string.
 *
 *    d=vsncpy(sv(d),sv(s));		Append dynamic string s onto d.
 *
 *    d=vsncpy(sv(d),sc(".c"));		Append a ".c" extension to d.
 *
 *
 * These lesser functions are also provided:
 *
 * void vsrm(char *s);		Free a string.  Do nothing if 's' is NULL.
 *
 * int sLEN(char *s);		Return the length of the string 's'.  If 's'
 *				is NULL, return 0.
 *
 * char *vstrunc(char *d,int len);
 *				Set the length of a string.  Expand the string
 *				with blanks if necessary.
 *
 * char *vsensure(char *d,int len);
 *				Expand the malloc block for the string if
 *				necessary so that a string of 'len' chars can
 *				fit in it.
 *
 * sLen(s)=10;			Set the length indicator of the string to 10.
 *
 * char *vsins(char *d,int off,int len);
 *				Insert a gap into a string.
 *
 * char *vsdel(char *d,int off,int len);
 *				Delete characters from a string.
 *
 * Other function are provided as well.  Look through the rest of the header
 * file.  The header file is kind of weird looking because it is intended to
 * handle dynamic arrays of any type with only a few changes.
 */

/* Functions and global variable you have to define.  Replace these with
 * macros or defines here if they are not to be actual functions
 */

/* An element with name 'a' */
typedef unsigned char sELEMENT;

/* Duplicate an element */
/* sELEMENT sdup(); */
#define sdup(a) (a)

/* Delete an element */
/* sELEMENT sdel(); */
#define sdel(a) do {} while(0)		/* effectively do nothing ;-) */

/* Compare a single element */
/* int scmp(); */
#define scmp(a,b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))

/* A blank element */
/* extern sELEMENT sblank; */
#define sblank ' '

/* A termination element */
/* extern sELEMENT sterm; */
#define sterm '\0'

/************************/
/* Creation/Destruction */
/************************/

/* sELEMENT *vsmk(int len);
 * Create a variable length array.  Space for 'len' elements is preallocated.
 */
sELEMENT *vsmk(int len);

/* void vsrm(sELEMENT *vary);
 * Free an array and everything which is in it.  Does nothing if 'vary' is
 * 0.
 */
void vsrm(sELEMENT *vary);

/********************/
/* Space management */
/********************/

/* int sSIZ(sELEMENT *vary);
 * int sSiz(sELEMENT *vary);
 * Access size part of array.  This int indicates the number of elements which
 * can fit in the array before realloc needs to be called.  It does not include
 * the extra space needed for the terminator and the header.
 *
 * sSIZ returns 0 if you pass it 0.  sSiz does not do this checking,
 * but can be used as an lvalue.
 */
#define sSiz(a) jalloc_siz(a)
#define sSIZ(a) ((a) ? sSiz(a) : 0)

/* int sLEN(sELEMENT *vary);
 * int sLen(sELEMENT *vary);
 * Access length part of array.  This int indicates the number of elements
 * currently in the array (not including the terminator).  This should be
 * used primarily for reading the size of the array.  It can be used for
 * setting the size of the array, but it must be used with care since it
 * does not eliminate elements (if the size decreases) or make sure there's
 * enough room (if the size increases).  See vensure and vtrunc.
 *
 * sLEN return a length of zero if 'vary' is 0.
 * sLen doesn't do this checking, but can be used as an lvalue
 */
#define sLen(a) jalloc_len(a)
#define sLEN(a) ((a) ? sLen(a) : 0)

/* int slen(const sELEMENT *ary);
 * Compute length of char or variable length array by searching for termination
 * element.  Returns 0 if 'vary' is 0.
 */
int slen(const sELEMENT *ary);

/* sELEMENT *vsensure(sELEMENT *vary, int len);
 * Make sure there's enough space in the array for 'len' elements.  Whenever
 * vsensure reallocs the array, it allocates 25% more than the necessary
 * minimum space in anticipation of future expansion.  If 'vary' is 0,
 * it creates a new array.
 */
sELEMENT *vsensure(sELEMENT *vary, int len);

/* sELEMENT *vstrunc(sELEMENT *vary, int len));
 * Truncate array to indicated size.  This zaps or expands with blank elements
 * and sets the LEN() of the array.  A new array is created if 'vary' is 0.
 */
sELEMENT *vstrunc(sELEMENT *vary, int len);

/************************************/
/* Function which write to an array */
/************************************/

/* sELEMENT *vsfill(sELEMENT *vary, int pos, sELEMENT el, int len);
 * Set 'len' element of 'vary' beginning at 'pos' to duplications of 'el'.
 * Ok, if pos/len are past end of array.  If 'vary' is 0, a new array is
 * created.
 *
 * This does not zap previous values.  If you need that to happen, call
 * vszap first.  It does move the terminator around properly though.
 */
sELEMENT *vsfill(sELEMENT *vary, int pos, sELEMENT el, int len);

/* sELEMENT *vsncpy(sELEMENT *vary, int pos, const sELEMENT *array, int len));
 * Copy 'len' elements from 'array' onto 'vary' beginning at position 'pos'.
 * 'array' can be a normal char array since the length is passed seperately.  The
 * elements are copied, not duplicated.  A new array is created if 'vary' is
 * 0.  This does not zap previous elements.
 */
sELEMENT *vsncpy(sELEMENT *vary, int pos, const sELEMENT *array, int len);

/* sELEMENT *vsndup(sELEMENT *vary, int pos, sELEMENT *array, int len));
 * Duplicate 'len' elements from 'array' onto 'vary' beginning at position
 * 'pos'.  'array' can be a char array since its length is passed seperately.  A
 * new array is created if 'vary' is 0.
 */
sELEMENT *vsndup(sELEMENT *vary, int pos, sELEMENT *array, int len);

/* sELEMENT *vsdup(sELEMENT *vary));
 * Duplicate array.  This is just a functionalized version of:
 *
 *   vsndup(NULL, 0, vary, sLEN(vary));
 *
 * but since you need to be able to refer to this particular function by
 * address often it's given here.
 *
 * (actually, there's bazillions of these simple combinations of the above
 * functions and the macros of the next section.  You'll probably want to make
 * functionalized instances of the ones you use most often - especially since
 * the macros aren't safe).
 */
sELEMENT *vsdup(sELEMENT *vary);

/* sELEMENT *vsset(sELEMENT *vary, int pos, sELEMENT element);
 * Set an element in an array.  Any value of 'pos' is valid.  A new array
 * is created if 'vary' is 0.  The previous contents of the position is
 * deleted.    This does not duplicate 'element'.  If you need 'element'
 * duplicated, call: vsset(vary,pos,sdup(element));
 */
sELEMENT *_vsset(sELEMENT *vary, int pos, sELEMENT el);

#define vsset(v,p,el)  \
 (!(v) || (p) > sLen(v) || (p) >= sSiz(v) ?  \
  _vsset((v), (p), (el)) \
 : \
  ((p) == sLen(v) ? \
   ((v)[(p) + 1] = 0, sLen(v) = (p) + 1, (v)[p] = (el), (v)) \
  : \
   ((v)[p] = (el), (v)) \
  ) \
 )

/* sELEMENT *vsadd(sELEMENT *vary, sELEMENT element);
 * Concatenate a single element to the end of 'vary'.  A new array is created
 * if 'vary' is 0.  This does not duplicate element: call
 * vsadd(vary,sdup(element));  If you need it duplicated.
 */
#define vsadd(v,el) \
 (!(v) || sLen(v) == sSiz(v) ? \
  _vsset((v), sLEN(v), (el)) \
 : \
  ((v)[sLen(v) + 1] = 0, (v)[sLen(v)] = (el), sLen(v) = sLen(v) + 1, (v)) \
 )

/**************************************/
/* Functions which read from an array */
/**************************************/

/* These macros are used to generate the address/size pairs which get
 * passed to the functions of the previous section.
 */

/* { sELEMENT *, int } sv(sELEMENT *array);
 * Return array, size pair.  Uses sLEN to get size.
 */
#define sv(a) (a), sLEN(a)

/* { sELEMENT *, int } sz(sELEMENT *array);
 * Return array, size pair.  Uses slen to get size.
 */
#define sz(a) (a), slen(a)

/* { sELEMENT *, int } sc(sELEMENT *array);
 * Return array, size pair.  Uses 'sizeof' to get size.
 */
#define sc(a) (const unsigned char *)(a), (sizeof(a) / sizeof(sELEMENT) - 1)

/* { sELEMENT *, int } srest(sELEMENT *vary, int pos);
 * Return array, size pair of rest of array beginning at pos.  If
 * pos is past end of array, gives size of 0.
 */
#define srest(a,p) ((a) + (p)), (((p) > sLEN(a)) ? 0 : sLen(a) - (p))

/* { sELEMENT *, int } spart(sELEMENT *vary, int pos, int len);
 * Return array,size pair of 'len' elements of array beginning with pos.  If
 * pos is past end of array, gives size of 0.  If pos+len is past end of array,
 * returns number of elements to end of array.
 */
#define spart(a,p,l) \
 ((a) + (p)), ((p) >= sLEN(a) ? 0 : ((p) + (l) > sLen(a) ? sLen(a) - (p) : (l)))

/* sELEMENT vsget(sELEMENT *vary, int pos);
 * Get an element from an array.  Any value of pos is valid; if it's past the
 * end of the array or if 'vary' is 0, the terminator is returned.  This
 * does not make a duplicate of the returned element.  If you want that, pass
 * the return value of this to sdup.
 */
#define vsget(a,p) ((p) >= sLEN(a) ? sterm : (a)[p])

/*************************/
/* Searching and Sorting */
/*************************/

/* int vsbsearch(const sELEMENT *ary, int len, sELEMENT element);
 * Do a binary search on a sorted variable length or char array.  Returns position
 * of matching element or the position where the element should be if it was
 * not found.  (You should test with scmp to find out which).
 *
 * Hmm... this should really indicate whether or not the element was found.
 */
int vsbsearch(const sELEMENT *ary, int len, sELEMENT el);

/* int vscmpn(sELEMENT *a, int alen, sELEMENT *b, int blen);
 *
 * Compare two arrays using scmp.  If 'a' > 'b', return 1.  If 'a' == 'b',
 * return 0.  If 'a' < 'b', return -1.  Longer strings are > shorter ones if
 * their beginning match.
 */
int vscmpn(sELEMENT *a, int alen, sELEMENT *b, int blen);

/* int vscmp(sELEMENT *a, sELEMENT *b);
 *
 * Functionalized version of: vscmpn(sv(a), sv(b));
 */
int vscmp(sELEMENT *a, sELEMENT *b);

/* int vsscan(const sELEMENT *a, int alen, const sELEMENT *b, int blen);
 * Find offset of first matching element in 'a' which matches any
 * of the elements passed in 'b'.  Array 'b' must be sorted.
 *
 * Hmm... this really needs to return what the found element is.
 */
int vsscan(const sELEMENT *a, int alen, const sELEMENT *b, int blen);

/* int vsspan(sELEMENT *a, int alen, sELEMENT *b, int blen);
 * Find offset of first matching element in 'a' which does not match any
 * of the elements passed in 'b'.  Array 'b' must be sorted.
 */
int vsspan(const sELEMENT *a, int alen, const sELEMENT *b, int blen);

#endif