11 #include "apistring.h"
12 #include <mruby/compile.h>
13 #include <mruby/irep.h>
14 #include <mruby/debug.h>
16 #define LINE_BUF_SIZE MAX_COMMAND_LINE
18 typedef struct source_file
{
25 source_file_free(mrb_state
*mrb
, source_file
*file
)
28 if (file
->path
!= NULL
) {
29 mrb_free(mrb
, file
->path
);
31 if (file
->fp
!= NULL
) {
40 build_path(mrb_state
*mrb
, const char *dir
, const char *base
)
45 len
= strlen(base
) + 1;
47 if (strcmp(dir
, ".")) {
48 len
+= strlen(dir
) + sizeof("/") - 1;
51 path
= (char*)mrb_malloc(mrb
, len
);
54 if (strcmp(dir
, ".")) {
64 dirname(mrb_state
*mrb
, const char *path
)
73 p
= strrchr(path
, '/');
74 len
= p
!= NULL
? (size_t)(p
- path
) : strlen(path
);
76 return mrdb_strndup(mrb
, path
, len
);
80 source_file_new(mrb_state
*mrb
, mrb_debug_context
*dbg
, char *filename
)
84 file
= (source_file
*)mrb_malloc(mrb
, sizeof(source_file
));
86 memset(file
, '\0', sizeof(source_file
));
87 file
->fp
= fopen(filename
, "rb");
89 if (file
->fp
== NULL
) {
90 source_file_free(mrb
, file
);
95 file
->path
= mrdb_strdup(mrb
, filename
);
96 if (file
->path
== NULL
) {
97 source_file_free(mrb
, file
);
104 remove_newlines(char *s
, FILE *fp
)
110 if ((len
= strlen(s
)) == 0) {
116 if (*p
!= '\r' && *p
!= '\n') {
121 /* peek the next character and skip '\n' */
122 if ((c
= fgetc(fp
)) != '\n') {
127 /* remove trailing newline characters */
128 while (s
<= p
&& (*p
== '\r' || *p
== '\n')) {
136 show_lines(source_file
*file
, uint16_t line_min
, uint16_t line_max
)
138 char buf
[LINE_BUF_SIZE
];
139 int show_lineno
= 1, found_newline
= 0, is_printed
= 0;
141 if (file
->fp
== NULL
) {
145 while (fgets(buf
, sizeof(buf
), file
->fp
) != NULL
) {
146 found_newline
= remove_newlines(buf
, file
->fp
);
148 if (line_min
<= file
->lineno
) {
150 printf("%-8d", file
->lineno
);
152 show_lineno
= found_newline
;
153 printf(found_newline
? "%s\n" : "%s", buf
);
158 if (line_max
< ++file
->lineno
) {
164 if (is_printed
&& !found_newline
) {
170 mrb_debug_get_source(mrb_state
*mrb
, mrdb_state
*mrdb
, const char *srcpath
, const char *filename
)
174 const char *search_path
[3];
176 const char *srcname
= strrchr(filename
, '/');
178 if (srcname
) srcname
++;
179 else srcname
= filename
;
181 search_path
[0] = srcpath
;
182 search_path
[1] = dirname(mrb
, mrb_debug_get_filename(mrb
, mrdb
->dbg
->irep
, 0));
183 search_path
[2] = ".";
185 for (i
= 0; i
< 3; i
++) {
186 if (search_path
[i
] == NULL
) {
190 if ((path
= build_path(mrb
, search_path
[i
], srcname
)) == NULL
) {
194 if ((fp
= fopen(path
, "rb")) == NULL
) {
203 mrb_free(mrb
, (void*)search_path
[1]);
209 mrb_debug_list(mrb_state
*mrb
, mrb_debug_context
*dbg
, char *filename
, uint16_t line_min
, uint16_t line_max
)
214 if (mrb
== NULL
|| dbg
== NULL
|| filename
== NULL
) {
215 return MRB_DEBUG_INVALID_ARGUMENT
;
218 ext
= strrchr(filename
, '.');
220 if (ext
== NULL
|| strcmp(ext
, ".rb")) {
221 printf("List command only supports .rb file.\n");
222 return MRB_DEBUG_INVALID_ARGUMENT
;
225 if (line_min
> line_max
) {
226 return MRB_DEBUG_INVALID_ARGUMENT
;
229 if ((file
= source_file_new(mrb
, dbg
, filename
)) != NULL
) {
230 show_lines(file
, line_min
, line_max
);
231 source_file_free(mrb
, file
);
235 printf("Invalid source file named %s.\n", filename
);
236 return MRB_DEBUG_INVALID_ARGUMENT
;