# XXX Here there be dragons.
# Top-level bootstrap of Nickle builtins in Nickle.
# As you might expect, ordering and details are crucial.

# Set up the library path correctly and
# provide the "library" command.
# Lives in this file because it's necessary
# for bootstrapping

extend namespace Command {
    /* actually controls library loading */
    public string nickle_path = nickle_libdir;

    if (Environ::check("NICKLEPATH"))
	nickle_path = Environ::get("NICKLEPATH");

    public bool lex_file (string name) 
	/*
	 * Push the file 'name' into the lexer and read input
	 * from there until exhausted.  Then return to the current
	 * file.
	 */
    {
	return Command::lex_input (File::open (name, "r"), name, false, false);
    }
	
    /* currently just does ~ expansion */
    public string glob(string filename) 
	/*
	 * Expand any leading ~/ in 'filename' to the value of the
	 * HOME environment variable and return the resulting string
	 */
    {
	if (filename[0] == '~' && filename[1] == '/') {
	    exception bad_glob();
	    if (!Environ::check("HOME"))
		raise bad_glob();
	    return Environ::get("HOME") + 
		String::substr(filename, 1, String::length(filename) - 1);
	}
	return filename;
    }

    string path_first (string path)
    {
	int	i = String::index (path, ":");

	if (i < 0)
	    return glob(path);
	if (i == 0)
	    return ".";
	return glob(String::substr (path, 0, i));
    }

    string path_rest (string path)
    {
	int	i = String::index (path, ":");
	if (i < 0)
	    return "";
	
	int	l = String::length (path);
	if (i == l-1)
	    return ".";
	return String::substr (path, i + 1, l - i - 1);
    }
    
    public bool lex_library (string name) 
	/*
	 * Search 'nickle_path' for the file 'name' and push any
	 * found file into the lexer.  Returns whether any
	 * file was found and read.
	 */
    {
	for (string path = nickle_path;
	     path != "";
	     path = path_rest (path))
	{
	    try
		return lex_file (path_first (path) + "/" + name);
	    catch File::open_error (string name,
				    File::error_type err,
				    string msg) {
		;
	    }
	}
	return false;
    }
    
    public bool lex_string (string s) 
	/*
	 * Push 's' into the lexer input stack
	 */
    {
	return Command::lex_input (File::string_read (s), s, false, false);
    }

    new ("library", lex_library);
}


# Load the prerequisites for the extra commands.
library "ctype.5c";
library "string.5c";
library "file.5c";
library "printf.5c";

# Get abort() in early, even if this means not autoimporting it
library "abort.5c";
import Abort;

library "history.5c";

# Now load the extra commands.
library "parse-args.5c";
library "command.5c";

# Note that some libraries extend namespaces, and
# thus aren't autoload/autoimport candidates.
library "math.5c";
library "prime_sieve.5c"
library "factorial.5c"
library "gamma.5c"
import Math;
library "scanf.5c";
library "socket.5c";

# Now autoload/autoimport the bonus stuff
# (But why?  Let the users do it.)
#autoload Mutex;
#autoload ARC4;
#autoload PRNG;
#autoload Process;

# parse the command line
extend namespace Command {
      process_args (&argv);
}
