/* patch-id.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2005 Canonical Limited * Authors: Robert Collins * * 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; }