Esempio n. 1
0
DWORD WINAPI UpdateThread(void *param)
{
	if(!TryEnterCriticalSection(&cs_update)) {
		return 1;
	}
	stack_update();
	LeaveCriticalSection(&cs_update);
	return 0;
}
Esempio n. 2
0
Node* reduce_graph(Node* root, int r)  {

    Node* aux, *rec;
    int check = 1;
    char num1, num2, debug;
    int n1, n2, res;

    rec = (Node*) malloc(sizeof(Node));
    rec->type = 'r';
    if (r == 1){
        stack[stack_point] = rec;
        stack_point++;
    }

    aux = root;

    while (aux != NULL) {
        stack[stack_point] = aux;
        aux = aux->left;
        stack_point = stack_point + 1;
    }
    stack_point = stack_point - 1;

    while (check != 0)  {
        switch (stack[stack_point]->type)   {
            case 'K':
                if (stack_point - 2 >= 0)   {
                    aux = K_reduction(stack[stack_point - 2]);


                    /* It points the rest of graph
                        to the K reducted sub-graph */
                    if ((stack_point - 3) >= 0 && stack[stack_point - 3]->type != 'r'){
                        stack[stack_point - 3]->left = aux;
                    }
                    else
                        root = aux;

                    if (stack_point < 3)
                        stack_point = 3;
                    if (stack[stack_point - 3]->type == 'r')
                        stack_point = stack_point - 3;
                    else
                        stack_point = stack_point - 2;


                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;

            // printf("KOPERATORRRRR\n");
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'S':
                if (stack_point - 3 >= 0)
                {
                    // scanf("%c", &debug);
                    aux = S_reduction(stack[stack_point - 3]);

                    if ((stack_point - 4) >= 0 && stack[stack_point - 4]->type != 'r')
                        stack[stack_point - 4]->left = aux;
                    else
                        root = aux;

                    if (stack_point < 4)
                        stack_point = 4;
                    if (stack[stack_point - 4]->type == 'r')
                        stack_point = stack_point - 4;
                    else
                        stack_point = stack_point - 3;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else{
                    check = 0;
                }
            // print_graph(root);
            // printf("\n\n");
            break;
            case 's':
                if (stack_point - 4 >= 0)
                {
                    aux = Sl_reduction(stack[stack_point - 4]);

                    if ((stack_point - 5) >= 0)
                        stack[stack_point - 5]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 4;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'B':
                if (stack_point - 3 >= 0)
                {
                    aux = B_reduction(stack[stack_point - 3]);

                    if ((stack_point - 4) >= 0)
                        stack[stack_point - 4]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 3;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'b':
                if (stack_point - 4 >= 0)
                {
                    aux = Bl_reduction(stack[stack_point - 4]);

                    if ((stack_point - 5) >= 0)
                        stack[stack_point - 5]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 4;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'C':
                if (stack_point - 3 >= 0)
                {
                    aux = C_reduction(stack[stack_point - 3]);

                    if ((stack_point - 4) >= 0)
                        stack[stack_point - 4]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 3;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'c':
                if (stack_point - 4 >= 0)
                {
                    aux = Cl_reduction(stack[stack_point - 4]);

                    if ((stack_point - 5) >= 0)
                        stack[stack_point - 5]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 4;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'I':
                if (stack_point - 1 >= 0)   {
                    aux = I_reduction(stack[stack_point - 1]);

                    if ((stack_point - 2) >= 0 && stack[stack_point - 2]->type != 'r'){
                        stack[stack_point - 2]->left = aux;
                        // stack[stack_point - 2]->type = '@';
                    }
                    else
                        root = aux;


                    if (stack_point < 2)
                        stack_point = 2;
                    if (stack[stack_point - 2]->type == 'r')
                        stack_point = stack_point - 2;
                    else
                        stack_point = stack_point - 1;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);

                }
                else{
                    check = 0;
                }
            // print_graph(root);
            // printf("\n\n");
            break;
            case ':':
                if (stack_point - 2 >= 0)   {
                    aux = list_reduction(stack[stack_point]);

                    if (stack[stack_point - 3] >= 0)
                        stack[stack_point - 3]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 2;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'h':
                if (stack_point - 1 >= 0){
                    if (stack[stack_point - 1]->right->left->type == ':' || stack[stack_point - 1]->right->left->type == 't'){
                        if (stack[stack_point - 1]->right->left->type == ':'){
                            aux = head_reduction(stack[stack_point - 1]->right->right);
                        }
                        else if (stack[stack_point - 1]->right->left->type == 't'){
                            aux = tail_reduction(stack[stack_point - 1]->right->right);
                            aux = head_reduction(aux->right);
                        }
                    }else  {
                        printf("Head de nao lista.\n");
                    }

                    if (stack_point - 2 >= 0)
                        stack[stack_point - 2]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 1;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                    check = 0;  // TIRAR ISSO AQUI      ||      SEM ISSO NAO FUNCIONA!
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case 't':
                if (stack_point - 1 >= 0){
                    if (stack[stack_point - 1]->right->left->type == ':' || stack[stack_point - 1]->right->left->type == 't')
                        aux = tail_reduction(stack[stack_point - 1]->right);
                    else
                        printf("Head de nao lista.\n");


                    if ((stack_point - 2) >= 0)
                        stack[stack_point - 2]->left = aux;
                    else
                        root = aux;

                    stack_point = stack_point - 1;
                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;
            case '=':
                // printf("\ncomparacao\n");
                // print_graph(stack[stack_point-4]);
                // scanf("%c", &debug);
                if (stack_point - 2 >= 0){


                    aux = comp_reduction(stack[stack_point - 2], '=');
                    root = aux;

                    stack_point = 0;
                    print_graph(aux);
                    while (aux->left != NULL){
                        stack[stack_point] = aux;
                        aux = aux->left;
                        stack_point = stack_point + 1;
                    }
                    stack[stack_point] = aux;
                    // printf("Saiu comparacao\n");
                }
                else
                    check = 0;
            // print_graph(root);
            // printf("\n\n");
            break;

            case '>':
                if (stack_point - 2 >= 0){
                    aux = comp_reduction(stack[stack_point - 2], '>');
                    root = aux;

                    stack_point = 0;
                    while (aux->left != NULL){
                        stack[stack_point] = aux;
                        aux = aux->left;
                        stack_point = stack_point + 1;
                    }
                    stack[stack_point] = aux;
                    // printf("Saiu gt\n");
                }
                else
                    check = 0;
            break;

            case '<':
                if (stack_point - 2 >= 0){
                    aux = comp_reduction(stack[stack_point - 2], '<');
                    root = aux;

                    stack_point = 0;
                    while (aux->left != NULL){
                        stack[stack_point] = aux;
                        aux = aux->left;
                        stack_point = stack_point + 1;
                    }
                    stack[stack_point] = aux;
                    // printf("Saiu lt\n");
                }
                else
                    check = 0;
            break;
            case '+':
                if (stack_point - 2 >= 0){

                    aux = add_reduction(stack[stack_point - 2]);

                    if ((stack_point - 3) >= 0 && stack[stack_point - 3]->type != 'r'){
                        stack[stack_point - 3]->left = aux;
                    }
                    else
                        root = aux;

                    if (stack_point < 3)
                        stack_point = 3;
                    if (stack[stack_point - 3]->type == 'r')
                        stack_point = stack_point - 3;
                    else
                        stack_point = stack_point - 2;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // printf("operador +\n");
            // print_graph(root);
            // printf("\n\n");
            break;

            case '-':
                if (stack_point - 2 >= 0){

                    aux = sub_reduction(stack[stack_point - 2]);


                    if ((stack_point - 3) >= 0 && stack[stack_point - 3]->type != 'r'){
                        stack[stack_point - 3]->left = aux;
                    }
                    else
                        root = aux;

                    if (stack_point < 3)
                        stack_point = 3;
                    if (stack[stack_point - 3]->type == 'r')
                        stack_point = stack_point - 3;
                    else
                        stack_point = stack_point - 2;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // printf("\noperador -\n");
            // print_graph(root);
            // printf("\n\n");
            break;
            case '*':
                if (stack_point - 2 >= 0){

                    aux = mul_reduction(stack[stack_point - 2]);


                    if ((stack_point - 3) >= 0 && stack[stack_point - 3]->type != 'r'){
                        stack[stack_point - 3]->left = aux;
                    }
                    else
                        root = aux;

                    if (stack_point < 3)
                        stack_point = 3;
                    if (stack[stack_point - 3]->type == 'r')
                        stack_point = stack_point - 3;
                    else
                        stack_point = stack_point - 2;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // printf("\noperador -\n");
            // print_graph(root);
            // printf("\n\n");
            break;
            case '/':
                if (stack_point - 2 >= 0){

                    aux = div_reduction(stack[stack_point - 2]);


                    if ((stack_point - 3) >= 0 && stack[stack_point - 3]->type != 'r'){
                        stack[stack_point - 3]->left = aux;
                    }
                    else
                        root = aux;

                    if (stack_point < 3)
                        stack_point = 3;
                    if (stack[stack_point - 3]->type == 'r')
                        stack_point = stack_point - 3;
                    else
                        stack_point = stack_point - 2;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else
                    check = 0;
            // printf("\noperador -\n");
            // print_graph(root);
            // printf("\n\n");
            break;
            case 'Y':
                if (stack_point - 1 >= 0)
                {
                    // scanf("%c", &debug);
                    aux = Y_reduction(stack[stack_point - 1]);

                    if ((stack_point - 2) >= 0 && stack[stack_point - 2]->type != 'r')
                        stack[stack_point - 2]->left = aux;
                    else
                        root = aux;

                    if (stack_point < 2)
                        stack_point = 2;
                    if (stack[stack_point - 2]->type == 'r')
                        stack_point = stack_point - 2;
                    else
                        stack_point = stack_point - 1;

                    stack[stack_point] = aux;
                    stack_point = stack_update(stack_point);
                }
                else{
                    check = 0;
                }
            // print_graph(root);
            // printf("\n\n");
            break;

            case 'n':
                // printf("\nn case!!!!\n");
                aux = stack[stack_point];
                root = aux;
                // print_graph(aux);
                // printf("\n");
                check = 0;
                break;

            default:
                // printf("\n");
                // printf("\nEntrou no default\n");
                // printf("STACK[STACK_POINT]");
                // print_graph(stack[stack_point]);
                // printf("%c\n", stack[stack_point]->type);
                // printf("\n\n");

                if (r == 0)
                    root = stack[stack_point];
                check = 0;
                break;
        }
    }

    return root;

}
Esempio n. 3
0
int __cdecl wmain(int argc, wchar_t *wargv[])
{
	int ret = 0;

	// Global URL cache to not download anything twice
	json_t *url_cache = json_object();
	// Repository ID cache to prioritize the most local repository if more
	// than one repository with the same name is discovered in the network
	json_t *id_cache = json_object();

	json_t *repo_list = NULL;

	const char *start_repo = "http://thcrap.nmlgc.net/repos/nmlgc/";

	json_t *sel_stack = NULL;
	json_t *new_cfg = json_pack("{s[]}", "patches");

	size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1;
	VLA(char, cur_dir, cur_dir_len);
	json_t *games = NULL;

	const char *run_cfg_fn = NULL;
	const char *run_cfg_fn_js = NULL;
	char *run_cfg_str = NULL;

	json_t *args = json_array_from_wchar_array(argc, wargv);

	wine_flag = GetProcAddress(
		GetModuleHandleA("kernel32.dll"), "wine_get_unix_file_name"
	) != 0;

	strings_mod_init();
	log_init(1);

	// Necessary to correctly process *any* input of non-ASCII characters
	// in the console subsystem
	w32u8_set_fallback_codepage(GetOEMCP());

	GetCurrentDirectory(cur_dir_len, cur_dir);
	PathAddBackslashA(cur_dir);
	str_slash_normalize(cur_dir);

	// Maximize the height of the console window... unless we're running under
	// Wine, where this 1) doesn't work and 2) messes up the console buffer
	if(!wine_flag) {
		CONSOLE_SCREEN_BUFFER_INFO sbi = {0};
		HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
		COORD largest = GetLargestConsoleWindowSize(console);
		HWND console_wnd = GetConsoleWindow();
		RECT console_rect;

		GetWindowRect(console_wnd, &console_rect);
		SetWindowPos(console_wnd, NULL, console_rect.left, 0, 0, 0, SWP_NOSIZE);
		GetConsoleScreenBufferInfo(console, &sbi);
		sbi.srWindow.Bottom = largest.Y - 4;
		SetConsoleWindowInfo(console, TRUE, &sbi.srWindow);
	}

	http_init();

	if(json_array_size(args) > 1) {
		start_repo = json_array_get_string(args, 1);
	}

	log_printf(
		"==========================================\n"
		"Touhou Community Reliant Automatic Patcher - Patch configuration tool\n"
		"==========================================\n"
		"\n"
		"\n"
		"This tool will create a new patch configuration for the\n"
		"Touhou Community Reliant Automatic Patcher.\n"
		"\n"
		"\n"
		"The configuration process has two steps:\n"
		"\n"
		"\t\t1. Selecting patches\n"
		"\t\t2. Download game-independent data\n"
		"\t\t3. Locating game installations\n"
		"\t\t4. Download game-specific data\n"
		"\n"
		"\n"
		"\n"
		"Patch repository discovery will start at\n"
		"\n"
		"\t%s\n"
		"\n"
		"You can specify a different URL as a command-line parameter.\n"
		"Additionally, all patches from previously discovered repositories, stored in\n"
		"subdirectories of the current directory, will be available for selection.\n"
		"\n"
		"\n",
		start_repo
	);
	pause();

	if(RepoDiscoverAtURL(start_repo, id_cache, url_cache)) {
		goto end;
	}
	if(RepoDiscoverFromLocal(id_cache, url_cache)) {
		goto end;
	}
	repo_list = RepoLoad();
	if(!json_object_size(repo_list)) {
		log_printf("No patch repositories available...\n");
		pause();
		goto end;
	}
	sel_stack = SelectPatchStack(repo_list);
	if(json_array_size(sel_stack)) {
		json_t *new_cfg_patches = json_object_get(new_cfg, "patches");
		size_t i;
		json_t *sel;

		log_printf("Downloading game-independent data...\n");
		stack_update(update_filter_global, NULL);

		/// Build the new run configuration
		json_array_foreach(sel_stack, i, sel) {
			json_array_append_new(new_cfg_patches, patch_build(sel));
		}
	}
Esempio n. 4
0
/*----------------------------------------------------------------------------
 * rumavl_delete - deletes a node. Beware! this function is the worst part of
 * the library. Think (and draw pictures) when you edit this function.
 *--------------------------------------------------------------------------*/
int rumavl_delete (RUMAVL *tree, const void *record)
{
    RUMAVL_NODE **node, *tmpnode;
    RUMAVL_STACK *stack;
    int dir, ln;

    if (tree->root == NULL)	/* tree is empty */
	return RUMAVL_ERR_NOENT;

    stack = NULL;
    node = &tree->root;

    /* Find desired node */
    while ((dir = rec_cmp(tree, record, NODE_REC(*node))) != 0){
	if (stack_push(tree, &stack, node, dir) != 0)
	    goto nomemout;

	if ((*node)->thread[LINK_NO(dir)] > 0){
	    /* desired node does not exist */
	    stack_destroy(tree, stack);
	    return RUMAVL_ERR_NOENT;
	}
	node = &(*node)->link[LINK_NO(dir)];
    }

    /* OK, we got the node to be deleted, now get confirmation from user */
    if (tree->delcb != NULL &&
	    (ln = tree->delcb(tree, *node, NODE_REC(*node), tree->udata)) 
	    != 0){
	stack_destroy(tree, stack);
	return ln;
    }

    if ((*node)->thread[LEFT] > 0){
	if ((*node)->thread[RIGHT] > 0){
	    /* ooh look, we're a leaf */
	    tmpnode = *node;
	    if (stack != NULL){
		/* This node has a parent, which will need to take over a
		 * thread from the node being deleted. First we work out
		 * which (left/right) child we are of parent, then give
		 * parent the respective thread. If the thread destination
		 * points back to us (edge of tree thread), update it to
		 * point to our parent. */
		ln = LINK_NO(stack->dir);
		(*stack->node)->link[ln] = tmpnode->link[ln];
		(*stack->node)->thread[ln] = tmpnode->thread[ln];
		if ((*stack->node)->thread[ln] == 2)
		    (*stack->node)->link[ln]->link[OTHER_LINK(ln)] =
			*stack->node;
	    }else{
		/* 
		 * the only time stack will == NULL is when we are
		 * deleting the root of the tree. We already know that
		 * this is a leaf, so we will be leaving the tree empty.
		 */
		tree->root = NULL;
	    }
	    node_destroy(tree, tmpnode);
	}else{
	    /* *node has only one child, and can be pruned by replacing
	     * *node with its only child. This block of code and the next
	     * should be identical, except that all directions and link
	     * numbers are opposite.
	     *
	     * Let node being deleted = DELNODE for this comment.
	     * DELNODE only has one child (the right child). The left
	     * most descendant of DELNODE will have a thread (left thread)
	     * pointing to DELNODE. This thread must be updated to point
	     * to the node currently pointed to by DELNODE's left thread.
	     *
	     * DELNODE's left thread may point to the opposite edge of the
	     * BST. In this case, the destination of the thread will have
	     * a thread back to DELNODE. This will need to be updated to
	     * point back to the leftmost descendant of DELNODE.
	     */
	    tmpnode = *node;		    /* node being deleted */
	    *node = (*node)->link[RIGHT];   /* right child */
	    /* find left most descendant */
	    while ((*node)->thread[LEFT] == 0) 
		node = &(*node)->link[LEFT];
	    /* inherit thread from node being deleted */
	    (*node)->link[LEFT] = tmpnode->link[LEFT];
	    (*node)->thread[LEFT] = tmpnode->thread[LEFT];
	    /* update reverse thread if necessary */
	    if ((*node)->thread[LEFT] == 2)
		(*node)->link[LEFT]->link[RIGHT] = *node;
	    node_destroy(tree, tmpnode);
	}
    }else if ((*node)->thread[RIGHT] > 0){
	/* see above */
	tmpnode = *node;
	*node = (*node)->link[LEFT];
	while ((*node)->thread[RIGHT] == 0)
	    node = &(*node)->link[RIGHT];
	(*node)->link[RIGHT] = tmpnode->link[RIGHT];
	(*node)->thread[RIGHT] = tmpnode->thread[RIGHT];
	if ((*node)->thread[RIGHT] == 2)
	    (*node)->link[RIGHT]->link[LEFT] = *node;
	node_destroy(tree, tmpnode);
    }else{
	/* Delete a node with children on both sides. We do this by replacing
	 * the node to be deleted (delnode) with its inner most child
	 * on the heavier side (repnode). This in place replacement is quicker
	 * than the previously used method of rotating delnode until it is a
	 * (semi) leaf.
	 *
	 * At this point node points to delnode's parent's link to delnode. */
	RUMAVL_NODE *repnode, *parent;
	int outdir, outln;

	/* find heaviest subtree */
	if ((*node)->balance > 0){
	    outdir = +1;    /* outter direction */
	    dir = -1;	    /* inner direction */
	    outln = 1;	    /* outer link number */
	    ln = 0;	    /* inner link number */
	}else{
	    outdir = -1;    /* same as above, but opposite subtree */
	    dir = +1;
	    outln = 0;
	    ln = 1;
	}
	
	/* Add node to be deleted to the list of nodes to be rebalanced.
	 * Rememer that the replacement node will actually be acted apon,
	 * and that the replacement node should feel the effect of its own
	 * move */
	if (stack_push(tree, &stack, node, outdir) != 0)
	    goto nomemout;
	
	parent = *node;
	repnode = parent->link[outln];

	if (repnode->thread[ln] != 0){
	    /* repnode inherits delnode's lighter tree, and balance, and gets
	     * balance readjusted below */
	    repnode->link[ln] = (*node)->link[ln];
	    repnode->thread[ln] = (*node)->thread[ln];
	    repnode->balance = (*node)->balance;
	}else{
	    /* Now we add delnodes direct child to the list of "to update".
	     * We pass a pointer to delnode's link to its direct child to 
	     * stack_push(), but that pointer is invalid, because when
	     * stack_update() tries to access the link, delnode would have
	     * been destroyed. So, we remember the stack position at which
	     * we passed the faulty pointer to stack_push, and update its
	     * node pointer when we find repnode to point to repnodes 
	     * link on the same side */
	    RUMAVL_STACK *tmpstack;

	    if (stack_push(tree, &stack, &parent->link[outln], dir) != 0)
		goto nomemout;

	    tmpstack = stack;

	    parent = repnode;
	    repnode = repnode->link[ln];

	    /* move towards the innermost child of delnode */		
	    while (repnode->thread[ln] == 0){
		if (stack_push(tree, &stack, &parent->link[ln], dir) != 0)
		    goto nomemout;
		parent = repnode;
		repnode = repnode->link[ln];
	    }

	    if (repnode->thread[outln] == 0){
		/* repnode's parent inherits repnodes only child */
		parent->link[ln] = repnode->link[outln];
	    }else{
		/* parent already has a link to repnode, but it must now be
		 * marked as a thread */
		parent->thread[ln] = 1;
	    }

	    repnode->link[0] = (*node)->link[0];
	    repnode->thread[0] = (*node)->thread[0];
	    repnode->link[1] = (*node)->link[1];
	    repnode->thread[1] = (*node)->thread[1];
	    repnode->balance = (*node)->balance;

	    /* see comment above */
	    tmpstack->node = &repnode->link[outln];
	}
	node_destroy(tree, *node);
	*node = repnode;

	/* innermost child in lighter tree has an invalid thread to delnode,
	 * update it to point to repnode */
	repnode = seq_next(repnode, dir);
	repnode->link[outln] = *node;
    }

    /* update parents' balances */
    stack_update(tree, stack, -1);
    return 0;

nomemout:
    stack_destroy(tree, stack);
    return RUMAVL_ERR_NOMEM;
}
Esempio n. 5
0
/*----------------------------------------------------------------------------
 * rumavl_set - set a node, overwriting if necessary, or creating if the node
 * does not exist
 *--------------------------------------------------------------------------*/
int rumavl_set (RUMAVL *tree, const void *record)
{
    RUMAVL_NODE **node, *tmp;
    RUMAVL_STACK *stack;
    int ln;
    
    if (tree->root == NULL){
	/* This is the first node in the tree */
	if ((tree->root = node_new(tree, record)) == NULL)
	    return RUMAVL_ERR_NOMEM;
	tree->root->link[LEFT] = tree->root;
	tree->root->link[RIGHT] = tree->root;
	tree->root->thread[LEFT] = 2;
	tree->root->thread[RIGHT] = 2;
	return 0;
    }

    /* Since the tree is not empty, we must descend towards the nodes ideal
     * possition, and we may even find an existing node with the same record.
     * We keep a list parents for the eventual node position, because these
     * parents may become inbalanced by a new insertion. */

    stack = NULL;
    node = &tree->root;
    for (;;){
	if ((ln = rec_cmp(tree, record, NODE_REC(*node))) == 0){
	    /* OK, we found the exact node we wish to set, and we now
	     * overwrite it. No change happens to the tree structure */
	    stack_destroy(tree, stack);
	    
	    if (tree->owcb != NULL &&
		    (ln = tree->owcb(tree, *node, NODE_REC(*node), 
				      record, tree->udata)) != 0){
		return ln;
	    }
	    
	    memcpy(NODE_REC(*node), record, tree->reclen);
	    return 0;
	}
	
	/* *node is not the node we seek */
	
	if (stack_push(tree, &stack, node, ln)){
	    stack_destroy(tree, stack);
	    return RUMAVL_ERR_NOMEM;
	}
	
	ln = LINK_NO(ln);
	if ((*node)->thread[ln] > 0){
	    /* This is as close to the correct node as we can get. We will
	     * now break and add the new node as a leaf */
	    break;
	}
	
	node = &(*node)->link[ln];
    }
	    
    /* we have reached a leaf, add new node here */
    if ((tmp = node_new(tree, record)) == NULL){
	stack_destroy(tree, stack);
	return RUMAVL_ERR_NOMEM;
    }
    /* new child inherits parent thread */
    tmp->link[ln] = (*node)->link[ln];
    tmp->thread[ln] = (*node)->thread[ln];
    if (tmp->thread[ln] == 2)
	tmp->link[ln]->link[OTHER_LINK(ln)] = tmp;
    
    tmp->link[OTHER_LINK(ln)] = *node;
    tmp->thread[OTHER_LINK(ln)] = 1;
    (*node)->link[ln] = tmp;
    (*node)->thread[ln] = 0;

    /* all parentage is now one level heavier - balance where necessary */
    stack_update(tree, stack, +1);
    
    return 0;
}