Make `LocalJumpError` a direct subclass of `StandardError`.
[mruby.git] / mrbgems / mruby-bin-debugger / tools / mrdb / apilist.c
blob66ddfa783cdcdb8ceab7c412619c1d2e7ed06922
1 /*
2 * apilist.c
3 */
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <string.h>
9 #include "mrdb.h"
10 #include "mrdberror.h"
11 #include "apilist.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;
68 char *dir;
70 if (path == NULL) {
71 return NULL;
74 p = strrchr(path, '/');
75 len = p != NULL ? (size_t)(p - path) : strlen(path);
77 dir = (char*)mrb_malloc(mrb, len + 1);
78 strncpy(dir, path, len);
79 dir[len] = '\0';
81 return dir;
84 static source_file*
85 source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
87 source_file *file;
89 file = (source_file*)mrb_malloc(mrb, sizeof(source_file));
91 memset(file, '\0', sizeof(source_file));
92 file->fp = fopen(filename, "rb");
94 if (file->fp == NULL) {
95 source_file_free(mrb, file);
96 return NULL;
99 file->lineno = 1;
100 file->path = (char*)mrb_malloc(mrb, strlen(filename) + 1);
101 strcpy(file->path, filename);
102 return file;
105 static mrb_bool
106 remove_newlines(char *s, FILE *fp)
108 int c;
109 char *p;
110 size_t len;
112 if ((len = strlen(s)) == 0) {
113 return FALSE;
116 p = s + len - 1;
118 if (*p != '\r' && *p != '\n') {
119 return FALSE;
122 if (*p == '\r') {
123 /* peek the next character and skip '\n' */
124 if ((c = fgetc(fp)) != '\n') {
125 ungetc(c, fp);
129 /* remove trailing newline characters */
130 while (s <= p && (*p == '\r' || *p == '\n')) {
131 *p-- = '\0';
134 return TRUE;
137 static void
138 show_lines(source_file *file, uint16_t line_min, uint16_t line_max)
140 char buf[LINE_BUF_SIZE];
141 int show_lineno = 1, found_newline = 0, is_printed = 0;
143 if (file->fp == NULL) {
144 return;
147 while (fgets(buf, sizeof(buf), file->fp) != NULL) {
148 found_newline = remove_newlines(buf, file->fp);
150 if (line_min <= file->lineno) {
151 if (show_lineno) {
152 printf("%-8d", file->lineno);
154 show_lineno = found_newline;
155 printf(found_newline ? "%s\n" : "%s", buf);
156 is_printed = 1;
159 if (found_newline) {
160 if (line_max < ++file->lineno) {
161 break;
166 if (is_printed && !found_newline) {
167 printf("\n");
171 char*
172 mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, const char *filename)
174 int i;
175 FILE *fp;
176 const char *search_path[3];
177 char *path = NULL;
178 const char *srcname = strrchr(filename, '/');
180 if (srcname) srcname++;
181 else srcname = filename;
183 search_path[0] = srcpath;
184 search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0));
185 search_path[2] = ".";
187 for (i = 0; i < 3; i++) {
188 if (search_path[i] == NULL) {
189 continue;
192 if ((path = build_path(mrb, search_path[i], srcname)) == NULL) {
193 continue;
196 if ((fp = fopen(path, "rb")) == NULL) {
197 mrb_free(mrb, path);
198 path = NULL;
199 continue;
201 fclose(fp);
202 break;
205 mrb_free(mrb, (void *)search_path[1]);
207 return path;
210 int32_t
211 mrb_debug_list(mrb_state *mrb, mrb_debug_context *dbg, char *filename, uint16_t line_min, uint16_t line_max)
213 char *ext;
214 source_file *file;
216 if (mrb == NULL || dbg == NULL || filename == NULL) {
217 return MRB_DEBUG_INVALID_ARGUMENT;
220 ext = strrchr(filename, '.');
222 if (ext == NULL || strcmp(ext, ".rb")) {
223 printf("List command only supports .rb file.\n");
224 return MRB_DEBUG_INVALID_ARGUMENT;
227 if (line_min > line_max) {
228 return MRB_DEBUG_INVALID_ARGUMENT;
231 if ((file = source_file_new(mrb, dbg, filename)) != NULL) {
232 show_lines(file, line_min, line_max);
233 source_file_free(mrb, file);
234 return MRB_DEBUG_OK;
236 else {
237 printf("Invalid source file named %s.\n", filename);
238 return MRB_DEBUG_INVALID_ARGUMENT;