1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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.
31 #include <sys/types.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
;
51 vg_rule_editor_get_type (void)
53 static GType type
= 0;
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
),
65 NULL
/*(GInstanceInitFunc) vg_rule_editor_init*/,
68 type
= g_type_register_static (GTK_TYPE_VBOX
, "VgRuleEditor", &info
, 0);
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
;
88 type_menu_changed (GtkMenuItem
*item
, gpointer user_data
)
90 VgRuleEditor
*editor
= user_data
;
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
);
99 rule_type_menu_new (VgRuleEditor
*editor
)
101 GtkWidget
*omenu
, *menu
, *item
;
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
);
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
);
162 grow_cb (GtkButton
*button
, VgRuleEditor
*editor
)
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);
175 shrink_cb (GtkButton
*button
, VgRuleEditor
*editor
)
179 if (editor
->callers
->len
== 1)
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);
188 call_stack_new (VgRuleEditor
*editor
)
190 GtkWidget
*vbox
, *hbox
, *button
;
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);
218 vg_rule_editor_init (VgRuleEditor
*editor
)
220 GtkWidget
*vbox
, *hbox
, *label
;
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);
285 vg_rule_editor_finalize (GObject
*obj
)
287 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
291 vg_rule_editor_destroy (GtkObject
*obj
)
293 GTK_OBJECT_CLASS (parent_class
)->destroy (obj
);
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
);
316 vg_rule_editor_new_from_rule (VgRule
*rule
)
318 VgRuleEditor
*editor
;
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
);
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
);
355 return GTK_WIDGET (editor
);
360 vg_rule_editor_new_from_summary (VgErrorSummary
*summary
)
362 VgRuleEditor
*editor
;
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 */
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
, '/')))
393 g_string_append (rule_name
, basename
);
397 g_string_append_c (rule_name
, '/');
399 g_ptr_array_add (editor
->callers
, call_stack_frame_new (ctype
, name
));
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
);
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
);
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
);
433 vg_rule_editor_get_name (VgRuleEditor
*editor
)
435 return gtk_entry_get_text (editor
->name
);
439 vg_rule_editor_set_name (VgRuleEditor
*editor
, const char *name
)
441 gtk_entry_set_text (editor
->name
, name
? name
: "");
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
);
452 vg_rule_editor_set_syscall (VgRuleEditor
*editor
, const char *syscall
)
454 gtk_entry_set_text (editor
->syscall
, syscall
? syscall
: "");
458 vg_rule_editor_add_caller (VgRuleEditor
*editor
, vgcaller_t type
, const char *name
)
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);
471 vg_rule_editor_get_rule (VgRuleEditor
*editor
)
473 GtkWidget
*omenu
, *entry
;
474 VgCaller
*caller
, *tail
;
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
);
516 vg_rule_editor_save (VgRuleEditor
*editor
, const char *filename
)
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
);
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
);