android
This commit is contained in:
parent
37f7eb3cf3
commit
fe496e840d
@ -2108,31 +2108,23 @@ X_API int YAP_InitConsult(int mode, const char *fname, char *full, int *osnop) {
|
||||
const char *fl = NULL;
|
||||
int lvl = push_text_stack();
|
||||
if (mode == YAP_BOOT_MODE) {
|
||||
mode = YAP_CONSULT_MODE;
|
||||
}
|
||||
char *bfp = Malloc(YAP_FILENAME_MAX + 1);
|
||||
bfp[0] = '\0';
|
||||
mode = YAP_CONSULT_MODE; }
|
||||
if (fname == NULL || fname[0] == '\0') {
|
||||
fname = Yap_BOOTFILE;
|
||||
fl = Yap_BOOTFILE;
|
||||
}
|
||||
if (fname) {
|
||||
fl = Yap_AbsoluteFile(fname, bfp, true);
|
||||
fl = Yap_AbsoluteFile(fname, true);
|
||||
if (!fl || !fl[0]) {
|
||||
pop_text_stack(lvl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
bool consulted = (mode == YAP_CONSULT_MODE);
|
||||
sno = Yap_OpenStream(fl, "r", MkAtomTerm(Yap_LookupAtom(bfp)));
|
||||
sno = Yap_OpenStream(fl, "r", MkAtomTerm(Yap_LookupAtom(fl)));
|
||||
if (sno < 0)
|
||||
return sno;
|
||||
if (!Yap_ChDir(dirname((char *)fl))) return -1;
|
||||
Yap_init_consult(consulted, bfp);
|
||||
*osnop = Yap_CheckAlias(AtomLoopStream);
|
||||
if (!Yap_AddAlias(AtomLoopStream, sno)) {
|
||||
Yap_CloseStream(sno);
|
||||
pop_text_stack(lvl);
|
||||
sno = -1;
|
||||
return sno;
|
||||
}
|
||||
Yap_init_consult(consulted, fl);
|
||||
GLOBAL_Stream[sno].name = Yap_LookupAtom(fl);
|
||||
GLOBAL_Stream[sno].user_name = MkAtomTerm(Yap_LookupAtom(fname));
|
||||
GLOBAL_Stream[sno].encoding = LOCAL_encoding;
|
||||
@ -2167,7 +2159,8 @@ X_API void YAP_EndConsult(int sno, int *osnop, const char *full) {
|
||||
if (osnop >= 0)
|
||||
Yap_AddAlias(AtomLoopStream, *osnop);
|
||||
Yap_end_consult();
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid ", " closing %s(%d), %d", full, *osnop, sno);
|
||||
// LOCAL_CurSlot);
|
||||
RECOVER_MACHINE_REGS();
|
||||
}
|
||||
|
||||
|
57
C/inlines.c
57
C/inlines.c
@ -51,6 +51,57 @@ static Int p_dif( USES_REGS1 );
|
||||
static Int p_eq( USES_REGS1 );
|
||||
static Int p_arg( USES_REGS1 );
|
||||
static Int p_functor( USES_REGS1 );
|
||||
static Int p_fail( USES_REGS1 );
|
||||
static Int p_true( USES_REGS1 );
|
||||
|
||||
/** @pred fail is iso
|
||||
|
||||
Always fails. Defined as if by:
|
||||
|
||||
~~~~~
|
||||
fail :- 2=1.
|
||||
~~~~~
|
||||
*/
|
||||
|
||||
/** @pred false is iso
|
||||
|
||||
The same as fail. Defined as if by:
|
||||
|
||||
~~~~~
|
||||
false :- 2=1.
|
||||
~~~~~
|
||||
*/
|
||||
|
||||
static Int p_fail( USES_REGS1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @pred true is iso
|
||||
Succeed.
|
||||
|
||||
Succeeds once. Defined as if by:
|
||||
|
||||
~~~~~
|
||||
true :- true.
|
||||
~~~~~
|
||||
*/
|
||||
|
||||
/** @pred otherwise is iso
|
||||
Succeed.
|
||||
|
||||
Succeeds once. Defined as if by:
|
||||
|
||||
~~~~~
|
||||
otherwise.
|
||||
~~~~~
|
||||
*/
|
||||
|
||||
|
||||
static Int p_true( USES_REGS1 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** @pred atom( _T_) is iso
|
||||
@ -1150,6 +1201,10 @@ cont_genarg( USES_REGS1 )
|
||||
CurrentModule = ARG_MODULE;
|
||||
Yap_InitCPredBack("genarg", 3, 3, genarg, cont_genarg,SafePredFlag);
|
||||
CurrentModule = cm;
|
||||
}
|
||||
Yap_InitCPred("true", 0, p_true, SafePredFlag);
|
||||
Yap_InitCPred("otherwise", 0, p_true, SafePredFlag);
|
||||
Yap_InitCPred("false", 0, p_fail, SafePredFlag);
|
||||
Yap_InitCPred("fail", 0, p_fail, SafePredFlag);
|
||||
}
|
||||
|
||||
|
||||
|
2
C/save.c
2
C/save.c
@ -1319,7 +1319,7 @@ static int commit_to_saved_state(const char *s, CELL *Astate, CELL *ATrail,
|
||||
LOCAL_PrologMode = BootMode;
|
||||
if (Yap_HeapBase) {
|
||||
if (falseGlobalPrologFlag(HALT_AFTER_CONSULT_FLAG) && !silentMode()) {
|
||||
Yap_AbsoluteFile(s, tmp, true);
|
||||
strcpy(tmp, Yap_AbsoluteFile(s, true));
|
||||
fprintf(stderr, "%% Restoring file %s\n", tmp);
|
||||
}
|
||||
Yap_CloseStreams(TRUE);
|
||||
|
@ -539,7 +539,8 @@ static inline int getchr(struct stream_desc *inp) {
|
||||
* **********************************\n", AtomName(inp->name)); */
|
||||
/* inp0 = inp; */
|
||||
/* } */
|
||||
int ch = inp->stream_wgetc_for_read(inp - GLOBAL_Stream);
|
||||
int sno = inp - GLOBAL_Stream;
|
||||
int ch = inp->stream_wgetc_for_read(sno);
|
||||
// fprintf(stderr,"%c", ch);
|
||||
return ch;
|
||||
}
|
||||
@ -1334,7 +1335,6 @@ TokEntry *Yap_tokenizer(struct stream_desc *st, bool store_comments,
|
||||
LOCAL_AnonVarTable = NULL;
|
||||
l = NULL;
|
||||
p = NULL; /* Just to make lint happy */
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "i %d", st - GLOBAL_Stream);
|
||||
ch = getchr(st);
|
||||
while (chtype(ch) == BS) {
|
||||
ch = getchr(st);
|
||||
|
16
C/stdpreds.c
16
C/stdpreds.c
@ -1349,13 +1349,17 @@ static Int p_statistics_lu_db_size(USES_REGS1) {
|
||||
}
|
||||
|
||||
static Int p_executable(USES_REGS1) {
|
||||
char tmp[YAP_FILENAME_MAX+1];
|
||||
if (GLOBAL_argv && GLOBAL_argv[0])
|
||||
Yap_AbsoluteFile(GLOBAL_argv[0], tmp, true);
|
||||
else
|
||||
strncpy(tmp, Yap_FindExecutable(), YAP_FILENAME_MAX);
|
||||
int lvl = push_text_stack();
|
||||
const char *tmp =
|
||||
|
||||
return Yap_unify(MkAtomTerm(Yap_LookupAtom(tmp)), ARG1);
|
||||
Yap_AbsoluteFile(GLOBAL_argv[0], true);
|
||||
if (!tmp || tmp[0] == '\0' ) {
|
||||
tmp = Malloc(YAP_FILENAME_MAX + 1);
|
||||
strncpy((char *)tmp, Yap_FindExecutable(), YAP_FILENAME_MAX);
|
||||
}
|
||||
Atom at = Yap_LookupAtom(tmp);
|
||||
pop_text_stack(lvl);
|
||||
return Yap_unify(MkAtomTerm(at), ARG1);
|
||||
}
|
||||
|
||||
static Int p_system_mode(USES_REGS1) {
|
||||
|
88
C/yap-args.c
88
C/yap-args.c
@ -20,6 +20,7 @@
|
||||
#include "YapHeap.h"
|
||||
#include "YapInterface.h"
|
||||
#include "YapStreams.h"
|
||||
#include "iopreds.h"
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
@ -161,34 +162,42 @@ const char *Yap_BINDIR, *Yap_ROOTDIR, *Yap_SHAREDIR, *Yap_LIBDIR, *Yap_DLLDIR,
|
||||
/* do initial boot by consulting the file boot.yap */
|
||||
static void consult(const char *b_file USES_REGS) {
|
||||
Term t;
|
||||
int boot_stream, osno;
|
||||
int c_stream, osno, oactive;
|
||||
Functor functor_query = Yap_MkFunctor(Yap_LookupAtom("?-"), 1);
|
||||
Functor functor_command1 = Yap_MkFunctor(Yap_LookupAtom(":-"), 1);
|
||||
Functor functor_compile2 = Yap_MkFunctor(Yap_LookupAtom("c_compile"), 1);
|
||||
|
||||
/* consult boot.pl */
|
||||
char *full = malloc(YAP_FILENAME_MAX + 1);
|
||||
int lvl = push_text_stack();
|
||||
char *full = Malloc(YAP_FILENAME_MAX + 1);
|
||||
full[0] = '\0';
|
||||
/* the consult mode does not matter here, really */
|
||||
boot_stream = YAP_InitConsult(YAP_BOOT_MODE, b_file, full, &osno);
|
||||
if (boot_stream < 0) {
|
||||
if ((osno = Yap_CheckAlias(AtomLoopStream)) < 0)
|
||||
osno = 0;
|
||||
c_stream = YAP_InitConsult(YAP_BOOT_MODE, b_file, full, &oactive);
|
||||
if (c_stream < 0) {
|
||||
pop_text_stack(lvl);
|
||||
fprintf(stderr, "[ FATAL ERROR: could not open stream %s ]\n", b_file);
|
||||
exit(1);
|
||||
}
|
||||
if (!Yap_AddAlias(AtomLoopStream, c_stream)) {
|
||||
pop_text_stack(lvl);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
CACHE_REGS
|
||||
YAP_Reset(YAP_FULL_RESET, false);
|
||||
Yap_StartSlots();
|
||||
Term vs = YAP_MkVarTerm(), pos = MkVarTerm();
|
||||
t = YAP_ReadClauseFromStream(boot_stream, vs, pos);
|
||||
t = YAP_ReadClauseFromStream(c_stream, vs, pos);
|
||||
// Yap_GetNèwSlot(t);
|
||||
if (t == 0) {
|
||||
fprintf(stderr, "[ SYNTAX ERROR: while parsing stream %s at line %ld ]\n",
|
||||
b_file, GLOBAL_Stream[boot_stream].linecount);
|
||||
b_file, GLOBAL_Stream[c_stream].linecount);
|
||||
} else if (IsVarTerm(t) || t == TermNil) {
|
||||
fprintf(stderr, "[ line %d: term cannot be compiled ]",
|
||||
GLOBAL_Stream[boot_stream].linecount);
|
||||
GLOBAL_Stream[c_stream].linecount);
|
||||
} else if (IsApplTerm(t) && (FunctorOfTerm(t) == functor_query ||
|
||||
FunctorOfTerm(t) == functor_command1)) {
|
||||
t = ArgOfTerm(1, t);
|
||||
@ -206,13 +215,8 @@ static void consult(const char *b_file USES_REGS) {
|
||||
}
|
||||
} while (t != TermEof);
|
||||
BACKUP_MACHINE_REGS();
|
||||
|
||||
YAP_EndConsult(boot_stream, &osno, full);
|
||||
free(full);
|
||||
#if DEBUG
|
||||
if (Yap_output_msg)
|
||||
fprintf(stderr, "Boot loaded\n");
|
||||
#endif
|
||||
YAP_EndConsult(c_stream, &osno, full);
|
||||
pop_text_stack(lvl);
|
||||
}
|
||||
|
||||
/** @brief A simple language for detecting where YAP stuff can be found
|
||||
@ -241,6 +245,19 @@ typedef struct config {
|
||||
const char **bootpl;
|
||||
} config_t;
|
||||
|
||||
#if __ANDROID__
|
||||
const char *gd_root[] = {"@RootDir", "/assets"};
|
||||
const char *gd_lib[] = {"@LibDir", "[lib]", "(root)/lib/" "x86"};
|
||||
const char *gd_share[] = {"@ShareDir", "(root)"};
|
||||
const char *gd_include[] = {"@IncludeDir", "[include]", "(root)/include"};
|
||||
const char *gd_dll[] = {"@DLLDir", "(lib)"};
|
||||
const char *gd_pl[] = {"@PlDir", "(share)/Yap", "@BootPlDir/../library"};
|
||||
const char *gd_commons[] = {"@CommonsDir", "(share)/PrologCommons"};
|
||||
const char *gd_ss[] = {"(dll)"};
|
||||
const char *gd_oss[] = {"."};
|
||||
const char *gd_bootpldir[] = {"@BootPlDir", "@PrologBootFile/..", "(pl)/pl"};
|
||||
const char *gd_bootpl[] = {"(bootpldir)" };
|
||||
#else
|
||||
const char *gd_root[] = {"@RootDir", "[root]", "(execdir)/.."};
|
||||
const char *gd_lib[] = {"@LibDir", "[lib]", "(root)/lib"};
|
||||
const char *gd_share[] = {"@ShareDir", "[share]", "(root)/share"};
|
||||
@ -252,8 +269,9 @@ const char *gd_ss[] = {"(dll)"};
|
||||
const char *gd_oss[] = {"."};
|
||||
const char *gd_bootpldir[] = {"@BootPlDir", "@PrologBootFile/..", "(pl)/pl"};
|
||||
const char *gd_bootpl[] = {"@PrologBootFile", "(bootpldir)/setup.yap"};
|
||||
#endif
|
||||
|
||||
static config_t *gnu(config_t *i) {
|
||||
static config_t *cfg(config_t *i) {
|
||||
i->root = gd_root;
|
||||
i->lib = gd_lib;
|
||||
i->share = gd_share;
|
||||
@ -272,10 +290,11 @@ static config_t *gnu(config_t *i) {
|
||||
/**
|
||||
* Search
|
||||
*/
|
||||
char *location(YAP_init_args *iap, const char *inp, char *out) {
|
||||
char *location(YAP_init_args *iap, const char *inp) {
|
||||
if (inp == NULL || inp[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
char * out = Malloc(FILENAME_MAX+1);
|
||||
out[0] = '\0';
|
||||
if (inp[0] == '(') {
|
||||
if (strstr(inp + 1, "root") == inp + 1 && Yap_ROOTDIR &&
|
||||
@ -311,8 +330,7 @@ char *location(YAP_init_args *iap, const char *inp, char *out) {
|
||||
strcpy(out, Yap_BOOTFILE);
|
||||
strcat(out, inp + strlen("(bootpl)"));
|
||||
} else if (strstr(inp + 1, "execdir") == inp + 1) {
|
||||
char *buf = Malloc(YAP_FILENAME_MAX + 1);
|
||||
const char *ex = Yap_AbsoluteFile(Yap_FindExecutable(), buf, true);
|
||||
const char *ex = Yap_AbsoluteFile(Yap_FindExecutable(), true);
|
||||
if (ex != NULL) {
|
||||
strcpy(out, dirname((char *)ex));
|
||||
strcat(out, "/");
|
||||
@ -447,17 +465,14 @@ static const char *find_directory(YAP_init_args *iap, const char *paths[],
|
||||
}
|
||||
int i = 0;
|
||||
while ((inp = paths[i++]) != NULL) {
|
||||
out[0] = '\0';
|
||||
const char *o = location(iap, inp, out);
|
||||
char qp[FILENAME_MAX + 1];
|
||||
if (o && o[0] && (o = Yap_AbsoluteFile(o, qp, false)) &&
|
||||
Yap_isDirectory(o)) {
|
||||
if (filename) {
|
||||
strcat(o, "/");
|
||||
strcat(o, filename);
|
||||
char *o = location(iap, inp);
|
||||
if (filename && o) {
|
||||
strcat(o, "/");
|
||||
strcat(o, filename);
|
||||
if (o =(const char *) Yap_AbsoluteFile(o, false)) {
|
||||
o = pop_output_text_stack(lvl, o);
|
||||
return o;
|
||||
}
|
||||
o = pop_output_text_stack(lvl, o);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
pop_text_stack(lvl);
|
||||
@ -467,7 +482,7 @@ static const char *find_directory(YAP_init_args *iap, const char *paths[],
|
||||
static void Yap_set_locations(YAP_init_args *iap) {
|
||||
config_t t, *template;
|
||||
|
||||
template = gnu(&t);
|
||||
template = cfg(&t);
|
||||
Yap_ROOTDIR = find_directory(iap, template->root, NULL);
|
||||
Yap_LIBDIR = find_directory(iap, template->lib, NULL);
|
||||
// Yap_BINDIR = find_directory(iap, template->bin, NULL);
|
||||
@ -475,7 +490,9 @@ static void Yap_set_locations(YAP_init_args *iap) {
|
||||
Yap_DLLDIR = find_directory(iap, template->dll, NULL);
|
||||
Yap_PLDIR = find_directory(iap, template->pl, NULL);
|
||||
Yap_BOOTPLDIR = find_directory(iap, template->bootpldir, NULL);
|
||||
Yap_BOOTFILE = find_directory(iap, template->bootpldir, "setup.yap");
|
||||
if (iap->PrologBootFile == NULL)
|
||||
iap->PrologBootFile = "boot.yap";
|
||||
Yap_BOOTFILE = find_directory(iap, template->bootpldir,iap->PrologBootFile );
|
||||
Yap_COMMONSDIR = find_directory(iap, template->commons, NULL);
|
||||
if (iap->SavedState == NULL)
|
||||
iap->SavedState = "startup.yss";
|
||||
@ -483,10 +500,7 @@ static void Yap_set_locations(YAP_init_args *iap) {
|
||||
if (iap->OutputSavedState == NULL)
|
||||
iap->OutputSavedState = "startup.yss";
|
||||
Yap_OUTPUT_STARTUP = find_directory(iap, template->ss, iap->OutputSavedState);
|
||||
if (iap->PrologBootFile == NULL)
|
||||
iap->PrologBootFile = "boot.yap";
|
||||
Yap_BOOTFILE = find_directory(iap, template->bootpldir, iap->PrologBootFile);
|
||||
if (Yap_ROOTDIR)
|
||||
if (Yap_ROOTDIR)
|
||||
setAtomicGlobalPrologFlag(HOME_FLAG,
|
||||
MkAtomTerm(Yap_LookupAtom(Yap_ROOTDIR)));
|
||||
if (Yap_PLDIR)
|
||||
@ -637,9 +651,9 @@ X_API YAP_file_type_t YAP_parse_yap_arguments(int argc, char *argv[],
|
||||
case 'B':
|
||||
iap->boot_file_type = YAP_BOOT_PL;
|
||||
if (p[1])
|
||||
iap->BootPlDir = p + 1;
|
||||
iap->PrologBootFile = p + 1;
|
||||
else if (argv[1] && *argv[1] != '-') {
|
||||
iap->BootPlDir = *++argv;
|
||||
iap->PrologBootFile = *++argv;
|
||||
argc--;
|
||||
}
|
||||
iap->install = true;
|
||||
@ -1160,6 +1174,7 @@ X_API YAP_file_type_t YAP_Init(YAP_init_args *yap_init) {
|
||||
/* tell the system who should cope with interrupts */
|
||||
Yap_ExecutionMode = yap_init->ExecutionMode;
|
||||
Yap_set_locations(yap_init);
|
||||
|
||||
if (!do_bootstrap && Yap_STARTUP && yap_init->boot_file_type != YAP_BOOT_PL &&
|
||||
Yap_SavedInfo(Yap_STARTUP, &minfo.Trail, &minfo.Stack, &minfo.Heap) &&
|
||||
Yap_Restore(Yap_STARTUP)) {
|
||||
@ -1179,6 +1194,7 @@ X_API YAP_file_type_t YAP_Init(YAP_init_args *yap_init) {
|
||||
Term t = MkAtomTerm(Yap_LookupAtom(Yap_OUTPUT_STARTUP));
|
||||
Term g = Yap_MkApplTerm(Yap_MkFunctor(Yap_LookupAtom("qsave_program"), 1),
|
||||
1, &t);
|
||||
|
||||
YAP_RunGoalOnce(g);
|
||||
}
|
||||
setAtomicGlobalPrologFlag(RESOURCE_DATABASE_FLAG,
|
||||
|
@ -568,7 +568,7 @@ List(APPEND YLIBS $<TARGET_OBJECTS:libswi>)
|
||||
if (WIN32 OR ANDROID)
|
||||
List(APPEND YLIBS $<TARGET_OBJECTS:Yapsqlite3>)
|
||||
List(APPEND YLIBS $<TARGET_OBJECTS:YAP++>)
|
||||
if (WITH_PYTHON)
|
||||
if (WIN32 AND WITH_PYTHON)
|
||||
List(APPEND YLIBS $<TARGET_OBJECTS:Py4YAP>)
|
||||
endif ()
|
||||
endif ()
|
||||
|
@ -9,13 +9,13 @@ set (CXX_SOURCES
|
||||
)
|
||||
list(APPEND LIBYAP_SOURCES ${CXX_SOURCES} PARENT_SCOPE)
|
||||
|
||||
if ( WIN32)
|
||||
if ( WIN32 OR ANDROID)
|
||||
add_component (YAP++ ${CXX_SOURCES} )
|
||||
|
||||
set_property( DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "_YAP_NOT_INSTALLED_=1;HAVE_CONFIG_H=1;_GNU_SOURCE;YAP_KERNEL=1" )
|
||||
else()
|
||||
add_lib(YAP++ ${CXX_SOURCES} )
|
||||
MY_target_link_libraries(YAP++ ${CMAKE_DL_LIBS} libYap)
|
||||
target_link_libraries(YAP++ ${CMAKE_DL_LIBS} libYap)
|
||||
|
||||
MY_install(TARGETS YAP++
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
|
@ -12,6 +12,7 @@ extern "C" {
|
||||
|
||||
#include "YapInterface.h"
|
||||
#include "blobs.h"
|
||||
#include "iopreds.h"
|
||||
|
||||
X_API char *Yap_TermToBuffer(Term t, encoding_t encodingp, int flags);
|
||||
|
||||
@ -843,8 +844,8 @@ void Yap_displayWithJava(int c) {
|
||||
|
||||
#endif
|
||||
|
||||
void YAPEngine::doInit(YAP_file_type_t BootMode) {
|
||||
if ((BootMode = YAP_Init(engine_args)) == YAP_FOUND_BOOT_ERROR) {
|
||||
void YAPEngine::doInit(YAP_file_type_t BootMode, YAPEngineArgs *engineArgs) {
|
||||
if ((BootMode = YAP_Init(engineArgs)) == YAP_FOUND_BOOT_ERROR) {
|
||||
return;
|
||||
throw YAPError();
|
||||
}
|
||||
@ -874,7 +875,7 @@ YAPEngine::YAPEngine(int argc, char *argv[],
|
||||
// if (cb)
|
||||
// setYAPCallback(cb);
|
||||
|
||||
doInit(BootMode);
|
||||
doInit(BootMode, engine_args);
|
||||
}
|
||||
|
||||
YAPPredicate::YAPPredicate(YAPAtom at) {
|
||||
|
@ -188,7 +188,7 @@ public:
|
||||
/// @brief Setup all arguments to a new engine
|
||||
struct X_API YAPEngineArgs : YAP_init_args {
|
||||
public:
|
||||
YAPEngineArgs() : yap_boot_params() {
|
||||
YAPEngineArgs() {
|
||||
const std::string *s = new std::string("startup.yss");
|
||||
Embedded = true;
|
||||
Yap_InitDefaults(this, (char *)s->c_str(), 0, nullptr);
|
||||
@ -294,7 +294,7 @@ private:
|
||||
YAPEngineArgs *engine_args;
|
||||
YAPCallback *_callback;
|
||||
YAPError yerror;
|
||||
void doInit(YAP_file_type_t BootMode);
|
||||
void doInit(YAP_file_type_t BootMode, YAPEngineArgs *cargs);
|
||||
YAP_dogoalinfo q;
|
||||
PredEntry *rewriteUndefEngineQuery(PredEntry *ap, Term t, Term tmod);
|
||||
|
||||
@ -303,7 +303,7 @@ public:
|
||||
YAPEngine(YAPEngineArgs *cargs) {
|
||||
engine_args = cargs;
|
||||
// doInit(cargs->boot_file_type);
|
||||
doInit(YAP_QLY);
|
||||
doInit(YAP_QLY, cargs);
|
||||
}; /// construct a new engine, including aaccess to callbacks
|
||||
/// construct a new engine using argc/argv list of arguments
|
||||
YAPEngine(int argc, char *argv[],
|
||||
|
2
H/Yap.h
2
H/Yap.h
@ -450,7 +450,7 @@ extern int Yap_output_msg;
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
extern AAssetManager *Yap_assetManager;
|
||||
extern AAssetManager *Yap_assetManager(void);
|
||||
|
||||
extern void *Yap_openAssetFile(const char *path);
|
||||
extern bool Yap_isAsset(const char *path);
|
||||
|
@ -295,7 +295,6 @@ extern int Yap_eq(Term, Term);
|
||||
/* iopreds.c */
|
||||
extern bool Yap_IsAbsolutePath(const char *p, bool);
|
||||
extern Atom Yap_TemporaryFile(const char *prefix, int *fd);
|
||||
extern const char *Yap_AbsoluteFile(const char *spec, char *obuf, bool expand);
|
||||
extern void Yap_InitPlIO( struct yap_boot_params *ts );
|
||||
extern void Yap_InitBackIO(void);
|
||||
extern void Yap_InitIOPreds(void);
|
||||
@ -413,9 +412,9 @@ extern int Yap_signal_index(const char *);
|
||||
#ifdef MAC
|
||||
extern void Yap_SetTextFile(char *);
|
||||
#endif
|
||||
extern const char *Yap_AbsoluteFile(const char *spec, bool expand);
|
||||
#if __ANDROID__
|
||||
#include <android/asset_manager.h>
|
||||
extern AAssetManager *Yap_assetManager;
|
||||
|
||||
extern void *Yap_openAssetFile(const char *path);
|
||||
extern bool Yap_isAsset(const char *path);
|
||||
@ -433,7 +432,6 @@ extern char *Yap_RegistryGetString(char *);
|
||||
extern void Yap_WinError(char *);
|
||||
#endif
|
||||
|
||||
extern const char *Yap_AbsoluteFile(const char *spec, char *obuf, bool ok);
|
||||
extern const char *Yap_AbsoluteFileInBuffer(const char *spec, char *outp, size_t sz,
|
||||
bool ok);
|
||||
extern bool Yap_ChDir(const char *path);
|
||||
|
@ -128,10 +128,7 @@ static inline VFS_t *vfs_owner(const char *fname) {
|
||||
while (me) {
|
||||
bool p = true;
|
||||
if ((me->vflags & VFS_HAS_PREFIX) && p) {
|
||||
const char *r = fname, *s = me->prefix;
|
||||
while (*s && p)
|
||||
p = *s++ == *r++;
|
||||
if (p && r > fname + 1)
|
||||
if (strstr(fname,me->prefix)==fname)
|
||||
return me;
|
||||
}
|
||||
if (me->vflags & VFS_HAS_SUFFIX && (sz = strlen(me->suffix)) &&
|
||||
|
84
os/assets.c
84
os/assets.c
@ -36,43 +36,71 @@ static char SccsId[] = "%W% %G%";
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/native_activity.h>
|
||||
|
||||
AAssetManager *Yap_assetManager;
|
||||
jobject *Yap_aref;
|
||||
JNIEnv *Yap_env;
|
||||
|
||||
AAssetManager *Yap_assetManager(void)
|
||||
{
|
||||
return AAssetManager_fromJava(Yap_env, Yap_aref);
|
||||
}
|
||||
|
||||
jboolean
|
||||
Java_pt_up_yap_app_YAPDroid_setAssetManager(JNIEnv *env, jclass clazz, jobject assetManager) {
|
||||
Yap_assetManager = AAssetManager_fromJava(env, assetManager);
|
||||
Yap_aref = (*env)->NewGlobalRef(env,assetManager);
|
||||
Yap_env = env;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
open_asset__(VFS_t *me, int sno, const char *fname, const char *io_mode) {
|
||||
open_asset(VFS_t *me, int sno, const char *fname, const char *io_mode) {
|
||||
int mode;
|
||||
const void *buf;
|
||||
|
||||
|
||||
AAsset *am = NULL;
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "open %s <%s>", fname, io_mode);
|
||||
if (strchr(io_mode, 'B'))
|
||||
mode = AASSET_MODE_BUFFER;
|
||||
else {
|
||||
mode = AASSET_MODE_UNKNOWN;
|
||||
}
|
||||
fname += strlen(me->prefix) + 1;
|
||||
AAsset *a = AAssetManager_open(Yap_assetManager, fname, mode);
|
||||
if (!a)
|
||||
GLOBAL_Stream[sno].name = Yap_LookupAtom(fname);
|
||||
fname += strlen(me->prefix)+1;
|
||||
// strcpy(dir, fname);
|
||||
// AAssetDir *dp = AAssetManager_openDir( Yap_assetManager(), dirname(dir) );
|
||||
// strcpy(dir, fname);
|
||||
// char *d = basename(dir);
|
||||
am = AAssetManager_open(Yap_assetManager(), fname, mode);
|
||||
// while (dp) {
|
||||
// char *f = AAssetDir_getNextFileName(dp);
|
||||
// __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "open %s <%s>", f, d);
|
||||
// if (f && strcasecmp(d,f) == 0) {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!am)
|
||||
return NULL;
|
||||
// try not to use it as an asset
|
||||
off64_t sz = AAsset_getLength64(a), sz0 = 0;
|
||||
off64_t sz = AAsset_getLength64(am), sz0 = 0;
|
||||
int fd;
|
||||
StreamDesc *st = GLOBAL_Stream + sno;
|
||||
if ((buf = AAsset_getBuffer(a))) {
|
||||
if ((buf = AAsset_getBuffer(am))) {
|
||||
// copy to memory
|
||||
bool rc = Yap_set_stream_to_buf(st, buf, sz);
|
||||
if (rc) AAsset_close(a);
|
||||
char *bf = malloc(sz);
|
||||
memcpy(bf, buf, sz);
|
||||
bool rc = Yap_set_stream_to_buf(st, bf, sz);
|
||||
if (rc) AAsset_close(am);
|
||||
st->vfs = NULL;
|
||||
st->vfs_handle = NULL;
|
||||
st->status = InMemory_Stream_f|Seekable_Stream_f|Input_Stream_f;
|
||||
return st;
|
||||
} else if ((fd = AAsset_openFileDescriptor64(a, &sz0, &sz)) >= 0) {
|
||||
} else if ((fd = AAsset_openFileDescriptor64(am, &sz0, &sz)) >= 0) {
|
||||
// can use it as read-only file
|
||||
st->file = fdopen(fd, "r");
|
||||
st->vfs = NULL;
|
||||
@ -81,10 +109,10 @@ open_asset__(VFS_t *me, int sno, const char *fname, const char *io_mode) {
|
||||
return st;
|
||||
} else {
|
||||
// should be done, but if not
|
||||
GLOBAL_Stream[sno].vfs_handle = a;
|
||||
GLOBAL_Stream[sno].vfs_handle = am;
|
||||
st->vfs = me;
|
||||
st->status = Input_Stream_f;
|
||||
return a;
|
||||
return am;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +136,7 @@ static int getc_asset(int sno) {
|
||||
|
||||
static void *opendir_a(VFS_t *me, const char *dirName) {
|
||||
dirName += strlen(me->prefix) + 1;
|
||||
return (void *) AAssetManager_openDir(Yap_assetManager, dirName);
|
||||
return (void *) AAssetManager_openDir(Yap_assetManager(), dirName);
|
||||
}
|
||||
|
||||
static const char *readdir_a(void *dirHandle) {
|
||||
@ -135,7 +163,7 @@ static bool stat_a(VFS_t *me, const char *fname, vfs_stat *out) {
|
||||
memcpy(&out->st_birthtimespec, (const void *) &out->st_birthtimespec,
|
||||
sizeof(struct timespec));
|
||||
}
|
||||
AAsset *a = AAssetManager_open(Yap_assetManager, fname, AASSET_MODE_UNKNOWN);
|
||||
AAsset *a = AAssetManager_open(Yap_assetManager(), fname, AASSET_MODE_UNKNOWN);
|
||||
// try not to use it as an asset
|
||||
out->st_size = AAsset_getLength64(a);
|
||||
AAsset_close(a);
|
||||
@ -145,23 +173,24 @@ static bool stat_a(VFS_t *me, const char *fname, vfs_stat *out) {
|
||||
|
||||
static
|
||||
bool is_dir_a(VFS_t *me, const char *dirName) {
|
||||
bool rc;
|
||||
dirName += strlen(me->prefix) + 1;
|
||||
dirName += strlen(me->prefix);
|
||||
if (dirName[0] == '\0')
|
||||
dirName = "/";
|
||||
// try not to use it as an asset
|
||||
AAssetDir *d = AAssetManager_openDir(Yap_assetManager, dirName);
|
||||
AAssetDir *d = AAssetManager_openDir(Yap_assetManager(), dirName);
|
||||
if (d == NULL)
|
||||
return false;
|
||||
rc = (AAssetDir_getNextFileName(d) != NULL);
|
||||
(AAssetDir_close(d));
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "isdir %s <%p>", dirName, d);
|
||||
AAssetDir_close(d);
|
||||
return rc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool exists_a(VFS_t *me, const char *dirName) {
|
||||
dirName += strlen(me->prefix) + 1;
|
||||
// try not to use it as an asset
|
||||
AAsset *d = AAssetManager_open(Yap_assetManager, dirName, AASSET_MODE_UNKNOWN);
|
||||
AAsset *d = AAssetManager_open(Yap_assetManager(), dirName, AASSET_MODE_UNKNOWN);
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid", "exists %s <%p>", dirName, d);
|
||||
if (d == NULL)
|
||||
return false;
|
||||
@ -170,16 +199,15 @@ bool exists_a(VFS_t *me, const char *dirName) {
|
||||
}
|
||||
|
||||
|
||||
extern char virtual_cwd[YAP_FILENAME_MAX + 1];
|
||||
char virtual_cwd[YAP_FILENAME_MAX + 1];
|
||||
|
||||
static bool set_cwd(VFS_t *me, const char *dirName) {
|
||||
|
||||
chdir("/assets");
|
||||
strcpy(virtual_cwd, dirName);
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid",
|
||||
"chdir %s", virtual_cwd);
|
||||
Yap_do_low_level_trace=1;
|
||||
return true;
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid",
|
||||
"chdir %s", virtual_cwd);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -198,7 +226,7 @@ Yap_InitAssetManager(void) {
|
||||
VFS_HAS_PREFIX; /// the main flags describing the operation of the Fs.
|
||||
me->prefix = "/assets";
|
||||
/** operations */
|
||||
me->open = open_asset__; /// open an object in this space
|
||||
me->open = open_asset; /// open an object in this space
|
||||
me->close = close_asset; /// close the object
|
||||
me->get_char = getc_asset; /// get an octet to the stream
|
||||
me->put_char = NULL; /// output an octet to the stream
|
||||
|
49
os/files.c
49
os/files.c
@ -163,6 +163,15 @@ static Int access_path(USES_REGS1) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
|
||||
return false;
|
||||
} else {
|
||||
VFS_t *vfs;
|
||||
char *s = RepAtom(AtomOfTerm(tname))->StrOfAE;
|
||||
if (!s) return false;
|
||||
if ((vfs = vfs_owner(s))) {
|
||||
vfs_stat st;
|
||||
bool rc = vfs->stat(vfs, s, &st);
|
||||
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
||||
return rc;
|
||||
}
|
||||
#if HAVE_STAT
|
||||
struct SYSTEM_STAT ss;
|
||||
char *file_name;
|
||||
@ -190,6 +199,15 @@ static Int exists_file(USES_REGS1) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
|
||||
return FALSE;
|
||||
} else {
|
||||
VFS_t *vfs;
|
||||
char *s = RepAtom(AtomOfTerm(tname))->StrOfAE;
|
||||
if (!s) return false;
|
||||
if ((vfs = vfs_owner(s))) {
|
||||
vfs_stat st;
|
||||
bool rc = vfs->stat(vfs, s, &st);
|
||||
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
||||
return rc;
|
||||
}
|
||||
#if HAVE_STAT
|
||||
struct SYSTEM_STAT ss;
|
||||
|
||||
@ -249,6 +267,12 @@ static Int time_file(USES_REGS1) {
|
||||
return FALSE;
|
||||
} else {
|
||||
const char *n = RepAtom(AtomOfTerm(tname))->StrOfAE;
|
||||
VFS_t *vfs;
|
||||
if ((vfs = vfs_owner(n))) {
|
||||
vfs_stat s;
|
||||
vfs->stat(vfs, n, &s);
|
||||
return Yap_unify(ARG2, MkIntegerTerm(s.st_mtimespec.tv_sec));
|
||||
}
|
||||
#if __WIN32
|
||||
FILETIME ft;
|
||||
HANDLE hdl;
|
||||
@ -304,6 +328,15 @@ static Int file_size(USES_REGS1) {
|
||||
"file_size/2");
|
||||
if (sno < 0)
|
||||
return (FALSE);
|
||||
VFS_t *vfs;
|
||||
char *s = RepAtom(GLOBAL_Stream[sno].name)->StrOfAE;
|
||||
if (!s) return false;
|
||||
if ((vfs = vfs_owner(s))) {
|
||||
vfs_stat st;
|
||||
vfs->stat(vfs, s, &st);
|
||||
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
||||
return Yap_unify_constant(ARG2, MkIntegerTerm(st.st_size));
|
||||
}
|
||||
if (GLOBAL_Stream[sno].status & Seekable_Stream_f &&
|
||||
!(GLOBAL_Stream[sno].status &
|
||||
(InMemory_Stream_f | Socket_Stream_f | Pipe_Stream_f))) {
|
||||
@ -457,6 +490,22 @@ static Int exists_directory(USES_REGS1) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, tname, "exists_directory/1");
|
||||
return FALSE;
|
||||
} else {
|
||||
VFS_t *vfs;
|
||||
char *s = Yap_VF(RepAtom(AtomOfTerm(tname))->StrOfAE);
|
||||
if (!s) return false;
|
||||
if ((vfs = vfs_owner(s))) {
|
||||
bool rc = true;
|
||||
void *o;
|
||||
if ((o=vfs->opendir(vfs, s))) {
|
||||
rc = true;
|
||||
vfs->closedir(o);
|
||||
} else {
|
||||
rc = false;
|
||||
}
|
||||
|
||||
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
||||
return rc;
|
||||
}
|
||||
#if HAVE_STAT
|
||||
struct SYSTEM_STAT ss;
|
||||
|
||||
|
46
os/iopreds.c
46
os/iopreds.c
@ -1217,8 +1217,7 @@ do_open(Term file_name, Term t2,
|
||||
int sno;
|
||||
StreamDesc *st;
|
||||
bool avoid_bom = false, needs_bom = false;
|
||||
const char *fname;
|
||||
char fbuf[FILENAME_MAX];
|
||||
const char *fname0;
|
||||
stream_flags_t flags;
|
||||
const char *s_encoding;
|
||||
encoding_t encoding;
|
||||
@ -1231,13 +1230,13 @@ do_open(Term file_name, Term t2,
|
||||
}
|
||||
if (!IsAtomTerm(file_name)) {
|
||||
if (IsStringTerm(file_name)) {
|
||||
fname = (char *)StringOfTerm(file_name);
|
||||
fname0 = (char *)StringOfTerm(file_name);
|
||||
} else {
|
||||
Yap_Error(DOMAIN_ERROR_SOURCE_SINK, file_name, "open/3");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
fname = RepAtom(AtomOfTerm(file_name))->StrOfAE;
|
||||
fname0 = RepAtom(AtomOfTerm(file_name))->StrOfAE;
|
||||
}
|
||||
// open mode
|
||||
if (IsVarTerm(t2)) {
|
||||
@ -1280,13 +1279,16 @@ do_open(Term file_name, Term t2,
|
||||
: false) ||
|
||||
trueGlobalPrologFlag(OPEN_EXPANDS_FILENAME_FLAG);
|
||||
// expand file name?
|
||||
fname = Yap_AbsoluteFile(fname, fbuf, ok);
|
||||
int lvl = push_text_stack();
|
||||
const char *fname = Yap_AbsoluteFile(fname0, ok);
|
||||
|
||||
if (!fname) {
|
||||
pop_text_stack(lvl);
|
||||
PlIOError(EXISTENCE_ERROR_SOURCE_SINK, ARG1, NULL);
|
||||
}
|
||||
|
||||
// Skip scripts that start with !#/.. or similar
|
||||
pop_text_stack(lvl);
|
||||
bool script =
|
||||
(args[OPEN_SCRIPT].used ? args[OPEN_SCRIPT].tvalue == TermTrue : false);
|
||||
// binary type
|
||||
@ -1307,7 +1309,8 @@ do_open(Term file_name, Term t2,
|
||||
#endif
|
||||
/* note that this matters for UNICODE style conversions */
|
||||
} else {
|
||||
Yap_Error(DOMAIN_ERROR_STREAM, tlist,
|
||||
pop_text_stack(lvl);
|
||||
Yap_Error(DOMAIN_ERROR_STREAM, tlist,
|
||||
"type is ~a, must be one of binary or text", t);
|
||||
}
|
||||
}
|
||||
@ -1333,10 +1336,11 @@ do_open(Term file_name, Term t2,
|
||||
} else if (open_mode == AtomAppend) {
|
||||
strncpy(io_mode, "a", 8);
|
||||
} else {
|
||||
Yap_Error(DOMAIN_ERROR_IO_MODE, MkAtomTerm(open_mode), "open/3");
|
||||
pop_text_stack(lvl);
|
||||
return false;
|
||||
}
|
||||
if ((sno = Yap_OpenStream(fname, io_mode, file_name)) < 0) {
|
||||
pop_text_stack(lvl);
|
||||
return false;
|
||||
}
|
||||
st = &GLOBAL_Stream[sno];
|
||||
@ -1369,12 +1373,12 @@ do_open(Term file_name, Term t2,
|
||||
st->encoding = enc_id(s_encoding, st->encoding);
|
||||
else
|
||||
st->encoding = encoding;
|
||||
if (script)
|
||||
open_header(sno, open_mode);
|
||||
if (fname != fbuf)
|
||||
freeBuffer(fname);
|
||||
if (script) {
|
||||
open_header(sno, open_mode);
|
||||
}
|
||||
pop_text_stack(lvl);
|
||||
|
||||
free(args);
|
||||
free(args);
|
||||
UNLOCK(st->streamlock);
|
||||
{
|
||||
Term t = Yap_MkStream(sno);
|
||||
@ -1497,11 +1501,16 @@ static Int p_file_expansion(USES_REGS1) { /* '$file_expansion'(+File,-Name) */
|
||||
PlIOError(INSTANTIATION_ERROR, file_name, "absolute_file_name/3");
|
||||
return (FALSE);
|
||||
}
|
||||
char tmp[YAP_FILENAME_MAX + 1];
|
||||
if (!Yap_AbsoluteFile(RepAtom(AtomOfTerm(file_name))->StrOfAE, tmp, false))
|
||||
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, file_name,
|
||||
"absolute_file_name/3"));
|
||||
return (Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(tmp))));
|
||||
int lvl = push_text_stack();
|
||||
const char *tmp;
|
||||
if ((tmp=Yap_AbsoluteFile(RepAtom(AtomOfTerm(file_name))->StrOfAE, false)) == NULL) {
|
||||
pop_text_stack(lvl);
|
||||
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, file_name,
|
||||
"absolute_file_name/3"));
|
||||
}
|
||||
bool rc = (Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(tmp))));
|
||||
pop_text_stack(lvl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Int p_open_null_stream(USES_REGS1) {
|
||||
@ -1558,12 +1567,13 @@ int Yap_OpenStream(const char *fname, const char *io_mode, Term user_name) {
|
||||
st->status = 0;
|
||||
fname = Yap_VF(fname);
|
||||
if ((vfsp = vfs_owner(fname)) != NULL) {
|
||||
if (!vfsp->open(vfsp, sno, fname, io_mode)) {
|
||||
if (!vfsp->open(vfsp, sno, fname, "r")) {
|
||||
UNLOCK(st->streamlock);
|
||||
PlIOError(EXISTENCE_ERROR_SOURCE_SINK, MkAtomTerm(Yap_LookupAtom(fname)),
|
||||
"%s", fname);
|
||||
return -1;
|
||||
}
|
||||
vfsp = GLOBAL_Stream[sno].vfs;
|
||||
} else {
|
||||
fd = st->file = fopen(fname, io_mode);
|
||||
if (fd == NULL) {
|
||||
|
@ -296,7 +296,7 @@ bool Yap_InitReadline(Term enable) {
|
||||
#endif
|
||||
// rl_outstream = stderr;
|
||||
using_history();
|
||||
const char *s = Yap_AbsoluteFile("~/.YAP.history", NULL, true);
|
||||
const char *s = Yap_AbsoluteFile("~/.YAP.history", true);
|
||||
history_file = s;
|
||||
if (read_history(s) != 0) {
|
||||
FILE *f = fopen(s, "a");
|
||||
|
207
os/sysbits.c
207
os/sysbits.c
@ -161,13 +161,11 @@ bool Yap_IsAbsolutePath(const char *p0, bool expand) {
|
||||
// this is necessary because
|
||||
// support for ~expansion at the beginning
|
||||
// systems like Android do not do this.
|
||||
static const char *PlExpandVars(const char *source, const char *root,
|
||||
char *result) {
|
||||
static const char *PlExpandVars(const char *source, const char *root) {
|
||||
CACHE_REGS
|
||||
int lvl = push_text_stack();
|
||||
const char *src = source;
|
||||
if (!result)
|
||||
result = Malloc(YAP_FILENAME_MAX + 1);
|
||||
char * result = Malloc(YAP_FILENAME_MAX + 1);
|
||||
|
||||
if (strlen(source) >= YAP_FILENAME_MAX) {
|
||||
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
|
||||
@ -346,13 +344,15 @@ char virtual_cwd[YAP_FILENAME_MAX + 1];
|
||||
|
||||
bool Yap_ChDir(const char *path) {
|
||||
bool rc = false;
|
||||
char qp[FILENAME_MAX + 1];
|
||||
const char *qpath = Yap_AbsoluteFile(path, qp, true);
|
||||
int lvl = push_text_stack();
|
||||
|
||||
VFS_t *v;
|
||||
if ((v = vfs_owner(path))) {
|
||||
return v->chdir(v, path);
|
||||
rc = v->chdir(v, path);
|
||||
pop_text_stack(lvl);
|
||||
return rc;
|
||||
}
|
||||
const char *qpath = Yap_AbsoluteFile(path, true);
|
||||
#if _WIN32
|
||||
rc = true;
|
||||
if (qpath != NULL && qpath[0] &&
|
||||
@ -362,47 +362,125 @@ bool Yap_ChDir(const char *path) {
|
||||
#else
|
||||
rc = (chdir(qpath) == 0);
|
||||
#endif
|
||||
if (qpath != qp && qpath != path && qpath != LOCAL_FileNameBuf &&
|
||||
qpath != LOCAL_FileNameBuf2)
|
||||
free((char *)qpath);
|
||||
pop_text_stack(lvl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const char *myrealpath(const char *path, char *out) {
|
||||
static char * close_path(char *b0,char *o0, char *o ){
|
||||
|
||||
if (b0[0] == '\0') {
|
||||
return o;
|
||||
} else if (!strcmp(b0, "..")) {
|
||||
while (o-- > o0) {
|
||||
if (dir_separator(*o)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (strcmp(b0, ".") != 0) {
|
||||
*o++ = '/';
|
||||
strcpy(o, b0);
|
||||
o += strlen(b0);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static char * clean_path(const char *path)
|
||||
{
|
||||
const char *p, *p0;
|
||||
int lvl = push_text_stack();
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid ", " looking at %s", path) ;
|
||||
char *o0 = Malloc(FILENAME_MAX+1),*o = o0;
|
||||
int ch;
|
||||
char *b0 = Malloc(FILENAME_MAX+1), *b = b0;
|
||||
p = p0 = path;
|
||||
while((ch = *p++)) {
|
||||
if (dir_separator(ch)) {
|
||||
if (b==b0) {
|
||||
o = o0;
|
||||
} else {
|
||||
b[0] = '\0';
|
||||
o = close_path(b0, o0, o);
|
||||
b = b0;
|
||||
}
|
||||
} else {
|
||||
*b++ = ch;
|
||||
}
|
||||
}
|
||||
if (!dir_separator(p[-1])) {
|
||||
b[0] = '\0';
|
||||
o = close_path(b0, o0, o);
|
||||
}
|
||||
if (o == o0)
|
||||
*o++ = '/';
|
||||
*o = '\0';
|
||||
__android_log_print(ANDROID_LOG_INFO, "YAPDroid ", " %s at %s, %p-%p", p0, o0, o, o0) ;
|
||||
return pop_output_text_stack(lvl,o0);
|
||||
|
||||
}
|
||||
|
||||
static const char *myrealpath(const char *path USES_REGS) {
|
||||
|
||||
int lvl = push_text_stack();
|
||||
VFS_t *v;
|
||||
char *out, *o;
|
||||
if (Yap_IsAbsolutePath(path,true)) {
|
||||
o = clean_path(path);
|
||||
if ((v = vfs_owner(o))
|
||||
) {
|
||||
return pop_output_text_stack(lvl, o);
|
||||
|
||||
}
|
||||
} else {
|
||||
out = Malloc(FILENAME_MAX+1);
|
||||
Yap_getcwd(out, FILENAME_MAX);
|
||||
strcat(out, "/");
|
||||
strcat(out, path);
|
||||
o = clean_path(out);
|
||||
if ((v = vfs_owner(o))) {
|
||||
return pop_output_text_stack(lvl, o);
|
||||
}
|
||||
}
|
||||
#if _WIN32
|
||||
DWORD retval = 0;
|
||||
|
||||
// notice that the file does not need to exist
|
||||
retval = GetFullPathName(path, YAP_FILENAME_MAX, out, NULL);
|
||||
pop_text_stack(lvl);
|
||||
retval = GetFullPathName(path, YAP_FILENAME_MAX, o, NULL);
|
||||
if (retval == 0) {
|
||||
Yap_WinError("Generating a full path name for a file");
|
||||
pop_text_stack(lvl);
|
||||
Yap_WinError("Generating a full path name for a file");
|
||||
return NULL;
|
||||
}
|
||||
return out;
|
||||
return pop_output_text_stack(lvl, o);
|
||||
#elif HAVE_REALPATH
|
||||
{
|
||||
char *rc = realpath(path, NULL);
|
||||
char *rc = realpath(path, o);
|
||||
|
||||
if (rc) {
|
||||
pop_text_stack(lvl);
|
||||
return rc;
|
||||
rc = pop_output_text_stack(lvl, rc);
|
||||
}
|
||||
// rc = NULL;
|
||||
if (errno == ENOENT || errno == EACCES) {
|
||||
char *base = Malloc(YAP_FILENAME_MAX + 1);
|
||||
strncpy(base, path, YAP_FILENAME_MAX);
|
||||
rc = realpath(dirname(base), out);
|
||||
char *base = Malloc(FILENAME_MAX + 1);
|
||||
strncpy(base, path, FILENAME_MAX);
|
||||
char *p = base+strlen(base);
|
||||
while (p>base && !dir_separator(*--p));
|
||||
if (p == base) p[1] = '\0';
|
||||
else p[0] = '\0';
|
||||
char *tmp = Malloc(FILENAME_MAX + 1);
|
||||
rc = realpath(base, tmp);
|
||||
|
||||
if (rc) {
|
||||
// base may haave been destroyed
|
||||
const char *b = basename((char *)path);
|
||||
size_t e = strlen(rc);
|
||||
// base may have been destroyed
|
||||
char *b = base+strlen(base);
|
||||
while (b>base && !dir_separator(*--b));
|
||||
if (b[0] && !dir_separator(b[0])) b++;
|
||||
size_t e = strlen(rc);
|
||||
size_t bs = strlen(b);
|
||||
|
||||
if (rc != out && rc != base) {
|
||||
rc = realloc(rc, e + bs + 2);
|
||||
rc = Realloc(rc, e + bs + 2);
|
||||
}
|
||||
#if _WIN32
|
||||
if (rc[e - 1] != '\\' && rc[e - 1] != '/') {
|
||||
@ -422,10 +500,8 @@ static const char *myrealpath(const char *path, char *out) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
out = malloc(strlen(path) + 1);
|
||||
strcpy(out, path);
|
||||
pop_text_stack(lvl);
|
||||
return out;
|
||||
return path;
|
||||
}
|
||||
|
||||
static const char *expandVars(const char *spec, char *u) {
|
||||
@ -456,11 +532,11 @@ static const char *expandVars(const char *spec, char *u) {
|
||||
*
|
||||
* @return tmp, or NULL, in malloced memory
|
||||
*/
|
||||
const char *Yap_AbsoluteFile(const char *spec, char *rc0, bool ok) {
|
||||
const char *Yap_AbsoluteFile(const char *spec, bool ok) {
|
||||
const char *rc;
|
||||
const char *spec1;
|
||||
const char *spec2;
|
||||
char rc1[YAP_FILENAME_MAX + 1];
|
||||
int lvl = push_text_stack();
|
||||
|
||||
/// spec gothe original spec;
|
||||
/// rc0 may be an outout buffer
|
||||
@ -480,7 +556,7 @@ const char *Yap_AbsoluteFile(const char *spec, char *rc0, bool ok) {
|
||||
/// spec gothe original spec;
|
||||
/// rc1 the internal buffer
|
||||
if (ok) {
|
||||
const char *q = PlExpandVars(spec1, NULL, rc1);
|
||||
const char *q = PlExpandVars(spec1, NULL);
|
||||
if (!q)
|
||||
spec2 = spec1;
|
||||
else
|
||||
@ -488,8 +564,8 @@ const char *Yap_AbsoluteFile(const char *spec, char *rc0, bool ok) {
|
||||
} else {
|
||||
spec2 = spec1;
|
||||
}
|
||||
rc = myrealpath(spec2, rc0);
|
||||
return rc;
|
||||
rc = myrealpath(spec2 PASS_REGS);
|
||||
return pop_output_text_stack(lvl,rc);
|
||||
}
|
||||
|
||||
static Term
|
||||
@ -678,14 +754,15 @@ static Int real_path(USES_REGS1) {
|
||||
}
|
||||
cmd = rc;
|
||||
#endif
|
||||
|
||||
rc0 = myrealpath(cmd, NULL);
|
||||
int lvl = push_text_stack();
|
||||
rc0 = myrealpath(cmd PASS_REGS);
|
||||
if (!rc0) {
|
||||
PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, NULL);
|
||||
}
|
||||
bool out = Yap_unify(MkAtomTerm(Yap_LookupAtom(rc0)), ARG2);
|
||||
freeBuffer(rc0);
|
||||
return out;
|
||||
pop_output_text_stack(lvl,rc0);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#define EXPAND_FILENAME_DEFS() \
|
||||
@ -859,7 +936,7 @@ static Int absolute_file_system_path(USES_REGS1) {
|
||||
pop_text_stack(l);
|
||||
return false;
|
||||
}
|
||||
if (!(fp = Yap_AbsoluteFile(text, NULL, true))) {
|
||||
if (!(fp = Yap_AbsoluteFile(text, true))) {
|
||||
pop_text_stack(l);
|
||||
return false;
|
||||
}
|
||||
@ -1086,8 +1163,8 @@ static Int true_file_name(USES_REGS1) {
|
||||
Term t = Deref(ARG1);
|
||||
const char *s;
|
||||
|
||||
if (IsVarTerm(t)) {
|
||||
Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
|
||||
if (IsVarTerm(t)) {
|
||||
Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
|
||||
return FALSE;
|
||||
}
|
||||
if (IsAtomTerm(t)) {
|
||||
@ -1095,13 +1172,14 @@ static Int true_file_name(USES_REGS1) {
|
||||
} else if (IsStringTerm(t)) {
|
||||
s = StringOfTerm(t);
|
||||
} else {
|
||||
Yap_Error(TYPE_ERROR_ATOM, t, "argument to true_file_name");
|
||||
Yap_Error(TYPE_ERROR_ATOM, t, "argument to true_file_name");
|
||||
return FALSE;
|
||||
}
|
||||
if (!(s = Yap_AbsoluteFile(s, LOCAL_FileNameBuf, true)))
|
||||
int l = push_text_stack();
|
||||
if (!(s = Yap_AbsoluteFile(s, true)))
|
||||
return false;
|
||||
bool rc = Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(s)));
|
||||
freeBuffer(s);
|
||||
pop_text_stack(l);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1119,7 +1197,7 @@ static Int p_expand_file_name(USES_REGS1) {
|
||||
pop_text_stack(l);
|
||||
return false;
|
||||
}
|
||||
if (!(text2 = PlExpandVars(text, NULL, NULL))) {
|
||||
if (!(text2 = PlExpandVars(text, NULL))) {
|
||||
pop_text_stack(l);
|
||||
return false;
|
||||
}
|
||||
@ -1129,27 +1207,30 @@ static Int p_expand_file_name(USES_REGS1) {
|
||||
}
|
||||
|
||||
static Int true_file_name3(USES_REGS1) {
|
||||
Term t = Deref(ARG1), t2 = Deref(ARG2);
|
||||
Term t = Deref(ARG1), t2 = Deref(ARG2);
|
||||
|
||||
if (IsVarTerm(t)) {
|
||||
Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
|
||||
return FALSE;
|
||||
}
|
||||
if (!IsAtomTerm(t)) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, t, "argument to true_file_name");
|
||||
return FALSE;
|
||||
}
|
||||
if (!IsVarTerm(t2)) {
|
||||
if (!IsAtomTerm(t)) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, t2, "argument to true_file_name");
|
||||
return FALSE;
|
||||
if (IsVarTerm(t)) {
|
||||
Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
|
||||
return FALSE;
|
||||
}
|
||||
// root = RepAtom(AtomOfTerm(t2))->StrOfAE;
|
||||
}
|
||||
char tmp[YAP_FILENAME_MAX + 1];
|
||||
if (!Yap_AbsoluteFile(RepAtom(AtomOfTerm(t))->StrOfAE, tmp, true))
|
||||
return FALSE;
|
||||
return Yap_unify(ARG3, MkAtomTerm(Yap_LookupAtom(tmp)));
|
||||
if (!IsAtomTerm(t)) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, t, "argument to true_file_name");
|
||||
return FALSE;
|
||||
}
|
||||
if (!IsVarTerm(t2)) {
|
||||
if (!IsAtomTerm(t)) {
|
||||
Yap_Error(TYPE_ERROR_ATOM, t2, "argument to true_file_name");
|
||||
return FALSE;
|
||||
}
|
||||
// root = RepAtom(AtomOfTerm(t2))->StrOfAE;
|
||||
}
|
||||
int lvl = push_text_stack();
|
||||
const char *tmp = Yap_AbsoluteFile(RepAtom(AtomOfTerm(t))->StrOfAE, true);
|
||||
Atom at = NULL;
|
||||
bool rc = (tmp != NULL &&
|
||||
(at = Yap_LookupAtom(tmp)) != NULL);
|
||||
pop_text_stack(lvl);
|
||||
return rc && Yap_unify(ARG3, MkAtomTerm(at));
|
||||
}
|
||||
|
||||
/* Executes $SHELL under Prolog */
|
||||
|
@ -52,7 +52,7 @@ if (ANDROID)
|
||||
|
||||
endif (ANDROID)
|
||||
|
||||
add_library( Yapsqlite3 SHARED
|
||||
add_library( Yapsqlite3 OBJECT
|
||||
${YAPSQLITE3_SOURCES} )
|
||||
|
||||
set_target_properties(Yapsqlite3
|
||||
@ -62,15 +62,13 @@ set_target_properties(Yapsqlite3
|
||||
POSITION_INDEPENDENT_CODE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(Yapsqlite3 libYap)
|
||||
#target_link_libraries(Yapsqlite3 libYap)
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(Yapsqlite3 android log)
|
||||
# target_link_libraries(Yapsqlite3 android log)
|
||||
|
||||
endif ()
|
||||
|
||||
install(TARGETS Yapsqlite3
|
||||
RUNTIME DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
ARCHIVE DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
LIBRARY DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
)
|
||||
#install(TARGETS Yapsqlite3
|
||||
# RUNTIME DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
# ARCHIVE DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
# LIBRARY DESTINATION ${YAP_INSTALL_DLLDIR}
|
||||
# )
|
||||
|
@ -18,22 +18,34 @@ FILE( MAKE_DIRECTORY ${YAP_APP_DIR}/src/generated/assets)
|
||||
set (GMP_LIBRARIES ${GMP_ROOT}/libgmp.so)
|
||||
|
||||
|
||||
add_custom_command (OUTPUT yap_swig.cpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}
|
||||
add_custom_target (pllib ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_library} ${pllib}
|
||||
)
|
||||
|
||||
add_custom_target (pllibpl ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}/pl
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_boot_library} ${pllib}/pl
|
||||
)
|
||||
add_custom_target (pllibos ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}/os
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_os_library} ${pllib}/os
|
||||
|
||||
)
|
||||
|
||||
add_custom_command (OUTPUT swig_streamer.cpp
|
||||
COMMAND ${SWIG_EXECUTABLE} -c++ -java -package ${SWIG_MODULE_NAME} -outdir ${CMAKE_SWIG_OUTDIR} -outcurrentdir -addextern -I${CMAKE_CURRENT_SOURCE_DIR} -o swig_streamer.cpp streamer.i
|
||||
DEPENDS streamer.i
|
||||
)
|
||||
|
||||
add_custom_command (OUTPUT yap_swig.cpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}/pl
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${pllib}/os
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_library} ${pllib}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_boot_library} ${pllib}/pl
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${pl_os_library} ${pllib}/os
|
||||
COMMAND ${SWIG_EXECUTABLE} -c++ -java -package ${SWIG_MODULE_NAME} -outdir ${CMAKE_SWIG_OUTDIR} -outcurrentdir -addextern -I${CMAKE_SOURCE_DIR}/CXX -I${CMAKE_SOURCE_DIR}/include -I${CMAKE_SOURCE_DIR}/H -I${CMAKE_SOURCE_DIR}/os -I${CMAKE_SOURCE_DIR}/OPTYap -I${CMAKE_BINARY_DIR} -I${GMP_INCLUDE_DIRS} -DX_API="" -o yap_swig.cpp ${SWIG_SOURCES}
|
||||
DEPENDS ${SWIG_SOURCES} YAP++
|
||||
)
|
||||
DEPENDS pllibos ${SWIG_SOURCES} YAP++ ${pl_boot_library}
|
||||
)
|
||||
|
||||
|
||||
add_custom_command (OUTPUT swig_streamer.cpp
|
||||
COMMAND ${SWIG_EXECUTABLE} -c++ -java -package ${SWIG_MODULE_NAME} -outdir ${CMAKE_SWIG_OUTDIR} -outcurrentdir -addextern -I${CMAKE_CURRENT_SOURCE_DIR} -o swig_streamer.cpp streamer.i
|
||||
DEPENDS streamer.i
|
||||
)
|
||||
|
||||
|
||||
# GMP_FOUND - true if GMP/MPIR was found
|
||||
@ -51,7 +63,7 @@ FILE( MAKE_DIRECTORY ${YAP_APP_DIR}/src/generated/assets)
|
||||
target_link_libraries(YAPJava ${GMP_LIBRARIES} )
|
||||
|
||||
|
||||
target_link_libraries( YAPJava YAP++ libYap android log)
|
||||
target_link_libraries( YAPJava libYap android log)
|
||||
|
||||
if (FALSE)
|
||||
|
||||
|
@ -41,6 +41,7 @@ and_open(struct vfs *me, int sno, const char *name, const char *io_mode) {
|
||||
GLOBAL_Stream[sno].vfs_handle = streamerInstance;
|
||||
GLOBAL_Stream[sno].vfs = me;
|
||||
GLOBAL_Stream[sno].status = Append_Stream_f | Output_Stream_f;
|
||||
GLOBAL_Stream[sno].name = Yap_LookupAtom(name);
|
||||
buff0.clear();
|
||||
return streamerInstance;
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ set(PL_BOOT_SOURCES
|
||||
swi.yap
|
||||
tabling.yap
|
||||
threads.yap
|
||||
top.yap
|
||||
udi.yap
|
||||
undefined.yap
|
||||
utils.yap
|
||||
@ -64,7 +65,7 @@ if (ANDROID)
|
||||
DEPENDS ${PL_BOOT_SOURCES}
|
||||
)
|
||||
file (INSTALL ${PL_BOOT_SOURCES} DESTINATION ${libpl}/pl)
|
||||
elif(CMAKE_CROSSCOMPILING)
|
||||
elseif(CMAKE_CROSSCOMPILING)
|
||||
add_custom_target(STARTUP ALL SOURCES
|
||||
DEPENDS ${PL_BOOT_SOURCES}
|
||||
)
|
||||
@ -73,7 +74,7 @@ else ()
|
||||
DEPENDS ${CMAKE_TOP_BINARY_DIR}/${YAP_STARTUP}
|
||||
)
|
||||
add_custom_command(OUTPUT ${CMAKE_TOP_BINARY_DIR}/${YAP_STARTUP}
|
||||
COMMAND yap-bin -B${CMAKE_SOURCE_DIR}/pl --output-saved-state=${CMAKE_TOP_BINARY_DIR}/${YAP_STARTUP}
|
||||
COMMAND yap-bin -B${CMAKE_SOURCE_DIR}/pl/boot.yap --output-saved-state=${CMAKE_TOP_BINARY_DIR}/${YAP_STARTUP}
|
||||
VERBATIM
|
||||
DEPENDS ${PL_BOOT_SOURCES} yap-bin
|
||||
)
|
||||
|
@ -161,6 +161,7 @@ print_message(L,E) :-
|
||||
|
||||
:- use_system_module( '$_boot', ['$cut_by'/1]).
|
||||
|
||||
|
||||
%:- start_low_level_trace.
|
||||
|
||||
% This is the YAP init file
|
||||
@ -291,6 +292,7 @@ initialize_prolog :-
|
||||
'qly.yap',
|
||||
'spy.yap',
|
||||
'udi.yap'].
|
||||
:- stop_low_level_trace.
|
||||
|
||||
|
||||
:- meta_predicate(log_event(+,:)).
|
||||
|
@ -240,31 +240,6 @@ not(G) :- \+ '$execute'(G).
|
||||
|
||||
|
||||
|
||||
/** @pred fail is iso
|
||||
|
||||
Always fails.
|
||||
*/
|
||||
fail :- fail.
|
||||
|
||||
/** @pred false is iso
|
||||
|
||||
The same as fail.
|
||||
*/
|
||||
false :- fail.
|
||||
|
||||
/** @pred true is iso
|
||||
Succeed.
|
||||
|
||||
Succeeds once.
|
||||
*/
|
||||
true :- true.
|
||||
|
||||
/** @pred otherwise is iso
|
||||
Succeed.
|
||||
|
||||
Succeeds once.
|
||||
*/
|
||||
otherwise.
|
||||
|
||||
/** @pred repeat is iso
|
||||
Succeeds repeatedly.
|
||||
|
@ -411,7 +411,7 @@ load_files(Files,Opts) :-
|
||||
'$check_use_module'(use_module(M,_,_), use_module(M)) :- !.
|
||||
'$check_use_module'(_, load_files) :- !.
|
||||
|
||||
'$lf'(V,_,Call, _ ) :- var(V), !,
|
||||
'$lf'(V,_,Call, _ ) :- var(V), !,
|
||||
'$do_error'(instantiation_error,Call).
|
||||
'$lf'([], _, _, _) :- !.
|
||||
'$lf'(M:X, _, Call, TOpts) :- !,
|
||||
@ -424,7 +424,7 @@ load_files(Files,Opts) :-
|
||||
).
|
||||
'$lf'([F|Fs], Mod, Call, TOpts) :- !,
|
||||
% clean up after each consult
|
||||
( '$lf'(F,Mod,Call, TOpts), fail ;
|
||||
( '$lf'(F,Mod,Call, TOpts), fail;
|
||||
'$lf'(Fs, Mod, Call, TOpts), fail;
|
||||
true
|
||||
).
|
||||
|
Reference in New Issue
Block a user