/* annotation-builder.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/exception.h" #include "hackerlab/bugs/panic.h" #include "hackerlab/os/errno.h" #include "hackerlab/char/str.h" #include "libarch/annotation-builder.h" /* local static functions */ static int arch_annotation_builder_destructor (void * data); static int arch_annotation_builder_find_file (arch_annotation_builder_t *builder, t_uchar const *file_id) { int position; for (position = 0; position < ar_size_arch_annotated_file (builder->files); ++position) if (!str_cmp (file_id, builder->files[position]->file_id)) return position; return -1; } void arch_annotation_builder_init (arch_annotation_builder_t *builder) { builder->files = NULL; builder->current_file = NULL; builder->current_patch = NULL; } int arch_annotation_builder_destructor (void * data) { arch_annotation_builder_t * builder = talloc_get_type (data, arch_annotation_builder_t); invariant (!!builder); arch_annotation_builder_finalise (builder); return 0; } arch_annotation_builder_t * arch_annotation_builder_new (void * context) { arch_annotation_builder_t * builder = talloc (context, arch_annotation_builder_t); arch_annotation_builder_init (builder); talloc_set_destructor (builder, arch_annotation_builder_destructor); return builder; } void arch_annotation_builder_finalise (arch_annotation_builder_t *builder) { arch_patch_delete (&builder->current_patch); } /** * \@brief note a file by its observed id, and the number of lines we need to annotate. */ void arch_annotation_builder_add_file (arch_annotation_builder_t *builder, t_uchar const *file_id, int size_if_start) { int position = arch_annotation_builder_find_file (builder, file_id); if (position != -1) { builder->current_file = builder->files[position]; return; } invariant (size_if_start != -1); ar_push_arch_annotated_file (&builder->files, arch_annotated_file_new (talloc_context, file_id, size_if_start)); builder->current_file = builder->files[ar_size_arch_annotated_file (builder->files) - 1]; talloc_steal (ar_base (builder->files), builder->current_file); talloc_steal (builder, ar_base (builder->files)); } int arch_annotation_builder_has_file (arch_annotation_builder_t *builder, t_uchar const *file_id) { return arch_annotation_builder_find_file(builder, file_id) != -1; } /** * \brief retrieve and remove the annotated file for file_id * \throw ENOENT if file_id is not in the annotated files list * \param builder the builder * \param context the talloc context for the returned file object * \param file_id the file to retrieve * \return an arch_annotated_file_t * */ arch_annotated_file_t * arch_annotation_builder_get_file (arch_annotation_builder_t *builder, void * context, t_uchar const *file_id) { arch_annotated_file_t *result; int position = arch_annotation_builder_find_file (builder, file_id); if (position == -1) Throw (exception (ENOENT, "arch_annotation_builder_get_file: No such file.")); result = *ar_ref_arch_annotated_file (&builder->files, position); for (; position < ar_size_arch_annotated_file (builder->files) - 1; ++position ) { *ar_ref_arch_annotated_file (&builder->files, position) = *ar_ref_arch_annotated_file (&builder->files, position + 1); } ar_pop_arch_annotated_file (&builder->files); builder->current_file = NULL; return talloc_steal (context, result); } /** * \@brief add a patch */ void arch_annotation_builder_add_patch (arch_annotation_builder_t *builder, arch_patch_id *patch, t_uchar const * creator) { arch_patch_delete (&builder->current_patch); builder->current_patch = arch_patch_new (patch->patch_id); arch_patch_creator_set (builder->current_patch, creator); } void arch_annotation_builder_subtract_line (arch_annotation_builder_t *builder, int old_offset) { invariant (builder->current_file != NULL); invariant (builder->current_patch != NULL); arch_annotated_file_note_subtract (builder->current_file, old_offset); } void arch_annotation_builder_add_line (arch_annotation_builder_t *builder, int line) { invariant (builder->current_file != NULL); invariant (builder->current_patch != NULL); arch_annotated_file_note_line (builder->current_file, line, builder->current_patch, 0); } void arch_annotation_builder_process_changes(arch_annotation_builder_t *builder, patch_line_changes_list changes) { int position; for (position = 0; position < ar_size_patch_line_change (changes); ++ position) { if (changes[position].operation == PATCH_ADD_LINE) { arch_annotation_builder_add_line(builder, changes[position].offset); } else { arch_annotation_builder_subtract_line(builder, changes[position].offset); } } }