source: EcnlProtoTool/trunk/prototool/src/cmdmisc.c@ 279

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

ファイルを追加、更新。

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 9.6 KB
Line 
1/*
2** cmdmisc.c - mruby debugger miscellaneous command functions
3**
4*/
5
6#include <stdlib.h>
7#include <string.h>
8
9#include "mruby/compile.h"
10#include "mrdb.h"
11
12typedef struct help_msg
13{
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{
126 mrb_bool parse_error;
127 mrb_bool has_line_min;
128 mrb_bool has_line_max;
129 char *filename;
130 uint16_t line_min;
131 uint16_t line_max;
132} listcmd_parser_state;
133
134static listcmd_parser_state*
135listcmd_parser_state_new(mrb_state *mrb)
136{
137 listcmd_parser_state *st = (listcmd_parser_state *)mrb_malloc(mrb, sizeof(listcmd_parser_state));
138 memset(st, 0, sizeof(listcmd_parser_state));
139 return st;
140}
141
142static void
143listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st)
144{
145 if (st != NULL) {
146 if (st->filename != NULL) {
147 mrb_free(mrb, st->filename);
148 }
149 mrb_free(mrb, st);
150 }
151}
152
153static mrb_bool
154parse_uint(char **sp, uint16_t *n)
155{
156 char *p;
157 int i;
158
159 if (*sp == NULL || **sp == '\0') {
160 return FALSE;
161 }
162
163 for (p = *sp; *p != '\0' && ISDIGIT(*p); p++);
164
165 if (p != *sp && (i = atoi(*sp)) >= 0) {
166 *n = (uint16_t)i;
167 *sp = p;
168 return TRUE;
169 }
170 return FALSE;
171}
172
173static mrb_bool
174skip_char(char **sp, char c)
175{
176 if (*sp != NULL && **sp == c) {
177 ++*sp;
178 return TRUE;
179 }
180 return FALSE;
181}
182
183static mrb_bool
184parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st)
185{
186 if (*sp == NULL || **sp == '\0') {
187 return FALSE;
188 }
189
190 st->has_line_min = FALSE;
191 st->has_line_max = FALSE;
192
193 if (parse_uint(sp, &st->line_min)) {
194 st->has_line_min = TRUE;
195 }
196 else {
197 return FALSE;
198 }
199
200 if (skip_char(sp, ',')) {
201 if (parse_uint(sp, &st->line_max)) {
202 st->has_line_max = TRUE;
203 }
204 else {
205 st->parse_error = TRUE;
206 return FALSE;
207 }
208 }
209 return TRUE;
210}
211
212static mrb_bool
213parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st)
214{
215 char *p;
216 int len;
217
218 if (st->filename != NULL) {
219 mrb_free(mrb, st->filename);
220 st->filename = NULL;
221 }
222
223 if ((p = strchr(*sp, ':')) != NULL) {
224 len = p - *sp;
225 }
226 else {
227 len = strlen(*sp);
228 }
229
230 if (len > 0) {
231 st->filename = mrb_malloc(mrb, len + 1);
232 strlcpy(st->filename, *sp, len + 1);
233 st->filename[len] = '\0';
234 *sp += len;
235 return TRUE;
236 }
237 else {
238 return FALSE;
239 }
240}
241
242char*
243replace_ext(mrb_state *mrb, const char *filename, const char *ext)
244{
245 size_t len, len2;
246 const char *p;
247 char *s;
248
249 if (filename == NULL) {
250 return NULL;
251 }
252
253 if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) {
254 len = p - filename;
255 }
256 else {
257 len = strlen(filename);
258 }
259
260 len2 = len + strlen(ext) + 1;
261 s = mrb_malloc(mrb, len2);
262 memset(s, '\0', len2);
263 strlcpy(s, filename, len);
264 strlcat(s, ext, len2);
265
266 return s;
267}
268
269static mrb_bool
270parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st)
271{
272 char *p;
273
274 switch (mrdb->wcnt) {
275 case 2:
276 p = mrdb->words[1];
277
278 /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */
279 if (!parse_lineno(mrb, &p, st)) {
280 if (parse_filename(mrb, &p, st)) {
281 if (skip_char(&p, ':')) {
282 if (!parse_lineno(mrb, &p, st)) {
283 st->parse_error = TRUE;
284 }
285 }
286 }
287 else {
288 st->parse_error = TRUE;
289 }
290 }
291 if (*p != '\0') {
292 st->parse_error = TRUE;
293 }
294 break;
295 case 1:
296 case 0:
297 /* do nothing */
298 break;
299 default:
300 st->parse_error = TRUE;
301 printf("too many arguments\n");
302 break;
303 }
304
305 if (!st->parse_error) {
306 if (!st->has_line_min) {
307 st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1;
308 }
309
310 if (!st->has_line_max) {
311 st->line_max = st->line_min + 9;
312 }
313
314 if (st->filename == NULL) {
315 if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) {
316 st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb");
317 }
318 }
319 }
320
321 if (st->parse_error || st->filename == NULL) {
322 return FALSE;
323 }
324
325 return TRUE;
326}
327
328static mrb_bool
329check_cmd_pattern(const char *pattern, const char *cmd)
330{
331 const char *lbracket, *rbracket, *p, *q;
332
333 if (pattern == NULL && cmd == NULL) {
334 return TRUE;
335 }
336 if (pattern == NULL || cmd == NULL) {
337 return FALSE;
338 }
339 if ((lbracket = strchr(pattern, '[')) == NULL) {
340 return !strcmp(pattern, cmd);
341 }
342 if ((rbracket = strchr(pattern, ']')) == NULL) {
343 return FALSE;
344 }
345 if (strncmp(pattern, cmd, lbracket - pattern)) {
346 return FALSE;
347 }
348
349 p = lbracket + 1;
350 q = (char *)cmd + (lbracket - pattern);
351
352 for (; p < rbracket && *q != '\0'; p++, q++) {
353 if (*p != *q) {
354 break;
355 }
356 }
357 return *q == '\0';
358}
359
360static help_msg*
361get_help_msg(char *cmd1, char *cmd2)
362{
363 help_msg *p;
364
365 if (cmd1 == NULL) {
366 return NULL;
367 }
368 for (p = help_msg_list; p->cmd1 != NULL; p++) {
369 if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) {
370 return p;
371 }
372 }
373 return NULL;
374}
375
376static mrb_bool
377show_short_help(void)
378{
379 help_msg *p;
380
381 printf("Commands\n");
382
383 for (p = help_msg_list; p->cmd1 != NULL; p++) {
384 if (p->cmd2 == NULL) {
385 printf(" %s -- %s\n", p->cmd1, p->short_msg);
386 }
387 else {
388 printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg);
389 }
390 }
391 return TRUE;
392}
393
394static mrb_bool
395show_long_help(char *cmd1, char *cmd2)
396{
397 help_msg *help;
398
399 if ((help = get_help_msg(cmd1, cmd2)) == NULL) {
400 return FALSE;
401 }
402 printf("%s", help->long_msg);
403 return TRUE;
404}
405
406dbgcmd_state
407dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb)
408{
409 mrb_bool is_valid;
410 int i;
411
412 switch (mrdb->wcnt) {
413 case 0:
414 case 1:
415 is_valid = show_short_help();
416 break;
417 case 2:
418 is_valid = show_long_help(mrdb->words[1], NULL);
419 break;
420 case 3:
421 is_valid = show_long_help(mrdb->words[1], mrdb->words[2]);
422 break;
423 default:
424 is_valid = FALSE;
425 break;
426 }
427
428 if (!is_valid) {
429 printf("Invalid command \"");
430 for (i = 1; i < mrdb->wcnt; i++) {
431 printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]);
432 }
433 printf("\". Try \"help\".\n");
434 }
435
436 return DBGST_PROMPT;
437}
438
439dbgcmd_state
440dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb)
441{
442 switch (mrdb->dbg->xm) {
443 case DBG_RUN:
444 case DBG_STEP:
445 case DBG_NEXT:
446 while (1) {
447 char c;
448 int buf;
449
450 printf("The program is running. Exit anyway? (y or n) ");
451 fflush(stdout);
452
453 if ((buf = getchar()) == EOF) {
454 InterlockedExchange(&mrdb->dbg->xm, DBG_QUIT);
455 break;
456 }
457 c = buf;
458 while (buf != '\n' && (buf = getchar()) != EOF);
459
460 if (c == 'y' || c == 'Y') {
461 InterlockedExchange(&mrdb->dbg->xm, DBG_QUIT);
462 break;
463 }
464 else if (c == 'n' || c == 'N') {
465 break;
466 }
467 else {
468 printf("Please answer y or n.\n");
469 }
470 }
471 break;
472 default:
473 InterlockedExchange(&mrdb->dbg->xm, DBG_QUIT);
474 break;
475 }
476
477 if (mrdb->dbg->xm == DBG_QUIT) {
478 struct RClass *exc;
479 exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception"));
480 mrb_raise(mrb, exc, "Exit mrdb.");
481 }
482 return DBGST_PROMPT;
483}
Note: See TracBrowser for help on using the repository browser.