#include "scheme.h"

/* zelk needs these variables to be global */
/*static*/ Object V_Load_Path, V_Load_Noisilyp, V_Load_Libraries;

#ifdef CAN_LOAD_OBJ
#  define Default_Load_Libraries LOAD_LIBRARIES
#else
#  define Default_Load_Libraries ""
#endif

#if defined(CAN_DUMP) || defined(USE_LD)
char Loader_Input[20];
#endif

#ifdef USE_LD
#  include "load.ld.c"
#else
#ifdef USE_RLD
#  include "load.rld.c"
#else
#ifdef USE_SHL
#  include "load.shl.c"
#endif
#endif
#endif

Init_Load () {
    Define_Variable (&V_Load_Path, "load-path",
	Cons (Make_String (".", 1),
	Cons (Make_String (SCM_DIR, sizeof (SCM_DIR) - 1),
	Cons (Make_String (LIB_DIR, sizeof (LIB_DIR) - 1), Null))));
    Define_Variable (&V_Load_Noisilyp, "load-noisily?", False);
    Define_Variable (&V_Load_Libraries, "load-libraries", 
	Make_String (Default_Load_Libraries, sizeof Default_Load_Libraries-1));
}

Init_Loadpath (s) char *s; {     /* No GC possible here */
    register char *p;
    Object path = Null;

    if (s[0] == '\0')
	return;
    while (1) {
	for (p = s; *p && *p != ','; p++)
	    ;
	path = Cons (Make_String (s, p-s), path);
	if (*p == '\0')
	    break;
	s = ++p;
    }
    Var_Set (V_Load_Path, path);
}

Object Is_O_File (name) Object name; {
    register char *p;
    register struct S_String *str;

    if (TYPE(name) == T_Symbol)
	name = SYMBOL(name)->name;
    str = STRING(name);
    p = str->data + str->size;
    return str->size >= 2 && *--p == 'o' && *--p == '.';
}

void Check_Loadarg (x) Object x; {
    Object tail;
    register t = TYPE(x);

    if (t == T_Symbol || t == T_String)
	return;
    if (t != T_Pair)
	Wrong_Type_Combination (x, "string, symbol, or list");
    for (tail = x; !Nullp (tail); tail = Cdr (tail)) {
	Object f = Car (tail);
	if (TYPE(f) != T_Symbol && TYPE(f) != T_String)
	    Wrong_Type_Combination (f, "string or symbol");
	if (!Is_O_File (f))
	    Primitive_Error ("~s: not an object file", f);
    }
}

Object General_Load (what, env) Object what, env; {
    Object oldenv;
    GC_Node;

    Check_Type (env, T_Environment);
    oldenv = The_Environment;
    GC_Link (oldenv);
    Switch_Environment (env);
    Check_Loadarg (what);
    if (TYPE(what) == T_Pair)
#ifdef CAN_LOAD_OBJ
	Load_Object (what)
#endif
	;
    else if (Is_O_File (what))
#ifdef CAN_LOAD_OBJ
	Load_Object (Cons (what, Null))
#endif
	;
    else
	Load_Source (what);
    Switch_Environment (oldenv);
    GC_Unlink;
    return Void;
}

Object P_Load (argc, argv) Object *argv; {
    return General_Load (argv[0], argc == 1 ? The_Environment : argv[1]);
}

Load_Source_Port (port) Object port; {
    Object val;
    GC_Node;

    GC_Link (port);
    while (1) {
	val = General_Read (port, 1);
	if (TYPE(val) == T_End_Of_File)
	    break;
	val = Eval (val);
	if (Truep (Var_Get (V_Load_Noisilyp))) {
	    Print (val);
	    (void)P_Newline (0, (Object *)0);
	}
    }
    GC_Unlink;
}

Load_Source (name) Object name; {
    Object port;
    GC_Node;

    port = General_Open_File (name, P_INPUT, Var_Get (V_Load_Path));
    GC_Link (port);
    Load_Source_Port (port);
    (void)P_Close_Input_Port (port);
    GC_Unlink;
}
