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

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 10.7 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 "l[ist]", NULL, "List specified line",
86 "Usage: list\n"
87 " list first[,last]\n"
88 " list filename:first[,last]\n"
89 "\n"
90 "Print lines from a source file.\n"
91 "\n"
92 "With first and last, list prints lines from first to last.\n"
93 "When last is empty, it stands for ten lines away from first.\n"
94 "With filename, list prints lines in the specified source file.\n"
95 },
96 {
97 "p[rint]", NULL, "Print value of expression",
98 "Usage: print expr\n"
99 "\n"
100 "It evaluates and prints the value of the mruby expression.\n"
101 "This is equivalent to the \'eval\' command.\n"
102 },
103 {
104 "q[uit]", NULL, "Exit mrdb",
105 "Usage: quit\n"
106 "\n"
107 "Exit mrdb.\n"
108 },
109 {
110 "r[un]", NULL, "Start debugged program",
111 "Usage: run\n"
112 "\n"
113 "Start debugged program.\n"
114 },
115 {
116 "s[tep]", NULL, "Step program until it reaches a different source line",
117 "Usage: step\n"
118 "\n"
119 "Step program until it reaches a different source line.\n"
120 },
121 { NULL, NULL, NULL, NULL }
122};
123
124typedef struct listcmd_parser_state {
125 mrb_bool parse_error;
126 mrb_bool has_line_min;
127 mrb_bool has_line_max;
128 char *filename;
129 uint16_t line_min;
130 uint16_t line_max;
131} listcmd_parser_state;
132
133static listcmd_parser_state*
134listcmd_parser_state_new(mrb_state *mrb)
135{
136 listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state));
137 memset(st, 0, sizeof(listcmd_parser_state));
138 return st;
139}
140
141static void
142listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st)
143{
144 if (st != NULL) {
145 if (st->filename != NULL) {
146 mrb_free(mrb, st->filename);
147 }
148 mrb_free(mrb, st);
149 }
150}
151
152static mrb_bool
153parse_uint(char **sp, uint16_t *n)
154{
155 char *p;
156 int i;
157
158 if (*sp == NULL || **sp == '\0') {
159 return FALSE;
160 }
161
162 for (p = *sp; *p != '\0' && ISDIGIT(*p); p++) ;
163
164 if (p != *sp && (i = atoi(*sp)) >= 0) {
165 *n = (uint16_t)i;
166 *sp = p;
167 return TRUE;
168 }
169 return FALSE;
170}
171
172static mrb_bool
173skip_char(char **sp, char c)
174{
175 if (*sp != NULL && **sp == c) {
176 ++*sp;
177 return TRUE;
178 }
179 return FALSE;
180}
181
182static mrb_bool
183parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st)
184{
185 if (*sp == NULL || **sp == '\0') {
186 return FALSE;
187 }
188
189 st->has_line_min = FALSE;
190 st->has_line_max = FALSE;
191
192 if (parse_uint(sp, &st->line_min)) {
193 st->has_line_min = TRUE;
194 }
195 else {
196 return FALSE;
197 }
198
199 if (skip_char(sp, ',')) {
200 if (parse_uint(sp, &st->line_max)) {
201 st->has_line_max = TRUE;
202 }
203 else {
204 st->parse_error = TRUE;
205 return FALSE;
206 }
207 }
208 return TRUE;
209}
210
211static mrb_bool
212parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st)
213{
214 char *p;
215 int len;
216
217 if (st->filename != NULL) {
218 mrb_free(mrb, st->filename);
219 st->filename = NULL;
220 }
221
222 if ((p = strchr(*sp, ':')) != NULL) {
223 len = p - *sp;
224 }
225 else {
226 len = strlen(*sp);
227 }
228
229 if (len > 0) {
230 st->filename = mrb_malloc(mrb, len + 1);
231 strncpy(st->filename, *sp, len);
232 st->filename[len] = '\0';
233 *sp += len;
234 return TRUE;
235 }
236 else {
237 return FALSE;
238 }
239}
240
241char*
242replace_ext(mrb_state *mrb, const char *filename, const char *ext)
243{
244 size_t len;
245 char *p, *s;
246
247 if (filename == NULL) {
248 return NULL;
249 }
250
251 if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) {
252 len = p - filename;
253 }
254 else {
255 len = strlen(filename);
256 }
257
258 s = mrb_malloc(mrb, len + strlen(ext) + 1);
259 memset(s, '\0', len + strlen(ext) + 1);
260 strncpy(s, filename, len);
261 strcat(s, ext);
262
263 return s;
264}
265
266static mrb_bool
267parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st)
268{
269 char *p;
270
271 switch (mrdb->wcnt) {
272 case 2:
273 p = mrdb->words[1];
274
275 /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */
276 if (!parse_lineno(mrb, &p, st)) {
277 if (parse_filename(mrb, &p, st)) {
278 if (skip_char(&p, ':')) {
279 if (!parse_lineno(mrb, &p, st)) {
280 st->parse_error = TRUE;
281 }
282 }
283 }
284 else {
285 st->parse_error = TRUE;
286 }
287 }
288 if (*p != '\0') {
289 st->parse_error = TRUE;
290 }
291 break;
292 case 1:
293 case 0:
294 /* do nothing */
295 break;
296 default:
297 st->parse_error = TRUE;
298 printf("too many arguments\n");
299 break;
300 }
301
302 if (!st->parse_error) {
303 if (!st->has_line_min) {
304 st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1;
305 }
306
307 if (!st->has_line_max) {
308 st->line_max = st->line_min + 9;
309 }
310
311 if (st->filename == NULL) {
312 if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) {
313 st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb");
314 }
315 }
316 }
317
318 if (st->parse_error || st->filename == NULL) {
319 return FALSE;
320 }
321
322 return TRUE;
323}
324
325static mrb_bool
326check_cmd_pattern(const char *pattern, const char *cmd)
327{
328 char *lbracket, *rbracket, *p, *q;
329
330 if (pattern == NULL && cmd == NULL) {
331 return TRUE;
332 }
333 if (pattern == NULL || cmd == NULL) {
334 return FALSE;
335 }
336 if((lbracket = strchr(pattern, '[')) == NULL) {
337 return !strcmp(pattern, cmd);
338 }
339 if ((rbracket = strchr(pattern, ']')) == NULL) {
340 return FALSE;
341 }
342 if (strncmp(pattern, cmd, lbracket - pattern)) {
343 return FALSE;
344 }
345
346 p = lbracket + 1;
347 q = (char *)cmd + (lbracket - pattern);
348
349 for ( ; p < rbracket && *q != '\0'; p++, q++) {
350 if (*p != *q) {
351 break;
352 }
353 }
354 return *q == '\0';
355}
356
357static help_msg*
358get_help_msg(char *cmd1, char *cmd2)
359{
360 help_msg *p;
361
362 if (cmd1 == NULL) {
363 return NULL;
364 }
365 for (p = help_msg_list; p->cmd1 != NULL; p++) {
366 if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) {
367 return p;
368 }
369 }
370 return NULL;
371}
372
373static mrb_bool
374show_short_help(void)
375{
376 help_msg *p;
377
378 printf("Commands\n");
379
380 for (p = help_msg_list; p->cmd1 != NULL; p++) {
381 if (p->cmd2 == NULL) {
382 printf(" %s -- %s\n", p->cmd1, p->short_msg);
383 }
384 else {
385 printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg);
386 }
387 }
388 return TRUE;
389}
390
391static mrb_bool
392show_long_help(char *cmd1, char *cmd2)
393{
394 help_msg *help;
395
396 if ((help = get_help_msg(cmd1, cmd2)) == NULL) {
397 return FALSE;
398 }
399 printf("%s", help->long_msg);
400 return TRUE;
401}
402
403dbgcmd_state
404dbgcmd_list(mrb_state *mrb, mrdb_state *mrdb)
405{
406 char *filename;
407 listcmd_parser_state *st = listcmd_parser_state_new(mrb);
408
409 if (parse_listcmd_args(mrb, mrdb, st)) {
410 if ((filename = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, st->filename)) == NULL) {
411 filename = st->filename;
412 }
413 mrb_debug_list(mrb, mrdb->dbg, filename, st->line_min, st->line_max);
414
415 if (filename != NULL && filename != st->filename) {
416 mrb_free(mrb, filename);
417 }
418 listcmd_parser_state_free(mrb, st);
419 }
420
421 return DBGST_PROMPT;
422}
423
424dbgcmd_state
425dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb)
426{
427 mrb_bool is_valid;
428 int i;
429
430 switch (mrdb->wcnt) {
431 case 0:
432 case 1:
433 is_valid = show_short_help();
434 break;
435 case 2:
436 is_valid = show_long_help(mrdb->words[1], NULL);
437 break;
438 case 3:
439 is_valid = show_long_help(mrdb->words[1], mrdb->words[2]);
440 break;
441 default:
442 is_valid = FALSE;
443 break;
444 }
445
446 if (!is_valid) {
447 printf("Invalid command \"");
448 for (i = 1; i < mrdb->wcnt; i++) {
449 printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]);
450 }
451 printf("\". Try \"help\".\n");
452 }
453
454 return DBGST_PROMPT;
455}
456
457dbgcmd_state
458dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb)
459{
460 switch (mrdb->dbg->xm) {
461 case DBG_RUN:
462 case DBG_STEP:
463 case DBG_NEXT:
464 while (1) {
465 char c;
466 int buf;
467
468 printf("The program is running. Exit anyway? (y or n) ");
469 fflush(stdout);
470
471 if ((buf = getchar()) == EOF) {
472 mrdb->dbg->xm = DBG_QUIT;
473 break;
474 }
475 c = buf;
476 while (buf != '\n' && (buf = getchar()) != EOF) ;
477
478 if (c == 'y' || c == 'Y') {
479 mrdb->dbg->xm = DBG_QUIT;
480 break;
481 }
482 else if (c == 'n' || c == 'N') {
483 break;
484 }
485 else {
486 printf("Please answer y or n.\n");
487 }
488 }
489 break;
490 default:
491 mrdb->dbg->xm = DBG_QUIT;
492 break;
493 }
494
495 if (mrdb->dbg->xm == DBG_QUIT) {
496 struct RClass *exc;
497 exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception"));
498 mrb_raise(mrb, exc, "Exit mrdb.");
499 }
500 return DBGST_PROMPT;
501}
Note: See TracBrowser for help on using the repository browser.