mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-20 11:23:06 +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