1
0
Fork 0

Add io.include() function to Nasal base library

io.inlude() loads and executes a Nasal file in place, effectively embedding
the script in the calling namespace. The function adds a symbol mark in the
namespace to avoid duplicate loading.

Additionally, in this path:

 + io.basename() & io.dirname(): Convenience functions for managing path
   strings. Designed after their unix counterparts.

 + string.normpath(): Improved support for relative paths. It can now handle
   paths starting with double dots, like ../../Directory
This commit is contained in:
Anton Gomez Alvedro 2013-11-04 13:58:04 +01:00 committed by Philosopher
parent b6f3e32212
commit 6ae3fae393
2 changed files with 65 additions and 13 deletions

View file

@ -8,6 +8,57 @@ var readfile = func(file) {
return buf;
}
# basename(<path>), dirname(<path>)
#
# Work like standard Unix commands: basename returns the file name from a given
# path, and dirname returns the directory part.
var basename = func(path) {
split("/", string.normpath(path))[-1];
};
var dirname = func(path) {
path = string.normpath(path);
substr(path, 0, size(path) - size(basename(path)));
};
# include(<filename>)
#
# Loads and executes a Nasal file in place. The file is searched for in the
# calling script directory and in standard FG directories (in that order).
#
# Examples:
#
# io.include("Aircraft/Generic/library.nas");
# io.include("my_other_file.nas");
var include = func(file) {
file = string.normpath(file);
var clr = caller();
var (ns, fn, fl) = clr;
var local_file = dirname(fl) ~ file;
var path = (stat(local_file) != nil)? local_file : resolvepath(file);
if (path == "") die("File not found: ", file);
var module = "__" ~ path ~ "__";
if (contains(ns, module))
return;
ns[module] = "included";
var code = call(compile, [readfile(path), path], var err = []);
if (size(err)) {
if (find("Parse error:", err[0]) < 0)
die(err[0]);
else
die(sprintf("%s\n in included file: %s", err[0], path));
}
call(bind(code, ns, fn), [], nil, ns);
}
# Loads Nasal file into namespace and executes it. The namespace
# (module name) is taken from the optional second argument, or
@ -33,8 +84,6 @@ var load_nasal = func(file, module = nil) {
var code = call(func compile(readfile(file), file), nil, var err = []);
if (size(err)) {
(func nil)(); # FIXME hack around Nasal bug
if (substr(err[0], 0, 12) == "Parse error:") { # hack around Nasal feature
var e = split(" at line ", err[0]);
if (size(e) == 2)

View file

@ -191,25 +191,28 @@ match = func(str, patt) {
##
# Removes superfluous slashes, empty and "." elements, expands
# all ".." elements, and turns all backslashes into slashes.
# The result will start with a slash if it started with a slash
# or backslash, it will end without slash. Should be applied to
# absolute property or file paths, otherwise ".." elements might
# be resolved wrongly.
# Removes superfluous slashes, empty and "." elements,
# expands all ".." elements keeping relative paths,
# and turns all backslashes into slashes.
# The result will start with a slash if it started with a slash or backslash,
# it will end without slash.
#
normpath = func(path) {
path = replace(path, "\\", "/");
var prefix = size(path) and path[0] == `/` ? "/" : "";
var stack = [];
var relative = 1;
foreach (var e; split("/", path)) {
if (e == "." or e == "")
continue;
elsif (e == "..")
elsif (e == ".." and !relative)
pop(stack);
else
else {
append(stack, e);
relative = 0;
}
}
return size(stack) ? prefix ~ join("/", stack) : "/";
}