* plugins/build-basic-autotools/build-basic-autotools.c,
[anjuta-git-plugin.git] / plugins / valgrind / vgrule-editor.c
blob3e5cef36c79ab6820da502c5bced426cd07ee955
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2003 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
36 #include <glib/gi18n.h>
38 #include "vgrule-editor.h"
41 static void vg_rule_editor_class_init (VgRuleEditorClass *klass);
42 static void vg_rule_editor_init (VgRuleEditor *editor);
43 static void vg_rule_editor_destroy (GtkObject *obj);
44 static void vg_rule_editor_finalize (GObject *obj);
47 static GtkVBoxClass *parent_class = NULL;
50 GType
51 vg_rule_editor_get_type (void)
53 static GType type = 0;
55 if (!type) {
56 static const GTypeInfo info = {
57 sizeof (VgRuleEditorClass),
58 NULL, /* base_class_init */
59 NULL, /* base_class_finalize */
60 (GClassInitFunc) vg_rule_editor_class_init,
61 NULL, /* class_finalize */
62 NULL, /* class_data */
63 sizeof (VgRuleEditor),
64 0, /* n_preallocs */
65 NULL /*(GInstanceInitFunc) vg_rule_editor_init*/,
68 type = g_type_register_static (GTK_TYPE_VBOX, "VgRuleEditor", &info, 0);
71 return type;
74 static void
75 vg_rule_editor_class_init (VgRuleEditorClass *klass)
77 GObjectClass *object_class = G_OBJECT_CLASS (klass);
78 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
80 parent_class = g_type_class_ref (GTK_TYPE_VBOX);
82 object_class->finalize = vg_rule_editor_finalize;
83 gtk_object_class->destroy = vg_rule_editor_destroy;
87 static void
88 type_menu_changed (GtkMenuItem *item, gpointer user_data)
90 VgRuleEditor *editor = user_data;
91 vgrule_t type;
93 type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "vgrule_t"));
95 gtk_widget_set_sensitive (GTK_WIDGET (editor->syscall), type == VG_RULE_PARAM);
98 static GtkWidget *
99 rule_type_menu_new (VgRuleEditor *editor)
101 GtkWidget *omenu, *menu, *item;
102 int i;
104 omenu = gtk_option_menu_new ();
105 menu = gtk_menu_new ();
107 for (i = 0; i < VG_RULE_LAST; i++) {
108 item = gtk_menu_item_new_with_label (vg_rule_type_to_name (i));
109 g_object_set_data (G_OBJECT (item), "vgrule_t", GINT_TO_POINTER (i));
110 g_signal_connect (item, "activate", G_CALLBACK (type_menu_changed), editor);
111 gtk_widget_show (item);
112 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
113 editor->types[i] = item;
116 gtk_widget_show (menu);
117 gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
119 return omenu;
122 static GtkWidget *
123 call_stack_frame_new (vgcaller_t type, const char *name)
125 GtkWidget *hbox, *omenu, *entry;
126 GtkWidget *menu, *item;
128 hbox = gtk_hbox_new (FALSE, 6);
130 omenu = gtk_option_menu_new ();
131 menu = gtk_menu_new ();
133 item = gtk_menu_item_new_with_label (_("Function"));
134 gtk_widget_show (item);
135 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
136 g_object_set_data (G_OBJECT (item), "vgcaller_t", GINT_TO_POINTER (VG_CALLER_FUNCTION));
138 item = gtk_menu_item_new_with_label (_("Shared Object"));
139 gtk_widget_show (item);
140 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
141 g_object_set_data (G_OBJECT (item), "vgcaller_t", GINT_TO_POINTER (VG_CALLER_OBJECT));
143 gtk_widget_show (menu);
144 gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
145 gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), (int) type);
147 gtk_widget_show (omenu);
148 gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 0);
150 entry = gtk_entry_new ();
151 gtk_entry_set_text (GTK_ENTRY (entry), name ? name : "");
152 gtk_widget_show (entry);
153 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
155 g_object_set_data (G_OBJECT (hbox), "omenu", omenu);
156 g_object_set_data (G_OBJECT (hbox), "entry", entry);
158 return hbox;
161 static void
162 grow_cb (GtkButton *button, VgRuleEditor *editor)
164 GtkWidget *caller;
165 int len;
167 len = editor->callers->len;
168 caller = call_stack_frame_new (0, NULL);
169 g_ptr_array_add (editor->callers, caller);
170 gtk_widget_show (caller);
171 gtk_box_pack_start (editor->call_stack, caller, FALSE, FALSE, 0);
174 static void
175 shrink_cb (GtkButton *button, VgRuleEditor *editor)
177 int i;
179 if (editor->callers->len == 1)
180 return;
182 i = editor->callers->len - 1;
183 gtk_widget_destroy (editor->callers->pdata[i]);
184 g_ptr_array_remove_index (editor->callers, editor->callers->len - 1);
187 static GtkWidget *
188 call_stack_new (VgRuleEditor *editor)
190 GtkWidget *vbox, *hbox, *button;
191 GtkWidget *widget;
192 int i;
194 vbox = gtk_vbox_new (FALSE, 3);
196 hbox = gtk_hbox_new (FALSE, 6);
197 button = gtk_button_new_with_label (_("Grow"));
198 gtk_widget_show (button);
199 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
200 g_signal_connect (button, "clicked", G_CALLBACK (grow_cb), editor);
201 button = gtk_button_new_with_label (_("Shrink"));
202 gtk_widget_show (button);
203 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
204 g_signal_connect (button, "clicked", G_CALLBACK (shrink_cb), editor);
205 gtk_widget_show (hbox);
206 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
208 for (i = 0; i < editor->callers->len; i++) {
209 widget = editor->callers->pdata[i];
210 gtk_widget_show (widget);
211 gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
214 return vbox;
217 static void
218 vg_rule_editor_init (VgRuleEditor *editor)
220 GtkWidget *vbox, *hbox, *label;
221 GtkWidget *widget;
223 vbox = GTK_WIDGET (editor);
224 gtk_box_set_spacing (GTK_BOX (vbox), 6);
226 hbox = gtk_hbox_new (FALSE, 6);
227 label = gtk_label_new (_("Rule name:"));
228 gtk_widget_show (label);
229 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
230 editor->name = GTK_ENTRY (widget = gtk_entry_new ());
231 gtk_widget_show (widget);
232 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
233 gtk_widget_show (hbox);
234 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
236 hbox = gtk_hbox_new (FALSE, 6);
237 label = gtk_label_new (_("Suppress messages of type:"));
238 gtk_widget_show (label);
239 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
240 editor->type = GTK_OPTION_MENU (widget = rule_type_menu_new (editor));
241 gtk_widget_show (widget);
242 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
243 gtk_widget_show (hbox);
244 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
246 hbox = gtk_hbox_new (FALSE, 6);
247 label = gtk_label_new (_("Suppress when using:"));
248 gtk_widget_show (label);
249 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
250 editor->addrcheck = GTK_TOGGLE_BUTTON (widget = gtk_check_button_new_with_label ("Addrcheck"));
251 gtk_widget_show (widget);
252 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
253 editor->memcheck = GTK_TOGGLE_BUTTON (widget = gtk_check_button_new_with_label ("Memcheck"));
254 gtk_widget_show (widget);
255 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
256 gtk_widget_show (hbox);
257 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
259 hbox = gtk_hbox_new (FALSE, 6);
260 label = gtk_label_new (_("System call:"));
261 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
262 gtk_widget_show (label);
263 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
264 editor->syscall = GTK_ENTRY (widget = gtk_entry_new ());
265 gtk_widget_show (widget);
266 gtk_widget_set_sensitive (widget, FALSE);
267 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
268 gtk_widget_show (hbox);
269 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
271 label = gtk_label_new (_("Call chain:"));
272 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
273 gtk_widget_show (label);
274 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
276 /*editor->callers = g_ptr_array_new ();
277 g_ptr_array_add (editor->callers, call_stack_frame_new (0, NULL));*/
279 editor->call_stack = GTK_BOX (widget = call_stack_new (editor));
280 gtk_widget_show (widget);
281 gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
284 static void
285 vg_rule_editor_finalize (GObject *obj)
287 G_OBJECT_CLASS (parent_class)->finalize (obj);
290 static void
291 vg_rule_editor_destroy (GtkObject *obj)
293 GTK_OBJECT_CLASS (parent_class)->destroy (obj);
297 GtkWidget *
298 vg_rule_editor_new (void)
300 VgRuleEditor *editor;
302 editor = g_object_new (VG_TYPE_RULE_EDITOR, NULL);
303 editor->callers = g_ptr_array_new ();
304 g_ptr_array_add (editor->callers, call_stack_frame_new (0, NULL));
306 vg_rule_editor_init (editor);
308 gtk_toggle_button_set_active (editor->addrcheck, TRUE);
309 gtk_toggle_button_set_active (editor->memcheck, TRUE);
311 return GTK_WIDGET (editor);
315 GtkWidget *
316 vg_rule_editor_new_from_rule (VgRule *rule)
318 VgRuleEditor *editor;
319 VgCaller *caller;
320 VgTool *tool;
322 editor = g_object_new (VG_TYPE_RULE_EDITOR, NULL);
323 editor->callers = g_ptr_array_new ();
325 caller = rule->callers;
326 while (caller != NULL) {
327 g_ptr_array_add (editor->callers, call_stack_frame_new (caller->type, caller->name));
329 caller = caller->next;
332 if (editor->callers->len == 0)
333 g_ptr_array_add (editor->callers, call_stack_frame_new (0, NULL));
335 vg_rule_editor_init (editor);
337 vg_rule_editor_set_type (editor, rule->type);
338 vg_rule_editor_set_name (editor, rule->name);
339 vg_rule_editor_set_syscall (editor, rule->syscall);
341 tool = rule->tools;
342 while (tool != NULL) {
343 if (!strcasecmp (tool->name, "core")) {
344 /* special case... */
345 g_object_set_data (G_OBJECT (editor), "core", GINT_TO_POINTER (TRUE));
346 } else if (!strcasecmp (tool->name, "Addrcheck")) {
347 gtk_toggle_button_set_active (editor->addrcheck, TRUE);
348 } else if (!strcasecmp (tool->name, "Memcheck")) {
349 gtk_toggle_button_set_active (editor->memcheck, TRUE);
352 tool = tool->next;
355 return GTK_WIDGET (editor);
359 GtkWidget *
360 vg_rule_editor_new_from_summary (VgErrorSummary *summary)
362 VgRuleEditor *editor;
363 VgErrorStack *stack;
364 GString *rule_name;
365 vgrule_t rtype;
366 char *syscall;
368 editor = g_object_new (VG_TYPE_RULE_EDITOR, NULL);
369 editor->callers = g_ptr_array_new ();
371 rule_name = g_string_new ("");
373 stack = summary->frames;
374 while (stack != NULL) {
375 const char *name = NULL;
376 const char *basename;
377 vgcaller_t ctype = 0;
379 /* if we can get a symbol, use it - otherwise try and use the shared object */
380 if (stack->symbol) {
381 name = stack->symbol;
382 ctype = VG_CALLER_FUNCTION;
383 g_string_append (rule_name, name);
384 } else if (stack->type == VG_STACK_OBJECT) {
385 name = stack->info.object;
386 ctype = VG_CALLER_OBJECT;
388 if (!(basename = strrchr (name, '/')))
389 basename = name;
390 else
391 basename++;
393 g_string_append (rule_name, basename);
396 if (stack->next)
397 g_string_append_c (rule_name, '/');
399 g_ptr_array_add (editor->callers, call_stack_frame_new (ctype, name));
401 stack = stack->next;
404 if (editor->callers->len == 0)
405 g_ptr_array_add (editor->callers, call_stack_frame_new (0, NULL));
407 vg_rule_editor_init (editor);
409 gtk_toggle_button_set_active (editor->addrcheck, TRUE);
410 gtk_toggle_button_set_active (editor->memcheck, TRUE);
412 syscall = NULL;
413 if (vg_rule_type_from_report (summary->report, &rtype, &syscall)) {
414 vg_rule_editor_set_type (editor, rtype);
415 if (syscall != NULL) {
416 vg_rule_editor_set_syscall (editor, syscall);
417 g_free (syscall);
420 g_string_append_c (rule_name, '(');
421 g_string_append (rule_name, vg_rule_type_to_name (rtype));
422 g_string_append_c (rule_name, ')');
425 vg_rule_editor_set_name (editor, rule_name->str);
426 g_string_free (rule_name, TRUE);
428 return GTK_WIDGET (editor);
432 const char *
433 vg_rule_editor_get_name (VgRuleEditor *editor)
435 return gtk_entry_get_text (editor->name);
438 void
439 vg_rule_editor_set_name (VgRuleEditor *editor, const char *name)
441 gtk_entry_set_text (editor->name, name ? name : "");
444 void
445 vg_rule_editor_set_type (VgRuleEditor *editor, vgrule_t type)
447 gtk_option_menu_set_history (editor->type, (int) type);
448 g_signal_emit_by_name (editor->types[type], "activate", editor);
451 void
452 vg_rule_editor_set_syscall (VgRuleEditor *editor, const char *syscall)
454 gtk_entry_set_text (editor->syscall, syscall ? syscall : "");
457 void
458 vg_rule_editor_add_caller (VgRuleEditor *editor, vgcaller_t type, const char *name)
460 GtkWidget *caller;
461 int len;
463 len = editor->callers->len;
464 caller = call_stack_frame_new (0, NULL);
465 g_ptr_array_add (editor->callers, caller);
466 gtk_widget_show (caller);
467 gtk_box_pack_start (editor->call_stack, caller, FALSE, FALSE, 0);
470 VgRule *
471 vg_rule_editor_get_rule (VgRuleEditor *editor)
473 GtkWidget *omenu, *entry;
474 VgCaller *caller, *tail;
475 const char *name;
476 VgRule *rule;
477 int type, i;
479 name = gtk_entry_get_text (editor->name);
480 type = gtk_option_menu_get_history (editor->type);
481 rule = vg_rule_new (type, name);
483 if (type == VG_RULE_PARAM)
484 rule->syscall = g_strdup (gtk_entry_get_text (editor->syscall));
486 if (gtk_toggle_button_get_active (editor->addrcheck))
487 vg_rule_add_tool (rule, "Addrcheck");
489 if (gtk_toggle_button_get_active (editor->memcheck))
490 vg_rule_add_tool (rule, "Memcheck");
492 if (!rule->tools && g_object_get_data (G_OBJECT (editor), "core")) {
493 /* this means we are editing a valgrind 1.9.x versioned supp file
494 which needs at least 1 'tool' specified to suppress */
495 vg_rule_add_tool (rule, "core");
498 tail = (VgCaller *) &rule->callers;
500 for (i = 0; i < editor->callers->len; i++) {
501 omenu = g_object_get_data (G_OBJECT (editor->callers->pdata[i]), "omenu");
502 entry = g_object_get_data (G_OBJECT (editor->callers->pdata[i]), "entry");
504 name = gtk_entry_get_text (GTK_ENTRY (entry));
505 type = gtk_option_menu_get_history (GTK_OPTION_MENU (omenu));
507 caller = vg_caller_new (type, name);
508 tail->next = caller;
509 tail = caller;
512 return rule;
515 void
516 vg_rule_editor_save (VgRuleEditor *editor, const char *filename)
518 GtkWindow *parent;
519 GtkWidget *dialog;
520 VgRule *rule;
521 off_t offset;
522 int fd;
524 parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor)));
526 if ((fd = open (filename, O_WRONLY | O_APPEND, 0666)) == -1) {
527 dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
528 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
529 _("Error saving to suppression file '%s': %s"),
530 filename, g_strerror (errno));
531 gtk_dialog_run (GTK_DIALOG (dialog));
532 gtk_widget_destroy (dialog);
533 return;
536 rule = vg_rule_editor_get_rule (editor);
538 /* find out where we currently are */
539 offset = lseek (fd, 0, SEEK_END);
541 if (vg_suppressions_file_append_rule (fd, rule) == -1 || fsync (fd) == -1) {
542 dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
543 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
544 _("Error saving to suppression file '%s': %s"),
545 filename, g_strerror (errno));
546 gtk_dialog_run (GTK_DIALOG (dialog));
547 gtk_widget_destroy (dialog);
549 ftruncate (fd, offset);
552 vg_rule_free (rule);
554 close (fd);