/* patch-id.c:
*
* vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
****************************************************************
* Copyright (C) 2005 Canonical Limited
* Authors: Robert Collins <robert.collins@canonical.com>
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/bugs/panic.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/char/str.h"
#include "hackerlab/sort/qsort.h"
#include "libarch/namespace.h"
#include "libarch/patch-id.h"
struct sort_spec
{
int reverse;
};
static int patch_id_cmp (void *va,
void *vb,
void *vdata);
static int arch_patch_id_destructor (void * data);
void
arch_patch_id_init (arch_patch_id *patch, t_uchar const *patch_id)
{
/* cannot use talloc onto the patch while this is
* allowed on the stack
*/
patch->patch_id = talloc_strdup (NULL, patch_id);
patch->archive = NULL;
patch->branch = NULL;
patch->version = NULL;
patch->revision = NULL;
patch->patchlevel = NULL;
}
void
arch_patch_id_init_archive (arch_patch_id *patch, t_uchar const *archive, t_uchar const *revision)
{
t_uchar *fqrevision = str_alloc_cat_many (0, archive, "/", revision, str_end);
arch_patch_id_init (patch, fqrevision);
lim_free (0, fqrevision);
}
/**
* \brief create a new patch with the id patch_id
* \param patch_id the patch id
* \return the patch, freshly allocated
*/
arch_patch_id *
arch_patch_id_new (t_uchar const * patch_id)
{
arch_patch_id * answer = 0;
answer = talloc (NULL, arch_patch_id);
talloc_set_destructor (answer, arch_patch_id_destructor);
arch_patch_id_init (answer, patch_id);
return answer;
}
/**
* \brief Create a copy of the given patch.
*
* This is mainly used in the same way str_save is used.
*/
arch_patch_id *
arch_patch_id_copy (arch_patch_id *patch)
{
return arch_patch_id_new (arch_patch_id_patch_id (patch));
}
/**
* \brief Create a new arch_patch_id initialized by the supplied archive and revision.
*/
arch_patch_id *
arch_patch_id_new_archive (t_uchar const *archive,
t_uchar const *revision)
{
arch_patch_id * answer = 0;
answer = talloc (NULL, arch_patch_id);
talloc_set_destructor (answer, arch_patch_id_destructor);
arch_patch_id_init_archive (answer, archive, revision);
return answer;
}
/**
* \brief Free the memory for the contained members, but not the object itself.
*/
void
arch_patch_id_finalise (arch_patch_id *patch)
{
talloc_free (patch->patch_id);
patch->patch_id = NULL;
lim_free (0, patch->archive);
patch->archive = NULL;
lim_free (0, patch->branch);
patch->branch = NULL;
lim_free (0, patch->version);
patch->version = NULL;
lim_free (0, patch->revision);
patch->revision = NULL;
lim_free (0, patch->patchlevel);
patch->patchlevel = NULL;
}
/**
* \brief Get the archive portion of the patch_id.
*/
t_uchar *
arch_patch_id_archive (arch_patch_id *patch)
{
if (!patch->archive)
patch->archive = arch_parse_package_name (arch_ret_archive, 0, patch->patch_id);
return patch->archive;
}
/**
* \brief Get the fully qualified version (where patches go).
*/
t_uchar *
arch_patch_id_branch (arch_patch_id *patch)
{
if (!patch->branch)
patch->branch = arch_fully_qualify (arch_patch_id_archive(patch), arch_patch_id_version (patch));
return patch->branch;
}
t_uchar *
arch_patch_id_version (arch_patch_id *patch)
{
if (!patch->version)
patch->version = arch_parse_package_name (arch_ret_package_version, 0, patch->patch_id);
return patch->version;
}
t_uchar *
arch_patch_id_revision (arch_patch_id *patch)
{
if (!patch->revision)
patch->revision = arch_parse_package_name (arch_ret_non_archive, 0, patch->patch_id);
return patch->revision;
}
t_uchar *
arch_patch_id_patch_id (arch_patch_id *patch)
{
return patch->patch_id;
}
t_uchar *
arch_patch_id_patchlevel (arch_patch_id *patch)
{
if (!patch->patchlevel)
patch->patchlevel = arch_parse_package_name (arch_ret_patch_level, 0, patch->patch_id);
return patch->patchlevel;
}
/**
* \brief Remove the arch_patch_ids from other_patches and put them in patches
*
* \param patches All patches will end up here
* \param other_patches This should end up empty.
*/
void
ar_patch_id_extend_taking (ar_patch_id * patches,
ar_patch_id * other_patches)
{
while (ar_size_patch_id (*other_patches) > 0)
{
ar_push_patch_id (patches, ar_pop_patch_id (other_patches));
talloc_steal (ar_base (*patches), (*patches)[ar_size_patch_id (*patches) - 1]);
}
ar_free_patch_id (other_patches);
}
/**
* \brief Compare two patch_ids using the individual components.
*/
int
arch_patch_id_cmp (arch_patch_id *a,
arch_patch_id *b)
{
return arch_names_cmp (arch_patch_id_patch_id (a), arch_patch_id_patch_id (b));
}
/**
* \brief Sort a list of arch_patch_ids base on their components.
*
* \sa arch_sort_table_by_name_field
*/
void
ar_sort_patch_id (ar_patch_id patches,
int reverse)
{
struct sort_spec spec = {reverse};
quicksort ((void *)patches, ar_size_patch_id (patches),
sizeof (arch_patch_id *), patch_id_cmp, (void *)&spec);
}
int
patch_id_cmp (void *va,
void *vb,
void *vdata)
{
arch_patch_id *a = 0;
arch_patch_id *b = 0;
struct sort_spec * spec = 0;
spec = (struct sort_spec *) vdata;
a = (arch_patch_id*) va;
b = (arch_patch_id*) vb;
if (spec->reverse)
{
return -arch_patch_id_cmp (a, b);
}
else
{
return arch_patch_id_cmp (a, b);
}
}
/**
* \brief free resources for patch ids. Until all the static instances are
* talloced, this must be assigned to every talloced instance
*/
int
arch_patch_id_destructor (void * data)
{
arch_patch_id * patch = talloc_get_type (data, arch_patch_id);
invariant (!!patch);
arch_patch_id_finalise (patch);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1