source: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 10.8 KB
Line 
1/*
2** cmdmisc.c - mruby debugger miscellaneous command functions
3**
4*/
5
6#include <ctype.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "apilist.h"
11#include <mruby/compile.h>
12
13typedef struct help_msg {
14 const char *cmd1;
15 const char *cmd2;
16 const char *short_msg;
17 const char *long_msg;
18} help_msg;
19
20static help_msg help_msg_list[] = {
21 {
22 "b[reak]", NULL, "Set breakpoint",
23 "Usage: break [file:]line\n"
24 " break [class:]method\n"
25 "\n"
26 "Set breakpoint at specified line or method.\n"
27 "If \'[file:]line\' is specified, break at start of code for that line (in a file).\n"
28 "If \'[class:]method\' is specified, break at start of code for that method (of the class).\n"
29 },
30 {
31 "c[ontinue]", NULL, "Continue program being debugged",
32 "Usage: continue [N]\n"
33 "\n"
34 "Continue program stopped by a breakpoint.\n"
35 "If N, which is non negative value, is passed,\n"
36 "proceed program until the N-th breakpoint is coming.\n"
37 "If N is not passed, N is assumed 1.\n"
38 },
39 {
40 "d[elete]", NULL, "Delete some breakpoints",
41 "Usage: delete [bpno1 [bpno2 [... [bpnoN]]]]\n"
42 "\n"
43 "Delete some breakpoints.\n"
44 "Arguments are breakpoint numbers with spaces in between.\n"
45 "To delete all breakpoints, give no argument.\n"
46 },
47 {
48 "dis[able]", NULL, "Disable some breakpoints",
49 "Usage: disable [bpno1 [bpno2 [... [bpnoN]]]]\n"
50 "\n"
51 "Disable some breakpoints.\n"
52 "Arguments are breakpoint numbers with spaces in between.\n"
53 "To disable all breakpoints, give no argument.\n"
54 },
55 {
56 "en[able]", NULL, "Enable some breakpoints",
57 "Usage: enable [bpno1 [bpno2 [... [bpnoN]]]]\n"
58 "\n"
59 "Enable some breakpoints.\n"
60 "Arguments are breakpoint numbers with spaces in between.\n"
61 "To enable all breakpoints, give no argument.\n"
62 },
63 {
64 "ev[al]", NULL, "Evaluate expression",
65 "Usage: eval expr\n"
66 "\n"
67 "It evaluates and prints the value of the mruby expression.\n"
68 "This is equivalent to the \'print\' command.\n"
69 },
70 {
71 "h[elp]", NULL, "Print this help",
72 "Usage: help [command]\n"
73 "\n"
74 "With no arguments, help displays a short list of commands.\n"
75 "With a command name as help argument, help displays how to use that command.\n"
76 },
77 {
78 "i[nfo]", "b[reakpoints]", "Status of breakpoints",
79 "Usage: info breakpoints [bpno1 [bpno2 [... [bpnoN]]]]\n"
80 "\n"
81 "Status of specified breakpoints (all user-settable breakpoints if no argument).\n"
82 "Arguments are breakpoint numbers with spaces in between.\n"
83 },
84 {
85 "i[nfo]", "l[ocals]", "Print name of local variables",
86 "Usage: info locals\n"
87 "\n"
88 "Print name of local variables.\n"
89 },
90 {
91 "l[ist]", NULL, "List specified line",
92 "Usage: list\n"
93 " list first[,last]\n"
94 " list filename:first[,last]\n"
95 "\n"
96 "Print lines from a source file.\n"
97 "\n"
98 "With first and last, list prints lines from first to last.\n"
99 "When last is empty, it stands for ten lines away from first.\n"
100 "With filename, list prints lines in the specified source file.\n"
101 },
102 {
103 "p[rint]", NULL, "Print value of expression",
104 "Usage: print expr\n"
105 "\n"
106 "It evaluates and prints the value of the mruby expression.\n"
107 "This is equivalent to the \'eval\' command.\n"
108 },
109 {
110 "q[uit]", NULL, "Exit mrdb",
111 "Usage: quit\n"
112 "\n"
113 "Exit mrdb.\n"
114 },
115 {
116 "r[un]", NULL, "Start debugged program",
117 "Usage: run\n"
118 "\n"
119 "Start debugged program.\n"
120 },
121 {
122 "s[tep]", NULL, "Step program until it reaches a different source line",
123 "Usage: step\n"
124 "\n"
125 "Step program until it reaches a different source line.\n"
126 },
127 { NULL, NULL, NULL, NULL }
128};
129
130typedef struct listcmd_parser_state {
131 mrb_bool parse_error;
132 mrb_bool has_line_min;
133 mrb_bool has_line_max;
134 char *filename;
135 uint16_t line_min;
136 uint16_t line_max;
137} listcmd_parser_state;
138
139static listcmd_parser_state*
140listcmd_parser_state_new(mrb_state *mrb)
141{
142 listcmd_parser_state *st = (listcmd_parser_state*)mrb_malloc(mrb, sizeof(listcmd_parser_state));
143 memset(st, 0, sizeof(listcmd_parser_state));
144 return st;
145}
146
147static void
148listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st)
149{
150 if (st != NULL) {
151 if (st->filename != NULL) {
152 mrb_free(mrb, st->filename);
153 }
154 mrb_free(mrb, st);
155 }
156}
157
158static mrb_bool
159parse_uint(char **sp, uint16_t *n)
160{
161 char *p;
162 int i;
163
164 if (*sp == NULL || **sp == '\0') {
165 return FALSE;
166 }
167
168 for (p = *sp; *p != '\0' && ISDIGIT(*p); p++) ;
169
170 if (p != *sp && (i = atoi(*sp)) >= 0) {
171 *n = (uint16_t)i;
172 *sp = p;
173 return TRUE;
174 }
175 return FALSE;
176}
177
178static mrb_bool
179skip_char(char **sp, char c)
180{
181 if (*sp != NULL && **sp == c) {
182 ++*sp;
183 return TRUE;
184 }
185 return FALSE;
186}
187
188static mrb_bool
189parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st)
190{
191 if (*sp == NULL || **sp == '\0') {
192 return FALSE;
193 }
194
195 st->has_line_min = FALSE;
196 st->has_line_max = FALSE;
197
198 if (parse_uint(sp, &st->line_min)) {
199 st->has_line_min = TRUE;
200 }
201 else {
202 return FALSE;
203 }
204
205 if (skip_char(sp, ',')) {
206 if (parse_uint(sp, &st->line_max)) {
207 st->has_line_max = TRUE;
208 }
209 else {
210 st->parse_error = TRUE;
211 return FALSE;
212 }
213 }
214 return TRUE;
215}
216
217static mrb_bool
218parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st)
219{
220 char *p;
221 int len;
222
223 if (st->filename != NULL) {
224 mrb_free(mrb, st->filename);
225 st->filename = NULL;
226 }
227
228 if ((p = strchr(*sp, ':')) != NULL) {
229 len = p - *sp;
230 }
231 else {
232 len = strlen(*sp);
233 }
234
235 if (len > 0) {
236 st->filename = (char*)mrb_malloc(mrb, len + 1);
237 strncpy(st->filename, *sp, len);
238 st->filename[len] = '\0';
239 *sp += len;
240 return TRUE;
241 }
242 else {
243 return FALSE;
244 }
245}
246
247char*
248replace_ext(mrb_state *mrb, const char *filename, const char *ext)
249{
250 size_t len;
251 const char *p;
252 char *s;
253
254 if (filename == NULL) {
255 return NULL;
256 }
257
258 if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) {
259 len = p - filename;
260 }
261 else {
262 len = strlen(filename);
263 }
264
265 s = (char*)mrb_malloc(mrb, len + strlen(ext) + 1);
266 memset(s, '\0', len + strlen(ext) + 1);
267 strncpy(s, filename, len);
268 strcat(s, ext);
269
270 return s;
271}
272
273static mrb_bool
274parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st)
275{
276 char *p;
277
278 switch (mrdb->wcnt) {
279 case 2:
280 p = mrdb->words[1];
281
282 /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */
283 if (!parse_lineno(mrb, &p, st)) {
284 if (parse_filename(mrb, &p, st)) {
285 if (skip_char(&p, ':')) {
286 if (!parse_lineno(mrb, &p, st)) {
287 st->parse_error = TRUE;
288 }
289 }
290 }
291 else {
292 st->parse_error = TRUE;
293 }
294 }
295 if (*p != '\0') {
296 st->parse_error = TRUE;
297 }
298 break;
299 case 1:
300 case 0:
301 /* do nothing */
302 break;
303 default:
304 st->parse_error = TRUE;
305 printf("too many arguments\n");
306 break;
307 }
308
309 if (!st->parse_error) {
310 if (!st->has_line_min) {
311 st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1;
312 }
313
314 if (!st->has_line_max) {
315 st->line_max = st->line_min + 9;
316 }
317
318 if (st->filename == NULL) {
319 if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) {
320 st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb");
321 }
322 }
323 }
324
325 if (st->parse_error || st->filename == NULL) {
326 return FALSE;
327 }
328
329 return TRUE;
330}
331
332static mrb_bool
333check_cmd_pattern(const char *pattern, const char *cmd)
334{
335 const char *lbracket, *rbracket, *p, *q;
336
337 if (pattern == NULL && cmd == NULL) {
338 return TRUE;
339 }
340 if (pattern == NULL || cmd == NULL) {
341 return FALSE;
342 }
343 if ((lbracket = strchr(pattern, '[')) == NULL) {
344 return !strcmp(pattern, cmd);
345 }
346 if ((rbracket = strchr(pattern, ']')) == NULL) {
347 return FALSE;
348 }
349 if (strncmp(pattern, cmd, lbracket - pattern)) {
350 return FALSE;
351 }
352
353 p = lbracket + 1;
354 q = (char *)cmd + (lbracket - pattern);
355
356 for ( ; p < rbracket && *q != '\0'; p++, q++) {
357 if (*p != *q) {
358 break;
359 }
360 }
361 return *q == '\0';
362}
363
364static help_msg*
365get_help_msg(char *cmd1, char *cmd2)
366{
367 help_msg *p;
368
369 if (cmd1 == NULL) {
370 return NULL;
371 }
372 for (p = help_msg_list; p->cmd1 != NULL; p++) {
373 if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) {
374 return p;
375 }
376 }
377 return NULL;
378}
379
380static mrb_bool
381show_short_help(void)
382{
383 help_msg *p;
384
385 printf("Commands\n");
386
387 for (p = help_msg_list; p->cmd1 != NULL; p++) {
388 if (p->cmd2 == NULL) {
389 printf(" %s -- %s\n", p->cmd1, p->short_msg);
390 }
391 else {
392 printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg);
393 }
394 }
395 return TRUE;
396}
397
398static mrb_bool
399show_long_help(char *cmd1, char *cmd2)
400{
401 help_msg *help;
402
403 if ((help = get_help_msg(cmd1, cmd2)) == NULL) {
404 return FALSE;
405 }
406 printf("%s", help->long_msg);
407 return TRUE;
408}
409
410dbgcmd_state
411dbgcmd_list(mrb_state *mrb, mrdb_state *mrdb)
412{
413 char *filename;
414 listcmd_parser_state *st = listcmd_parser_state_new(mrb);
415
416 if (parse_listcmd_args(mrb, mrdb, st)) {
417 if ((filename = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, st->filename)) == NULL) {
418 filename = st->filename;
419 }
420 mrb_debug_list(mrb, mrdb->dbg, filename, st->line_min, st->line_max);
421
422 if (filename != NULL && filename != st->filename) {
423 mrb_free(mrb, filename);
424 }
425 listcmd_parser_state_free(mrb, st);
426 }
427
428 return DBGST_PROMPT;
429}
430
431dbgcmd_state
432dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb)
433{
434 mrb_bool is_valid;
435 int i;
436
437 switch (mrdb->wcnt) {
438 case 0:
439 case 1:
440 is_valid = show_short_help();
441 break;
442 case 2:
443 is_valid = show_long_help(mrdb->words[1], NULL);
444 break;
445 case 3:
446 is_valid = show_long_help(mrdb->words[1], mrdb->words[2]);
447 break;
448 default:
449 is_valid = FALSE;
450 break;
451 }
452
453 if (!is_valid) {
454 printf("Invalid command \"");
455 for (i = 1; i < mrdb->wcnt; i++) {
456 printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]);
457 }
458 printf("\". Try \"help\".\n");
459 }
460
461 return DBGST_PROMPT;
462}
463
464dbgcmd_state
465dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb)
466{
467 switch (mrdb->dbg->xm) {
468 case DBG_RUN:
469 case DBG_STEP:
470 case DBG_NEXT:
471 while (1) {
472 char c;
473 int buf;
474
475 printf("The program is running. Exit anyway? (y or n) ");
476 fflush(stdout);
477
478 if ((buf = getchar()) == EOF) {
479 mrdb->dbg->xm = DBG_QUIT;
480 break;
481 }
482 c = buf;
483 while (buf != '\n' && (buf = getchar()) != EOF) ;
484
485 if (c == 'y' || c == 'Y') {
486 mrdb->dbg->xm = DBG_QUIT;
487 break;
488 }
489 else if (c == 'n' || c == 'N') {
490 break;
491 }
492 else {
493 printf("Please answer y or n.\n");
494 }
495 }
496 break;
497 default:
498 mrdb->dbg->xm = DBG_QUIT;
499 break;
500 }
501
502 if (mrdb->dbg->xm == DBG_QUIT) {
503 struct RClass *exc;
504 exc = mrb_define_class(mrb, "DebuggerExit", mrb->eException_class);
505 mrb_raise(mrb, exc, "Exit mrdb.");
506 }
507 return DBGST_PROMPT;
508}
Note: See TracBrowser for help on using the repository browser.