debugger: switched advanded UI off by default, and implemented certain changes asked...
[deliverable/titan.core.git] / core / DebuggerUI.cc
CommitLineData
f08ff9ca
BB
1/******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *
10 * Baranyi, Botond – initial implementation
11 *
12 ******************************************************************************/
13
14#include "DebuggerUI.hh"
15#include "DebugCommands.hh"
16#include "Debugger.hh"
f08ff9ca
BB
17#include <stdio.h>
18#include <ctype.h>
19
5ea46818
BB
20#ifdef ADVANCED_DEBUGGER_UI
21#include "../mctr2/editline/libedit/src/editline/readline.h"
22// use a different file, than the MCTR CLI, since not all commands are the same
23#define TTCN3_HISTORY_FILENAME ".ttcn3_history_single"
24#endif
25
f08ff9ca
BB
26#define PROMPT_TEXT "DEBUG> "
27#define BATCH_TEXT "batch"
f57971fe 28#define HELP_TEXT "help"
f08ff9ca 29
f08ff9ca
BB
30const TTCN_Debugger_UI::command_t TTCN_Debugger_UI::debug_command_list[] = {
31 { D_SWITCH_TEXT, D_SWITCH, D_SWITCH_TEXT " on|off",
32 "Switch the debugger on or off." },
33 { D_SET_BREAKPOINT_TEXT, D_SET_BREAKPOINT,
34 D_SET_BREAKPOINT_TEXT " <module> <line> [<batch_file>]",
35 "Add a breakpoint at the specified location, or change the batch file of "
f57971fe 36 "an existing breakpoint." },
f08ff9ca
BB
37 { D_REMOVE_BREAKPOINT_TEXT, D_REMOVE_BREAKPOINT,
38 D_REMOVE_BREAKPOINT_TEXT " all|<module> [all|<line>]", "Remove a breakpoint, "
39 "or all breakpoints from a module, or all breakpoints from all modules." },
40 { D_SET_AUTOMATIC_BREAKPOINT_TEXT, D_SET_AUTOMATIC_BREAKPOINT,
41 D_SET_AUTOMATIC_BREAKPOINT_TEXT " error|fail on|off [<batch_file>]",
42 "Switch an automatic breakpoint (truggered by an event) on or off, and/or "
43 "change its batch file." },
44 { D_SET_OUTPUT_TEXT, D_SET_OUTPUT,
45 D_SET_OUTPUT_TEXT " console|file|both [file_name]",
46 "Set the output of the debugger." },
47 { D_SET_GLOBAL_BATCH_FILE_TEXT, D_SET_GLOBAL_BATCH_FILE,
48 D_SET_GLOBAL_BATCH_FILE_TEXT " on|off [batch_file_name]",
49 "Set whether a batch file should be executed automatically when test execution "
50 "is halted (breakpoint-specific batch files override this setting)." },
1cb5b229
BB
51 { D_PRINT_SETTINGS_TEXT, D_PRINT_SETTINGS, D_PRINT_SETTINGS_TEXT,
52 "Prints the debugger's settings." },
f08ff9ca
BB
53 { D_PRINT_CALL_STACK_TEXT, D_PRINT_CALL_STACK, D_PRINT_CALL_STACK_TEXT,
54 "Print call stack." },
55 { D_SET_STACK_LEVEL_TEXT, D_SET_STACK_LEVEL, D_SET_STACK_LEVEL_TEXT " <level>",
56 "Set the stack level to print debug information from." },
57 { D_LIST_VARIABLES_TEXT, D_LIST_VARIABLES,
58 D_LIST_VARIABLES_TEXT " local|global|comp|all [pattern]",
59 "List variable names." },
60 { D_PRINT_VARIABLE_TEXT, D_PRINT_VARIABLE,
61 D_PRINT_VARIABLE_TEXT " <variable_name>|$ [{ <variable_name>|$}]",
62 "Print current value of one or more variables ('$' is substituted with the "
63 "result of the last " D_LIST_VARIABLES_TEXT " command)." },
64 { D_OVERWRITE_VARIABLE_TEXT, D_OVERWRITE_VARIABLE,
65 D_OVERWRITE_VARIABLE_TEXT " <variable_name> <value>",
66 "Overwrite the current value of a variable." },
67 { D_PRINT_SNAPSHOTS_TEXT, D_PRINT_SNAPSHOTS, D_PRINT_SNAPSHOTS_TEXT,
68 "Print snapshots of function calls until this point." },
69 // D_SET_SNAPSHOT_BEHAVIOR_TEXT
70 { D_STEP_OVER_TEXT, D_STEP_OVER, D_STEP_OVER_TEXT,
71 "Resume test execution until the next line of code (in this function or the "
72 "caller function)." },
73 { D_STEP_INTO_TEXT, D_STEP_INTO, D_STEP_INTO_TEXT,
74 "Resume test execution until the next line of code (on any stack level)." },
75 { D_STEP_OUT_TEXT, D_STEP_OUT, D_STEP_OUT_TEXT,
76 "Resume test execution until the next line of code in the caller function." },
77 { D_RUN_TO_CURSOR_TEXT, D_RUN_TO_CURSOR, D_RUN_TO_CURSOR_TEXT " <module> <line>",
78 "Resume test execution until the specified location." },
79 { D_HALT_TEXT, D_HALT, D_HALT_TEXT, "Halt test execution." },
80 { D_CONTINUE_TEXT, D_CONTINUE, D_CONTINUE_TEXT, "Resume halted test execution." },
81 { D_EXIT_TEXT, D_EXIT, D_EXIT_TEXT " test|all",
82 "Exit the current test or the execution of all tests." },
83 { NULL, D_ERROR, NULL, NULL }
84};
85
5ea46818 86#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca 87char* TTCN_Debugger_UI::ttcn3_history_filename = NULL;
5ea46818 88#endif
f08ff9ca
BB
89
90/** local function for extracting the command name and its arguments from an
91 * input line
92 * @param arguments [in] input line
93 * @param len [in] length of the input line
94 * @param start [in] indicates the position to start searching from
95 * @param start [out] the next argument's start position (set to len if no further
96 * arguments were found)
97 * @param end [out] the position of the first character after the next argument */
98static void get_next_argument_loc(const char* arguments, size_t len, size_t& start, size_t& end)
99{
100 while (start < len && isspace(arguments[start])) {
101 ++start;
102 }
103 end = start;
104 while (end < len && !isspace(arguments[end])) {
105 ++end;
106 }
107}
108
109void TTCN_Debugger_UI::process_command(const char* p_line_read)
110{
111 // locate the command text
112 size_t len = strlen(p_line_read);
113 size_t start = 0;
114 size_t end = 0;
115 get_next_argument_loc(p_line_read, len, start, end);
116 if (start == len) {
117 // empty command
118 return;
119 }
5ea46818 120#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca 121 add_history(p_line_read + start);
5ea46818 122#endif
f08ff9ca
BB
123 for (const command_t *command = debug_command_list; command->name != NULL;
124 ++command) {
125 if (!strncmp(p_line_read + start, command->name, end - start)) {
126 // count the arguments
127 int argument_count = 0;
128 size_t start_tmp = start;
129 size_t end_tmp = end;
130 while (start_tmp < len) {
131 start_tmp = end_tmp;
132 get_next_argument_loc(p_line_read, len, start_tmp, end_tmp);
133 if (start_tmp < len) {
134 ++argument_count;
135 }
136 }
137 // extract the arguments into a string array
138 char** arguments;
139 if (argument_count > 0) {
140 arguments = new char*[argument_count];
141 for (int i = 0; i < argument_count; ++i) {
142 start = end;
143 get_next_argument_loc(p_line_read, len, start, end);
144 arguments[i] = mcopystrn(p_line_read + start, end - start);
145 }
146 }
147 else {
148 arguments = NULL;
149 }
150 ttcn3_debugger.execute_command(command->commandID, argument_count, arguments);
151 if (argument_count > 0) {
152 for (int i = 0; i < argument_count; ++i) {
153 Free(arguments[i]);
154 }
155 delete [] arguments;
156 }
157 return;
158 }
159 }
160 if (!strncmp(p_line_read + start, BATCH_TEXT, end - start)) {
161 start = end;
162 get_next_argument_loc(p_line_read, len, start, end); // just to skip to the argument
163 // the entire argument list is treated as one file name (even if it contains spaces)
164 execute_batch_file(p_line_read + start);
165 return;
166 }
f57971fe
BB
167 if (!strncmp(p_line_read + start, HELP_TEXT, end - start)) {
168 start = end;
169 get_next_argument_loc(p_line_read, len, start, end); // just to skip to the argument
170 help(p_line_read + start);
171 return;
172 }
f08ff9ca
BB
173 puts("Unknown command, try again...");
174}
175
f57971fe
BB
176void TTCN_Debugger_UI::help(const char* p_argument)
177{
178 if (*p_argument == 0) {
179 puts("Help is available for the following commands:");
180 printf(BATCH_TEXT);
181 for (const command_t *command = debug_command_list;
182 command->name != NULL; command++) {
183 printf(" %s", command->name);
184 }
185 putchar('\n');
186 }
187 else {
188 for (const command_t *command = debug_command_list;
189 command->name != NULL; command++) {
190 if (!strncmp(p_argument, command->name, strlen(command->name))) {
191 printf("%s usage: %s\n%s\n", command->name, command->synopsis,
192 command->description);
193 return;
194 }
195 }
196 if (!strcmp(p_argument, BATCH_TEXT)) {
197 puts(BATCH_TEXT " usage: " BATCH_TEXT "\nRun commands from batch file.");
198 }
199 else {
200 printf("No help for %s.\n", p_argument);
201 }
202 }
203}
204
f08ff9ca
BB
205void TTCN_Debugger_UI::init()
206{
5ea46818 207#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca
BB
208 // initialize history library
209 using_history();
210 // calculate history file name
211 const char *home_directory = getenv("HOME");
212 if (home_directory == NULL) {
213 home_directory = ".";
214 }
215 ttcn3_history_filename = mprintf("%s/%s", home_directory, TTCN3_HISTORY_FILENAME);
216 // read history from file, don't bother if it does not exist
217 read_history(ttcn3_history_filename);
218 // set our own command completion function
219 rl_completion_entry_function = (Function*)complete_command;
5ea46818 220#endif
f08ff9ca
BB
221}
222
223void TTCN_Debugger_UI::clean_up()
224{
5ea46818 225#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca
BB
226 if (write_history(ttcn3_history_filename)) {
227 puts("Could not save debugger command history.");
228 }
229 Free(ttcn3_history_filename);
5ea46818 230#endif
f08ff9ca
BB
231}
232
233void TTCN_Debugger_UI::read_loop()
234{
235 while (ttcn3_debugger.is_halted()) {
5ea46818 236#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca
BB
237 // print the prompt and read a line using the readline(), which
238 // automatically handles command completion and command history
239 char* line = readline(PROMPT_TEXT);
240 if (line != NULL) {
5ea46818
BB
241#else
242 // simplified debugger UI: use a simple fgets
243 printf(PROMPT_TEXT);
244 char line[1024];
245 char* res = fgets(line, sizeof(line), stdin);
246 if (res != NULL) {
247#endif
f08ff9ca 248 process_command(line);
5ea46818 249#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca 250 free(line);
5ea46818 251#endif
f08ff9ca
BB
252 }
253 else {
254 // EOF was received -> exit all
255 puts("exit all");
256 char** args = new char*[1];
257 args[0] = (char*)"all";
258 ttcn3_debugger.execute_command(D_EXIT, 1, args);
259 delete [] args;
260 }
261 }
262}
263
264void TTCN_Debugger_UI::execute_batch_file(const char* p_file_name)
265{
266 FILE* fp = fopen(p_file_name, "r");
267 if (fp == NULL) {
268 printf("Failed to open file '%s' for reading.\n", p_file_name);
269 return;
270 }
271 else {
272 printf("Executing batch file '%s'.\n", p_file_name);
273 }
274 char line[1024];
275 while (fgets(line, sizeof(line), fp) != NULL) {
276 size_t len = strlen(line);
277 if (line[len - 1] == '\n') {
278 line[len - 1] = '\0';
279 --len;
280 }
281 if (len != 0) {
282 printf("%s\n", line);
283 process_command(line);
284 }
285 }
286 if (!feof(fp)) {
287 printf("Error occurred while reading batch file '%s' (error code: %d).\n",
288 p_file_name, ferror(fp));
289 }
290 fclose(fp);
291}
292
293void TTCN_Debugger_UI::print(const char* p_str)
294{
295 puts(p_str);
296}
297
5ea46818 298#ifdef ADVANCED_DEBUGGER_UI
f08ff9ca
BB
299char* TTCN_Debugger_UI::complete_command(const char* p_prefix, int p_state)
300{
301 static int command_index;
302 static size_t prefix_len;
303 const char *command_name;
304
305 if (p_state == 0) {
306 command_index = 0;
307 prefix_len = strlen(p_prefix);
308 }
309
310 while ((command_name = debug_command_list[command_index].name)) {
311 ++command_index;
312 if (strncmp(p_prefix, command_name, prefix_len) == 0) {
313 // must allocate buffer for returned string (readline() frees it)
314 return strdup(command_name);
315 }
316 }
317 // no match found
318 return NULL;
5ea46818
BB
319}
320#endif
This page took 0.058336 seconds and 5 git commands to generate.