mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
5c804cf68f
- stdlib.h - stddef.h - stdint.h - stdarg.h - limits.h - float.h
239 lines
4.4 KiB
C
239 lines
4.4 KiB
C
/*
|
|
* apilist.c
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "mrdb.h"
|
|
#include "mrdberror.h"
|
|
#include "apilist.h"
|
|
#include "apistring.h"
|
|
#include <mruby/compile.h>
|
|
#include <mruby/irep.h>
|
|
#include <mruby/debug.h>
|
|
|
|
#define LINE_BUF_SIZE MAX_COMMAND_LINE
|
|
|
|
typedef struct source_file {
|
|
char *path;
|
|
uint16_t lineno;
|
|
FILE *fp;
|
|
} source_file;
|
|
|
|
static void
|
|
source_file_free(mrb_state *mrb, source_file *file)
|
|
{
|
|
if (file != NULL) {
|
|
if (file->path != NULL) {
|
|
mrb_free(mrb, file->path);
|
|
}
|
|
if (file->fp != NULL) {
|
|
fclose(file->fp);
|
|
file->fp = NULL;
|
|
}
|
|
mrb_free(mrb, file);
|
|
}
|
|
}
|
|
|
|
static char*
|
|
build_path(mrb_state *mrb, const char *dir, const char *base)
|
|
{
|
|
int len;
|
|
char *path = NULL;
|
|
|
|
len = strlen(base) + 1;
|
|
|
|
if (strcmp(dir, ".")) {
|
|
len += strlen(dir) + sizeof("/") - 1;
|
|
}
|
|
|
|
path = (char*)mrb_malloc(mrb, len);
|
|
memset(path, 0, len);
|
|
|
|
if (strcmp(dir, ".")) {
|
|
strcat(path, dir);
|
|
strcat(path, "/");
|
|
}
|
|
strcat(path, base);
|
|
|
|
return path;
|
|
}
|
|
|
|
static char*
|
|
dirname(mrb_state *mrb, const char *path)
|
|
{
|
|
size_t len;
|
|
const char *p;
|
|
|
|
if (path == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
p = strrchr(path, '/');
|
|
len = p != NULL ? (size_t)(p - path) : strlen(path);
|
|
|
|
return mrdb_strndup(mrb, path, len);
|
|
}
|
|
|
|
static source_file*
|
|
source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
|
|
{
|
|
source_file *file;
|
|
|
|
file = (source_file*)mrb_malloc(mrb, sizeof(source_file));
|
|
|
|
memset(file, '\0', sizeof(source_file));
|
|
file->fp = fopen(filename, "rb");
|
|
|
|
if (file->fp == NULL) {
|
|
source_file_free(mrb, file);
|
|
return NULL;
|
|
}
|
|
|
|
file->lineno = 1;
|
|
file->path = mrdb_strdup(mrb, filename);
|
|
if (file->path == NULL) {
|
|
source_file_free(mrb, file);
|
|
return NULL;
|
|
}
|
|
return file;
|
|
}
|
|
|
|
static mrb_bool
|
|
remove_newlines(char *s, FILE *fp)
|
|
{
|
|
int c;
|
|
char *p;
|
|
size_t len;
|
|
|
|
if ((len = strlen(s)) == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
p = s + len - 1;
|
|
|
|
if (*p != '\r' && *p != '\n') {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*p == '\r') {
|
|
/* peek the next character and skip '\n' */
|
|
if ((c = fgetc(fp)) != '\n') {
|
|
ungetc(c, fp);
|
|
}
|
|
}
|
|
|
|
/* remove trailing newline characters */
|
|
while (s <= p && (*p == '\r' || *p == '\n')) {
|
|
*p-- = '\0';
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
show_lines(source_file *file, uint16_t line_min, uint16_t line_max)
|
|
{
|
|
char buf[LINE_BUF_SIZE];
|
|
int show_lineno = 1, found_newline = 0, is_printed = 0;
|
|
|
|
if (file->fp == NULL) {
|
|
return;
|
|
}
|
|
|
|
while (fgets(buf, sizeof(buf), file->fp) != NULL) {
|
|
found_newline = remove_newlines(buf, file->fp);
|
|
|
|
if (line_min <= file->lineno) {
|
|
if (show_lineno) {
|
|
printf("%-8d", file->lineno);
|
|
}
|
|
show_lineno = found_newline;
|
|
printf(found_newline ? "%s\n" : "%s", buf);
|
|
is_printed = 1;
|
|
}
|
|
|
|
if (found_newline) {
|
|
if (line_max < ++file->lineno) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_printed && !found_newline) {
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
char*
|
|
mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, const char *filename)
|
|
{
|
|
int i;
|
|
FILE *fp;
|
|
const char *search_path[3];
|
|
char *path = NULL;
|
|
const char *srcname = strrchr(filename, '/');
|
|
|
|
if (srcname) srcname++;
|
|
else srcname = filename;
|
|
|
|
search_path[0] = srcpath;
|
|
search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0));
|
|
search_path[2] = ".";
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (search_path[i] == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if ((path = build_path(mrb, search_path[i], srcname)) == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if ((fp = fopen(path, "rb")) == NULL) {
|
|
mrb_free(mrb, path);
|
|
path = NULL;
|
|
continue;
|
|
}
|
|
fclose(fp);
|
|
break;
|
|
}
|
|
|
|
mrb_free(mrb, (void *)search_path[1]);
|
|
|
|
return path;
|
|
}
|
|
|
|
int32_t
|
|
mrb_debug_list(mrb_state *mrb, mrb_debug_context *dbg, char *filename, uint16_t line_min, uint16_t line_max)
|
|
{
|
|
char *ext;
|
|
source_file *file;
|
|
|
|
if (mrb == NULL || dbg == NULL || filename == NULL) {
|
|
return MRB_DEBUG_INVALID_ARGUMENT;
|
|
}
|
|
|
|
ext = strrchr(filename, '.');
|
|
|
|
if (ext == NULL || strcmp(ext, ".rb")) {
|
|
printf("List command only supports .rb file.\n");
|
|
return MRB_DEBUG_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (line_min > line_max) {
|
|
return MRB_DEBUG_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if ((file = source_file_new(mrb, dbg, filename)) != NULL) {
|
|
show_lines(file, line_min, line_max);
|
|
source_file_free(mrb, file);
|
|
return MRB_DEBUG_OK;
|
|
}
|
|
else {
|
|
printf("Invalid source file named %s.\n", filename);
|
|
return MRB_DEBUG_INVALID_ARGUMENT;
|
|
}
|
|
}
|