9 changed files with 1606 additions and 0 deletions
-
303src/testers/binarytree.c
-
42src/testers/configtest.c
-
54src/testers/hash.c
-
55src/testers/mmapfiletest.c
-
54src/testers/mmapfiletest2.c
-
797src/testers/rbtree.c
-
176src/testers/rbtree2.c
-
107src/testers/usertest.c
-
18src/testers/uuid.c
@ -0,0 +1,303 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
|
|||
struct element |
|||
{ |
|||
int data; |
|||
|
|||
struct element * parent; |
|||
struct element * left; |
|||
struct element * right; |
|||
}; |
|||
|
|||
struct element * |
|||
newElement(int data) |
|||
{ |
|||
struct element * el = malloc(sizeof(struct element)); |
|||
el->data = data; |
|||
el->parent = NULL; |
|||
el->left = NULL; |
|||
el->right = NULL; |
|||
|
|||
return el; |
|||
} |
|||
|
|||
/** |
|||
* find element in tree |
|||
*/ |
|||
struct element * |
|||
findElement(struct element * tree, int data) |
|||
{ |
|||
while (NULL != tree) { |
|||
if (tree->data == data) { |
|||
break; |
|||
} |
|||
|
|||
if (data < tree->data) { |
|||
tree = tree->left; |
|||
} else { |
|||
tree = tree->right; |
|||
} |
|||
} |
|||
|
|||
return tree; |
|||
} |
|||
|
|||
/** |
|||
* insert element in tree |
|||
*/ |
|||
void |
|||
insertElement(struct element ** tree, int data) |
|||
{ |
|||
struct element * node = *tree; |
|||
|
|||
if (NULL == node) { |
|||
*tree = newElement(data); |
|||
return; |
|||
} |
|||
|
|||
while (data != node->data) { |
|||
if (data < node->data) { |
|||
if (NULL == node->left) { |
|||
node->left = newElement(data); |
|||
node->left->parent = node; |
|||
return; |
|||
} else { |
|||
node = node->left; |
|||
} |
|||
} else { |
|||
if (NULL == node->right) { |
|||
node->right = newElement(data); |
|||
node->right->parent = node; |
|||
return; |
|||
} else { |
|||
node = node->right; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* delete element from tree |
|||
* here multiple functions are involved.... |
|||
* ======================================================================= |
|||
*/ |
|||
/** |
|||
* find minimum of the right subtree aka leftmost leaf of right subtree |
|||
* aka left in-order successor. |
|||
* We return the parent of the element in the out argument parent. |
|||
* This can be NULL wenn calling. |
|||
*/ |
|||
struct element * |
|||
findInOrderSuccessor(struct element * tree) |
|||
{ |
|||
struct element * node = tree->right; |
|||
|
|||
while (NULL != node->left) { |
|||
node = node->left; |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
void |
|||
deleteElement(struct element ** tree, int data) |
|||
{ |
|||
struct element * node = *tree; |
|||
|
|||
// find the relevant node and it's parent |
|||
while (NULL != node && node->data != data) { |
|||
if (data < node->data) { |
|||
node = node->left; |
|||
} else { |
|||
node = node->right; |
|||
} |
|||
} |
|||
|
|||
// element not found |
|||
if (NULL == node) { |
|||
return; |
|||
} |
|||
|
|||
// distinuish 3 cases, where the resolving of each case leads to the |
|||
// precondition of the other. |
|||
|
|||
// case 1: two children |
|||
if (NULL != node->left && NULL != node->right) { |
|||
struct element * successor = findInOrderSuccessor(node); |
|||
|
|||
node->data = successor->data; |
|||
node = successor; |
|||
} |
|||
|
|||
// case 2: one child wither left or right |
|||
if (NULL != node->left) { |
|||
//node->data = node->left->data; |
|||
//node = node->left; |
|||
if (NULL != node->parent) { |
|||
if (node == node->parent->left) { |
|||
node->parent->left = node->left; |
|||
} else { |
|||
node->parent->right = node->left; |
|||
} |
|||
} |
|||
node->left->parent = node->parent; |
|||
} |
|||
|
|||
if (NULL != node->right) { |
|||
//node->data = node->right->data; |
|||
//node = node->right; |
|||
if (NULL != node->parent) { |
|||
if (node == node->parent->left) { |
|||
node->parent->left = node->right; |
|||
} else { |
|||
node->parent->right = node->right; |
|||
} |
|||
} |
|||
node->right->parent = node->parent; |
|||
} |
|||
|
|||
// case 3: we are a leaf |
|||
if (NULL != node->parent) { |
|||
if (node == node->parent->left) { |
|||
node->parent->left = NULL; |
|||
} else { |
|||
node->parent->right = NULL; |
|||
} |
|||
} |
|||
|
|||
if (node == *tree) { |
|||
if (NULL != node->left) { |
|||
*tree = node->left; |
|||
} else if (NULL != node->right) { |
|||
*tree = node->right; |
|||
} else { |
|||
*tree = NULL; |
|||
} |
|||
} |
|||
|
|||
free(node); |
|||
} |
|||
|
|||
|
|||
void |
|||
traverse(struct element * tree, void (*cb)(int, int)) |
|||
{ |
|||
struct element * previous = tree; |
|||
struct element * node = tree; |
|||
int depth = 1; |
|||
|
|||
/* |
|||
* I think this has something like O(n+log(n)) on a ballanced |
|||
* tree because I have to traverse back the rightmost leaf to |
|||
* the root to get a break condition. |
|||
*/ |
|||
while (node) { |
|||
/* |
|||
* If we come from the right so nothing and go to our |
|||
* next parent. |
|||
*/ |
|||
if (previous == node->right) { |
|||
previous = node; |
|||
node = node->parent; |
|||
depth--; |
|||
continue; |
|||
} |
|||
|
|||
if ((NULL == node->left || previous == node->left)) { |
|||
/* |
|||
* If there are no more elements to the left or we |
|||
* came from the left, process data. |
|||
*/ |
|||
cb(node->data, depth); |
|||
previous = node; |
|||
|
|||
if (NULL != node->right) { |
|||
node = node->right; |
|||
depth++; |
|||
} else { |
|||
node = node->parent; |
|||
depth--; |
|||
} |
|||
} else { |
|||
/* |
|||
* if there are more elements to the left go there. |
|||
*/ |
|||
previous = node; |
|||
node = node->left; |
|||
depth++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void printElement(int data, int depth) |
|||
{ |
|||
int i; |
|||
|
|||
printf("%02d(%02d)", data, depth); |
|||
for (i=0; i<depth; i++) printf("-"); |
|||
puts(""); |
|||
} |
|||
|
|||
/** |
|||
* ======================================================================= |
|||
*/ |
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
struct element * root = NULL; |
|||
|
|||
insertElement(&root, 13); |
|||
insertElement(&root, 8); |
|||
insertElement(&root, 16); |
|||
insertElement(&root, 11); |
|||
insertElement(&root, 3); |
|||
insertElement(&root, 9); |
|||
insertElement(&root, 12); |
|||
insertElement(&root, 10); |
|||
|
|||
/* |
|||
* delete does not work correctly here.. |
|||
* luckily I do not need the simple binary trees anymore |
|||
* as I have rbtrees. |
|||
*/ |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 8); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 11); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 13); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 3); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 16); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 10); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 9); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
deleteElement(&root, 12); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,42 @@ |
|||
#include <stdio.h> |
|||
|
|||
#include "class.h" |
|||
#include "commons.h" |
|||
#include "config/config.h" |
|||
#include "config/value.h" |
|||
#include "utils/memory.h" |
|||
|
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
Config config = new(Config, "./testconfig.cfg"); |
|||
ConfigValue val; |
|||
|
|||
val = configGet(config, CSTRA("dummy")); |
|||
|
|||
if (NULL != val) { |
|||
switch (val->type) { |
|||
case CONFIG_VALUE_STRING: |
|||
printf( |
|||
"Value for dummy: (STRING): %s\n", |
|||
(val->value).string); |
|||
break; |
|||
|
|||
case CONFIG_VALUE_NUMERIC: |
|||
printf( |
|||
"Value for dummy: (NUMERIC): %lld\n", |
|||
(val->value).number); |
|||
break; |
|||
|
|||
default: |
|||
printf("Invalid config...that should never happen\n"); |
|||
} |
|||
} |
|||
|
|||
delete(config); |
|||
memCleanup(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,54 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include "class.h" |
|||
#include "commons.h" |
|||
#include "utils/memory.h" |
|||
|
|||
#include "hash.h" |
|||
#include "utils/memory.h" |
|||
|
|||
|
|||
/** |
|||
* ======================================================================= |
|||
*/ |
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
Hash hash = new(Hash); |
|||
HashValue deleted; |
|||
|
|||
hashAdd(hash, new(HashValue, CSTRA("foo"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("hjkfdd"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("j8frheff"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("f9e0g"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("gfrk9e0"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("fr09ie"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("fu8de9"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("rehw78"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("fcrne9"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("new8"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("fdhe78"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("dhew8"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("jfde9w8"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("dhe7w89"), CSTRA("bar"))); |
|||
hashAdd(hash, new(HashValue, CSTRA("fduew89"), CSTRA("bar"))); |
|||
|
|||
deleted = hashDelete(hash, CSTRA("f9e0g")); |
|||
delete(deleted); |
|||
deleted = hashDelete(hash, CSTRA("fcrne9")); |
|||
delete(deleted); |
|||
deleted = hashDelete(hash, CSTRA("fr09ie")); |
|||
delete(deleted); |
|||
deleted = hashDelete(hash, CSTRA("jfde9w8")); |
|||
delete(deleted); |
|||
deleted = hashDelete(hash, CSTRA("j8frheff")); |
|||
delete(deleted); |
|||
|
|||
delete(hash); |
|||
memCleanup(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,55 @@ |
|||
// for mmap |
|||
#include <sys/mman.h> |
|||
|
|||
// for random |
|||
#include <stdlib.h> |
|||
|
|||
// for open and fstat |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
|
|||
// for puts |
|||
#include <stdio.h> |
|||
|
|||
// for time |
|||
#include <time.h> |
|||
|
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
struct stat st; |
|||
char * map; |
|||
size_t position; |
|||
char print_buf[101]; |
|||
int i; |
|||
|
|||
print_buf[100] = '\0'; |
|||
|
|||
int fd = open("./mmapfiletest.c", O_RDONLY); |
|||
|
|||
fstat(fd, &st); |
|||
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
|||
|
|||
srandom(time(NULL)); |
|||
position = random() % (st.st_size - 100); |
|||
|
|||
for (i=0; i<100; i+=10) { |
|||
print_buf[i+0] = map[position + i + 0]; |
|||
print_buf[i+1] = map[position + i + 1]; |
|||
print_buf[i+2] = map[position + i + 2]; |
|||
print_buf[i+3] = map[position + i + 3]; |
|||
print_buf[i+4] = map[position + i + 4]; |
|||
print_buf[i+5] = map[position + i + 5]; |
|||
print_buf[i+6] = map[position + i + 6]; |
|||
print_buf[i+7] = map[position + i + 7]; |
|||
print_buf[i+8] = map[position + i + 8]; |
|||
print_buf[i+9] = map[position + i + 9]; |
|||
} |
|||
|
|||
puts(print_buf); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,54 @@ |
|||
// for random |
|||
#include <stdlib.h> |
|||
|
|||
// for puts |
|||
#include <stdio.h> |
|||
|
|||
// for time |
|||
#include <time.h> |
|||
|
|||
#include "class.h" |
|||
#include "commons.h" |
|||
#include "utils/memory.h" |
|||
|
|||
#include "asset.h" |
|||
|
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
size_t i; |
|||
size_t position; |
|||
char print_buf[101]; |
|||
|
|||
Asset asset = new(Asset, CSTRA("./src/mmapfiletest.c")); |
|||
|
|||
print_buf[100] = '\0'; |
|||
|
|||
srandom(time(NULL)); |
|||
position = random() % (asset->size - 100); |
|||
|
|||
for (i=0; i<100; i+=10) { |
|||
print_buf[i+0] = asset->data[position+i+0]; |
|||
print_buf[i+1] = asset->data[position+i+1]; |
|||
print_buf[i+2] = asset->data[position+i+2]; |
|||
print_buf[i+3] = asset->data[position+i+3]; |
|||
print_buf[i+4] = asset->data[position+i+4]; |
|||
print_buf[i+5] = asset->data[position+i+5]; |
|||
print_buf[i+6] = asset->data[position+i+6]; |
|||
print_buf[i+7] = asset->data[position+i+7]; |
|||
print_buf[i+8] = asset->data[position+i+8]; |
|||
print_buf[i+9] = asset->data[position+i+9]; |
|||
} |
|||
|
|||
if (NULL != asset->mime_type) { |
|||
puts(asset->mime_type); |
|||
} |
|||
puts(print_buf); |
|||
|
|||
delete(asset); |
|||
memCleanup(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,797 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#define NVALUES 10 |
|||
|
|||
enum rbColor {rbBlack=1, rbRed=2}; |
|||
|
|||
|
|||
struct element |
|||
{ |
|||
size_t size; |
|||
void * ptr; |
|||
|
|||
enum rbColor color; |
|||
|
|||
struct element * next; |
|||
struct element * last; |
|||
|
|||
struct element * parent; |
|||
struct element * left; |
|||
struct element * right; |
|||
}; |
|||
|
|||
struct element * |
|||
newElement(size_t size) |
|||
{ |
|||
struct element * element = malloc(size + sizeof(struct element)); |
|||
|
|||
element->size = size; |
|||
element->ptr = element + sizeof(struct element); |
|||
|
|||
element->next = NULL; |
|||
element->last = NULL; |
|||
|
|||
element->color = rbRed; |
|||
element->parent = NULL; |
|||
element->left = NULL; |
|||
element->right = NULL; |
|||
|
|||
return element; |
|||
} |
|||
|
|||
/** |
|||
* find element in tree |
|||
*/ |
|||
struct element * |
|||
findElement(struct element * tree, size_t size) |
|||
{ |
|||
struct element * fitting = NULL; |
|||
|
|||
while (NULL != tree) { |
|||
if (tree->size == size) { |
|||
fitting = tree; |
|||
break; |
|||
} |
|||
|
|||
if (size > tree->size) { |
|||
tree = tree->right; |
|||
} else { |
|||
fitting = tree; |
|||
tree = tree->left; |
|||
} |
|||
} |
|||
|
|||
return fitting; |
|||
} |
|||
|
|||
/* |
|||
* function to get specific elements needed for |
|||
* rb handling, grandparent, uncle and sibbling |
|||
*/ |
|||
struct element * |
|||
grandparent(struct element * node) |
|||
{ |
|||
if (NULL != node && NULL != node->parent) { |
|||
return node->parent->parent; |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
struct element * |
|||
uncle(struct element * node) |
|||
{ |
|||
struct element * gp = grandparent(node); |
|||
|
|||
if (NULL == gp) { |
|||
return NULL; |
|||
} |
|||
|
|||
if (node->parent == gp->left) { |
|||
return gp->right; |
|||
} |
|||
|
|||
return gp->left; |
|||
} |
|||
|
|||
struct element * |
|||
sibling(struct element * node) |
|||
{ |
|||
if (NULL == node) { |
|||
return NULL; |
|||
} |
|||
|
|||
if (NULL == node->parent->left || node == node->parent->left) { |
|||
return node->parent->right; |
|||
} else { |
|||
return node->parent->left; |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* tree modifications...needed for rb handling. |
|||
*/ |
|||
void |
|||
rotateLeft(struct element ** tree, struct element * node) |
|||
{ |
|||
struct element * rightChild = node->right; |
|||
struct element * rcLeftSub = node->right->left; |
|||
|
|||
rightChild->left = node; |
|||
rightChild->parent = node->parent; |
|||
node->right = rcLeftSub; |
|||
if (NULL != rcLeftSub) { |
|||
rcLeftSub->parent = node; |
|||
} |
|||
|
|||
if (node->parent) { |
|||
if (node->parent->left == node) { |
|||
node->parent->left = rightChild; |
|||
} else { |
|||
node->parent->right = rightChild; |
|||
} |
|||
} else { |
|||
*tree = rightChild; |
|||
} |
|||
|
|||
node->parent = rightChild; |
|||
} |
|||
|
|||
void |
|||
rotateRight(struct element ** tree, struct element * node) |
|||
{ |
|||
struct element * leftChild = node->left; |
|||
struct element * lcRightSub = node->left->right; |
|||
|
|||
leftChild->right = node; |
|||
leftChild->parent = node->parent; |
|||
node->left = lcRightSub; |
|||
if (NULL != lcRightSub) { |
|||
lcRightSub->parent = node; |
|||
} |
|||
|
|||
if (node->parent) { |
|||
if (node->parent->left == node) { |
|||
node->parent->left = leftChild; |
|||
} else { |
|||
node->parent->right = leftChild; |
|||
} |
|||
} else { |
|||
*tree = leftChild; |
|||
} |
|||
|
|||
node->parent = leftChild; |
|||
} |
|||
|
|||
void |
|||
replaceNode( |
|||
struct element ** tree, |
|||
struct element * node1, |
|||
struct element * node2) |
|||
{ |
|||
if (NULL != node1->parent) { |
|||
if (node1 == node1->parent->left) { |
|||
node1->parent->left = node2; |
|||
} else { |
|||
node1->parent->right = node2; |
|||
} |
|||
} else { |
|||
*tree = node2; |
|||
} |
|||
|
|||
if (NULL != node2) { |
|||
node2->parent = node1->parent; |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* insert element in tree |
|||
*/ |
|||
struct element * |
|||
insertElement(struct element ** tree, struct element * element) |
|||
{ |
|||
struct element * node = *tree; |
|||
struct element * new_node = NULL; |
|||
struct element * u; |
|||
struct element * g; |
|||
|
|||
element->next = NULL; |
|||
element->last = NULL; |
|||
|
|||
element->color = rbRed; |
|||
element->parent = NULL; |
|||
element->left = NULL; |
|||
element->right = NULL; |
|||
|
|||
// if tree is empty it's simple... :) |
|||
if (NULL == node) { |
|||
*tree = node = new_node = element; |
|||
} else { |
|||
// normal binary tree add.... |
|||
while (NULL != node) { |
|||
if (element->size < node->size) { |
|||
if (NULL == node->left) { |
|||
node->left = element; |
|||
node->left->parent = node; |
|||
new_node = node = node->left; |
|||
break; |
|||
} else { |
|||
node = node->left; |
|||
} |
|||
} else if (element->size > node->size) { |
|||
if (NULL == node->right) { |
|||
node->right = element; |
|||
node->right->parent = node; |
|||
new_node = node = node->right; |
|||
break; |
|||
} else { |
|||
node = node->right; |
|||
} |
|||
} else { |
|||
if (NULL == node->next) { |
|||
node->next = element; |
|||
node->last = element; |
|||
} else { |
|||
node->last->next = element; |
|||
node->last = element; |
|||
} |
|||
return node; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (NULL != new_node) { |
|||
/* |
|||
* handle reballancing rb style |
|||
*/ |
|||
while (1) { |
|||
// case 1 |
|||
if (node->parent == NULL) { |
|||
node->color = rbBlack; |
|||
// we're done.... :) |
|||
break; |
|||
} |
|||
|
|||
// case 2 |
|||
if (node->parent->color == rbBlack) { |
|||
// Tree is still valid ... wow, again we're done... :) |
|||
break; |
|||
} |
|||
|
|||
// case 3 |
|||
u = uncle(node); |
|||
g = grandparent(node); |
|||
|
|||
if (u != NULL && u->color == rbRed) { |
|||
node->parent->color = rbBlack; |
|||
u->color = rbBlack; |
|||
g->color = rbRed; |
|||
|
|||
node = g; |
|||
continue; |
|||
} |
|||
|
|||
// case 4 |
|||
if (node == node->parent->right && node->parent == g->left) { |
|||
rotateLeft(tree, node->parent); |
|||
node = node->left; |
|||
} else if (node == node->parent->left && node->parent == g->right) { |
|||
|
|||
rotateRight(tree, node->parent); |
|||
node = node->right; |
|||
} |
|||
|
|||
// case 5 |
|||
g = grandparent(node); |
|||
|
|||
node->parent->color = rbBlack; |
|||
g->color = rbRed; |
|||
|
|||
if (node == node->parent->left) { |
|||
rotateRight(tree, g); |
|||
} else { |
|||
rotateLeft(tree, g); |
|||
} |
|||
|
|||
// we're done.. |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return new_node; |
|||
} |
|||
|
|||
/** |
|||
* delete element from tree |
|||
* here multiple functions are involved.... |
|||
* ======================================================================= |
|||
*/ |
|||
/** |
|||
* find minimum of the right subtree aka leftmost leaf of right subtree |
|||
* aka left in-order successor. |
|||
* We return the parent of the element in the out argument parent. |
|||
* This can be NULL wenn calling. |
|||
* |
|||
* 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160, |
|||
* left = 0x0, right = 0x0} |
|||
* 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070, |
|||
* left = 0x6030e0, right = 0x6031e0} |
|||
* |
|||
*/ |
|||
struct element * |
|||
findInOrderSuccessor(struct element * tree) |
|||
{ |
|||
struct element * node = tree->right; |
|||
|
|||
while (NULL != node->left) { |
|||
node = node->left; |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
struct element * deleteOneChild(struct element **, struct element *); |
|||
|
|||
struct element * |
|||
deleteElement(struct element ** tree, struct element * element) |
|||
{ |
|||
struct element * node = *tree; |
|||
struct element * del_node; |
|||
struct element * child; |
|||
struct element * s; |
|||
|
|||
// find the relevant node and it's parent |
|||
while (NULL != node) { |
|||
|
|||
if (element->size < node->size) { |
|||
node = node->left; |
|||
} else if (element->size > node->size) { |
|||
node = node->right; |
|||
} else { |
|||
if (NULL != node->next) { |
|||
if (NULL != node->parent) { |
|||
if (node == node->parent->left) { |
|||
node->parent->left = node->next; |
|||
} else { |
|||
node->parent->right = node->next; |
|||
} |
|||
} else { |
|||
*tree = node->next; |
|||
} |
|||
|
|||
if (NULL != node->left) { |
|||
node->left->parent = node->next; |
|||
} |
|||
|
|||
if (NULL != node->right) { |
|||
node->right->parent = node->next; |
|||
} |
|||
|
|||
node->next->last = node->last; |
|||
node->next->color = node->color; |
|||
node->next->parent = node->parent; |
|||
node->next->left = node->left; |
|||
node->next->right = node->right; |
|||
|
|||
return node; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// element not found |
|||
if (NULL == node) { |
|||
return node; |
|||
} |
|||
|
|||
del_node = node; |
|||
|
|||
// now our cases follows...the first one is the same as with |
|||
// simple binary search trees. Two non null children. |
|||
|
|||
// case 1: two children |
|||
if (NULL != node->left && NULL != node->right) { |
|||
struct element * successor = findInOrderSuccessor(node); |
|||
|
|||
enum rbColor tmpcolor = successor->color; |
|||
struct element * tmpparent = successor->parent; |
|||
struct element * tmpleft = successor->left; |
|||
struct element * tmpright = successor->right; |
|||
|
|||
replaceNode(tree, node, successor); |
|||
|
|||
successor->color = node->color; |
|||
successor->left = node->left; |
|||
successor->left->parent = successor; |
|||
// the right one might be successor... |
|||
if (node->right == successor) { |
|||
successor->right = node; |
|||
node->parent = successor; |
|||
} else { |
|||
successor->right = node->right; |
|||
node->right->parent = successor; |
|||
node->parent = tmpparent; |
|||
tmpparent->left = node; |
|||
} |
|||
|
|||
node->color = tmpcolor; |
|||
node->left = tmpleft; |
|||
node->right = tmpright; |
|||
} |
|||
|
|||
// Precondition: n has at most one non-null child. |
|||
child = (NULL == node->right) ? node->left : node->right; |
|||
replaceNode(tree, node, child); |
|||
|
|||
// delete one child case |
|||
// TODO this is overly complex as simply derived from the function... |
|||
// maybe this can be simplified. Maybe not...check. |
|||
if (node->color == rbBlack) { |
|||
if (NULL != child && child->color == rbRed) { |
|||
child->color = rbBlack; |
|||
// done despite modifying tree itself if neccessary.. |
|||
return del_node; |
|||
} else { |
|||
if (NULL != child) { |
|||
node = child; |
|||
} else { |
|||
node->color = rbBlack; |
|||
node->left = NULL; |
|||
node->right = NULL; |
|||
} |
|||
} |
|||
} else { |
|||
return del_node; |
|||
} |
|||
|
|||
// delete and rb rebalance... |
|||
while(1) { |
|||
// case 1 |
|||
if (NULL == node->parent) { |
|||
// done again |
|||
break; |
|||
} |
|||
|
|||
// case 2 |
|||
s = sibling(node); |
|||
|
|||
if (NULL != s && s->color == rbRed) { |
|||
node->parent->color = rbRed; |
|||
s->color = rbBlack; |
|||
|
|||
/* |
|||
* detect which child we are...assumption |
|||
* if we are not parent->right and parent->right is not |
|||
* null we must be left, even if its set to NULL previously |
|||
*/ |
|||
if (NULL != node->parent->right && node != node->parent->right) { |
|||
rotateLeft(tree, node->parent); |
|||
} else { |
|||
rotateRight(tree, node->parent); |
|||
} |
|||
} |
|||
|
|||
s = sibling(node); |
|||
// case 3 / 4 |
|||
if (NULL == s || ((s->color == rbBlack) && |
|||
(NULL == s->left || s->left->color == rbBlack) && |
|||
(NULL == s->right || s->right->color == rbBlack))) { |
|||
|
|||
if (NULL != s) { |
|||
s->color = rbRed; |
|||
} |
|||
|
|||
if (node->parent->color == rbBlack) { |
|||
// case 3 |
|||
node = node->parent; |
|||
continue; |
|||
} else { |
|||
// case 4 |
|||
node->parent->color = rbBlack; |
|||
// and done again... |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// case 5 |
|||
if (NULL != s && s->color == rbBlack) { |
|||
// this if statement is trivial, |
|||
// due to case 2 (even though case 2 changed the sibling to a |
|||
// sibling's child, |
|||
// the sibling's child can't be red, since no red parent can |
|||
// have a red child). |
|||
// |
|||
// the following statements just force the red to be on the |
|||
// left of the left of the parent, |
|||
// or right of the right, so case 6 will rotate correctly. |
|||
if ((node == node->parent->left) && |
|||
(NULL == s->right || s->right->color == rbBlack) && |
|||
(NULL != s->left && s->left->color == rbRed)) { |
|||
|
|||
// this last test is trivial too due to cases 2-4. |
|||
s->color = rbRed; |
|||
s->left->color = rbBlack; |
|||
|
|||
rotateRight(tree, s); |
|||
} else if ((node == node->parent->right) && |
|||
(NULL == s->left || s->left->color == rbBlack) && |
|||
(NULL != s->right && s->right->color == rbRed)) { |
|||
// this last test is trivial too due to cases 2-4. |
|||
s->color = rbRed; |
|||
s->right->color = rbBlack; |
|||
|
|||
rotateLeft(tree, s); |
|||
} |
|||
} |
|||
|
|||
s = sibling(node); |
|||
// case 6 |
|||
if (NULL != s) { |
|||
s->color = node->parent->color; |
|||
} |
|||
|
|||
if (NULL != node && NULL != node->parent) { |
|||
node->parent->color = rbBlack; |
|||
|
|||
/* |
|||
* detect which child we are...assumption |
|||
* if we are not parent->right and parent->right is not |
|||
* null we must be left, even if its set to NULL previously |
|||
*/ |
|||
if (NULL != node->parent->right && node != node->parent->right) { |
|||
if (NULL != s->right) { |
|||
s->right->color = rbBlack; |
|||
} |
|||
rotateLeft(tree, node->parent); |
|||
} else { |
|||
if (NULL != s->left) { |
|||
s->left->color = rbBlack; |
|||
} |
|||
rotateRight(tree, node->parent); |
|||
} |
|||
} |
|||
|
|||
// done... |
|||
break; |
|||
} |
|||
|
|||
//deleteOneChild(tree, node); |
|||
|
|||
return del_node; |
|||
} |
|||
|
|||
|
|||
void |
|||
traverse(struct element * tree, void (*cb)(struct element *, int)) |
|||
{ |
|||
struct element * previous = tree; |
|||
struct element * node = tree; |
|||
int depth = 1; |
|||
|
|||
/* |
|||
* I think this has something like O(n+log(n)) on a ballanced |
|||
* tree because I have to traverse back the rightmost leaf to |
|||
* the root to get a break condition. |
|||
*/ |
|||
while (node) { |
|||
/* |
|||
* If we come from the right so nothing and go to our |
|||
* next parent. |
|||
*/ |
|||
if (previous == node->right) { |
|||
previous = node; |
|||
node = node->parent; |
|||
depth--; |
|||
continue; |
|||
} |
|||
|
|||
if ((NULL == node->left || previous == node->left)) { |
|||
/* |
|||
* If there are no more elements to the left or we |
|||
* came from the left, process data. |
|||
*/ |
|||
cb(node, depth); |
|||
previous = node; |
|||
|
|||
if (NULL != node->right) { |
|||
node = node->right; |
|||
depth++; |
|||
} else { |
|||
node = node->parent; |
|||
depth--; |
|||
} |
|||
} else { |
|||
/* |
|||
* if there are more elements to the left go there. |
|||
*/ |
|||
previous = node; |
|||
node = node->left; |
|||
depth++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void |
|||
post(struct element * tree, void (*cb)(struct element *, int)) |
|||
{ |
|||
struct element * previous = tree; |
|||
struct element * node = tree; |
|||
int depth = 1; |
|||
|
|||
/* |
|||
* I think this has something like O(n+log(n)) on a ballanced |
|||
* tree because I have to traverse back the rightmost leaf to |
|||
* the root to get a break condition. |
|||
*/ |
|||
while (node) { |
|||
/* |
|||
* If we come from the right so nothing and go to our |
|||
* next parent. |
|||
*/ |
|||
if ((NULL == node->left && NULL == node->right) |
|||
|| previous == node->right) { |
|||
|
|||
struct element * parent = node->parent; |
|||
|
|||
cb(node, depth); |
|||
|
|||
previous = node; |
|||
node = parent; |
|||
depth--; |
|||
continue; |
|||
} |
|||
|
|||
if ((NULL == node->left || previous == node->left)) { |
|||
/* |
|||
* If there are no more elements to the left or we |
|||
* came from the left, process data. |
|||
*/ |
|||
previous = node; |
|||
|
|||
if (NULL != node->right) { |
|||
node = node->right; |
|||
depth++; |
|||
} else { |
|||
node = node->parent; |
|||
depth--; |
|||
} |
|||
} else { |
|||
/* |
|||
* if there are more elements to the left go there. |
|||
*/ |
|||
previous = node; |
|||
node = node->left; |
|||
depth++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void printElement(struct element * node, int depth) |
|||
{ |
|||
int i; |
|||
|
|||
printf("%s %010zu:%p(%02d)", |
|||
(node->color==rbRed)?"R":"B", |
|||
node->size, |
|||
node->ptr, |
|||
depth); |
|||
for (i=0; i<depth; i++) printf("-"); |
|||
puts(""); |
|||
|
|||
node = node->next; |
|||
while (NULL != node) { |
|||
printf(" %s %010zu:%p(%02d)", |
|||
(node->color==rbRed)?"R":"B", |
|||
node->size, |
|||
node->ptr, |
|||
depth); |
|||
for (i=0; i<depth; i++) printf("-"); |
|||
puts(""); |
|||
node = node->next; |
|||
} |
|||
} |
|||
|
|||
void cleanup(struct element * node, int depth) |
|||
{ |
|||
while (NULL != node) { |
|||
printf("free node: "); |
|||
printElement(node, 0); |
|||
struct element * next = node->next; |
|||
free(node); |
|||
node = next; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ======================================================================= |
|||
*/ |
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
struct element * root = NULL; |
|||
struct element * found = NULL; |
|||
|
|||
insertElement(&root, newElement(40)); |
|||
insertElement(&root, newElement(50)); |
|||
insertElement(&root, newElement(60)); |
|||
insertElement(&root, newElement(70)); |
|||
insertElement(&root, newElement(80)); |
|||
insertElement(&root, newElement(45)); |
|||
insertElement(&root, newElement(75)); |
|||
insertElement(&root, newElement(85)); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
insertElement(&root, newElement(70)); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
found = findElement(root, 10); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 10); |
|||
} else { |
|||
printElement(found, 0); |
|||
} |
|||
puts(""); |
|||
|
|||
found = findElement(root, 64); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 64); |
|||
} else { |
|||
printElement(found, 0); |
|||
} |
|||
puts(""); |
|||
|
|||
found = findElement(root, 90); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 90); |
|||
} else { |
|||
printElement(found, 0); |
|||
} |
|||
puts(""); |
|||
|
|||
free(deleteElement(&root, findElement(root, 70))); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
insertElement(&root, newElement(80)); |
|||
insertElement(&root, newElement(50)); |
|||
insertElement(&root, newElement(80)); |
|||
|
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
found = deleteElement(&root, findElement(root, 80)); |
|||
printf("up to free: %p\n", found); |
|||
free(found); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
found = deleteElement(&root, findElement(root, 50)); |
|||
printf("up to free: %p\n", found); |
|||
free(found); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
found = deleteElement(&root, findElement(root, 70)); |
|||
printf("up to free: %p\n", found); |
|||
free(found); |
|||
puts("traverse"); |
|||
traverse(root, printElement); |
|||
puts(""); |
|||
|
|||
// post(root, cleanup); |
|||
// |
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,176 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include "class.h" |
|||
#include "commons.h" |
|||
#include "utils/memory.h" |
|||
|
|||
#include "tree.h" |
|||
#include "utils/memory.h" |
|||
|
|||
#define NVALUES 10 |
|||
|
|||
int |
|||
insertCompare(const void * tval, const void * search) |
|||
{ |
|||
return *(const int *)tval - *(const int *)search; |
|||
} |
|||
|
|||
void |
|||
freeNode(const void * data, const int depth) |
|||
{ |
|||
printf("now free %d at %p\n", *(int*)data, data); |
|||
MEM_FREE(data); |
|||
} |
|||
|
|||
void |
|||
printNode(const void * _node, const int depth) |
|||
{ |
|||
Tree node = (Tree)_node; |
|||
int value = *(int *)node->data; |
|||
int i; |
|||
|
|||
for (i=1; i<7; i++) i<=depth?printf("-"):printf(" "); |
|||
printf("%p:%d p:%p l:%p r:%p\n", |
|||
node, value, node->parent, node->left, node->right); |
|||
|
|||
// printf("%s %010d(%02d)", |
|||
// (node->color==rbRed)?"R":"B", |
|||
// value, |
|||
// depth); |
|||
} |
|||
|
|||
|
|||
void * |
|||
newEle(int value) |
|||
{ |
|||
void * val = memMalloc(sizeof(int)); |
|||
|
|||
*(int*)val = value; |
|||
return val; |
|||
} |
|||
|
|||
/** |
|||
* ======================================================================= |
|||
*/ |
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
Tree root = NULL; |
|||
int * found = NULL; |
|||
int * element = NULL; |
|||
|
|||
int search10 = 10; |
|||
int search64 = 64; |
|||
int search70 = 70; |
|||
int search80 = 80; |
|||
int search50 = 50; |
|||
|
|||
treeInsert(&root, newEle(40), insertCompare); |
|||
treeInsert(&root, newEle(50), insertCompare); |
|||
treeInsert(&root, newEle(60), insertCompare); |
|||
treeInsert(&root, newEle(70), insertCompare); |
|||
treeInsert(&root, newEle(80), insertCompare); |
|||
treeInsert(&root, newEle(45), insertCompare); |
|||
treeInsert(&root, newEle(75), insertCompare); |
|||
treeInsert(&root, newEle(85), insertCompare); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
element = newEle(70); |
|||
found = treeInsert(&root, element, insertCompare); |
|||
printf("insert %p(%d) got %p(%d)\n", element, *element, found, *found); |
|||
if (found != element) { |
|||
printf("remove duplicate"); |
|||
MEM_FREE(element); |
|||
} |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
found = treeFind(root, &search10, insertCompare); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 10); |
|||
} else { |
|||
printf("found %d\n", *found); |
|||
} |
|||
puts(""); |
|||
|
|||
found = treeFind(root, &search64, insertCompare); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 64); |
|||
} else { |
|||
printf("found %d\n", *found); |
|||
} |
|||
puts(""); |
|||
|
|||
found = treeFind(root, &search70, insertCompare); |
|||
if (NULL == found) { |
|||
printf("can't find segmenet of minimum size: %d\n", 70); |
|||
} else { |
|||
printf("found %d\n", *found); |
|||
} |
|||
puts(""); |
|||
|
|||
found = treeDelete(&root, (void *)&search70, insertCompare); |
|||
printf("delete %p(%d) got %p(%d)\n", &search70, search70, found, *found); |
|||
MEM_FREE(found); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
found = treeInsert(&root, (void *)&search80, insertCompare); |
|||
printf("insert %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
|||
found = treeInsert(&root, (void *)&search50, insertCompare); |
|||
printf("insert %p(%d) got %p(%d)\n", &search50, search50, found, *found); |
|||
found = treeInsert(&root, (void *)&search80, insertCompare); |
|||
printf("insert %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
|||
|
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
found = treeDelete(&root, (void *)&search80, insertCompare); |
|||
printf("delete %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
|||
MEM_FREE(found); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
found = treeDelete(&root, (void *)&search50, insertCompare); |
|||
printf("delete %p(%d) got %p(%d)\n", &search50, search50, found, *found); |
|||
MEM_FREE(found); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
found = treeDelete(&root, (void *)&search70, insertCompare); |
|||
printf("delete %p(%d) got %p(%d)\n", &search70, search70, found, found?*found:-1); |
|||
MEM_FREE(found); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
element = newEle(60); |
|||
found = treeDelete(&root, element, insertCompare); |
|||
printf("delete %p(%d) got %p(%d)\n", |
|||
element, |
|||
*element, |
|||
found, |
|||
found?*found:-1); |
|||
if (found != element) { |
|||
MEM_FREE(element); |
|||
} |
|||
MEM_FREE(found); |
|||
puts("traverse"); |
|||
treeWalk(root, printNode); |
|||
puts(""); |
|||
|
|||
treeDestroy(&root, freeNode); |
|||
memCleanup(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,107 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <gdbm.h> |
|||
#include <errno.h> |
|||
#include <string.h> |
|||
|
|||
#include "class.h" |
|||
#include "commons.h" |
|||
#include "user.h" |
|||
#include "storage.h" |
|||
|
|||
#include "utils/memory.h" |
|||
|
|||
void |
|||
printUser(Storage users, const char * key, size_t nkey) |
|||
{ |
|||
User user = new(User, NULL); |
|||
|
|||
user->email = (char *)key, |
|||
user->nemail = &nkey; |
|||
|
|||
if (NULL == userLoad(user, users)) { |
|||
fprintf(stderr, "can't find user: %s\n", key); |
|||
} else { |
|||
puts("found user:"); |
|||
puts(user->email); |
|||
puts(user->firstname); |
|||
puts(user->surname); |
|||
|
|||
delete(user); |
|||
} |
|||
} |
|||
|
|||
void |
|||
insertUser( |
|||
Storage users, |
|||
const char * email, size_t nemail, |
|||
const char * firstname, size_t nfirstname, |
|||
const char * surname, size_t nsurname) |
|||
{ |
|||
User insert = new(User, |
|||
email, nemail, |
|||
firstname, nfirstname, |
|||
surname, nsurname); |
|||
|
|||
userSave(insert, users); |
|||
delete(insert); |
|||
} |
|||
|
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
Storage users = new(Storage, CSTRA("./users.db")); |
|||
|
|||
if (NULL == users) { |
|||
fprintf(stderr, "%s\n", gdbm_strerror(gdbm_errno)); |
|||
fprintf(stderr, "%s\n", strerror(errno)); |
|||
return 1; |
|||
} |
|||
|
|||
insertUser( |
|||
users, |
|||
CSTRA("georg"), |
|||
CSTRA("Georg"), |
|||
CSTRA("Hopp")); |
|||
insertUser( |
|||
users, |
|||
CSTRA("georg@steffers.org"), |
|||
CSTRA("Georg"), |
|||
CSTRA("Hopp")); |
|||
insertUser( |
|||
users, |
|||
CSTRA("drachenfrau1982@gmx.net"), |
|||
CSTRA("Gundula"), |
|||
CSTRA("Hopp")); |
|||
|
|||
printUser(users, CSTRA("foo@bar.de")); |
|||
puts(""); |
|||
printUser(users, CSTRA("drachenfrau1982@gmx.net")); |
|||
puts(""); |
|||
printUser(users, CSTRA("georg@steffers.org")); |
|||
|
|||
delete(users); |
|||
|
|||
users = new(Storage, CSTRA("./users.db")); |
|||
|
|||
insertUser( |
|||
users, |
|||
CSTRA("drachenfrau1982@gmx.net"), |
|||
CSTRA("Stefanie"), |
|||
CSTRA("Hopp")); |
|||
|
|||
puts(""); |
|||
printUser(users, CSTRA("foo@bar.de")); |
|||
puts(""); |
|||
printUser(users, CSTRA("drachenfrau1982@gmx.net")); |
|||
puts(""); |
|||
printUser(users, CSTRA("georg@steffers.org")); |
|||
|
|||
delete(users); |
|||
|
|||
memCleanup(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set et ts=4 sw=4: |
|||
@ -0,0 +1,18 @@ |
|||
#include <uuid/uuid.h> |
|||
#include <stdio.h> |
|||
|
|||
int |
|||
main(int argc, char * argv[]) |
|||
{ |
|||
uuid_t uuid; |
|||
char uuid_str[37]; |
|||
|
|||
uuid_generate(uuid); |
|||
uuid_unparse(uuid, uuid_str); |
|||
|
|||
printf("%s\n", uuid_str); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue