mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-28 10:46:33 +08:00
Import of Troy Hanson's uthash package, v1.9.6
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,376 @@
|
|||||||
|
utarray: dynamic array macros for C
|
||||||
|
===================================
|
||||||
|
Troy D. Hanson <thanson@users.sourceforge.net>
|
||||||
|
v1.9.5, November 2011
|
||||||
|
|
||||||
|
include::sflogo.txt[]
|
||||||
|
include::topnav_utarray.txt[]
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
include::toc.txt[]
|
||||||
|
|
||||||
|
A set of general-purpose dynamic array macros for C structures are included with
|
||||||
|
uthash in `utarray.h`. To use these macros in your own C program, just
|
||||||
|
copy `utarray.h` into your source directory and use it in your programs.
|
||||||
|
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
The dynamic array supports basic operations such as push, pop, and erase on the
|
||||||
|
array elements. These array elements can be any simple datatype or structure.
|
||||||
|
The array <<operations,operations>> are based loosely on the C++ STL vector methods.
|
||||||
|
|
||||||
|
Internally the dynamic array contains a contiguous memory region into which
|
||||||
|
the elements are copied. This buffer is grown as needed using `realloc` to
|
||||||
|
accomodate all the data that is pushed into it.
|
||||||
|
|
||||||
|
Download
|
||||||
|
~~~~~~~~
|
||||||
|
To download the `utarray.h` header file, follow the link on the
|
||||||
|
http://uthash.sourceforge.net[uthash home page].
|
||||||
|
|
||||||
|
BSD licensed
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
This software is made available under the
|
||||||
|
link:license.html[revised BSD license].
|
||||||
|
It is free and open source.
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
~~~~~~~~~
|
||||||
|
The 'utarray' macros have been tested on:
|
||||||
|
|
||||||
|
* Linux,
|
||||||
|
* Mac OS X,
|
||||||
|
* Windows, using Visual Studio 2008 and Visual Studio 2010
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Declaration
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
The array itself has the data type `UT_array`, regardless of the type of
|
||||||
|
elements to be stored in it. It is declared like,
|
||||||
|
|
||||||
|
UT_array *nums;
|
||||||
|
|
||||||
|
New and free
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
The next step is to create the array using `utarray_new`. Later when you're
|
||||||
|
done with the array, `utarray_free` will free it and all its elements.
|
||||||
|
|
||||||
|
Push, pop, etc
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
The central features of the utarray involve putting elements into it, taking
|
||||||
|
them out, and iterating over them. There are several <<operations,operations>>
|
||||||
|
to pick from that deal with either single elements or ranges of elements at a
|
||||||
|
time. In the examples below we will use only the push operation to insert
|
||||||
|
elements.
|
||||||
|
|
||||||
|
Elements
|
||||||
|
--------
|
||||||
|
|
||||||
|
Support for dynamic arrays of integers or strings is especially easy. These are
|
||||||
|
best shown by example:
|
||||||
|
|
||||||
|
Integers
|
||||||
|
~~~~~~~~
|
||||||
|
This example makes a utarray of integers, pushes 0-9 into it, then prints it.
|
||||||
|
Lastly it frees it.
|
||||||
|
|
||||||
|
.Integer elements
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_array *nums;
|
||||||
|
int i, *p;
|
||||||
|
|
||||||
|
utarray_new(nums,&ut_int_icd);
|
||||||
|
for(i=0; i < 10; i++) utarray_push_back(nums,&i);
|
||||||
|
|
||||||
|
for(p=(int*)utarray_front(nums);
|
||||||
|
p!=NULL;
|
||||||
|
p=(int*)utarray_next(nums,p)) {
|
||||||
|
printf("%d\n",*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
utarray_free(nums);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The second argument to `utarray_push_back` is always a 'pointer' to the type
|
||||||
|
(so a literal cannot be used). So for integers, it is an `int*`.
|
||||||
|
|
||||||
|
Strings
|
||||||
|
~~~~~~~
|
||||||
|
In this example we make a utarray of strings, push two strings into it, print
|
||||||
|
it and free it.
|
||||||
|
|
||||||
|
.String elements
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_array *strs;
|
||||||
|
char *s, **p;
|
||||||
|
|
||||||
|
utarray_new(strs,&ut_str_icd);
|
||||||
|
|
||||||
|
s = "hello"; utarray_push_back(strs, &s);
|
||||||
|
s = "world"; utarray_push_back(strs, &s);
|
||||||
|
p = NULL;
|
||||||
|
while ( (p=(char**)utarray_next(strs,p))) {
|
||||||
|
printf("%s\n",*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
utarray_free(strs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
In this example, since the element is a `char*`, we pass a pointer to it
|
||||||
|
(`char**`) as the second argument to `utarray_push_back`. Note that "push" makes
|
||||||
|
a copy of the source string and pushes that copy into the array.
|
||||||
|
|
||||||
|
About UT_icd
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Arrays be made of any type of element, not just integers and strings. The
|
||||||
|
elements can be basic types or structures. Unless you're dealing with integers
|
||||||
|
and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need
|
||||||
|
to define a `UT_icd` helper structure. This structure contains everything that
|
||||||
|
utarray needs to initialize, copy or destruct elements.
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t sz;
|
||||||
|
init_f *init;
|
||||||
|
ctor_f *copy;
|
||||||
|
dtor_f *dtor;
|
||||||
|
} UT_icd;
|
||||||
|
|
||||||
|
The three function pointers `init`, `copy`, and `dtor` have these prototypes:
|
||||||
|
|
||||||
|
typedef void (ctor_f)(void *dst, const void *src);
|
||||||
|
typedef void (dtor_f)(void *elt);
|
||||||
|
typedef void (init_f)(void *elt);
|
||||||
|
|
||||||
|
The `sz` is just the size of the element being stored in the array.
|
||||||
|
|
||||||
|
The `init` function will be invoked whenever utarray needs to initialize an
|
||||||
|
empty element. This only happens as a byproduct of `utarray_resize` or
|
||||||
|
`utarray_extend_back`. If `init` is `NULL`, it defaults to zero filling the
|
||||||
|
new element using memset.
|
||||||
|
|
||||||
|
The `copy` function is used whenever an element is copied into the array.
|
||||||
|
It is invoked during `utarray_push_back`, `utarray_insert`, `utarray_inserta`,
|
||||||
|
or `utarray_concat`. If `copy` is `NULL`, it defaults to a bitwise copy using
|
||||||
|
memcpy.
|
||||||
|
|
||||||
|
The `dtor` function is used to clean up an element that is being removed from
|
||||||
|
the array. It may be invoked due to `utarray_resize`, `utarray_pop_back`,
|
||||||
|
`utarray_erase`, `utarray_clear`, `utarray_done` or `utarray_free`. If the
|
||||||
|
elements need no cleanup upon destruction, `dtor` may be `NULL`.
|
||||||
|
|
||||||
|
Scalar types
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The next example uses `UT_icd` with all its defaults to make a utarray of
|
||||||
|
`long` elements. This example pushes two longs, prints them, and frees the
|
||||||
|
array.
|
||||||
|
|
||||||
|
.long elements
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_array *nums;
|
||||||
|
long l, *p;
|
||||||
|
utarray_new(nums, &long_icd);
|
||||||
|
|
||||||
|
l=1; utarray_push_back(nums, &l);
|
||||||
|
l=2; utarray_push_back(nums, &l);
|
||||||
|
|
||||||
|
p=NULL;
|
||||||
|
while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p);
|
||||||
|
|
||||||
|
utarray_free(nums);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Structures
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
Structures can be used as utarray elements. If the structure requires no
|
||||||
|
special effort to initialize, copy or destruct, we can use `UT_icd` with all
|
||||||
|
its defaults. This example shows a structure that consists of two integers. Here
|
||||||
|
we push two values, print them and free the array.
|
||||||
|
|
||||||
|
.Structure (simple)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
} intpair_t;
|
||||||
|
|
||||||
|
UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
UT_array *pairs;
|
||||||
|
intpair_t ip, *p;
|
||||||
|
utarray_new(pairs,&intpair_icd);
|
||||||
|
|
||||||
|
ip.a=1; ip.b=2; utarray_push_back(pairs, &ip);
|
||||||
|
ip.a=10; ip.b=20; utarray_push_back(pairs, &ip);
|
||||||
|
|
||||||
|
for(p=(intpair_t*)utarray_front(pairs);
|
||||||
|
p!=NULL;
|
||||||
|
p=(intpair_t*)utarray_next(pairs,p)) {
|
||||||
|
printf("%d %d\n", p->a, p->b);
|
||||||
|
}
|
||||||
|
|
||||||
|
utarray_free(pairs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The real utility of `UT_icd` is apparent when the elements of the utarray are
|
||||||
|
structures that require special work to initialize, copy or destruct.
|
||||||
|
|
||||||
|
For example, when a structure contains pointers to related memory areas that
|
||||||
|
need to be copied when the structure is copied (and freed when the structure is
|
||||||
|
freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`.
|
||||||
|
|
||||||
|
Here we take an example of a structure that contains an integer and a string.
|
||||||
|
When this element is copied (such as when an element is pushed into the array),
|
||||||
|
we want to "deep copy" the `s` pointer (so the original element and the new
|
||||||
|
element point to their own copies of `s`). When an element is destructed, we
|
||||||
|
want to "deep free" its copy of `s`. Lastly, this example is written to work
|
||||||
|
even if `s` has the value `NULL`.
|
||||||
|
|
||||||
|
.Structure (complex)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "utarray.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int a;
|
||||||
|
char *s;
|
||||||
|
} intchar_t;
|
||||||
|
|
||||||
|
void intchar_copy(void *_dst, const void *_src) {
|
||||||
|
intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
|
||||||
|
dst->a = src->a;
|
||||||
|
dst->s = src->s ? strdup(src->s) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intchar_dtor(void *_elt) {
|
||||||
|
intchar_t *elt = (intchar_t*)_elt;
|
||||||
|
if (elt->s) free(elt->s);
|
||||||
|
}
|
||||||
|
|
||||||
|
UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_array *intchars;
|
||||||
|
intchar_t ic, *p;
|
||||||
|
utarray_new(intchars, &intchar_icd);
|
||||||
|
|
||||||
|
ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic);
|
||||||
|
ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic);
|
||||||
|
|
||||||
|
p=NULL;
|
||||||
|
while( (p=(intchar_t*)utarray_next(intchars,p))) {
|
||||||
|
printf("%d %s\n", p->a, (p->s ? p->s : "null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
utarray_free(intchars);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[[operations]]
|
||||||
|
Reference
|
||||||
|
---------
|
||||||
|
This table lists all the utarray operations. These are loosely based on the C++
|
||||||
|
vector class.
|
||||||
|
|
||||||
|
Operations
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
[width="100%",cols="50<m,40<",grid="none",options="none"]
|
||||||
|
|===============================================================================
|
||||||
|
| utarray_new(UT_array *a, UT_icd *icd)| allocate a new array
|
||||||
|
| utarray_free(UT_array *a) | free an allocated array
|
||||||
|
| utarray_init(UT_array *a,UT_icd *icd)| init an array (non-alloc)
|
||||||
|
| utarray_done(UT_array *a) | dispose of an array (non-allocd)
|
||||||
|
| utarray_reserve(UT_array *a,int n) | ensure space available for 'n' more elements
|
||||||
|
| utarray_push_back(UT_array *a,void *p) | push element p onto a
|
||||||
|
| utarray_pop_back(UT_array *a) | pop last element from a
|
||||||
|
| utarray_extend_back(UT_array *a) | push empty element onto a
|
||||||
|
| utarray_len(UT_array *a) | get length of a
|
||||||
|
| utarray_eltptr(UT_array *a,int j) | get pointer of element from index
|
||||||
|
| utarray_eltidx(UT_array *a,void *e) | get index of element from pointer
|
||||||
|
| utarray_insert(UT_array *a,void *p, int j) | insert element p to index j
|
||||||
|
| utarray_inserta(UT_array *a,UT_array *w, int j) | insert array w into array a at index j
|
||||||
|
| utarray_resize(UT_array *dst,int num) | extend or shrink array to num elements
|
||||||
|
| utarray_concat(UT_array *dst,UT_array *src) | copy src to end of dst array
|
||||||
|
| utarray_erase(UT_array *a,int pos,int len) | remove len elements from a[pos]..a[pos+len-1]
|
||||||
|
| utarray_clear(UT_array *a) | clear all elements from a, setting its length to zero
|
||||||
|
| utarray_sort(UT_array *a,cmpfcn *cmp) | sort elements of a using comparison function
|
||||||
|
| utarray_find(UT_array *a,void *v, cmpfcn *cmp) | find element v in utarray (must be sorted)
|
||||||
|
| utarray_front(UT_array *a) | get first element of a
|
||||||
|
| utarray_next(UT_array *a,void *e) | get element of a following e (front if e is NULL)
|
||||||
|
| utarray_prev(UT_array *a,void *e) | get element of a before e (back if e is NULL)
|
||||||
|
| utarray_back(UT_array *a) | get last element of a
|
||||||
|
|===============================================================================
|
||||||
|
|
||||||
|
Notes
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
1. `utarray_new` and `utarray_free` are used to allocate a new array and free it,
|
||||||
|
while `utarray_init` and `utarray_done` can be used if the UT_array is already
|
||||||
|
allocated and just needs to be initialized or have its internal resources
|
||||||
|
freed.
|
||||||
|
2. `utarray_reserve` takes the "delta" of elements to reserve (not the total
|
||||||
|
desired capacity of the array-- this differs from the C++ STL "reserve" notion)
|
||||||
|
3. `utarray_sort` expects a comparison function having the usual `strcmp` -like
|
||||||
|
convention where it accepts two elements (a and b) and returns a negative
|
||||||
|
value if a precedes b, 0 if a and b sort equally, and positive if b precedes a.
|
||||||
|
This is an example of a comparison function:
|
||||||
|
|
||||||
|
int intsort(const void *a,const void*b) {
|
||||||
|
int _a = *(int*)a;
|
||||||
|
int _b = *(int*)b;
|
||||||
|
return _a - _b;
|
||||||
|
}
|
||||||
|
|
||||||
|
4. `utarray_find` uses a binary search to locate an element having a certain value
|
||||||
|
according to the given comparison function. The utarray must be first sorted
|
||||||
|
using the same comparison function. An example of using `utarray_find` with
|
||||||
|
a utarray of strings is included in `tests/test61.c`.
|
||||||
|
|
||||||
|
5. A 'pointer' to a particular element (obtained using `utarray_eltptr` or
|
||||||
|
`utarray_front`, `utarray_next`, `utarray_prev`, `utarray_back`) becomes invalid whenever
|
||||||
|
another element is inserted into the utarray. This is because the internal
|
||||||
|
memory management may need to `realloc` the element storage to a new address.
|
||||||
|
For this reason, it's usually better to refer to an element by its integer
|
||||||
|
'index' in code whose duration may include element insertion.
|
||||||
|
|
||||||
|
// vim: set nowrap syntax=asciidoc:
|
||||||
|
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
utlist: linked list macros for C structures
|
||||||
|
===========================================
|
||||||
|
Troy D. Hanson <thanson@users.sourceforge.net>
|
||||||
|
v1.9.5, November 2011
|
||||||
|
|
||||||
|
include::sflogo.txt[]
|
||||||
|
include::topnav_utlist.txt[]
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
include::toc.txt[]
|
||||||
|
|
||||||
|
A set of general-purpose 'linked list' macros for C structures are included with
|
||||||
|
uthash in `utlist.h`. To use these macros in your own C program, just
|
||||||
|
copy `utlist.h` into your source directory and use it in your programs.
|
||||||
|
|
||||||
|
#include "utlist.h"
|
||||||
|
|
||||||
|
These macros support the basic linked list operations: adding and deleting
|
||||||
|
elements, sorting them and iterating over them.
|
||||||
|
|
||||||
|
Download
|
||||||
|
~~~~~~~~
|
||||||
|
To download the `utlist.h` header file, follow the link on the
|
||||||
|
http://uthash.sourceforge.net[uthash home page].
|
||||||
|
|
||||||
|
BSD licensed
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
This software is made available under the
|
||||||
|
link:license.html[revised BSD license].
|
||||||
|
It is free and open source.
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
~~~~~~~~~
|
||||||
|
The 'utlist' macros have been tested on:
|
||||||
|
|
||||||
|
* Linux,
|
||||||
|
* Mac OS X, and
|
||||||
|
* Windows, using Visual Studio 2008, Visual Studio 2010, or Cygwin/MinGW.
|
||||||
|
|
||||||
|
Using utlist
|
||||||
|
------------
|
||||||
|
|
||||||
|
Types of lists
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
Three types of linked lists are supported:
|
||||||
|
|
||||||
|
- *singly-linked* lists,
|
||||||
|
- *doubly-linked* lists, and
|
||||||
|
- *circular, doubly-linked* lists
|
||||||
|
|
||||||
|
Efficiency
|
||||||
|
^^^^^^^^^^
|
||||||
|
For all types of lists, prepending elements and deleting elements are
|
||||||
|
constant-time operations. Appending to a singly-linked list is an 'O(n)'
|
||||||
|
operation but appending to a doubly-linked list is constant time using these
|
||||||
|
macros. (This is because, in the utlist implementation of the doubly-linked
|
||||||
|
list, the head element's `prev` member points back to the list tail, even when
|
||||||
|
the list is non-circular). Sorting is an 'O(n log(n))' operation. Iteration
|
||||||
|
and searching are `O(n)` for all list types.
|
||||||
|
|
||||||
|
List elements
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
You can use any structure with these macros, as long as the structure
|
||||||
|
contains a `next` pointer. If you want to make a doubly-linked list,
|
||||||
|
the element also needs to have a `prev` pointer.
|
||||||
|
|
||||||
|
typedef struct element {
|
||||||
|
char *name;
|
||||||
|
struct element *prev; /* needed for a doubly-linked list only */
|
||||||
|
struct element *next; /* needed for singly- or doubly-linked lists */
|
||||||
|
} element;
|
||||||
|
|
||||||
|
You can name your structure anything. In the example above it is called `element`.
|
||||||
|
Within a particular list, all elements must be of the same type.
|
||||||
|
|
||||||
|
List head
|
||||||
|
~~~~~~~~~
|
||||||
|
The list head is simply a pointer to your element structure. You can name it
|
||||||
|
anything. *It must be initialized to `NULL`*.
|
||||||
|
|
||||||
|
element *head = NULL;
|
||||||
|
|
||||||
|
List operations
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The lists support inserting or deleting elements, sorting the elements and
|
||||||
|
iterating over them.
|
||||||
|
|
||||||
|
[width="100%",cols="10<m,10<m,10<m",grid="cols",options="header"]
|
||||||
|
|===============================================================================
|
||||||
|
|Singly-linked | Doubly-linked | Circular, doubly-linked
|
||||||
|
|LL_PREPEND(head,add); | DL_PREPEND(head,add); | CDL_PREPEND(head,add;
|
||||||
|
|LL_APPEND(head,add); | DL_APPEND(head,add); |
|
||||||
|
|LL_CONCAT(head1,head2); | DL_CONCAT(head1,head2); |
|
||||||
|
|LL_DELETE(head,del); | DL_DELETE(head,del); | CDL_DELETE(head,del);
|
||||||
|
|LL_SORT(head,cmp); | DL_SORT(head,cmp); | CDL_SORT(head,cmp);
|
||||||
|
|LL_FOREACH(head,elt) {...}| DL_FOREACH(head,elt) {...} | CDL_FOREACH(head,elt) {...}
|
||||||
|
|LL_FOREACH_SAFE(head,elt,tmp) {...}| DL_FOREACH_SAFE(head,elt,tmp) {...} | CDL_FOREACH_SAFE(head,elt,tmp1,tmp2) {...}
|
||||||
|
|LL_SEARCH_SCALAR(head,elt,mbr,val);| DL_SEARCH_SCALAR(head,elt,mbr,val); | CDL_SEARCH_SCALAR(head,elt,mbr,val);
|
||||||
|
|LL_SEARCH(head,elt,like,cmp);| DL_SEARCH(head,elt,like,cmp); | CDL_SEARCH(head,elt,like,cmp);
|
||||||
|
|===============================================================================
|
||||||
|
|
||||||
|
'Prepend' means to insert an element in front of the existing list head (if any),
|
||||||
|
changing the list head to the new element. 'Append' means to add an element at the
|
||||||
|
end of the list, so it becomes the new tail element. 'Concatenate' takes two
|
||||||
|
properly constructed lists and appends the second list to the first. (Visual
|
||||||
|
Studio 2008 does not support `LL_CONCAT` and `DL_CONCAT`, but VS2010 is ok.)
|
||||||
|
|
||||||
|
The 'sort' operation never moves the elements in memory; rather it only adjusts
|
||||||
|
the list order by altering the `prev` and `next` pointers in each element. Also
|
||||||
|
the sort operation can change the list head to point to a new element.
|
||||||
|
|
||||||
|
The 'foreach' operation is for easy iteration over the list from the head to the
|
||||||
|
tail. A usage example is shown below. You can of course just use the `prev` and
|
||||||
|
`next` pointers directly instead of using the 'foreach' macros.
|
||||||
|
The 'foreach_safe' operation should be used if you plan to delete any of the list
|
||||||
|
elements while iterating.
|
||||||
|
|
||||||
|
The 'search' operation is a shortcut for iteration in search of a particular
|
||||||
|
element. It is not any faster than manually iterating and testing each element.
|
||||||
|
There are two forms: the "scalar" version searches for an element using a
|
||||||
|
simple equality test on a given structure member, while the general version takes an
|
||||||
|
element to which all others in the list will be compared using a `cmp` function.
|
||||||
|
|
||||||
|
|
||||||
|
The parameters shown in the table above are explained here:
|
||||||
|
|
||||||
|
head::
|
||||||
|
The list head (a pointer to your list element structure).
|
||||||
|
add::
|
||||||
|
A pointer to the list element structure you are adding to the list.
|
||||||
|
del::
|
||||||
|
A pointer to the list element structure you are deleting from the list.
|
||||||
|
elt::
|
||||||
|
A pointer that will be assigned to each list element in succession (see
|
||||||
|
example) in the case of iteration macros; also, the output pointer from
|
||||||
|
the search macros.
|
||||||
|
like::
|
||||||
|
An element pointer, having the same type as `elt`, for which the search macro
|
||||||
|
seeks a match (if found, the match is stored in `elt`). A match is determined
|
||||||
|
by the given `cmp` function.
|
||||||
|
cmp::
|
||||||
|
pointer to comparison function which accepts two arguments-- these are
|
||||||
|
pointers to two element structures to be compared. The comparison function
|
||||||
|
must return an `int` that is negative, zero, or positive, which specifies
|
||||||
|
whether the first item should sort before, equal to, or after the second item,
|
||||||
|
respectively. (In other words, the same convention that is used by `strcmp`).
|
||||||
|
Note that under Visual Studio 2008 you may need to declare the two arguments
|
||||||
|
as `void *` and then cast them back to their actual types.
|
||||||
|
tmp::
|
||||||
|
A pointer of the same type as `elt`. Used internally. Need not be initialized.
|
||||||
|
mbr::
|
||||||
|
In the scalar search macro, the name of a member within the `elt` structure which
|
||||||
|
will be tested (using `==`) for equality with the value `val`.
|
||||||
|
val::
|
||||||
|
In the scalar search macro, specifies the value of (of structure member
|
||||||
|
`field`) of the element being sought.
|
||||||
|
|
||||||
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
This example program reads names from a text file (one name per line), and
|
||||||
|
appends each name to a doubly-linked list. Then it sorts and prints them.
|
||||||
|
|
||||||
|
.A doubly-linked list
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "utlist.h"
|
||||||
|
|
||||||
|
#define BUFLEN 20
|
||||||
|
|
||||||
|
typedef struct el {
|
||||||
|
char bname[BUFLEN];
|
||||||
|
struct el *next, *prev;
|
||||||
|
} el;
|
||||||
|
|
||||||
|
int namecmp(el *a, el *b) {
|
||||||
|
return strcmp(a->bname,b->bname);
|
||||||
|
}
|
||||||
|
|
||||||
|
el *head = NULL; /* important- initialize to NULL! */
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
el *name, *elt, *tmp, etmp;
|
||||||
|
|
||||||
|
char linebuf[BUFLEN];
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
if ( (file = fopen( "test11.dat", "r" )) == NULL ) {
|
||||||
|
perror("can't open: ");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(linebuf,BUFLEN,file) != NULL) {
|
||||||
|
if ( (name = (el*)malloc(sizeof(el))) == NULL) exit(-1);
|
||||||
|
strncpy(name->bname,linebuf,BUFLEN);
|
||||||
|
DL_APPEND(head, name);
|
||||||
|
}
|
||||||
|
DL_SORT(head, namecmp);
|
||||||
|
DL_FOREACH(head,elt) printf("%s", elt->bname);
|
||||||
|
|
||||||
|
memcpy(&etmp.bname, "WES\n", 5);
|
||||||
|
DL_SEARCH(head,elt,&etmp,namecmp);
|
||||||
|
if (elt) printf("found %s\n", elt->bname);
|
||||||
|
|
||||||
|
/* now delete each element, use the safe iterator */
|
||||||
|
DL_FOREACH_SAFE(head,elt,tmp) {
|
||||||
|
DL_DELETE(head,elt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// vim: set nowrap syntax=asciidoc:
|
||||||
|
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
utstring: dynamic string macros for C
|
||||||
|
=====================================
|
||||||
|
Troy D. Hanson <thanson@users.sourceforge.net>
|
||||||
|
v1.9.5, November 2011
|
||||||
|
|
||||||
|
include::sflogo.txt[]
|
||||||
|
include::topnav_utstring.txt[]
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
include::toc.txt[]
|
||||||
|
|
||||||
|
A set of very basic dynamic string macros for C programs are included with
|
||||||
|
uthash in `utstring.h`. To use these macros in your own C program, just
|
||||||
|
copy `utstring.h` into your source directory and use it in your programs.
|
||||||
|
|
||||||
|
#include "utstring.h"
|
||||||
|
|
||||||
|
The dynamic string supports basic operations such as inserting data (including
|
||||||
|
binary data-- despite its name, utstring is not limited to string content),
|
||||||
|
concatenation, getting the length and content, and clearing it. The string
|
||||||
|
<<operations,operations>> are listed below.
|
||||||
|
|
||||||
|
Download
|
||||||
|
~~~~~~~~
|
||||||
|
To download the `utstring.h` header file, follow the link on the
|
||||||
|
http://uthash.sourceforge.net[uthash home page].
|
||||||
|
|
||||||
|
BSD licensed
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
This software is made available under the
|
||||||
|
link:license.html[revised BSD license].
|
||||||
|
It is free and open source.
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
~~~~~~~~~
|
||||||
|
The 'utstring' macros have been tested on:
|
||||||
|
|
||||||
|
* Linux,
|
||||||
|
* Windows, using Visual Studio 2008 and Visual Studio 2010
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Declaration
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
The dynamic string itself has the data type `UT_string`. It is declared like,
|
||||||
|
|
||||||
|
UT_string *str;
|
||||||
|
|
||||||
|
New and free
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
The next step is to create the string using `utstring_new`. Later when you're
|
||||||
|
done with it, `utstring_free` will free it and all its content.
|
||||||
|
|
||||||
|
Manipulation
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
The `utstring_printf` or `utstring_bincpy` operations insert (copy) data into
|
||||||
|
the string. To concatenate one utstring to another, use `utstring_concat`. To
|
||||||
|
clear the content of the string, use `utstring_clear`. The length of the string
|
||||||
|
is available from `utstring_len`, and its content from `utstring_body`. This
|
||||||
|
evaluates to a `char*`. The buffer it points to is always null-terminated.
|
||||||
|
So, it can be used directly with external functions that expect a string.
|
||||||
|
This automatic null terminator is not counted in the length of the string.
|
||||||
|
|
||||||
|
Samples
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
These examples show how to use utstring.
|
||||||
|
|
||||||
|
.Sample 1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utstring.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_string *s;
|
||||||
|
|
||||||
|
utstring_new(s);
|
||||||
|
utstring_printf(s, "hello world!" );
|
||||||
|
printf("%s\n", utstring_body(s));
|
||||||
|
|
||||||
|
utstring_free(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The next example is meant to demonstrate that printf 'appends' to the string.
|
||||||
|
It also shows concatenation.
|
||||||
|
|
||||||
|
.Sample 2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utstring.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_string *s, *t;
|
||||||
|
|
||||||
|
utstring_new(s);
|
||||||
|
utstring_new(t);
|
||||||
|
|
||||||
|
utstring_printf(s, "hello " );
|
||||||
|
utstring_printf(s, "world " );
|
||||||
|
|
||||||
|
utstring_printf(t, "hi " );
|
||||||
|
utstring_printf(t, "there " );
|
||||||
|
|
||||||
|
utstring_concat(s, t);
|
||||||
|
printf("length: %u\n", utstring_len(s));
|
||||||
|
printf("%s\n", utstring_body(s));
|
||||||
|
|
||||||
|
utstring_free(s);
|
||||||
|
utstring_free(t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The last example shows how binary data can be inserted into the string. It also
|
||||||
|
clears the string and prints new data into it.
|
||||||
|
|
||||||
|
.Sample 3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "utstring.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
UT_string *s;
|
||||||
|
char binary[] = "\xff\xff";
|
||||||
|
|
||||||
|
utstring_new(s);
|
||||||
|
utstring_bincpy(s, binary, sizeof(binary));
|
||||||
|
printf("length is %u\n", utstring_len(s));
|
||||||
|
|
||||||
|
utstring_clear(s);
|
||||||
|
utstring_printf(s,"number %d", 10);
|
||||||
|
printf("%s\n", utstring_body(s));
|
||||||
|
|
||||||
|
utstring_free(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[[operations]]
|
||||||
|
Reference
|
||||||
|
---------
|
||||||
|
These are the utstring operations.
|
||||||
|
|
||||||
|
Operations
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
[width="100%",cols="50<m,40<",grid="none",options="none"]
|
||||||
|
|===============================================================================
|
||||||
|
| utstring_new(s) | allocate a new utstring
|
||||||
|
| utstring_renew(s) | allocate a new utstring (if s is `NULL`) otherwise clears it
|
||||||
|
| utstring_free(s) | free an allocated utstring
|
||||||
|
| utstring_init(s) | init a utstring (non-alloc)
|
||||||
|
| utstring_done(s) | dispose of a utstring (non-allocd)
|
||||||
|
| utstring_printf(s,fmt,...) | printf into a utstring (appends)
|
||||||
|
| utstring_bincpy(s,bin,len) | insert binary data of length len (appends)
|
||||||
|
| utstring_concat(dst,src) | concatenate src utstring to end of dst utstring
|
||||||
|
| utstring_clear(s) | clear the content of s (setting its length to 0)
|
||||||
|
| utstring_len(s) | obtain the length of s as an unsigned integer
|
||||||
|
| utstring_body(s) | get `char*` to body of s (buffer is always null-terminated)
|
||||||
|
|===============================================================================
|
||||||
|
|
||||||
|
Notes
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
1. `utstring_new` and `utstring_free` are used to allocate a new string and free it,
|
||||||
|
while `utstring_init` and `utstring_done` can be used if the UT_string is already
|
||||||
|
allocated and just needs to be initialized or have its internal resources
|
||||||
|
freed.
|
||||||
|
2. `utstring_printf` is actually a function defined statically in `utstring.h`
|
||||||
|
rather than a macro.
|
||||||
|
|
||||||
|
// vim: set nowrap syntax=asciidoc:
|
||||||
|
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2008-2012, Troy D. Hanson http://uthash.sourceforge.net
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* a dynamic array implementation using macros
|
||||||
|
* see http://uthash.sourceforge.net/utarray
|
||||||
|
*/
|
||||||
|
#ifndef UTARRAY_H
|
||||||
|
#define UTARRAY_H
|
||||||
|
|
||||||
|
#define UTARRAY_VERSION 1.9.6
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define _UNUSED_ __attribute__ ((__unused__))
|
||||||
|
#else
|
||||||
|
#define _UNUSED_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h> /* size_t */
|
||||||
|
#include <string.h> /* memset, etc */
|
||||||
|
#include <stdlib.h> /* exit */
|
||||||
|
|
||||||
|
#define oom() exit(-1)
|
||||||
|
|
||||||
|
typedef void (ctor_f)(void *dst, const void *src);
|
||||||
|
typedef void (dtor_f)(void *elt);
|
||||||
|
typedef void (init_f)(void *elt);
|
||||||
|
typedef struct {
|
||||||
|
size_t sz;
|
||||||
|
init_f *init;
|
||||||
|
ctor_f *copy;
|
||||||
|
dtor_f *dtor;
|
||||||
|
} UT_icd;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned i,n;/* i: index of next available slot, n: num slots */
|
||||||
|
UT_icd icd; /* initializer, copy and destructor functions */
|
||||||
|
char *d; /* n slots of size icd->sz*/
|
||||||
|
} UT_array;
|
||||||
|
|
||||||
|
#define utarray_init(a,_icd) do { \
|
||||||
|
memset(a,0,sizeof(UT_array)); \
|
||||||
|
(a)->icd=*_icd; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_done(a) do { \
|
||||||
|
if ((a)->n) { \
|
||||||
|
if ((a)->icd.dtor) { \
|
||||||
|
size_t _ut_i; \
|
||||||
|
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||||
|
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
free((a)->d); \
|
||||||
|
} \
|
||||||
|
(a)->n=0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_new(a,_icd) do { \
|
||||||
|
a=(UT_array*)malloc(sizeof(UT_array)); \
|
||||||
|
utarray_init(a,_icd); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_free(a) do { \
|
||||||
|
utarray_done(a); \
|
||||||
|
free(a); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_reserve(a,by) do { \
|
||||||
|
if (((a)->i+by) > ((a)->n)) { \
|
||||||
|
while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
|
||||||
|
if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_push_back(a,p) do { \
|
||||||
|
utarray_reserve(a,1); \
|
||||||
|
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
|
||||||
|
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_pop_back(a) do { \
|
||||||
|
if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
|
||||||
|
else { (a)->i--; } \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_extend_back(a) do { \
|
||||||
|
utarray_reserve(a,1); \
|
||||||
|
if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
|
||||||
|
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
|
||||||
|
(a)->i++; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_len(a) ((a)->i)
|
||||||
|
|
||||||
|
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
|
||||||
|
#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) )))
|
||||||
|
|
||||||
|
#define utarray_insert(a,p,j) do { \
|
||||||
|
utarray_reserve(a,1); \
|
||||||
|
if (j > (a)->i) break; \
|
||||||
|
if ((j) < (a)->i) { \
|
||||||
|
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
|
||||||
|
((a)->i - (j))*((a)->icd.sz)); \
|
||||||
|
} \
|
||||||
|
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
|
||||||
|
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
|
||||||
|
(a)->i++; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_inserta(a,w,j) do { \
|
||||||
|
if (utarray_len(w) == 0) break; \
|
||||||
|
if (j > (a)->i) break; \
|
||||||
|
utarray_reserve(a,utarray_len(w)); \
|
||||||
|
if ((j) < (a)->i) { \
|
||||||
|
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
|
||||||
|
_utarray_eltptr(a,j), \
|
||||||
|
((a)->i - (j))*((a)->icd.sz)); \
|
||||||
|
} \
|
||||||
|
if ((a)->icd.copy) { \
|
||||||
|
size_t _ut_i; \
|
||||||
|
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
|
||||||
|
(a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
|
||||||
|
utarray_len(w)*((a)->icd.sz)); \
|
||||||
|
} \
|
||||||
|
(a)->i += utarray_len(w); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_resize(dst,num) do { \
|
||||||
|
size_t _ut_i; \
|
||||||
|
if (dst->i > (size_t)(num)) { \
|
||||||
|
if ((dst)->icd.dtor) { \
|
||||||
|
for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
|
||||||
|
(dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} else if (dst->i < (size_t)(num)) { \
|
||||||
|
utarray_reserve(dst,num-dst->i); \
|
||||||
|
if ((dst)->icd.init) { \
|
||||||
|
for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
|
||||||
|
(dst)->icd.init(utarray_eltptr(dst,_ut_i)); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
dst->i = num; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_concat(dst,src) do { \
|
||||||
|
utarray_inserta((dst),(src),utarray_len(dst)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_erase(a,pos,len) do { \
|
||||||
|
if ((a)->icd.dtor) { \
|
||||||
|
size_t _ut_i; \
|
||||||
|
for(_ut_i=0; _ut_i < len; _ut_i++) { \
|
||||||
|
(a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if ((a)->i > (pos+len)) { \
|
||||||
|
memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \
|
||||||
|
(((a)->i)-(pos+len))*((a)->icd.sz)); \
|
||||||
|
} \
|
||||||
|
(a)->i -= (len); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_renew(a,u) do { \
|
||||||
|
if (a) utarray_clear(a); \
|
||||||
|
else utarray_new((a),(u)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_clear(a) do { \
|
||||||
|
if ((a)->i > 0) { \
|
||||||
|
if ((a)->icd.dtor) { \
|
||||||
|
size_t _ut_i; \
|
||||||
|
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||||
|
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
(a)->i = 0; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_sort(a,cmp) do { \
|
||||||
|
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
|
||||||
|
|
||||||
|
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
|
||||||
|
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
|
||||||
|
#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
|
||||||
|
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
|
||||||
|
#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd.sz) : -1)
|
||||||
|
|
||||||
|
/* last we pre-define a few icd for common utarrays of ints and strings */
|
||||||
|
static void utarray_str_cpy(void *dst, const void *src) {
|
||||||
|
char **_src = (char**)src, **_dst = (char**)dst;
|
||||||
|
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
|
||||||
|
}
|
||||||
|
static void utarray_str_dtor(void *elt) {
|
||||||
|
char **eltc = (char**)elt;
|
||||||
|
if (*eltc) free(*eltc);
|
||||||
|
}
|
||||||
|
static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
|
||||||
|
static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
|
||||||
|
static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UTARRAY_H */
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2008-2012, Troy D. Hanson http://uthash.sourceforge.net
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* a dynamic string implementation using macros
|
||||||
|
* see http://uthash.sourceforge.net/utstring
|
||||||
|
*/
|
||||||
|
#ifndef UTSTRING_H
|
||||||
|
#define UTSTRING_H
|
||||||
|
|
||||||
|
#define UTSTRING_VERSION 1.9.6
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define _UNUSED_ __attribute__ ((__unused__))
|
||||||
|
#else
|
||||||
|
#define _UNUSED_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#define oom() exit(-1)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *d;
|
||||||
|
size_t n; /* allocd size */
|
||||||
|
size_t i; /* index of first unused byte */
|
||||||
|
} UT_string;
|
||||||
|
|
||||||
|
#define utstring_reserve(s,amt) \
|
||||||
|
do { \
|
||||||
|
if (((s)->n - (s)->i) < (size_t)(amt)) { \
|
||||||
|
(s)->d = (char*)realloc((s)->d, (s)->n + amt); \
|
||||||
|
if ((s)->d == NULL) oom(); \
|
||||||
|
(s)->n += amt; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_init(s) \
|
||||||
|
do { \
|
||||||
|
(s)->n = 0; (s)->i = 0; (s)->d = NULL; \
|
||||||
|
utstring_reserve(s,100); \
|
||||||
|
(s)->d[0] = '\0'; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_done(s) \
|
||||||
|
do { \
|
||||||
|
if ((s)->d != NULL) free((s)->d); \
|
||||||
|
(s)->n = 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_free(s) \
|
||||||
|
do { \
|
||||||
|
utstring_done(s); \
|
||||||
|
free(s); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_new(s) \
|
||||||
|
do { \
|
||||||
|
s = (UT_string*)calloc(sizeof(UT_string),1); \
|
||||||
|
if (!s) oom(); \
|
||||||
|
utstring_init(s); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_renew(s) \
|
||||||
|
do { \
|
||||||
|
if (s) { \
|
||||||
|
utstring_clear(s); \
|
||||||
|
} else { \
|
||||||
|
utstring_new(s); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_clear(s) \
|
||||||
|
do { \
|
||||||
|
(s)->i = 0; \
|
||||||
|
(s)->d[0] = '\0'; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_bincpy(s,b,l) \
|
||||||
|
do { \
|
||||||
|
utstring_reserve((s),(l)+1); \
|
||||||
|
if (l) memcpy(&(s)->d[(s)->i], b, l); \
|
||||||
|
(s)->i += l; \
|
||||||
|
(s)->d[(s)->i]='\0'; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_concat(dst,src) \
|
||||||
|
do { \
|
||||||
|
utstring_reserve((dst),((src)->i)+1); \
|
||||||
|
if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
|
||||||
|
(dst)->i += (src)->i; \
|
||||||
|
(dst)->d[(dst)->i]='\0'; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define utstring_len(s) ((unsigned)((s)->i))
|
||||||
|
|
||||||
|
#define utstring_body(s) ((s)->d)
|
||||||
|
|
||||||
|
_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
|
||||||
|
int n;
|
||||||
|
va_list cp;
|
||||||
|
while (1) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
cp = ap;
|
||||||
|
#else
|
||||||
|
va_copy(cp, ap);
|
||||||
|
#endif
|
||||||
|
n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
|
||||||
|
va_end(cp);
|
||||||
|
|
||||||
|
if ((n > -1) && (n < (int)(s->n-s->i))) {
|
||||||
|
s->i += n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else try again with more space. */
|
||||||
|
if (n > -1) utstring_reserve(s,n+1); /* exact */
|
||||||
|
else utstring_reserve(s,(s->n)*2); /* 2x */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
utstring_printf_va(s,fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* UTSTRING_H */
|
||||||
Reference in New Issue
Block a user