/* main.c -- chibi-scheme command-line app */ /* Copyright (c) 2009 Alex Shinn. All rights reserved. */ /* BSD-style license: http://synthcode.com/license.txt */ #ifdef PLAN9 #define file_exists_p(path, buf) (stat(path, buf, 128) >= 0) #else #include #define file_exists_p(path, buf) (! stat(path, buf)) #endif #include "chibi/eval.h" char *chibi_module_dir = NULL; sexp find_module_file (sexp ctx, char *file) { sexp res; int mlen, flen; char *path; #ifdef PLAN9 unsigned char buf[128]; #else struct stat buf_str; struct stat *buf = &buf_str; #endif if (file_exists_p(file, buf)) return sexp_c_string(ctx, file, -1); if (! chibi_module_dir) { #ifndef PLAN9 chibi_module_dir = getenv("CHIBI_MODULE_DIR"); if (! chibi_module_dir) #endif chibi_module_dir = sexp_module_dir; } mlen = strlen(chibi_module_dir); flen = strlen(file); path = (char*) malloc(mlen+flen+2); memcpy(path, chibi_module_dir, mlen); path[mlen] = '/'; memcpy(path+mlen+1, file, flen); path[mlen+flen+1] = '\0'; if (file_exists_p(path, buf)) res = sexp_c_string(ctx, path, mlen+flen+2); else res = SEXP_FALSE; free(path); return res; } sexp sexp_load_module_file (sexp ctx, char *file, sexp env) { sexp res = SEXP_VOID; sexp_gc_var2(path, irr); sexp_gc_preserve2(ctx, path, irr); path = find_module_file(ctx, file); if (! sexp_stringp(path)) { path = sexp_c_string(ctx, chibi_module_dir, -1); irr = sexp_cons(ctx, path, SEXP_NULL); path = sexp_c_string(ctx, file, -1); irr = sexp_cons(ctx, path, irr); res = sexp_user_exception(ctx, SEXP_FALSE, "couldn't find file to load in ./ or module dir", irr); } else { res = sexp_load(ctx, path, env); } sexp_gc_release2(ctx); return res; } sexp sexp_init_environments (sexp ctx) { sexp res, env; sexp_gc_var1(confenv); env = sexp_context_env(ctx); sexp_env_define(ctx, env, sexp_intern(ctx, "*command-line-arguments*"), SEXP_NULL); res = sexp_load_module_file(ctx, sexp_init_file, env); #if USE_MODULES if (! sexp_exceptionp(res)) { res = SEXP_UNDEF; sexp_gc_preserve1(ctx, confenv); confenv = sexp_make_env(ctx); sexp_env_copy(ctx, confenv, env, SEXP_FALSE); sexp_load_module_file(ctx, sexp_config_file, confenv); sexp_env_define(ctx, env, sexp_intern(ctx, "*config-env*"), confenv); sexp_env_define(ctx, confenv, sexp_intern(ctx, "*config-env*"), confenv); sexp_gc_release1(ctx); } #endif return res; } void repl (sexp ctx) { sexp in, out, err; sexp_gc_var4(obj, tmp, res, env); sexp_gc_preserve4(ctx, obj, tmp, res, env); env = sexp_context_env(ctx); sexp_context_tracep(ctx) = 1; in = sexp_eval_string(ctx, "(current-input-port)", env); out = sexp_eval_string(ctx, "(current-output-port)", env); err = sexp_eval_string(ctx, "(current-error-port)", env); sexp_port_sourcep(in) = 1; while (1) { sexp_write_string(ctx, "> ", out); sexp_flush(ctx, out); obj = sexp_read(ctx, in); if (obj == SEXP_EOF) break; if (sexp_exceptionp(obj)) { sexp_print_exception(ctx, obj, err); } else { tmp = sexp_env_bindings(env); sexp_context_top(ctx) = 0; res = sexp_eval(ctx, obj, env); #if USE_WARN_UNDEFS sexp_warn_undefs(ctx, sexp_env_bindings(env), tmp, err); #endif if (res != SEXP_VOID) { sexp_write(ctx, res, out); sexp_write_char(ctx, '\n', out); } } } sexp_gc_release4(ctx); } void run_main (int argc, char **argv) { sexp env, out=NULL, res=SEXP_VOID, ctx; sexp_sint_t i, quit=0, init_loaded=0; sexp_gc_var2(str, args); ctx = sexp_make_eval_context(NULL, NULL, NULL); sexp_gc_preserve2(ctx, str, args); env = sexp_context_env(ctx); out = sexp_eval_string(ctx, "(current-output-port)", env); args = SEXP_NULL; /* parse options */ for (i=1; i < argc && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 'e': case 'p': if (! init_loaded++) sexp_init_environments(ctx); res = sexp_read_from_string(ctx, argv[i+1]); if (! sexp_exceptionp(res)) res = sexp_eval(ctx, res, env); if (sexp_exceptionp(res)) { sexp_print_exception(ctx, res, out); quit = 1; break; } else if (argv[i][1] == 'p') { sexp_write(ctx, res, out); sexp_write_char(ctx, '\n', out); } quit=1; i++; break; case 'l': if (! init_loaded++) sexp_init_environments(ctx); sexp_load_module_file(ctx, argv[++i], env); break; case 'q': init_loaded = 1; break; case 'm': chibi_module_dir = argv[++i]; break; case 's': for (argc=argc-1; argc>i+1; argc--) args = sexp_cons(ctx, str=sexp_c_string(ctx,argv[argc],-1), args); argc++; break; default: errx(1, "unknown option: %s", argv[i]); } } if (! quit) { if (! init_loaded) res = sexp_init_environments(ctx); sexp_env_define(ctx, env, sexp_intern(ctx, "*command-line-arguments*"), args); if (res && sexp_exceptionp(res)) sexp_print_exception(ctx, res, sexp_eval_string(ctx, "(current-error-port)", env)); if (i < argc) for ( ; i < argc; i++) res = sexp_load(ctx, str=sexp_c_string(ctx, argv[i], -1), env); else repl(ctx); } sexp_gc_release2(ctx); } int main (int argc, char **argv) { sexp_scheme_init(); run_main(argc, argv); return 0; }