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 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
|
/*
* Dynamic string library
* Copyright
* (C) 1992 Joseph H. Allen
*
* This file is part of JOE (Joe's Own Editor)
*/
#ifndef _JOE_VS_H
#define _JOE_VS_H 1
/***
*
* 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))
/* Compare a single element- case insensitive */
int sicmp(unsigned char a, unsigned char b);
/* 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 PARAMS((int len));
/* void vsrm(sELEMENT *vary);
* Free an array and everything which is in it. Does nothing if 'vary' is
* 0.
*/
void vsrm PARAMS((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) ((a) ? *((int *)(a) - 2) : 0)
#define sSiz(a) (*((int *)(a) - 2))
/* 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) ((a) ? *((int *)(a) - 1) : 0)
#define sLen(a) (*((int *)(a) - 1))
/* int slen(sELEMENT *ary);
* Compute length of char or variable length array by searching for termination
* element. Returns 0 if 'vary' is 0.
*/
int slen PARAMS((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 PARAMS((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 PARAMS((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 PARAMS((sELEMENT *vary, int pos, sELEMENT el, int len));
/* sELEMENT *vsncpy(sELEMENT *vary, int pos, 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 PARAMS((sELEMENT *vary, int pos, 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 PARAMS((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 PARAMS((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 PARAMS((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) (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])
/**********************/
/* Insertion/Deletion */
/**********************/
#ifdef junk
/* sELEMENT *vsins(sELEMENT *vary, int pos, int n));
* Insert n empty slots into the array. If 'pos' >= the length of the array,
* the array is simply extended. The new slots are not set to anything.
* This does not set the elements in the created hole to any particular
* value: use vsfill if you need that to occur.
*/
sELEMENT *vsins PARAMS((sELEMENT *vary, int pos, int n));
/* sELEMENT *vsdel(sELEMENT *vary, int pos, int n));
* Delete n slots from the array. This does not zap the elements first; call
* vszap first if you need this to happen.
*/
sELEMENT *vsdel PARAMS((SELEMENT *vary, int pos, int n));
/*************************/
/* Searching and Sorting */
/*************************/
/* sELEMENT *vssort(sELEMENT *ary, int len))
* Sort the elements of an array (char or variable length) using qsort().
*/
sELEMENT *vssort PARAMS((sELEMENT *ary, int len));
#endif
/* int vsbsearch(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 PARAMS((sELEMENT *ary, int len, sELEMENT el));
#ifdef junk
/* int vsfirst(sELEMENT *ary, int len, sELEMENT element);
* Find offset to first matching element in 'vary' or return ~0 if not found.
*/
int vsfirst PARAMS((sELEMENT *ary, int len, sELEMENT element));
/* int vslast(sELEMENT *ary, int len, sELEMENT element);
* Find offset to last matching element in 'vary' or return ~0 if none found.
*/
int vslast PARAMS((sELEMENT *ary, int len, sELEMENT element));
/* int vss(sELEMENT *a, int alen, sELEMENT *b, int blen);
* Do a substring search on 'a'. Return offset from 'a' to first matching
* occurance of 'b' in 'a' or return ~0 if none found.
*/
int vss PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
#endif
/* 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 PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
/* int vscmp(sELEMENT *a, sELEMENT *b);
*
* Functionalized version of: vscmpn(sv(a), sv(b));
*/
int vscmp PARAMS((sELEMENT *a, sELEMENT *b));
#ifdef junk
/* int vsicmpn(sELEMENT *a, int alen, sELEMENT *b, int blen);
*
* Compare two arrays using sicmp. If 'a' > 'b', return 1. If 'a' == 'b',
* return 0. If 'a' < 'b', return -1. Longer strings are > shorter ones if
* their beginning match.
*
* This is same as vscmpn except that it is case insensitive.
*/
int vsicmpn PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
/* int vsicmp(sELEMENT *a, sELEMENT *b);
*
* Functionalized version of: vsicmpn(sv(a), sv(b));
*/
int vsicmp PARAMS((sELEMENT *a, sELEMENT *b));
#endif
/* int vsscan(sELEMENT *a, int alen, 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 PARAMS((sELEMENT *a, int alen, 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 PARAMS((sELEMENT *a, int alen, sELEMENT *b, int blen));
/***************/
/* Other stuff */
/***************/
#ifdef junk
/* char *vsread(char *d, int p, int (*getC)(void *ptr), void *ptr);
* Replace 'd' with next line read from read-character function 'getC'. If
* 'd' is 0, a new string is allocated. If there is no more input, the string
* is freed and 0 is returned. The \n is deleted from the entered line.
*
* 'ptr' is passed as the first arg to 'getC'. 'getC' should return -1 if
* there is no more input.
*/
unsigned char *vsread PARAMS(());
/* char *vwords(char *s, char **a, int len, char t);
*
* Generate a 't'-seperated word list from the words in the zero-terminated
* array of zero-terminated strings 'a'. For example a simple 'echo.c':
*
* main(argc, argv)
* char *argv[];
* {
* printf("%s\n",vwords(NULL,argv,argc,' ')):
* }
*
*/
unsigned char *vwords PARAMS(());
#endif
#endif
|