mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-27 15:10:53 +00:00
Implement RLang.spp for templated scripting ##lang (#17067)
Co-authored-by: pancake <pancake@nopcode.org>
This commit is contained in:
parent
4b35fd9f19
commit
13e1636d97
@ -5,7 +5,4 @@ OBJS=lang.o
|
||||
R2DEPS=r_util r_cons
|
||||
|
||||
include ../rules.mk
|
||||
|
||||
pop:
|
||||
make
|
||||
r2 -c '#!rust' -
|
||||
CFLAGS+=-I$(SHLR)/spp
|
||||
|
@ -9,6 +9,7 @@ R_LIB_VERSION(r_lang);
|
||||
#include "p/vala.c" // hardcoded
|
||||
#include "p/rust.c" // hardcoded
|
||||
#include "p/zig.c" // hardcoded
|
||||
#include "p/spp.c" // hardcoded
|
||||
#include "p/c.c" // hardcoded
|
||||
#include "p/lib.c"
|
||||
#if __UNIX__
|
||||
@ -49,6 +50,7 @@ R_API RLang *r_lang_new(void) {
|
||||
r_lang_add (lang, &r_lang_plugin_vala);
|
||||
r_lang_add (lang, &r_lang_plugin_rust);
|
||||
r_lang_add (lang, &r_lang_plugin_zig);
|
||||
r_lang_add (lang, &r_lang_plugin_spp);
|
||||
r_lang_add (lang, &r_lang_plugin_pipe);
|
||||
r_lang_add (lang, &r_lang_plugin_lib);
|
||||
|
||||
@ -255,6 +257,7 @@ R_API int r_lang_prompt(RLang *lang) {
|
||||
|
||||
/* foo */
|
||||
for (;;) {
|
||||
r_cons_flush ();
|
||||
snprintf (buf, sizeof (buf)-1, "%s> ", lang->cur->name);
|
||||
r_line_set_prompt (buf);
|
||||
#if 0
|
||||
|
@ -8,12 +8,15 @@ r_lang_sources = [
|
||||
#'p/rust.c',
|
||||
#'p/vala.c'
|
||||
#'p/zig.c',
|
||||
#'p/spp.c',
|
||||
]
|
||||
|
||||
spp_inc = [platform_inc, include_directories('../../shlr/spp')]
|
||||
|
||||
r_lang = library('r_lang', r_lang_sources,
|
||||
include_directories: [platform_inc],
|
||||
include_directories: [platform_inc, spp_inc],
|
||||
c_args: library_cflags,
|
||||
dependencies: [r_util_dep, r_cons_dep],
|
||||
dependencies: [r_util_dep, spp_dep, r_cons_dep],
|
||||
install: true,
|
||||
implicit_include_directories: false,
|
||||
soversion: r2_libversion
|
||||
|
48
libr/lang/p/spp.c
Normal file
48
libr/lang/p/spp.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* radare - LGPL - Copyright 2020 pancake */
|
||||
|
||||
#include "r_lib.h"
|
||||
#include "r_core.h"
|
||||
#include "r_lang.h"
|
||||
#define USE_R2 1
|
||||
|
||||
static RLang *Glang = NULL;
|
||||
#include <spp.h>
|
||||
#include "spp_r2.inc"
|
||||
|
||||
static int lang_spp_init(RLang *l) {
|
||||
Glang = l;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lang_spp_run(RLang *lang, const char *code, int len) {
|
||||
Output out;
|
||||
out.fout = NULL;
|
||||
out.cout = r_strbuf_new (NULL);
|
||||
r_strbuf_init (out.cout);
|
||||
spp_proc_set (&spp_r2_proc, NULL, 0);
|
||||
char *c = strdup (code);
|
||||
spp_eval (c, &out);
|
||||
free (c);
|
||||
char *data = r_strbuf_drain (out.cout);
|
||||
r_cons_printf ("%s\n", data);
|
||||
free (data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lang_spp_file(RLang *lang, const char *file) {
|
||||
size_t len;
|
||||
char *code = r_file_slurp (file, &len);
|
||||
int res = lang_spp_run (lang, code, len);
|
||||
free (code);
|
||||
return res;
|
||||
}
|
||||
|
||||
static RLangPlugin r_lang_plugin_spp = {
|
||||
.name = "spp",
|
||||
.ext = "spp",
|
||||
.license = "MIT",
|
||||
.desc = "SPP template programs",
|
||||
.run = lang_spp_run,
|
||||
.init = (void*)lang_spp_init,
|
||||
.run_file = (void*)lang_spp_file,
|
||||
};
|
442
libr/lang/p/spp_r2.inc
Normal file
442
libr/lang/p/spp_r2.inc
Normal file
@ -0,0 +1,442 @@
|
||||
/* SPP-R2, a template programming language with r2 integration */
|
||||
|
||||
#include <r_util.h>
|
||||
|
||||
static char *spp_r2_var_get(char *var) {
|
||||
return r_sys_getenv (var);
|
||||
}
|
||||
|
||||
static int spp_r2_var_set(const char *var, const char *val) {
|
||||
return r_sys_setenv (var, val);
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_set) {
|
||||
char *eq, *val = "";
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
for (eq = buf; eq[0]; eq++) {
|
||||
switch (eq[0]) {
|
||||
case '-':
|
||||
case '.':
|
||||
eq[0] = '_';
|
||||
break;
|
||||
}
|
||||
}
|
||||
eq = strchr (buf, ' ');
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
val = eq + 1;
|
||||
}
|
||||
if (spp_r2_var_set (buf, val) == -1) {
|
||||
fprintf (stderr, "Invalid variable name '%s' at line %d\n", buf, state->lineno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_get) {
|
||||
char *var;
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
var = spp_r2_var_get (buf);
|
||||
if (var) {
|
||||
r_cons_printf ("%s", var);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_getrandom) {
|
||||
int max;
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
// XXX srsly? this is pretty bad random
|
||||
srandom (r_sys_getpid ()); // TODO: change this to be portable
|
||||
max = atoi (buf);
|
||||
if (max > 0) {
|
||||
max = (int)(rand () % max);
|
||||
}
|
||||
r_cons_printf ("%d", max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_add) {
|
||||
char res[32];
|
||||
char *var, *eq = strchr (buf, ' ');
|
||||
int ret = 0;
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
var = spp_r2_var_get (buf);
|
||||
if (var) {
|
||||
ret = atoi (var);
|
||||
}
|
||||
ret += atoi (eq + 1);
|
||||
snprintf (res, sizeof (res), "%d", ret);
|
||||
r_sys_setenv (buf, res);
|
||||
} else {
|
||||
/* syntax error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_sub) {
|
||||
char *eq = strchr (buf, ' ');
|
||||
char *var;
|
||||
int ret = 0;
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
var = spp_r2_var_get (buf);
|
||||
ret = var? atoi (var): 0;
|
||||
ret -= atoi (eq + 1);
|
||||
r_sys_setenv (buf, eq + 1);
|
||||
} else {
|
||||
/* syntax error */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_trace) {
|
||||
if (state->echo[state->ifl]) {
|
||||
fprintf (stderr, "%.1000s\n", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: deprecate */
|
||||
static TAG_CALLBACK(spp_r2_echo) {
|
||||
if (state->echo[state->ifl]) {
|
||||
r_cons_printf ("%s", buf);
|
||||
}
|
||||
// TODO: add variable replacement here?? not necessary, done by {{get}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_error) {
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
fprintf (stderr, "ERROR: %s (line=%d)\n", buf, state->lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_warning) {
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
fprintf (stderr, "WARNING: %s (line=%d)\n", buf, state->lineno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_r2) {
|
||||
char *str = Glang->cmd_str (Glang->user, buf);
|
||||
if (str) {
|
||||
r_cons_printf ("%s", str);
|
||||
free (str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_system) {
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
char *str = r_sys_cmd_str (buf, NULL, NULL);
|
||||
if (str) {
|
||||
r_cons_printf ("%s", str);
|
||||
free (str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_include) {
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
char *incdir = getenv ("SPP_INCDIR");
|
||||
if (incdir) {
|
||||
char *b = strdup (incdir);
|
||||
if (!b) {
|
||||
return 0;
|
||||
}
|
||||
char *p = realloc (b, strlen (b) + strlen (buf) + 3);
|
||||
if (p) {
|
||||
b = p;
|
||||
strcat (b, "/");
|
||||
strcat (b, buf);
|
||||
spp_file (b, out);
|
||||
}
|
||||
free (b);
|
||||
} else {
|
||||
spp_file (buf, out);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_if) {
|
||||
char *var = spp_r2_var_get (buf);
|
||||
state->echo[state->ifl + 1] = (var && *var != '0' && *var != '\0') ? 1 : 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* {{ ifeq $path / }} */
|
||||
static TAG_CALLBACK(spp_r2_ifeq) {
|
||||
char *value = buf;
|
||||
char *eq = strchr (buf, ' ');
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
value = spp_r2_var_get (value);
|
||||
if (value && !strcmp (value, eq + 1)) {
|
||||
state->echo[state->ifl + 1] = 1;
|
||||
} else {
|
||||
state->echo[state->ifl + 1] = 0;
|
||||
}
|
||||
} else {
|
||||
value = spp_r2_var_get (buf);
|
||||
if (!value || !*value) {
|
||||
state->echo[state->ifl + 1] = 1;
|
||||
} else {
|
||||
state->echo[state->ifl + 1] = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_hex) {
|
||||
size_t i;
|
||||
for (i = 0; buf[i]; i++) {
|
||||
if (isdigit (buf[i])) {
|
||||
int ch, b = buf[i + 2];
|
||||
buf[i + 2] = '\0';
|
||||
sscanf (buf + i, "%02x", &ch);
|
||||
r_cons_printf ("%c", ch & 0xff);
|
||||
buf[i + 2] = b;
|
||||
buf = buf + 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_grepline) {
|
||||
FILE *fd;
|
||||
char b[1024];
|
||||
int line;
|
||||
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 1;
|
||||
}
|
||||
char *ptr = strchr (buf, ' ');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
fd = fopen (buf, "r");
|
||||
line = atoi (ptr+1);
|
||||
if (fd) {
|
||||
while (!feof (fd) && line--) {
|
||||
if (!fgets (b, 1023, fd)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose (fd);
|
||||
r_cons_printf ("%s", b);
|
||||
} else {
|
||||
eprintf ("Unable to open '%s'\n", buf);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_else) {
|
||||
state->echo[state->ifl] = state->echo[state->ifl] ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_ifnot) {
|
||||
spp_r2_if (state, out, buf);
|
||||
spp_r2_else (state, out, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_ifin) {
|
||||
char *var, *ptr;
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 1;
|
||||
}
|
||||
ptr = strchr (buf, ' ');
|
||||
state->echo[state->ifl + 1] = 0;
|
||||
if (ptr) {
|
||||
*ptr='\0';
|
||||
var = getenv (buf);
|
||||
if (strstr (ptr + 1, var)) {
|
||||
state->echo[state->ifl + 1] = 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_endif) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_default) {
|
||||
if (!state->echo[state->ifl]) {
|
||||
return 0;
|
||||
}
|
||||
if (buf[-1] != ';') { /* commented tag */
|
||||
fprintf (stderr, "WARNING: invalid command: '%s' at line %d\n", buf, state->lineno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_SYSTEM
|
||||
static FILE *spp_r2_pipe_fd = NULL;
|
||||
#endif
|
||||
|
||||
static TAG_CALLBACK(spp_r2_pipe) {
|
||||
#if HAVE_SYSTEM
|
||||
spp_r2_pipe_fd = popen (buf, "w");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *spp_r2_switch_str = NULL;
|
||||
|
||||
static TAG_CALLBACK(spp_r2_switch) {
|
||||
char *var = spp_r2_var_get (buf);
|
||||
if (var) {
|
||||
spp_r2_switch_str = strdup (var);
|
||||
} else {
|
||||
spp_r2_switch_str = strdup ("");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_case) {
|
||||
state->echo[state->ifl] = strcmp (buf, spp_r2_switch_str)?0:1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_endswitch) {
|
||||
free (spp_r2_switch_str);
|
||||
spp_r2_switch_str = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static TAG_CALLBACK(spp_r2_endpipe) {
|
||||
#if HAVE_SYSTEM
|
||||
/* TODO: Get output here */
|
||||
int ret = 0, len = 0;
|
||||
int outlen = 4096;
|
||||
char *str = (char *)malloc (4096);
|
||||
char *tstr;
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
len += ret;
|
||||
ret = fread (str + len, 1, 1023, spp_r2_pipe_fd);
|
||||
if (ret + 1024 > outlen) {
|
||||
outlen += 4096;
|
||||
tstr = realloc (str, outlen);
|
||||
if (!tstr) {
|
||||
fprintf (stderr, "Out of memory.\n");
|
||||
break;
|
||||
}
|
||||
str = tstr;
|
||||
}
|
||||
} while (ret > 0);
|
||||
str[len] = '\0';
|
||||
r_cons_printf ("%s", str);
|
||||
if (spp_r2_pipe_fd) {
|
||||
pclose (spp_r2_pipe_fd);
|
||||
}
|
||||
spp_r2_pipe_fd = NULL;
|
||||
free (str);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PUT_CALLBACK(spp_r2_fputs) {
|
||||
#if HAVE_SYSTEM
|
||||
if (spp_r2_pipe_fd) {
|
||||
fprintf (spp_r2_pipe_fd, "%s", buf);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
r_cons_printf ("%s", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SppTag spp_r2_tags[] = {
|
||||
{ "get", spp_r2_get },
|
||||
{ "hex", spp_r2_hex },
|
||||
{ "getrandom", spp_r2_getrandom },
|
||||
{ "grepline", spp_r2_grepline },
|
||||
{ "set", spp_r2_set },
|
||||
{ "add", spp_r2_add },
|
||||
{ "sub", spp_r2_sub },
|
||||
{ "switch", spp_r2_switch },
|
||||
{ "case", spp_r2_case },
|
||||
{ "endswitch", spp_r2_endswitch },
|
||||
{ "echo", spp_r2_echo },
|
||||
{ "error", spp_r2_error },
|
||||
{ "warning", spp_r2_warning },
|
||||
{ "trace", spp_r2_trace },
|
||||
{ "ifin", spp_r2_ifin },
|
||||
{ "ifnot", spp_r2_ifnot },
|
||||
{ "ifeq", spp_r2_ifeq },
|
||||
{ "if", spp_r2_if },
|
||||
{ "else", spp_r2_else },
|
||||
{ "endif", spp_r2_endif },
|
||||
{ "pipe", spp_r2_pipe },
|
||||
{ "endpipe", spp_r2_endpipe },
|
||||
{ "include", spp_r2_include },
|
||||
{ "system", spp_r2_system },
|
||||
{ "r2", spp_r2_r2 },
|
||||
{ NULL, spp_r2_default },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static ARG_CALLBACK(spp_r2_arg_i) {
|
||||
r_sys_setenv ("SPP_INCDIR", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ARG_CALLBACK(spp_r2_arg_d) {
|
||||
/* TODO: Handle error */
|
||||
char *eq = strchr (arg, '=');
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
spp_r2_var_set (arg, eq+1);
|
||||
} else {
|
||||
spp_r2_var_set (arg, "");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct Arg spp_r2_args[] = {
|
||||
{ "-I", "add include directory", 1, spp_r2_arg_i },
|
||||
{ "-D", "define value of variable", 1, spp_r2_arg_d },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DLL_LOCAL SppProc spp_r2_proc = {
|
||||
.name = "sppr2",
|
||||
.tags = (struct Tag **)spp_r2_tags,
|
||||
.args = (struct Arg **)spp_r2_args,
|
||||
.token = " ",
|
||||
.eof = NULL,
|
||||
.tag_pre = "{",
|
||||
.tag_post = "}",
|
||||
.chop = 1,
|
||||
.fputs = spp_r2_fputs,
|
||||
.multiline = NULL,
|
||||
.default_echo = 1,
|
||||
.tag_begin = 0,
|
||||
};
|
@ -83,7 +83,7 @@ r_util_sources = [
|
||||
'annotated_code.c'
|
||||
]
|
||||
|
||||
r_util_deps = [ldl, mth, pth, utl, sdb_dep, zlib_dep, platform_deps]
|
||||
r_util_deps = [ldl, mth, spp_dep, pth, utl, sdb_dep, zlib_dep, platform_deps]
|
||||
if host_machine.system().startswith('freebsd') or host_machine.system().startswith('netbsd')
|
||||
# backtrace_symbols_fd requires -lexecinfo
|
||||
r_util_deps += [cc.find_library('execinfo')]
|
||||
|
@ -1,5 +1,6 @@
|
||||
SPPPATH=../../shlr/spp/
|
||||
CFLAGS+=-DHAVE_FORK=$(HAVE_FORK)
|
||||
CFLAGS+=-I../../shlr
|
||||
SPP_OBJS=spp.o
|
||||
SPPOBJS=$(addprefix ${SPPPATH},${SPP_OBJS})
|
||||
OBJS+=$(SPPOBJS)
|
||||
|
@ -261,6 +261,7 @@ io.zip
|
||||
io.r2k
|
||||
io.ar
|
||||
io.rbuf
|
||||
lang.spp
|
||||
lang.vala
|
||||
parse.6502_pseudo
|
||||
parse.arm_pseudo
|
||||
|
@ -37,6 +37,7 @@ test:
|
||||
done
|
||||
|
||||
install:
|
||||
mkdir -p ${BINDIR}
|
||||
${INSTALL_BIN} ${BIN} ${BINDIR}
|
||||
|
||||
uninstall:
|
||||
|
@ -87,7 +87,7 @@ static TAG_CALLBACK(spp_getrandom) {
|
||||
return 0;
|
||||
}
|
||||
// XXX srsly? this is pretty bad random
|
||||
srandom (r_sys_getpid()); // TODO: change this to be portable
|
||||
srandom (r_sys_getpid ()); // TODO: change this to be portable
|
||||
max = atoi (buf);
|
||||
if (max > 0) {
|
||||
max = (int)(rand () % max);
|
||||
|
@ -148,10 +148,13 @@ err_r_sys_get_env:
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int r_sys_getpid() {
|
||||
#if __WINDOWS__
|
||||
return (unsigned int)GetCurrentProcessId();
|
||||
int r_sys_getpid() {
|
||||
#if __UNIX__
|
||||
return getpid();
|
||||
#elif __WINDOWS__
|
||||
return GetCurrentProcessId();
|
||||
#else
|
||||
return (unsigned int)getpid();
|
||||
#warning r_sys_getpid not implemented for this platform
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ void r_strbuf_fini(SStrBuf *sb);
|
||||
void r_strbuf_init(SStrBuf *sb);
|
||||
int r_sys_setenv(const char *key, const char *value);
|
||||
char *r_sys_getenv(const char *key);
|
||||
unsigned int r_sys_getpid();
|
||||
int r_sys_getpid(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -5,7 +5,8 @@
|
||||
#include "config.h"
|
||||
|
||||
S_API int spp_run(char *buf, Output *out) {
|
||||
int i, ret = 0;
|
||||
size_t i;
|
||||
int ret = 0;
|
||||
char *tok;
|
||||
|
||||
D fprintf (stderr, "SPP_RUN(%s)\n", buf);
|
||||
@ -101,6 +102,13 @@ int do_fputs(Output *out, char *str) {
|
||||
return printed;
|
||||
}
|
||||
|
||||
S_API void spp_proc_eval(SppProc *p, char *buf, Output *out) {
|
||||
SppProc *op = proc;
|
||||
proc = p;
|
||||
spp_eval (buf, out);
|
||||
proc = op;
|
||||
}
|
||||
|
||||
S_API void spp_eval(char *buf, Output *out) {
|
||||
char *ptr, *ptr2;
|
||||
char *ptrr = NULL;
|
||||
@ -294,21 +302,24 @@ S_API void spp_proc_list() {
|
||||
}
|
||||
}
|
||||
|
||||
S_API void spp_proc_set(struct Proc *p, char *arg, int fail) {
|
||||
int i, j;
|
||||
if (arg)
|
||||
for (j = 0; procs[j]; j++) {
|
||||
if (!strcmp (procs[j]->name, arg)) {
|
||||
proc = procs[j];
|
||||
D printf ("SET PROC:(%s)(%s)\n", arg, proc->name);
|
||||
break;
|
||||
S_API void spp_proc_set(SppProc *p, const char *arg, int fail) {
|
||||
size_t i;
|
||||
bool found = false;
|
||||
if (arg) {
|
||||
for (i = 0; procs[i]; i++) {
|
||||
if (!strcmp (procs[i]->name, arg)) {
|
||||
proc = procs[i];
|
||||
found = true;
|
||||
D printf ("SET PROC:(%s)(%s)\n", arg, proc->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arg && *arg && !procs[j] && fail) {
|
||||
if (arg && *arg && !procs[i] && fail) {
|
||||
fprintf (stderr, "Invalid preprocessor name '%s'\n", arg);
|
||||
return;
|
||||
}
|
||||
if (!proc) {
|
||||
if (!found || !proc) {
|
||||
proc = p;
|
||||
}
|
||||
if (proc) {
|
||||
@ -318,7 +329,7 @@ S_API void spp_proc_set(struct Proc *p, char *arg, int fail) {
|
||||
proc->state.echo[i] = proc->default_echo;
|
||||
}
|
||||
//args = (struct Arg*)proc->args;
|
||||
tags = (struct Tag*)proc->tags;
|
||||
tags = (SppTag*)proc->tags;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,19 +119,19 @@ typedef struct SppBuf {
|
||||
#define PUT_CALLBACK(x) int x (Output *out, char *buf)
|
||||
#define IS_SPACE(x) ((x==' ')||(x=='\t')||(x=='\r')||(x=='\n'))
|
||||
|
||||
struct Tag {
|
||||
typedef struct Tag {
|
||||
const char *name;
|
||||
TAG_CALLBACK((*callback));
|
||||
};
|
||||
} SppTag;
|
||||
|
||||
struct Arg {
|
||||
typedef struct Arg {
|
||||
const char *flag;
|
||||
const char *desc;
|
||||
int has_arg;
|
||||
ARG_CALLBACK((*callback));
|
||||
};
|
||||
} SppArg;
|
||||
|
||||
struct Proc {
|
||||
typedef struct Proc {
|
||||
const char *name;
|
||||
struct Tag **tags;
|
||||
struct Arg **args;
|
||||
@ -146,15 +146,16 @@ struct Proc {
|
||||
int default_echo;
|
||||
SppState state;
|
||||
SppBuf buf;
|
||||
};
|
||||
} SppProc;
|
||||
|
||||
S_API int spp_file(const char *file, Output *out);
|
||||
S_API int spp_run(char *buf, Output *out);
|
||||
S_API void spp_eval(char *buf, Output *out);
|
||||
S_API void spp_proc_eval(SppProc *p, char *buf, Output *out);
|
||||
S_API void spp_io(FILE *in, Output *out);
|
||||
S_API void spp_proc_list(void);
|
||||
S_API void spp_proc_list_kw(void);
|
||||
S_API void spp_proc_set(struct Proc *p, char *arg, int fail);
|
||||
S_API void spp_proc_set(SppProc *p, const char *arg, int fail);
|
||||
|
||||
#if DEBUG
|
||||
#define D if (1)
|
||||
|
@ -40,6 +40,12 @@ RebuildIOSDebug() {
|
||||
fi
|
||||
}
|
||||
|
||||
RebuildSpp() {
|
||||
Rebuild shlr/spp
|
||||
Rebuild libr/util
|
||||
Rebuild libr/lang
|
||||
}
|
||||
|
||||
RebuildJava() {
|
||||
Rebuild shlr/java
|
||||
Rebuild libr/asm
|
||||
|
@ -17,3 +17,16 @@ EXPECT=<<EOF
|
||||
hello world
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=.spp
|
||||
FILE=-
|
||||
CMDS=<<EOF
|
||||
. scripts/r2test.spp
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Test
|
||||
hello world
|
||||
Eron
|
||||
|
||||
EOF
|
||||
RUN
|
||||
|
3
test/scripts/r2test.spp
Normal file
3
test/scripts/r2test.spp
Normal file
@ -0,0 +1,3 @@
|
||||
Test
|
||||
{r2 ?e hello world}
|
||||
Eron
|
Loading…
Reference in New Issue
Block a user