diff options
Diffstat (limited to 'sediff/result_item_render.c')
-rw-r--r-- | sediff/result_item_render.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/sediff/result_item_render.c b/sediff/result_item_render.c new file mode 100644 index 0000000..36fbbfb --- /dev/null +++ b/sediff/result_item_render.c @@ -0,0 +1,421 @@ +/** + * @file + * Common rendering routines for result items. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "result_item_render.h" + +#include <assert.h> + +static const char *form_name_map[] = { + "Added", "Added New Type", "Removed", "Removed Missing Type", "Modified" +}; +static const char *form_name_long_map[] = { + "Added", "Added because of new type", "Removed", "Removed because of missing type", "Modified" +}; +static const char *tag_map[] = { + "added-header", "added-header", "removed-header", "removed-header", "modified-header" +}; +static const poldiff_form_e form_map[] = { + POLDIFF_FORM_ADDED, POLDIFF_FORM_ADD_TYPE, + POLDIFF_FORM_REMOVED, POLDIFF_FORM_REMOVE_TYPE, + POLDIFF_FORM_MODIFIED +}; + +/** + * Show a single diff item string. This will add the appropriate + * color tags based upon the item's first non-space character. + */ +void result_item_print_string(GtkTextBuffer * tb, GtkTextIter * iter, const char *s, unsigned int indent_level) +{ + const char *c; + unsigned int i; + size_t start = 0, end = 0; + static const char *indent = "\t"; + const gchar *tag = NULL; + for (i = 0; i < indent_level; i++) { + gtk_text_buffer_insert(tb, iter, indent, -1); + } + for (c = s; *c && tag == NULL; c++) { + switch (*c) { + case '+': + { + tag = "added"; + break; + } + case '-': + { + tag = "removed"; + break; + } + case ' ': + case '\t': + case '\n': + { + break; + } + default: + { + tag = "modified"; + break; + } + } + } + for (c = s; *c; c++, end++) { + if (*c == '\n' && *(c + 1) != '\0') { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start + 1, tag, NULL); + for (i = 0; i < indent_level; i++) { + gtk_text_buffer_insert(tb, iter, indent, -1); + } + start = end + 1; + } + } + if (start < end) { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start, tag, NULL); + } +} + +void result_item_print_string_inline(GtkTextBuffer * tb, GtkTextIter * iter, const char *s, unsigned int indent_level) +{ + const char *c = s; + unsigned int i; + size_t start = 0, end = 0; + static const char *indent = "\t"; + const gchar *current_tag = "modified"; + for (i = 0; i < indent_level; i++) { + gtk_text_buffer_insert(tb, iter, indent, -1); + } + for (; *c; c++, end++) { + switch (*c) { + case '+': + { + if (end > 0) { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start, current_tag, NULL); + } + start = end; + current_tag = "added"; + break; + } + case '-': + { + if (end > 0) { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start, current_tag, NULL); + } + start = end; + current_tag = "removed"; + break; + } + case '\n': + { + if (*(c + 1) != '\0') { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start + 1, current_tag, NULL); + for (i = 0; i < indent_level; i++) { + gtk_text_buffer_insert(tb, iter, indent, -1); + } + start = end + 1; + } + break; + } + case ' ': + { + if (current_tag != "modified") { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start + 1, current_tag, NULL); + start = end + 1; + current_tag = "modified"; + } + break; + } + } + } + if (start < end) { + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s + start, end - start, current_tag, NULL); + } +} + +void result_item_print_string_avrule(GtkTextBuffer * tb, GtkTextIter * iter, const char *s, unsigned int indent_level) +{ + const char *c, *next_c; + const char *tag = NULL, *init_tag; + unsigned int i; + static const char *indent = "\t"; + for (i = 0; i < indent_level; i++) { + gtk_text_buffer_insert(tb, iter, indent, -1); + } + for (c = s; *c && tag == NULL; c++) { + switch (*c) { + case '+': + { + tag = "added"; + break; + } + case '-': + { + tag = "removed"; + break; + } + case ' ': + case '\t': + case '\n': + { + break; + } + default: + { + tag = "modified"; + break; + } + } + } + init_tag = tag; + c = strchr(s, '{'); + assert(c != NULL); + /* advance past the opening brace (which designates start of + * the permissions list) and the following space character */ + c += 2; + gtk_text_buffer_insert_with_tags_by_name(tb, iter, s, c - s, init_tag, NULL); + while (*c != '}') { + assert(*c != '\0'); + next_c = strchr(c, ' '); + assert(next_c != NULL); + switch (*c) { + case '+': + { + tag = "added"; + break; + } + case '-': + { + tag = "removed"; + break; + } + default: + { + tag = init_tag; + } + } + gtk_text_buffer_insert_with_tags_by_name(tb, iter, c, next_c - c, tag, "inline-link", NULL); + gtk_text_buffer_insert_with_tags_by_name(tb, iter, " ", 1, init_tag, NULL); + /* advance past the space */ + c = next_c + 1; + } + gtk_text_buffer_insert_with_tags_by_name(tb, iter, c, -1, init_tag, NULL); +} + +void result_item_print_diff(result_item_t * item, GtkTextBuffer * tb, poldiff_form_e form) +{ + GtkTextIter iter; + const apol_vector_t *v; + size_t i; + void *elem; + char *s = NULL; + + gtk_text_buffer_get_end_iter(tb, &iter); + v = result_item_get_vector(item); + for (i = 0; i < apol_vector_get_size(v); i++) { + elem = apol_vector_get_element(v, i); + if (result_item_get_form(item, elem) == form) { + s = result_item_get_string(item, elem); + result_item_print_string(tb, &iter, s, 1); + free(s); + gtk_text_buffer_insert(tb, &iter, "\n", -1); + } + } +} + +void result_item_print_rule_diff(result_item_t * item, GtkTextBuffer * tb, poldiff_form_e form) +{ + GtkTextIter iter; + const apol_vector_t *v; + size_t i; + void *elem; + char *s = NULL; + + gtk_text_buffer_get_end_iter(tb, &iter); + v = result_item_get_vector(item); + for (i = 0; i < apol_vector_get_size(v); i++) { + elem = apol_vector_get_element(v, i); + if (result_item_get_form(item, elem) == form) { + s = result_item_get_string(item, elem); + if (form != POLDIFF_FORM_MODIFIED) { + result_item_print_string(tb, &iter, s, 1); + } else { + result_item_print_string_inline(tb, &iter, s, 1); + } + free(s); + gtk_text_buffer_insert(tb, &iter, "\n", -1); + } + } +} + +void result_item_print_summary(result_item_t * item, GtkTextBuffer * tb) +{ + GtkTextIter iter; + int i, forms[5]; + GString *string = g_string_new(""); + + gtk_text_buffer_get_end_iter(tb, &iter); + g_string_printf(string, "%s:\n", result_item_get_label(item)); + gtk_text_buffer_insert_with_tags_by_name(tb, &iter, string->str, -1, "subheader", NULL); + + int was_run = 0; + result_item_get_forms(item, forms); + for (i = 0; i < 5; i++) { + if (forms[i] > 0) { + g_string_printf(string, "\t%s: %zd\n", + form_name_long_map[i], result_item_get_num_differences(item, form_map[i])); + gtk_text_buffer_insert_with_tags_by_name(tb, &iter, string->str, -1, tag_map[i], NULL); + was_run = 1; + } + } + if (!was_run && result_item_is_supported(item)) { + gtk_text_buffer_set_text(tb, "This component has not yet been diffed.", -1); + } + g_string_free(string, TRUE); +} + +/** + * Show a common header when printing a policy component diff. + */ +void result_item_print_header(result_item_t * item, GtkTextBuffer * tb, poldiff_form_e form) +{ + GtkTextIter iter; + int i, forms[5]; + GString *string = g_string_new(""); + char *tag = NULL; + const char *label = result_item_get_label(item); + int add_separator = 0; + + gtk_text_buffer_get_end_iter(tb, &iter); + result_item_get_forms(item, forms); + g_string_printf(string, "%s (", label); + for (i = 0; i < 5; i++) { + if (forms[i] > 0) { + g_string_append_printf(string, "%s%zd %s", + (add_separator ? ", " : ""), + result_item_get_num_differences(item, form_map[i]), form_name_map[i]); + add_separator = 1; + } + } + g_string_append_printf(string, ")\n\n"); + gtk_text_buffer_insert_with_tags_by_name(tb, &iter, string->str, -1, "header", NULL); + + switch (form) { + case POLDIFF_FORM_ADDED: + { + g_string_printf(string, "Added %s:", label); + tag = "added-header"; + break; + } + case POLDIFF_FORM_ADD_TYPE: + { + g_string_printf(string, "Added %s because of new type:", label); + tag = "added-header"; + break; + } + case POLDIFF_FORM_REMOVED: + { + g_string_printf(string, "Removed %s:", label); + tag = "removed-header"; + break; + } + case POLDIFF_FORM_REMOVE_TYPE: + { + g_string_printf(string, "Removed %s because of missing type:", label); + tag = "removed-header"; + break; + } + case POLDIFF_FORM_MODIFIED: + { + g_string_printf(string, "Modified %s:", label); + tag = "modified-header"; + break; + } + default: + { + assert(0); + tag = NULL; + } + } + g_string_append_printf(string, " %zd\n", result_item_get_num_differences(item, form)); + gtk_text_buffer_insert_with_tags_by_name(tb, &iter, string->str, -1, tag, NULL); + g_string_free(string, TRUE); +} + +void result_item_print_linenos(GtkTextBuffer * tb, GtkTextIter * iter, + const gchar * prefix, const apol_vector_t * linenos, const gchar * tag, GString * string) +{ + size_t i; + unsigned long lineno; + gtk_text_buffer_insert(tb, iter, " [", -1); + if (prefix != NULL) { + gtk_text_buffer_insert(tb, iter, prefix, -1); + } + for (i = 0; i < apol_vector_get_size(linenos); i++) { + lineno = (unsigned long)apol_vector_get_element(linenos, i); + if (i > 0) { + gtk_text_buffer_insert(tb, iter, ", ", -1); + } + g_string_printf(string, "%lu", lineno); + gtk_text_buffer_insert_with_tags_by_name(tb, iter, string->str, -1, tag, NULL); + } + gtk_text_buffer_insert(tb, iter, "]", -1); +} + +void result_item_print_modified_range(result_item_t * item, const poldiff_range_t * range, GtkTextBuffer * tb, GtkTextIter * iter) +{ + poldiff_t *diff = result_item_get_diff(item); + char *orig_s = poldiff_range_to_string_brief(diff, range); + char *next_s = orig_s; + GString *string = g_string_new(""); + + /* first line should always be printed with normal font */ + char *s = strsep(&next_s, "\n"); + result_item_print_string(tb, iter, s, 1); + gtk_text_buffer_insert(tb, iter, "\n", -1); + + /* if the next line is minimum category set differences then + * display it */ + if (strncmp(next_s, " minimum categories:", strlen(" minimum categories:")) == 0) { + s = strsep(&next_s, "\n"); + result_item_print_string_inline(tb, iter, s, 1); + gtk_text_buffer_insert(tb, iter, "\n", -1); + } + /* all subsequent lines are printed as normal (yes, this + * discards lines from poldiff_range_to_string_brief() */ + free(orig_s); + apol_vector_t *levels = poldiff_range_get_levels(range); + size_t i; + for (i = 0; i < apol_vector_get_size(levels); i++) { + poldiff_level_t *l = apol_vector_get_element(levels, i); + s = poldiff_level_to_string_brief(diff, l); + g_string_printf(string, " %s", s); + if (poldiff_level_get_form(l) != POLDIFF_FORM_MODIFIED) { + result_item_print_string(tb, iter, string->str, 1); + } else { + result_item_print_string_inline(tb, iter, string->str, 1); + } + free(s); + } + g_string_free(string, TRUE); +} |