Merge pull request #6553 from mruby/add-vm-comments
[mruby.git] / mrbgems / mruby-bin-debugger / tools / mrdb / apilist.c
blob0fc087bdf96adb939b820a70f543eef25216eb57
1 /*
2 * apilist.c
3 */
5 #include <ctype.h>
6 #include <string.h>
8 #include "mrdb.h"
9 #include "mrdberror.h"
10 #include "apilist.h"
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 {
19 char *path;
20 uint16_t lineno;
21 FILE *fp;
22 } source_file;
24 static void
25 source_file_free(mrb_state *mrb, source_file *file)
27 if (file != NULL) {
28 if (file->path != NULL) {
29 mrb_free(mrb, file->path);
31 if (file->fp != NULL) {
32 fclose(file->fp);
33 file->fp = NULL;
35 mrb_free(mrb, file);
39 static char*
40 build_path(mrb_state *mrb, const char *dir, const char *base)
42 int len;
43 char *path = NULL;
45 len = strlen(base) + 1;
47 if (strcmp(dir, ".")) {
48 len += strlen(dir) + sizeof("/") - 1;
51 path = (char*)mrb_malloc(mrb, len);
52 memset(path, 0, len);
54 if (strcmp(dir, ".")) {
55 strcat(path, dir);
56 strcat(path, "/");
58 strcat(path, base);
60 return path;
63 static char*
64 dirname(mrb_state *mrb, const char *path)
66 size_t len;
67 const char *p;
69 if (path == NULL) {
70 return NULL;
73 p = strrchr(path, '/');
74 len = p != NULL ? (size_t)(p - path) : strlen(path);
76 return mrdb_strndup(mrb, path, len);
79 static source_file*
80 source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
82 source_file *file;
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);
91 return NULL;
94 file->lineno = 1;
95 file->path = mrdb_strdup(mrb, filename);
96 if (file->path == NULL) {
97 source_file_free(mrb, file);
98 return NULL;
100 return file;
103 static mrb_bool
104 remove_newlines(char *s, FILE *fp)
106 int c;
107 char *p;
108 size_t len;
110 if ((len = strlen(s)) == 0) {
111 return FALSE;
114 p = s + len - 1;
116 if (*p != '\r' && *p != '\n') {
117 return FALSE;
120 if (*p == '\r') {
121 /* peek the next character and skip '\n' */
122 if ((c = fgetc(fp)) != '\n') {
123 ungetc(c, fp);
127 /* remove trailing newline characters */
128 while (s <= p && (*p == '\r' || *p == '\n')) {
129 *p-- = '\0';
132 return TRUE;
135 static void
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) {
142 return;
145 while (fgets(buf, sizeof(buf), file->fp) != NULL) {
146 found_newline = remove_newlines(buf, file->fp);
148 if (line_min <= file->lineno) {
149 if (show_lineno) {
150 printf("%-8d", file->lineno);
152 show_lineno = found_newline;
153 printf(found_newline ? "%s\n" : "%s", buf);
154 is_printed = 1;
157 if (found_newline) {
158 if (line_max < ++file->lineno) {
159 break;
164 if (is_printed && !found_newline) {
165 printf("\n");
169 char*
170 mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, const char *filename)
172 int i;
173 FILE *fp;
174 const char *search_path[3];
175 char *path = NULL;
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) {
187 continue;
190 if ((path = build_path(mrb, search_path[i], srcname)) == NULL) {
191 continue;
194 if ((fp = fopen(path, "rb")) == NULL) {
195 mrb_free(mrb, path);
196 path = NULL;
197 continue;
199 fclose(fp);
200 break;
203 mrb_free(mrb, (void*)search_path[1]);
205 return path;
208 int32_t
209 mrb_debug_list(mrb_state *mrb, mrb_debug_context *dbg, char *filename, uint16_t line_min, uint16_t line_max)
211 char *ext;
212 source_file *file;
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);
232 return MRB_DEBUG_OK;
234 else {
235 printf("Invalid source file named %s.\n", filename);
236 return MRB_DEBUG_INVALID_ARGUMENT;