blob: d56b6964dc693066f2b710eeac9b453210523132 [file] [log] [blame]
/*
* node_tree.c: an editor for tracking repository deltas changes
*
* ====================================================================
* Copyright (c) 2000-2002 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
#include <stdio.h>
#define APR_WANT_STRFUNC
#include <apr_want.h>
#include "apr_pools.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_fs.h"
#include "svn_repos.h"
#include "repos.h"
/*** Node creation and assembly structures and routines. ***/
static svn_repos_node_t *
create_node (const char *name,
apr_pool_t *pool)
{
svn_repos_node_t *node = apr_pcalloc (pool, sizeof (svn_repos_node_t));
node->action = 'R';
node->kind = svn_node_unknown;
node->name = apr_pstrdup (pool, name);
return node;
}
static svn_repos_node_t *
create_sibling_node (svn_repos_node_t *elder,
const char *name,
apr_pool_t *pool)
{
svn_repos_node_t *tmp_node;
/* No ELDER sibling? That's just not gonna work out. */
if (! elder)
return NULL;
/* Run to the end of the list of siblings of ELDER. */
tmp_node = elder;
while (tmp_node->sibling)
tmp_node = tmp_node->sibling;
/* Create a new youngest sibling and return that. */
return (tmp_node->sibling = create_node (name, pool));
}
static svn_repos_node_t *
create_child_node (svn_repos_node_t *parent,
const char *name,
apr_pool_t *pool)
{
/* No PARENT node? That's just not gonna work out. */
if (! parent)
return NULL;
/* If PARENT has no children, create its first one and return that. */
if (! parent->child)
return (parent->child = create_node (name, pool));
/* If PARENT already has a child, create a new sibling for its first
child and return that. */
return create_sibling_node (parent->child, name, pool);
}
static svn_repos_node_t *
find_child_by_name (svn_repos_node_t *parent,
const char *name)
{
svn_repos_node_t *tmp_node;
/* No PARENT node, or a barren PARENT? Nothing to find. */
if ((! parent) || (! parent->child))
return NULL;
/* Look through the children for a node with a matching name. */
tmp_node = parent->child;
while (1)
{
if (! strcmp (tmp_node->name, name))
{
return tmp_node;
}
else
{
if (tmp_node->sibling)
tmp_node = tmp_node->sibling;
else
break;
}
}
return NULL;
}
/*** Editor functions and batons. ***/
struct edit_baton
{
svn_fs_t *fs;
svn_fs_root_t *root;
svn_fs_root_t *base_root;
apr_pool_t *pool;
apr_pool_t *node_pool;
svn_repos_node_t *node;
};
struct dir_baton
{
svn_stringbuf_t *path;
struct edit_baton *edit_baton;
svn_repos_node_t *node;
};
struct file_baton
{
svn_stringbuf_t *path;
struct dir_baton *dir_baton;
svn_repos_node_t *node;
};
struct window_handler_baton
{
svn_repos_node_t *node;
};
static svn_error_t *
delete_entry (svn_stringbuf_t *name,
svn_revnum_t revision,
void *parent_baton)
{
struct dir_baton *d = (struct dir_baton *) parent_baton;
struct edit_baton *eb = (struct edit_baton *) d->edit_baton;
svn_stringbuf_t *full_path;
svn_repos_node_t *node;
int is_dir;
/* Construct the full path of this entry based on its parent. */
full_path = svn_stringbuf_dup (d->path, eb->pool);
svn_path_add_component (full_path, name);
/* Was this a dir or file (we have to check the base root for this one) */
SVN_ERR (svn_fs_is_dir (&is_dir, eb->base_root, full_path->data, eb->pool));
/* Get (or create) the change node and update it. */
node = find_child_by_name (d->node, name->data);
if (! node)
node = create_child_node (d->node, name->data, eb->node_pool);
if (is_dir)
node->kind = svn_node_dir;
else
node->kind = svn_node_file;
node->action = 'D';
return SVN_NO_ERROR;
}
static svn_error_t *
open_root (void *edit_baton,
svn_revnum_t base_revision,
void **root_baton)
{
struct edit_baton *eb = (struct edit_baton *) edit_baton;
struct dir_baton *d = apr_pcalloc (eb->pool, sizeof (*d));
d->path = (svn_stringbuf_t *) svn_stringbuf_create ("", eb->pool);
d->edit_baton = eb;
d->node = (eb->node = create_node ("", eb->node_pool));
d->node->kind = svn_node_dir;
d->node->action = 'R';
*root_baton = d;
return SVN_NO_ERROR;
}
static svn_error_t *
open_directory (svn_stringbuf_t *name,
void *parent_baton,
svn_revnum_t base_revision,
void **child_baton)
{
struct dir_baton *pd = (struct dir_baton *) parent_baton;
struct edit_baton *eb = (struct edit_baton *) pd->edit_baton;
struct dir_baton *d = apr_pcalloc (pd->edit_baton->pool, sizeof (*d));
/* Construct the full path of the new directory */
d->path = svn_stringbuf_dup (pd->path, eb->pool);
svn_path_add_component (d->path, name);
/* Fill in other baton members */
d->edit_baton = eb;
d->node = create_child_node (pd->node, name->data, eb->node_pool);
d->node->kind = svn_node_dir;
d->node->action = 'R';
*child_baton = d;
return SVN_NO_ERROR;
}
static svn_error_t *
add_directory (svn_stringbuf_t *name,
void *parent_baton,
svn_stringbuf_t *copyfrom_path,
svn_revnum_t copyfrom_revision,
void **child_baton)
{
struct dir_baton *pd = (struct dir_baton *) parent_baton;
struct edit_baton *eb = (struct edit_baton *) pd->edit_baton;
struct dir_baton *d = apr_pcalloc (pd->edit_baton->pool, sizeof (*d));
/* Construct the full path of the new directory */
d->path = svn_stringbuf_dup (pd->path, eb->pool);
svn_path_add_component (d->path, name);
/* Fill in other baton members */
d->edit_baton = eb;
d->node = create_child_node (pd->node, name->data, eb->node_pool);
d->node->kind = svn_node_dir;
d->node->action = 'A';
*child_baton = d;
return SVN_NO_ERROR;
}
static svn_error_t *
open_file (svn_stringbuf_t *name,
void *parent_baton,
svn_revnum_t base_revision,
void **file_baton)
{
struct dir_baton *pd = (struct dir_baton *) parent_baton;
struct edit_baton *eb = (struct edit_baton *) pd->edit_baton;
struct file_baton *fb = apr_pcalloc (pd->edit_baton->pool, sizeof (*fb));
/* Construct the full path of the new directory */
fb->path = svn_stringbuf_dup (pd->path, eb->pool);
svn_path_add_component (fb->path, name);
/* Fill in other baton members */
fb->dir_baton = pd;
fb->node = create_child_node (pd->node, name->data, eb->node_pool);
fb->node->kind = svn_node_file;
fb->node->action = 'R';
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
add_file (svn_stringbuf_t *name,
void *parent_baton,
svn_stringbuf_t *copyfrom_path,
svn_revnum_t copyfrom_revision,
void **file_baton)
{
struct dir_baton *pd = (struct dir_baton *) parent_baton;
struct edit_baton *eb = (struct edit_baton *) pd->edit_baton;
struct file_baton *fb = apr_pcalloc (pd->edit_baton->pool, sizeof (*fb));
/* Construct the full path of the new directory */
fb->path = svn_stringbuf_dup (pd->path, eb->pool);
svn_path_add_component (fb->path, name);
/* Fill in other baton members */
fb->dir_baton = pd;
fb->node = create_child_node (pd->node, name->data, eb->node_pool);
fb->node->kind = svn_node_file;
fb->node->action = 'A';
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
window_handler (svn_txdelta_window_t *window, void *baton)
{
return SVN_NO_ERROR;
}
static svn_error_t *
apply_textdelta (void *file_baton,
svn_txdelta_window_handler_t *handler,
void **handler_baton)
{
struct file_baton *fb = (struct file_baton *) file_baton;
struct edit_baton *eb = (struct edit_baton *) fb->dir_baton->edit_baton;
struct window_handler_baton *whb = apr_palloc (eb->pool, sizeof (*whb));
whb->node = fb->node;
whb->node->text_mod = TRUE;
*handler = window_handler;
*handler_baton = whb;
return SVN_NO_ERROR;
}
static svn_error_t *
change_file_prop (void *file_baton,
svn_stringbuf_t *name,
svn_stringbuf_t *value)
{
struct file_baton *fb = (struct file_baton *) file_baton;
fb->node->prop_mod = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
change_dir_prop (void *parent_baton,
svn_stringbuf_t *name,
svn_stringbuf_t *value)
{
struct dir_baton *d = (struct dir_baton *) parent_baton;
d->node->prop_mod = TRUE;
return SVN_NO_ERROR;
}
svn_error_t *
svn_repos_node_editor (const svn_delta_edit_fns_t **editor,
void **edit_baton,
svn_repos_t *repos,
svn_fs_root_t *base_root,
svn_fs_root_t *root,
apr_pool_t *node_pool,
apr_pool_t *pool)
{
svn_delta_edit_fns_t *my_editor;
struct edit_baton *my_edit_baton;
/* Set up the editor. */
my_editor = svn_delta_old_default_editor (pool);
my_editor->open_root = open_root;
my_editor->delete_entry = delete_entry;
my_editor->add_directory = add_directory;
my_editor->open_directory = open_directory;
my_editor->add_file = add_file;
my_editor->open_file = open_file;
my_editor->apply_textdelta = apply_textdelta;
my_editor->change_file_prop = change_file_prop;
my_editor->change_dir_prop = change_dir_prop;
/* Set up the edit baton. */
my_edit_baton = apr_pcalloc (pool, sizeof (*my_edit_baton));
my_edit_baton->node_pool = node_pool;
my_edit_baton->pool = pool;
my_edit_baton->fs = repos->fs;
my_edit_baton->root = root;
my_edit_baton->base_root = base_root;
*editor = my_editor;
*edit_baton = my_edit_baton;
return SVN_NO_ERROR;
}
svn_repos_node_t *
svn_repos_node_from_baton (void *edit_baton)
{
struct edit_baton *eb = (struct edit_baton *) edit_baton;
return eb->node;
}
/*
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end:
*/