1 /*
2  *  local.c
3  *
4  *  Copyright 2012 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <string.h>
21 
22 #include "common.h"
23 
24 enum
25 {
26 	LOCAL_NAME,
27 	LOCAL_DISPLAY,
28 	LOCAL_VALUE,
29 	LOCAL_HB_MODE,
30 	LOCAL_MR_MODE,
31 	LOCAL_ARG1
32 };
33 
34 static ScpTreeStore *store;
35 static GtkTreeSelection *selection;
36 
on_local_display_edited(G_GNUC_UNUSED GtkCellRendererText * renderer,gchar * path_str,gchar * new_text,G_GNUC_UNUSED gpointer gdata)37 static void on_local_display_edited(G_GNUC_UNUSED GtkCellRendererText *renderer,
38 	gchar *path_str, gchar *new_text, G_GNUC_UNUSED gpointer gdata)
39 {
40 	view_display_edited(store, thread_state >= THREAD_STOPPED && frame_id, path_str,
41 		"07-gdb-set var %s=%s", new_text);
42 }
43 
44 static const TreeCell local_cells[] =
45 {
46 	{ "local_display", G_CALLBACK(on_local_display_edited) },
47 	{ NULL, NULL }
48 };
49 
50 typedef struct _LocalData
51 {
52 	char *name;
53 	gboolean entry;
54 } LocalData;
55 
local_node_variable(const ParseNode * node,const LocalData * ld)56 static void local_node_variable(const ParseNode *node, const LocalData *ld)
57 {
58 	iff (node->type == PT_ARRAY, "variables: contains value")
59 	{
60 		GArray *nodes = (GArray *) node->value;
61 		ParseVariable var;
62 
63 		if (parse_variable(nodes, &var, NULL))
64 		{
65 			GtkTreeIter iter;
66 			const char *arg1 = parse_find_value(nodes, "arg");
67 
68 			if (!arg1 || ld->entry || !g_str_has_suffix(var.name, "@entry"))
69 			{
70 				scp_tree_store_append_with_values(store, &iter, NULL, LOCAL_NAME,
71 					var.name, LOCAL_DISPLAY, var.display, LOCAL_VALUE, var.value,
72 					LOCAL_HB_MODE, var.hb_mode, LOCAL_MR_MODE, var.mr_mode,
73 					LOCAL_ARG1, arg1, -1);
74 
75 				if (!g_strcmp0(var.name, ld->name))
76 					gtk_tree_selection_select_iter(selection, &iter);
77 			}
78 			parse_variable_free(&var);
79 		}
80 	}
81 }
82 
on_local_variables(GArray * nodes)83 void on_local_variables(GArray *nodes)
84 {
85 	if (utils_matches_frame(parse_grab_token(nodes)))
86 	{
87 		GtkTreeIter iter;
88 		LocalData ld = { NULL, stack_entry() };
89 
90 		if (gtk_tree_selection_get_selected(selection, NULL, &iter))
91 			gtk_tree_model_get((GtkTreeModel *) store, &iter, LOCAL_NAME, &ld.name, -1);
92 
93 		locals_clear();
94 		parse_foreach(parse_lead_array(nodes), (GFunc) local_node_variable, &ld);
95 		g_free(ld.name);
96 	}
97 }
98 
locals_clear(void)99 void locals_clear(void)
100 {
101 	store_clear(store);
102 }
103 
locals_send_update(char token)104 static void locals_send_update(char token)
105 {
106 	debug_send_format(F, "0%c%c%s%s-stack-list-variables 1", token, FRAME_ARGS);
107 }
108 
locals_update(void)109 gboolean locals_update(void)
110 {
111 	if (view_stack_update())
112 		return FALSE;
113 
114 	if (frame_id)
115 		locals_send_update('4');
116 	else
117 		locals_clear();
118 
119 	return TRUE;
120 }
121 
122 static GObject *local_display;
123 
locals_update_state(DebugState state)124 void locals_update_state(DebugState state)
125 {
126 	g_object_set(local_display, "editable", (state & DS_DEBUG) != 0, NULL);
127 }
128 
on_local_refresh(G_GNUC_UNUSED const MenuItem * menu_item)129 static void on_local_refresh(G_GNUC_UNUSED const MenuItem *menu_item)
130 {
131 	locals_send_update('2');
132 }
133 
on_local_unsorted(G_GNUC_UNUSED const MenuItem * menu_item)134 static void on_local_unsorted(G_GNUC_UNUSED const MenuItem *menu_item)
135 {
136 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
137 		GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
138 }
139 
on_local_copy(const MenuItem * menu_item)140 static void on_local_copy(const MenuItem *menu_item)
141 {
142 	menu_copy(selection, menu_item);
143 }
144 
on_local_modify(const MenuItem * menu_item)145 static void on_local_modify(const MenuItem *menu_item)
146 {
147 	menu_modify(selection, menu_item);
148 }
149 
on_local_watch(G_GNUC_UNUSED const MenuItem * menu_item)150 static void on_local_watch(G_GNUC_UNUSED const MenuItem *menu_item)
151 {
152 	GtkTreeIter iter;
153 	const char *name;
154 
155 	if (gtk_tree_selection_get_selected(selection, NULL, &iter))
156 	{
157 		scp_tree_store_get(store, &iter, LOCAL_NAME, &name, -1);
158 		watch_add(name);
159 	}
160 }
161 
on_local_inspect(G_GNUC_UNUSED const MenuItem * menu_item)162 static void on_local_inspect(G_GNUC_UNUSED const MenuItem *menu_item)
163 {
164 	menu_inspect(selection);
165 }
166 
on_local_hbit_display(const MenuItem * menu_item)167 static void on_local_hbit_display(const MenuItem *menu_item)
168 {
169 	menu_hbit_display(selection, menu_item);
170 }
171 
on_local_hbit_update(const MenuItem * menu_item)172 static void on_local_hbit_update(const MenuItem *menu_item)
173 {
174 	menu_hbit_update(selection, menu_item);
175 }
176 
on_local_mr_mode(const MenuItem * menu_item)177 static void on_local_mr_mode(const MenuItem *menu_item)
178 {
179 	menu_mber_update(selection, menu_item);
180 }
181 
182 #define DS_FRESHABLE (DS_DEBUG | DS_EXTRA_2)
183 #define DS_COPYABLE (DS_BASICS | DS_EXTRA_1)
184 #define DS_MODIFYABLE (DS_DEBUG | DS_EXTRA_1)
185 #define DS_WATCHABLE (DS_BASICS | DS_EXTRA_1)
186 #define DS_INSPECTABLE (DS_NOT_BUSY | DS_EXTRA_1)
187 #define DS_REPARSABLE (DS_BASICS | DS_EXTRA_1)
188 
189 static MenuItem local_menu_items[] =
190 {
191 	{ "local_refresh",    on_local_refresh,  DS_FRESHABLE,   NULL, NULL },
192 	{ "local_unsorted",   on_local_unsorted, 0,              NULL, NULL },
193 	{ "local_copy",       on_local_copy,     DS_COPYABLE,    NULL, NULL },
194 	{ "local_modify",     on_local_modify,   DS_MODIFYABLE,  NULL, NULL },
195 	{ "local_watch",      on_local_watch,    DS_WATCHABLE,   NULL, NULL },
196 	{ "local_inspect",    on_local_inspect,  DS_INSPECTABLE, NULL, NULL },
197 	MENU_HBIT_ITEMS(local),
198 	{ "local_mr_mode",    on_local_mr_mode,  DS_REPARSABLE,  NULL, NULL },
199 	{ NULL, NULL, 0, NULL, NULL }
200 };
201 
local_menu_extra_state(void)202 static guint local_menu_extra_state(void)
203 {
204 	return (gtk_tree_selection_get_selected(selection, NULL, NULL) << DS_INDEX_1) |
205 		((frame_id != NULL) << DS_INDEX_2);
206 }
207 
208 static MenuInfo local_menu_info = { local_menu_items, local_menu_extra_state, 0 };
209 
on_local_menu_show(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED gpointer gdata)210 static void on_local_menu_show(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer gdata)
211 {
212 	menu_mber_display(selection, menu_item_find(local_menu_items, "local_mr_mode"));
213 }
214 
on_local_modify_button_release(GtkWidget * widget,GdkEventButton * event,GtkWidget * menu)215 static void on_local_modify_button_release(GtkWidget *widget, GdkEventButton *event,
216 	GtkWidget *menu)
217 {
218 	menu_shift_button_release(widget, event, menu, on_local_modify);
219 }
220 
on_local_mr_mode_button_release(GtkWidget * widget,GdkEventButton * event,GtkWidget * menu)221 static void on_local_mr_mode_button_release(GtkWidget *widget, GdkEventButton *event,
222 	GtkWidget *menu)
223 {
224 	menu_mber_button_release(selection, widget, event, menu);
225 }
226 
local_init(void)227 void local_init(void)
228 {
229 	GtkWidget *menu;
230 
231 	view_connect("local_view", &store, &selection, local_cells, "local_window",
232 		&local_display);
233 	menu = menu_select("local_menu", &local_menu_info, selection);
234 
235 	g_signal_connect(menu, "show", G_CALLBACK(on_local_menu_show), NULL);
236 	g_signal_connect(get_widget("local_modify"), "button-release-event",
237 		G_CALLBACK(on_local_modify_button_release), menu);
238 	g_signal_connect(get_widget("local_mr_mode"), "button-release-event",
239 		G_CALLBACK(on_local_mr_mode_button_release), menu);
240 }
241