2150 lines
55 KiB
C
2150 lines
55 KiB
C
/*************************************************************************
|
|
* *
|
|
* YAP Prolog *
|
|
* *
|
|
* Yap Prolog was developed at NCCUP - Universidade do Porto *
|
|
* *
|
|
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
|
|
* *
|
|
**************************************************************************
|
|
* PrologPathProkoh
|
|
* *
|
|
* File: sysbits.c *
|
|
* Last rev: 4/03/88 *
|
|
* mods: *
|
|
* comments: very much machine dependent routines *
|
|
* *
|
|
*************************************************************************/
|
|
#ifdef SCCS
|
|
static char SccsId[] = "%W% %G%";
|
|
#endif
|
|
|
|
#include "sysbits.h"
|
|
|
|
/// File Error Handler
|
|
static void FileError(yap_error_number type, Term where, const char *format,
|
|
...) {
|
|
|
|
if (trueLocalPrologFlag(FILEERRORS_FLAG)) {
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
/* now build the error string */
|
|
Yap_Error(type, TermNil, format, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
|
|
static Int p_sh(USES_REGS1);
|
|
static Int p_shell(USES_REGS1);
|
|
static Int p_system(USES_REGS1);
|
|
static Int p_mv(USES_REGS1);
|
|
static Int p_dir_sp(USES_REGS1);
|
|
static Int p_getenv(USES_REGS1);
|
|
static Int p_putenv(USES_REGS1);
|
|
static Term do_glob(const char *spec, bool ok_to);
|
|
#ifdef MACYAP
|
|
|
|
static int chdir(char *);
|
|
/* #define signal skel_signal */
|
|
#endif /* MACYAP */
|
|
static const char *expandVars(const char *spec, char *u);
|
|
|
|
void exit(int);
|
|
|
|
static void freeBuffer(const void *ptr) {
|
|
CACHE_REGS
|
|
if (ptr == NULL || ptr == LOCAL_FileNameBuf || ptr == LOCAL_FileNameBuf2)
|
|
return;
|
|
free((void *)ptr);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Yap_WinError(char *yap_error) {
|
|
char msg[256];
|
|
/* Error, we could not read time */
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
msg, 256, NULL);
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil, "%s at %s", msg, yap_error);
|
|
}
|
|
#endif /* __WINDOWS__ */
|
|
|
|
#define is_valid_env_char(C) \
|
|
(((C) >= 'a' && (C) <= 'z') || ((C) >= 'A' && (C) <= 'Z') || (C) == '_')
|
|
|
|
#if __ANDROID__
|
|
|
|
AAssetManager *Yap_assetManager;
|
|
|
|
void *Yap_openAssetFile(const char *path) {
|
|
const char *p = path + 8;
|
|
AAsset *asset = AAssetManager_open(Yap_assetManager, p, AASSET_MODE_UNKNOWN);
|
|
return asset;
|
|
}
|
|
|
|
bool Yap_isAsset(const char *path) {
|
|
if (Yap_assetManager == NULL)
|
|
return false;
|
|
return path[0] == '/' && path[1] == 'a' && path[2] == 's' && path[3] == 's' &&
|
|
path[4] == 'e' && path[5] == 't' && path[6] == 's' &&
|
|
(path[7] == '/' || path[7] == '\0');
|
|
}
|
|
|
|
bool Yap_AccessAsset(const char *name, int mode) {
|
|
AAssetManager *mgr = Yap_assetManager;
|
|
const char *bufp = name + 7;
|
|
|
|
if (bufp[0] == '/')
|
|
bufp++;
|
|
if ((mode & W_OK) == W_OK) {
|
|
return false;
|
|
}
|
|
// directory works if file exists
|
|
AAssetDir *assetDir = AAssetManager_openDir(mgr, bufp);
|
|
if (assetDir) {
|
|
AAssetDir_close(assetDir);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Yap_AssetIsFile(const char *name) {
|
|
AAssetManager *mgr = Yap_assetManager;
|
|
const char *bufp = name + 7;
|
|
if (bufp[0] == '/')
|
|
bufp++;
|
|
// check if file is a directory.
|
|
AAsset *asset = AAssetManager_open(mgr, bufp, AASSET_MODE_UNKNOWN);
|
|
if (!asset)
|
|
return false;
|
|
AAsset_close(asset);
|
|
return true;
|
|
}
|
|
|
|
bool Yap_AssetIsDir(const char *name) {
|
|
AAssetManager *mgr = Yap_assetManager;
|
|
const char *bufp = name + 7;
|
|
if (bufp[0] == '/')
|
|
bufp++;
|
|
// check if file is a directory.
|
|
AAssetDir *assetDir = AAssetManager_openDir(mgr, bufp);
|
|
if (!assetDir) {
|
|
return false;
|
|
}
|
|
AAssetDir_close(assetDir);
|
|
AAsset *asset = AAssetManager_open(mgr, bufp, AASSET_MODE_UNKNOWN);
|
|
if (!asset)
|
|
return true;
|
|
AAsset_close(asset);
|
|
return false;
|
|
}
|
|
|
|
int64_t Yap_AssetSize(const char *name) {
|
|
AAssetManager *mgr = Yap_assetManager;
|
|
const char *bufp = name + 7;
|
|
if (bufp[0] == '/')
|
|
bufp++;
|
|
AAsset *asset = AAssetManager_open(mgr, bufp, AASSET_MODE_UNKNOWN);
|
|
if (!asset)
|
|
return -1;
|
|
off64_t len = AAsset_getLength64(asset);
|
|
AAsset_close(asset);
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
/// is_directory: verifies whether an expanded file name
|
|
/// points at a readable directory
|
|
static bool is_directory(const char *FileName) {
|
|
#ifdef __ANDROID__
|
|
if (Yap_isAsset(FileName)) {
|
|
return Yap_AssetIsDir(FileName);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef __WINDOWS__
|
|
DWORD dwAtts = GetFileAttributes(FileName);
|
|
if (dwAtts == INVALID_FILE_ATTRIBUTES)
|
|
return false;
|
|
return (dwAtts & FILE_ATTRIBUTE_DIRECTORY);
|
|
#elif HAVE_LSTAT
|
|
struct stat buf;
|
|
|
|
if (lstat(FileName, &buf) == -1) {
|
|
/* return an error number */
|
|
return false;
|
|
}
|
|
return S_ISDIR(buf.st_mode);
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"stat not available in this configuration");
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/// has_access just calls access
|
|
/// it uses F_OK, R_OK and friend
|
|
static bool has_access(const char *FileName, int mode) {
|
|
#ifdef __ANDROID__
|
|
if (Yap_isAsset(FileName)) {
|
|
return Yap_AccessAsset(FileName, mode);
|
|
}
|
|
#endif
|
|
#if HAVE_ACCESS
|
|
if (access(FileName, mode) == 0)
|
|
return true;
|
|
if (errno == EINVAL) {
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "bad flags to access");
|
|
}
|
|
return false;
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"access not available in this configuration");
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static bool exists(const char *f) {
|
|
#if _MSC_VER
|
|
return has_access(f, 00);
|
|
#else
|
|
return has_access(f, F_OK);
|
|
#endif
|
|
}
|
|
|
|
static int dir_separator(int ch) {
|
|
#ifdef MAC
|
|
return (ch == ':');
|
|
#elif ATARI || _MSC_VER
|
|
return (ch == '\\');
|
|
#elif defined(__MINGW32__) || defined(__CYGWIN__)
|
|
return (ch == '\\' || ch == '/');
|
|
#else
|
|
return (ch == '/');
|
|
#endif
|
|
}
|
|
|
|
int Yap_dir_separator(int ch) { return dir_separator(ch); }
|
|
|
|
#if __WINDOWS__
|
|
#include <psapi.h>
|
|
|
|
char *libdir = NULL;
|
|
#endif
|
|
|
|
bool Yap_IsAbsolutePath(const char *p0) {
|
|
// verify first if expansion is needed: ~/ or $HOME/
|
|
const char *p = expandVars(p0, LOCAL_FileNameBuf);
|
|
bool nrc;
|
|
#if _WIN32 || __MINGW32__
|
|
nrc = !PathIsRelative(p);
|
|
#else
|
|
nrc = (p[0] == '/');
|
|
#endif
|
|
return nrc;
|
|
}
|
|
|
|
#define isValidEnvChar(C) \
|
|
(((C) >= 'a' && (C) <= 'z') || ((C) >= 'A' && (C) <= 'Z') || (C) == '_')
|
|
|
|
// 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) {
|
|
CACHE_REGS
|
|
const char *src = source;
|
|
if (!result)
|
|
result = malloc(YAP_FILENAME_MAX + 1);
|
|
|
|
if (strlen(source) >= YAP_FILENAME_MAX) {
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
|
|
"%s in true_file-name is larger than the buffer size (%d bytes)",
|
|
source, strlen(source));
|
|
}
|
|
/* step 1: eating home information */
|
|
if (source[0] == '~') {
|
|
if (dir_separator(source[1]) || source[1] == '\0') {
|
|
char *s;
|
|
src++;
|
|
#if defined(_WIN32)
|
|
s = getenv("HOMEDRIVE");
|
|
if (s != NULL)
|
|
strncpy(result, getenv("HOMEDRIVE"), YAP_FILENAME_MAX);
|
|
// s = getenv("HOMEPATH");
|
|
#else
|
|
s = getenv("HOME");
|
|
#endif
|
|
if (s != NULL)
|
|
strncpy(result, s, YAP_FILENAME_MAX);
|
|
strcat(result, src);
|
|
return result;
|
|
} else {
|
|
#if HAVE_GETPWNAM
|
|
struct passwd *user_passwd;
|
|
char *res = result;
|
|
|
|
src++;
|
|
while (!dir_separator((*res = *src)) && *res != '\0')
|
|
res++, src++;
|
|
res[0] = '\0';
|
|
if ((user_passwd = getpwnam(result)) == NULL) {
|
|
FileError(SYSTEM_ERROR_OPERATING_SYSTEM,
|
|
MkAtomTerm(Yap_LookupAtom(source)),
|
|
"User %s does not exist in %s", result, source);
|
|
return NULL;
|
|
}
|
|
strncpy(result, user_passwd->pw_dir, YAP_FILENAME_MAX);
|
|
strcat(result, src);
|
|
#else
|
|
FileError(
|
|
SYSTEM_ERROR_OPERATING_SYSTEM, MkAtomTerm(Yap_LookupAtom(source)),
|
|
"User %s cannot be found in %s, missing getpwnam", result, source);
|
|
return NULL;
|
|
#endif
|
|
}
|
|
return result;
|
|
}
|
|
// do VARIABLE expansion
|
|
else if (source[0] == '$') {
|
|
/* follow SICStus expansion rules */
|
|
char v[YAP_FILENAME_MAX + 1];
|
|
int ch;
|
|
char *s, *res;
|
|
src = source + 1;
|
|
if (src[0] == '{') {
|
|
res = v;
|
|
src++;
|
|
while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch != '}') {
|
|
res++;
|
|
}
|
|
if (ch == '}') {
|
|
// {...}
|
|
// done
|
|
res[0] = '\0';
|
|
}
|
|
} else {
|
|
res = v;
|
|
while ((*res = (ch = *src++)) && isValidEnvChar(ch) && ch != '}') {
|
|
res++;
|
|
}
|
|
src--;
|
|
res[0] = '\0';
|
|
}
|
|
if ((s = (char *)getenv(v))) {
|
|
strcpy(result, s);
|
|
strcat(result, src);
|
|
} else
|
|
strcpy(result, src);
|
|
} else {
|
|
size_t tocp = strlen(src);
|
|
if (root) {
|
|
tocp = strlen(root) + 1;
|
|
}
|
|
if (tocp > YAP_FILENAME_MAX) {
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, MkStringTerm(src),
|
|
"path too long");
|
|
return NULL;
|
|
}
|
|
if (root) {
|
|
strncpy(result, root, YAP_FILENAME_MAX);
|
|
strncat(result, "/", YAP_FILENAME_MAX);
|
|
strncat(result, source, YAP_FILENAME_MAX);
|
|
} else {
|
|
strncpy(result, source, strlen(src) + 1);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
// straightforward conversion from Unix style to WIN style
|
|
// check cygwin path.cc for possible improvements
|
|
static char *unix2win(const char *source, char *target, int max) {
|
|
char *s = target;
|
|
const char *s0 = source;
|
|
char *s1;
|
|
int ch;
|
|
|
|
if (s == NULL)
|
|
s = malloc(YAP_FILENAME_MAX + 1);
|
|
s1 = s;
|
|
// win32 syntax
|
|
// handle drive notation, eg //a/
|
|
if (s0[0] == '\0') {
|
|
s[0] = '.';
|
|
s[1] = '\0';
|
|
return s;
|
|
}
|
|
if (s0[0] == '/' && s0[1] == '/' && isalpha(s0[2]) && s0[3] == '/') {
|
|
s1[0] = s0[2];
|
|
s1[1] = ':';
|
|
s1[2] = '\\';
|
|
s0 += 4;
|
|
s1 += 3;
|
|
}
|
|
while ((ch = *s1++ = *s0++)) {
|
|
if (ch == '$') {
|
|
s1[-1] = '%';
|
|
ch = *s0;
|
|
// handle $(....)
|
|
if (ch == '{') {
|
|
s0++;
|
|
while ((ch = *s0++) != '}') {
|
|
*s1++ = ch;
|
|
if (ch == '\0')
|
|
return FALSE;
|
|
}
|
|
*s1++ = '%';
|
|
} else {
|
|
while (((ch = *s1++ = *s0++) >= 'A' && ch <= 'Z') ||
|
|
(ch >= 'a' && ch <= 'z') || (ch == '-') ||
|
|
(ch >= '0' && ch <= '9') || (ch == '_'))
|
|
;
|
|
s1[-1] = '%';
|
|
*s1++ = ch;
|
|
if (ch == '\0') {
|
|
s1--;
|
|
s0--;
|
|
}
|
|
}
|
|
} else if (ch == '/')
|
|
s1[-1] = '\\';
|
|
}
|
|
return s;
|
|
}
|
|
#endif
|
|
|
|
static char *OsPath(const char *p, char *buf) { return (char *)p; }
|
|
|
|
static char *PrologPath(const char *Y, char *X) { return (char *)Y; }
|
|
|
|
#if _WIN32
|
|
#define HAVE_BASENAME 1
|
|
#define HAVE_REALPATH 1
|
|
#endif
|
|
|
|
static bool ChDir(const char *path) {
|
|
bool rc = false;
|
|
const char *qpath = Yap_AbsoluteFile(path, true);
|
|
|
|
#ifdef __ANDROID__
|
|
if (GLOBAL_AssetsWD) {
|
|
freeBuffer(GLOBAL_AssetsWD);
|
|
GLOBAL_AssetsWD = NULL;
|
|
}
|
|
if (Yap_isAsset(qpath)) {
|
|
AAssetManager *mgr = Yap_assetManager;
|
|
|
|
const char *ptr = qpath + 8;
|
|
AAssetDir *d;
|
|
if (ptr[0] == '/')
|
|
ptr++;
|
|
d = AAssetManager_openDir(mgr, ptr);
|
|
if (d) {
|
|
GLOBAL_AssetsWD = malloc(strlen(qpath) + 1);
|
|
strcpy(GLOBAL_AssetsWD, qpath);
|
|
AAssetDir_close(d);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
GLOBAL_AssetsWD = NULL;
|
|
}
|
|
#endif
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
|
|
if ((rc = (SetCurrentDirectory(qpath) != 0)) == 0) {
|
|
Yap_WinError("SetCurrentDirectory failed");
|
|
}
|
|
#else
|
|
rc = (chdir(qpath) == 0);
|
|
#endif
|
|
free((char *)qpath);
|
|
return rc;
|
|
}
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
char *BaseName(const char *X) {
|
|
char *qpath = unix2win(X, NULL, YAP_FILENAME_MAX);
|
|
char base[YAP_FILENAME_MAX], ext[YAP_FILENAME_MAX];
|
|
_splitpath(qpath, NULL, NULL, base, ext);
|
|
strcpy(qpath, base);
|
|
strcat(qpath, ext);
|
|
return qpath;
|
|
}
|
|
|
|
const char *DirName(const char *X) {
|
|
char dir[YAP_FILENAME_MAX];
|
|
char drive[YAP_FILENAME_MAX];
|
|
char *o = unix2win(X, NULL, YAP_FILENAME_MAX);
|
|
int err;
|
|
if (!o)
|
|
return NULL;
|
|
if ((err = _splitpath_s(o, drive, YAP_FILENAME_MAX - 1, dir,
|
|
YAP_FILENAME_MAX - 1, NULL, 0, NULL, 0)) != 0) {
|
|
FileError(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
|
|
"could not perform _splitpath %s: %s", X, strerror(errno));
|
|
return NULL;
|
|
}
|
|
strncpy(o, drive, YAP_FILENAME_MAX - 1);
|
|
strncat(o, dir, YAP_FILENAME_MAX - 1);
|
|
return o;
|
|
}
|
|
#endif
|
|
|
|
static const char *myrealpath(const char *path) {
|
|
char *out = LOCAL_FileNameBuf;
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
DWORD retval = 0;
|
|
|
|
// notice that the file does not need to exist
|
|
retval = GetFullPathName(path, YAP_FILENAME_MAX, out, NULL);
|
|
|
|
if (retval == 0) {
|
|
Yap_WinError("Generating a full path name for a file");
|
|
return NULL;
|
|
}
|
|
return out;
|
|
#elif HAVE_REALPATH
|
|
{
|
|
char *rc = realpath(path, NULL);
|
|
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
// rc = NULL;
|
|
if (errno == ENOENT || errno == EACCES) {
|
|
char base[YAP_FILENAME_MAX];
|
|
strncpy(base, path, YAP_FILENAME_MAX - 1);
|
|
rc = realpath(dirname((char *)path), NULL);
|
|
|
|
if (rc) {
|
|
const char *b = basename(base);
|
|
size_t e = strlen(rc);
|
|
size_t bs = strlen(b);
|
|
|
|
rc = realloc(rc, e + bs + 2);
|
|
#if _WIN32
|
|
if (rc[e - 1] != '\\' && rc[e - 1] != '/') {
|
|
rc[e] = '\\';
|
|
rc[e + 1] = '\0';
|
|
}
|
|
#else
|
|
if (rc[e - 1] != '/') {
|
|
rc[e] = '/';
|
|
rc[e + 1] = '\0';
|
|
}
|
|
#endif
|
|
strcat(rc, b);
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
out = malloc(strlen(path) + 1);
|
|
strcpy(out, path);
|
|
return out;
|
|
}
|
|
|
|
static const char *expandVars(const char *spec, char *u) {
|
|
CACHE_REGS
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
char *out;
|
|
|
|
// first pass, remove Unix style stuff
|
|
if ((out = unix2win(spec, u, YAP_FILENAME_MAX)) == NULL)
|
|
return NULL;
|
|
spec = u;
|
|
#endif
|
|
bool ok_to = LOCAL_PrologMode && !(LOCAL_PrologMode & BootMode);
|
|
if (ok_to) {
|
|
Term t = do_glob(spec, true);
|
|
if (IsPairTerm(t))
|
|
return RepAtom(AtomOfTerm(HeadOfTerm(t)))->StrOfAE;
|
|
return NULL;
|
|
}
|
|
return spec;
|
|
}
|
|
|
|
/**
|
|
* generate absolute path, if ok first expand SICStus Prolog style
|
|
*
|
|
* @param[in] spec the file path, including `~` and `$`.
|
|
* @param[in] ok where to process `~` and `$`.
|
|
*
|
|
* @return tmp, or NULL, in malloced memory
|
|
*/
|
|
const char *Yap_AbsoluteFile(const char *spec, bool ok) {
|
|
const char *p;
|
|
const char *rc;
|
|
rc = PlExpandVars(spec, NULL, NULL);
|
|
if (!rc)
|
|
rc = spec;
|
|
if ((p = myrealpath(rc))) {
|
|
return p;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
freeBuffer(rc);
|
|
}
|
|
|
|
/**
|
|
* generate absolute path and stores path in an user given buffer. If
|
|
* NULL, uses a temporary buffer that must be quickly released.
|
|
*
|
|
* if ok first expand variable names and do globbing
|
|
*
|
|
* @param[in] spec the file path, including `~` and `$`.
|
|
* @param[in] ok where to process `~` and `$`.
|
|
*
|
|
* @return tmp, or NULL, in malloced memory
|
|
*/
|
|
const char *Yap_AbsoluteFileInBuffer(const char *spec, char *out, size_t sz,
|
|
bool ok) {
|
|
CACHE_REGS
|
|
const char *p;
|
|
const char *rc;
|
|
if (ok) {
|
|
rc = expandVars(spec, LOCAL_FileNameBuf);
|
|
if (!rc)
|
|
return spec;
|
|
} else {
|
|
rc = spec;
|
|
}
|
|
|
|
if ((p = myrealpath(rc))) {
|
|
if (!out) {
|
|
out = LOCAL_FileNameBuf;
|
|
sz = YAP_FILENAME_MAX - 1;
|
|
}
|
|
if (p != out) {
|
|
strncpy(out, p, sz);
|
|
freeBuffer(p);
|
|
return out;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Term
|
|
/* Expand the string for the program to run. */
|
|
do_glob(const char *spec, bool glob_vs_wordexp) {
|
|
CACHE_REGS
|
|
char u[YAP_FILENAME_MAX + 1];
|
|
char *espec = u;
|
|
if (spec == NULL) {
|
|
return TermNil;
|
|
}
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
{
|
|
WIN32_FIND_DATA find;
|
|
HANDLE hFind;
|
|
CELL *dest;
|
|
Term tf;
|
|
|
|
// first pass, remove Unix style stuff
|
|
if (unix2win(espec, u, YAP_FILENAME_MAX) == NULL)
|
|
return TermNil;
|
|
espec = (const char *)u;
|
|
|
|
hFind = FindFirstFile(espec, &find);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
return TermNil;
|
|
} else {
|
|
tf = AbsPair(HR);
|
|
HR[0] = MkAtomTerm(Yap_LookupAtom(find.cFileName));
|
|
HR[1] = TermNil;
|
|
dest = HR + 1;
|
|
HR += 2;
|
|
while (FindNextFile(hFind, &find)) {
|
|
*dest = AbsPair(HR);
|
|
HR[0] = MkAtomTerm(Yap_LookupAtom(find.cFileName));
|
|
HR[1] = TermNil;
|
|
dest = HR + 1;
|
|
HR += 2;
|
|
}
|
|
FindClose(hFind);
|
|
}
|
|
return tf;
|
|
}
|
|
#elif HAVE_WORDEXP || HAVE_GLOB
|
|
strncpy(espec, spec, sizeof(u));
|
|
/* Expand the string for the program to run. */
|
|
size_t pathcount;
|
|
#if HAVE_GLOB
|
|
glob_t gresult;
|
|
#endif
|
|
#if HAVE_WORDEXP
|
|
wordexp_t wresult;
|
|
#endif
|
|
#if HAVE_GLOB || HAVE_WORDEXP
|
|
char **ss = NULL;
|
|
int flags = 0, j;
|
|
#endif
|
|
if (glob_vs_wordexp) {
|
|
#if HAVE_GLOB
|
|
#ifdef GLOB_NOCHECK
|
|
flags = GLOB_NOCHECK;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
#ifdef GLOB_BRACE
|
|
flags |= GLOB_BRACE | GLOB_TILDE;
|
|
#endif
|
|
switch (glob(espec, flags, NULL, &gresult)) {
|
|
case 0: /* Successful. */
|
|
ss = gresult.gl_pathv;
|
|
pathcount = gresult.gl_pathc;
|
|
if (pathcount) {
|
|
break;
|
|
}
|
|
case GLOB_NOMATCH:
|
|
globfree(&gresult);
|
|
{ return TermNil; }
|
|
case GLOB_ABORTED:
|
|
PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, "glob aborted: %sn",
|
|
strerror(errno));
|
|
globfree(&gresult);
|
|
return TermNil;
|
|
case GLOB_NOSPACE:
|
|
Yap_Error(RESOURCE_ERROR_HEAP, ARG1, "glob ran out of space: %sn",
|
|
strerror(errno));
|
|
globfree(&gresult);
|
|
return TermNil;
|
|
/* If the error was WRDE_NOSPACE,
|
|
then perhaps part of the result was allocated. */
|
|
default: /* Some other error. */
|
|
return TermNil;
|
|
}
|
|
#endif
|
|
} else {
|
|
#if HAVE_WORDEXP
|
|
int rc;
|
|
memset(&wresult, 0, sizeof(wresult));
|
|
switch ((rc = wordexp(espec, &wresult, flags))) {
|
|
case 0: /* Successful. */
|
|
ss = wresult.we_wordv;
|
|
pathcount = wresult.we_wordc;
|
|
if (pathcount) {
|
|
break;
|
|
} else {
|
|
Term t;
|
|
t = MkAtomTerm(Yap_LookupAtom(expandVars(espec, NULL)));
|
|
wordfree(&wresult);
|
|
return MkPairTerm(t, TermNil);
|
|
}
|
|
case WRDE_NOSPACE:
|
|
/* If the error was WRDE_NOSPACE,
|
|
then perhaps part of the result was allocated. */
|
|
Yap_Error(RESOURCE_ERROR_HEAP, ARG1, "wordexp ran out of space: %s",
|
|
strerror(errno));
|
|
wordfree(&wresult);
|
|
return TermNil;
|
|
default: /* Some other error. */
|
|
PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, "wordexp failed: %s",
|
|
strerror(errno));
|
|
wordfree(&wresult);
|
|
return TermNil;
|
|
}
|
|
#endif
|
|
}
|
|
const char *tmp;
|
|
Term tf = TermNil;
|
|
for (j = 0; j < pathcount; j++) {
|
|
const char *s = ss[pathcount - (j + 1)];
|
|
tmp = s;
|
|
// if (!exists(s))
|
|
// continue;
|
|
Atom a = Yap_LookupAtom(tmp);
|
|
tf = MkPairTerm(MkAtomTerm(a), tf);
|
|
}
|
|
#if HAVE_GLOB
|
|
if (glob_vs_wordexp)
|
|
globfree(&gresult);
|
|
#endif
|
|
#if HAVE_WORDEXP
|
|
if (!glob_vs_wordexp)
|
|
wordfree(&wresult);
|
|
#endif
|
|
return tf;
|
|
#else
|
|
// just use basic
|
|
return MkPairTerm(MkAtomTerm(Yap_LookupAtom(espec)), TermNil);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @pred prolog_expanded_file_system_path( +PrologPath, +ExpandVars, -OSPath )
|
|
*
|
|
* Apply basic transformations to paths, and conidtionally apply
|
|
* traditional SICStus-style variable expansion.
|
|
*
|
|
* @param PrologPath the source, may be atom or string
|
|
* @param ExpandVars expand initial occurrence of ~ or $
|
|
* @param Prefix add this path before _PrologPath_
|
|
* @param OSPath pathname.
|
|
*
|
|
* @return
|
|
*/
|
|
static Int prolog_realpath(USES_REGS1) {
|
|
Term t1 = Deref(ARG1);
|
|
const char *cmd;
|
|
|
|
if (IsAtomTerm(t1)) {
|
|
cmd = RepAtom(AtomOfTerm(t1))->StrOfAE;
|
|
} else if (IsStringTerm(t1)) {
|
|
cmd = StringOfTerm(t1);
|
|
} else {
|
|
return false;
|
|
}
|
|
const char *rc = myrealpath(cmd);
|
|
if (!rc) {
|
|
PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, ARG1, strerror(errno));
|
|
return false;
|
|
}
|
|
bool r = Yap_unify(MkAtomTerm(Yap_LookupAtom(rc)), ARG2);
|
|
freeBuffer((char *)rc);
|
|
return r;
|
|
}
|
|
|
|
#define EXPAND_FILENAME_DEFS() \
|
|
PAR("parameter_expansion", isatom, EXPAND_FILENAME_PARAMETER_EXPANSION) \
|
|
, PAR("commands", booleanFlag, EXPAND_FILENAME_COMMANDS), \
|
|
PAR(NULL, ok, EXPAND_FILENAME_END)
|
|
|
|
#define PAR(x, y, z) z
|
|
|
|
typedef enum expand_filename_enum_choices {
|
|
EXPAND_FILENAME_DEFS()
|
|
} expand_filename_enum_choices_t;
|
|
|
|
#undef PAR
|
|
|
|
#define PAR(x, y, z) \
|
|
{ x, y, z }
|
|
|
|
static const param_t expand_filename_defs[] = {EXPAND_FILENAME_DEFS()};
|
|
#undef PAR
|
|
|
|
static Term do_expand_file_name(Term t1, Term opts USES_REGS) {
|
|
xarg *args;
|
|
expand_filename_enum_choices_t i;
|
|
bool use_system_expansion = true;
|
|
char *tmpe = NULL;
|
|
const char *spec;
|
|
Term tf;
|
|
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, NULL);
|
|
return TermNil;
|
|
} else if (IsAtomTerm(t1)) {
|
|
spec = AtomTermName(t1);
|
|
} else if (IsStringTerm(t1)) {
|
|
spec = StringOfTerm(t1);
|
|
} else {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, NULL);
|
|
return TermNil;
|
|
}
|
|
args = Yap_ArgListToVector(opts, expand_filename_defs, EXPAND_FILENAME_END);
|
|
if (args == NULL) {
|
|
return TermNil;
|
|
}
|
|
tmpe = malloc(YAP_FILENAME_MAX + 1);
|
|
|
|
for (i = 0; i < EXPAND_FILENAME_END; i++) {
|
|
if (args[i].used) {
|
|
Term t = args[i].tvalue;
|
|
switch (i) {
|
|
case EXPAND_FILENAME_PARAMETER_EXPANSION:
|
|
if (t == TermProlog) {
|
|
const char *s = expandVars(spec, LOCAL_FileNameBuf);
|
|
if (s == NULL) {
|
|
return TermNil;
|
|
}
|
|
strcpy(tmpe, s);
|
|
} else if (t == TermTrue) {
|
|
use_system_expansion = true;
|
|
} else if (t == TermFalse) {
|
|
use_system_expansion = false;
|
|
}
|
|
break;
|
|
case EXPAND_FILENAME_COMMANDS:
|
|
if (!use_system_expansion) {
|
|
use_system_expansion = true;
|
|
#if 0 // def WRDE_NOCMD
|
|
if (t == TermFalse) {
|
|
flags = WRDE_NOCMD;
|
|
}
|
|
#endif
|
|
}
|
|
case EXPAND_FILENAME_END:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!use_system_expansion) {
|
|
return MkPairTerm(MkAtomTerm(Yap_LookupAtom(expandVars(spec, NULL))),
|
|
TermNil);
|
|
}
|
|
tf = do_glob(spec, true);
|
|
return tf;
|
|
}
|
|
|
|
/* @pred expand_file_name( +Pattern, -ListOfPaths) is det
|
|
|
|
This builtin receives a pattern and expands it into a list of files.
|
|
In Unix-like systems, YAP applies glob to expand patterns such as '*', '.',
|
|
and '?'. Further variable expansion
|
|
may also happen. glob is shell-dependent: som Yap_InitCPred
|
|
("absolute_file_system_path", 2, absolute_file_system_path, 0);
|
|
Yap_InitCPred ("real_path", 2, prolog_realpath, 0);
|
|
Yap_InitCPred ("true_file_name", 2,
|
|
true_file_name, SyncPredFlag);
|
|
Yap_InitCPred ("true_file_name", 3, true_file_name3, SyncPredFlag);
|
|
e shells allow command execution and brace-expansion.
|
|
|
|
*/
|
|
static Int expand_file_name(USES_REGS1) {
|
|
Term tf = do_expand_file_name(Deref(ARG1), TermNil PASS_REGS);
|
|
if (tf == 0)
|
|
return false;
|
|
return Yap_unify(tf, ARG2);
|
|
}
|
|
|
|
static Int expand_file_name3(USES_REGS1) {
|
|
Term tf = do_expand_file_name(Deref(ARG1), Deref(ARG2) PASS_REGS);
|
|
return Yap_unify(tf, ARG3);
|
|
}
|
|
|
|
/*
|
|
static char *canoniseFileName( char *path) {
|
|
#if HAVE_REALPATH && HAVE_BASENAME
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
char *o = malloc(YAP_FILENAME_MAX+1);
|
|
if (!o)
|
|
return NULL;
|
|
// first pass, remove Unix style stuff
|
|
if (unix2win(path, o, YAP_FILENAME_MAX) == NULL)
|
|
return NULL;
|
|
path = o;
|
|
#endif
|
|
char *rc;
|
|
if (tmp == NULL) return NULL;
|
|
rc = myrealpath(path);
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
freeBuffer(o);
|
|
#endif
|
|
return rc;
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
static Int absolute_file_system_path(USES_REGS1) {
|
|
Term t = Deref(ARG1);
|
|
const char *fp;
|
|
bool rc;
|
|
char s[MAXPATHLEN + 1];
|
|
const char *text = Yap_TextTermToText(t, s, MAXPATHLEN);
|
|
|
|
if (text == NULL) {
|
|
return false;
|
|
}
|
|
if (!(fp = Yap_AbsoluteFile(RepAtom(AtomOfTerm(t))->StrOfAE, true)))
|
|
return false;
|
|
rc = Yap_unify(Yap_MkTextTerm(fp, t), ARG2);
|
|
if (fp != s)
|
|
freeBuffer((void *)fp);
|
|
return rc;
|
|
}
|
|
|
|
static Int prolog_to_os_filename(USES_REGS1) {
|
|
Term t = Deref(ARG1), t2 = Deref(ARG2);
|
|
char *fp;
|
|
char out[MAXPATHLEN + 1];
|
|
|
|
if (IsVarTerm(t)) {
|
|
|
|
if (IsVarTerm(t2)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t, "prolog_to_os_filename");
|
|
return false;
|
|
} else if (IsAtomTerm(t2)) {
|
|
if (!(fp = PrologPath(RepAtom(AtomOfTerm(t2))->StrOfAE, out)))
|
|
return false;
|
|
return Yap_unify(ARG1, MkAtomTerm(Yap_LookupAtom(fp)));
|
|
} else {
|
|
Yap_Error(TYPE_ERROR_ATOM, t2, "prolog_to_os_filename");
|
|
return false;
|
|
}
|
|
} else if (!IsAtomTerm(t)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t, "prolog_to_os_filename");
|
|
return false;
|
|
}
|
|
|
|
if (!(fp = OsPath(RepAtom(AtomOfTerm(t))->StrOfAE, out)))
|
|
return false;
|
|
return Yap_unify(MkAtomTerm(Yap_LookupAtom(fp)), ARG2);
|
|
}
|
|
|
|
Atom Yap_TemporaryFile(const char *prefix, int *fd) {
|
|
#if HAVE_MKSTEMP
|
|
char *tmp = malloc(PATH_MAX);
|
|
int n;
|
|
int f;
|
|
if (tmp == NULL)
|
|
return NIL;
|
|
strncpy(tmp, prefix, PATH_MAX - 1);
|
|
n = strlen(tmp);
|
|
if (n >= 6 && tmp[n - 1] == 'X' && tmp[n - 2] == 'X' && tmp[n - 3] == 'X' &&
|
|
tmp[n - 4] == 'X' && tmp[n - 5] == 'X' && tmp[n - 6] == 'X')
|
|
f = mkstemp(tmp);
|
|
else {
|
|
strncat(tmp, "XXXXXX", PATH_MAX - 1);
|
|
f = mkstemp(tmp);
|
|
}
|
|
if (fd)
|
|
*fd = f;
|
|
return Yap_LookupAtom(tmp);
|
|
#else
|
|
return AtomNil;
|
|
#endif
|
|
}
|
|
|
|
/** @pred make_directory(+ _Dir_)
|
|
|
|
Create a directory _Dir_. The name of the directory must be an atom.
|
|
|
|
*/
|
|
static Int make_directory(USES_REGS1) {
|
|
const char *fd = AtomName(AtomOfTerm(ARG1));
|
|
#if defined(__MINGW32__) || _MSC_VER
|
|
if (_mkdir(fd) == -1) {
|
|
#else
|
|
if (mkdir(fd, 0777) == -1) {
|
|
#endif
|
|
/* return an error number */
|
|
return false; // errno?
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static Int p_rmdir(USES_REGS1) {
|
|
const char *fd = AtomName(AtomOfTerm(ARG1));
|
|
#if defined(__MINGW32__) || _MSC_VER
|
|
if (_rmdir(fd) == -1) {
|
|
#else
|
|
if (rmdir(fd) == -1) {
|
|
#endif
|
|
/* return an error number */
|
|
return (Yap_unify(ARG2, MkIntTerm(errno)));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool initSysPath(Term tlib, Term tcommons, bool dir_done,
|
|
bool commons_done) {
|
|
CACHE_REGS
|
|
int len;
|
|
|
|
#if __WINDOWS__
|
|
{
|
|
char *dir;
|
|
if ((dir = Yap_RegistryGetString("library")) && is_directory(dir)) {
|
|
if (!Yap_unify(tlib, MkAtomTerm(Yap_LookupAtom(dir))))
|
|
return FALSE;
|
|
}
|
|
dir_done = true;
|
|
if ((dir = Yap_RegistryGetString("prolog_commons")) && is_directory(dir)) {
|
|
if (!Yap_unify(tcommons, MkAtomTerm(Yap_LookupAtom(dir))))
|
|
return FALSE;
|
|
}
|
|
commons_done = true;
|
|
}
|
|
if (dir_done && commons_done)
|
|
return TRUE;
|
|
#endif
|
|
strncpy(LOCAL_FileNameBuf, YAP_SHAREDIR, YAP_FILENAME_MAX);
|
|
strncat(LOCAL_FileNameBuf, "/", YAP_FILENAME_MAX);
|
|
len = strlen(LOCAL_FileNameBuf);
|
|
if (!dir_done) {
|
|
strncat(LOCAL_FileNameBuf, "Yap", YAP_FILENAME_MAX);
|
|
if (is_directory(LOCAL_FileNameBuf)) {
|
|
if (!Yap_unify(tlib, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf))))
|
|
return FALSE;
|
|
dir_done = true;
|
|
}
|
|
}
|
|
if (!commons_done) {
|
|
LOCAL_FileNameBuf[len] = '\0';
|
|
strncat(LOCAL_FileNameBuf, "PrologCommons", YAP_FILENAME_MAX);
|
|
if (is_directory(LOCAL_FileNameBuf)) {
|
|
if (!Yap_unify(tcommons, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf))))
|
|
return FALSE;
|
|
}
|
|
commons_done = true;
|
|
}
|
|
if (dir_done && commons_done)
|
|
return TRUE;
|
|
|
|
#if __WINDOWS__
|
|
{
|
|
size_t buflen;
|
|
char *pt;
|
|
/* couldn't find it where it was supposed to be,
|
|
let's try using the executable */
|
|
if (!GetModuleFileName(NULL, LOCAL_FileNameBuf, YAP_FILENAME_MAX)) {
|
|
Yap_WinError("could not find executable name");
|
|
/* do nothing */
|
|
return FALSE;
|
|
}
|
|
buflen = strlen(LOCAL_FileNameBuf);
|
|
pt = LOCAL_FileNameBuf + buflen;
|
|
while (*--pt != '\\') {
|
|
/* skip executable */
|
|
if (pt == LOCAL_FileNameBuf) {
|
|
FileError(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
|
|
"could not find executable name");
|
|
/* do nothing */
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (*--pt != '\\') {
|
|
/* skip parent directory "bin\\" */
|
|
if (pt == LOCAL_FileNameBuf) {
|
|
FileError(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil,
|
|
"could not find executable name");
|
|
/* do nothing */
|
|
return FALSE;
|
|
}
|
|
}
|
|
/* now, this is a possible location for the ROOT_DIR, let's look for a share
|
|
* directory here */
|
|
pt[1] = '\0';
|
|
/* grosse */
|
|
strncat(LOCAL_FileNameBuf, "lib\\Yap", YAP_FILENAME_MAX);
|
|
libdir = Yap_AllocCodeSpace(strlen(LOCAL_FileNameBuf) + 1);
|
|
strncpy(libdir, LOCAL_FileNameBuf, strlen(LOCAL_FileNameBuf) + 1);
|
|
pt[1] = '\0';
|
|
strncat(LOCAL_FileNameBuf, "share", YAP_FILENAME_MAX);
|
|
}
|
|
strncat(LOCAL_FileNameBuf, "\\", YAP_FILENAME_MAX);
|
|
len = strlen(LOCAL_FileNameBuf);
|
|
strncat(LOCAL_FileNameBuf, "Yap", YAP_FILENAME_MAX);
|
|
if (!dir_done && is_directory(LOCAL_FileNameBuf)) {
|
|
if (!Yap_unify(tlib, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf))))
|
|
return FALSE;
|
|
}
|
|
dir_done = true;
|
|
LOCAL_FileNameBuf[len] = '\0';
|
|
strncat(LOCAL_FileNameBuf, "PrologCommons", YAP_FILENAME_MAX);
|
|
if (!commons_done && is_directory(LOCAL_FileNameBuf)) {
|
|
if (!Yap_unify(tcommons, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf))))
|
|
return FALSE;
|
|
}
|
|
commons_done = true;
|
|
#endif
|
|
return dir_done && commons_done;
|
|
}
|
|
|
|
static Int libraries_directories(USES_REGS1) {
|
|
return initSysPath(ARG1, ARG2, false, false);
|
|
}
|
|
|
|
static Int system_library(USES_REGS1) {
|
|
return initSysPath(ARG1, MkVarTerm(), false, true);
|
|
}
|
|
|
|
static Int commons_library(USES_REGS1) {
|
|
return initSysPath(MkVarTerm(), ARG1, true, false);
|
|
}
|
|
|
|
static Int p_dir_sp(USES_REGS1) {
|
|
#if ATARI || _MSC_VER || defined(__MINGW32__)
|
|
Term t = MkIntTerm('\\');
|
|
Term t2 = MkIntTerm('/');
|
|
#else
|
|
Term t = MkIntTerm('/');
|
|
Term t2 = MkIntTerm('/');
|
|
#endif
|
|
|
|
return Yap_unify_constant(ARG1, t) || Yap_unify_constant(ARG1, t2);
|
|
}
|
|
|
|
void Yap_InitPageSize(void) {
|
|
#ifdef _WIN32
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo(&si);
|
|
Yap_page_size = si.dwPageSize;
|
|
#elif HAVE_UNISTD_H
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
|
Yap_page_size = getpagesize();
|
|
#elif defined(_AIX)
|
|
Yap_page_size = sysconf(_SC_PAGE_SIZE);
|
|
#elif !defined(_SC_PAGESIZE)
|
|
Yap_page_size = getpagesize();
|
|
#else
|
|
Yap_page_size = sysconf(_SC_PAGESIZE);
|
|
#endif
|
|
#else
|
|
bla bla
|
|
#endif
|
|
}
|
|
|
|
/* TrueFileName -> Finds the true name of a file */
|
|
|
|
#ifdef __MINGW32__
|
|
#include <ctype.h>
|
|
#endif
|
|
|
|
static int volume_header(char *file) {
|
|
#if _MSC_VER || defined(__MINGW32__)
|
|
char *ch = file;
|
|
int c;
|
|
|
|
while ((c = ch[0]) != '\0') {
|
|
if (isalnum(c))
|
|
ch++;
|
|
else
|
|
return (c == ':');
|
|
}
|
|
#endif
|
|
return (FALSE);
|
|
}
|
|
|
|
int Yap_volume_header(char *file) { return volume_header(file); }
|
|
|
|
const char *Yap_getcwd(const char *cwd, size_t cwdlen) {
|
|
#if _WIN32 || defined(__MINGW32__)
|
|
if (GetCurrentDirectory(cwdlen, (char *)cwd) == 0) {
|
|
Yap_WinError("GetCurrentDirectory failed");
|
|
return NULL;
|
|
}
|
|
return (char *)cwd;
|
|
#elif __ANDROID__
|
|
if (GLOBAL_AssetsWD) {
|
|
return strncpy((char *)cwd, (const char *)GLOBAL_AssetsWD, cwdlen);
|
|
}
|
|
|
|
#endif
|
|
return getcwd((char *)cwd, cwdlen);
|
|
}
|
|
|
|
static Int working_directory(USES_REGS1) {
|
|
char dir[YAP_FILENAME_MAX + 1];
|
|
Term t1 = Deref(ARG1), t2;
|
|
if (!IsVarTerm(t1) && !IsAtomTerm(t1)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, "working_directory");
|
|
}
|
|
if (!Yap_unify(t1,
|
|
MkAtomTerm(Yap_LookupAtom(Yap_getcwd(dir, YAP_FILENAME_MAX)))))
|
|
return false;
|
|
t2 = Deref(ARG2);
|
|
if (IsVarTerm(t2)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t2, "working_directory");
|
|
}
|
|
if (!IsAtomTerm(t2)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t2, "working_directory");
|
|
}
|
|
ChDir(RepAtom(AtomOfTerm(t2))->StrOfAE);
|
|
return true;
|
|
}
|
|
|
|
/** Yap_findFile(): tries to locate a file, no expansion should be performed/
|
|
*
|
|
*
|
|
* @param isource the proper file
|
|
* @param idef the default name fo rthe file, ie, startup.yss
|
|
* @param root the prefix
|
|
* @param result the output
|
|
* @param access verify whether the file has access permission
|
|
* @param ftype saved state, object, saved file, prolog file
|
|
* @param expand_root expand $ ~, etc
|
|
* @param in_lib library file
|
|
*
|
|
* @return
|
|
*/
|
|
const char *Yap_findFile(const char *isource, const char *idef,
|
|
const char *iroot, char *result, bool access,
|
|
file_type_t ftype, bool expand_root, bool in_lib) {
|
|
char save_buffer[YAP_FILENAME_MAX + 1];
|
|
const char *root, *source = isource;
|
|
int rc = FAIL_RESTORE;
|
|
int try
|
|
= 0;
|
|
|
|
while (rc == FAIL_RESTORE) {
|
|
bool done = false;
|
|
// { CACHE_REGS __android_log_print(ANDROID_LOG_ERROR, __FUNCTION__,
|
|
// "try=%d %s %s", try, isource, iroot) ; }
|
|
switch (try ++) {
|
|
case 0: // path or file name is given;
|
|
root = iroot;
|
|
if (iroot || isource) {
|
|
source = (isource ? isource : idef);
|
|
} else {
|
|
done = true;
|
|
}
|
|
break;
|
|
case 1: // library directory is given in command line
|
|
if (in_lib && ftype == YAP_SAVED_STATE) {
|
|
root = iroot;
|
|
source = (isource ? isource : idef);
|
|
} else
|
|
done = true;
|
|
break;
|
|
case 2: // use environment variable YAPLIBDIR
|
|
#if HAVE_GETENV
|
|
if (in_lib) {
|
|
if (ftype == YAP_SAVED_STATE || ftype == YAP_OBJ) {
|
|
root = getenv("YAPLIBDIR");
|
|
} else {
|
|
root = getenv("YAPSHAREDIR");
|
|
}
|
|
source = (isource ? isource : idef);
|
|
} else
|
|
done = true;
|
|
break;
|
|
#else
|
|
done = true;
|
|
#endif
|
|
break;
|
|
case 3: // use compilation variable YAPLIBDIR
|
|
if (in_lib) {
|
|
source = (isource ? isource : idef);
|
|
if (ftype == YAP_PL || ftype == YAP_QLY) {
|
|
root = YAP_SHAREDIR;
|
|
} else {
|
|
root = YAP_LIBDIR;
|
|
}
|
|
} else
|
|
done = true;
|
|
break;
|
|
|
|
case 4: // WIN stuff: registry
|
|
#if __WINDOWS__
|
|
if (in_lib) {
|
|
source = (ftype == YAP_PL || ftype == YAP_QLY ? "library" : "startup");
|
|
source = Yap_RegistryGetString(source);
|
|
root = NULL;
|
|
} else
|
|
#endif
|
|
done = true;
|
|
break;
|
|
|
|
case 5: // search from the binary
|
|
{
|
|
#ifndef __ANDROID__
|
|
done = true;
|
|
break;
|
|
#endif
|
|
const char *pt = Yap_FindExecutable();
|
|
|
|
if (pt) {
|
|
source =
|
|
(ftype == YAP_SAVED_STATE || ftype == YAP_OBJ ? "../../lib/Yap"
|
|
: "../../share/Yap");
|
|
if (Yap_findFile(source, NULL, pt, save_buffer, access, ftype,
|
|
expand_root, in_lib))
|
|
root = save_buffer;
|
|
else
|
|
done = true;
|
|
} else {
|
|
done = true;
|
|
}
|
|
source = (isource ? isource : idef);
|
|
} break;
|
|
case 6: // default, try current directory
|
|
if (!isource && ftype == YAP_SAVED_STATE)
|
|
source = idef;
|
|
root = NULL;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if (done)
|
|
continue;
|
|
// { CACHE_REGS __android_log_print(ANDROID_LOG_ERROR, __FUNCTION__,
|
|
// "root= %s %s ", root, source) ; }
|
|
const char *work = PlExpandVars(source, root, result);
|
|
|
|
// expand names in case you have
|
|
// to add a prefix
|
|
if (!access || exists(work))
|
|
return work; // done
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char *Yap_locateFile(const char *source, char *result, bool in_lib) {
|
|
return Yap_findFile(source, NULL, NULL, result, true, YAP_PL, true, in_lib);
|
|
}
|
|
|
|
static Int true_file_name(USES_REGS1) {
|
|
Term t = Deref(ARG1);
|
|
|
|
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 (!Yap_AbsoluteFileInBuffer(RepAtom(AtomOfTerm(t))->StrOfAE,
|
|
LOCAL_FileNameBuf, YAP_FILENAME_MAX - 1, true))
|
|
return FALSE;
|
|
return Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf)));
|
|
}
|
|
|
|
static Int p_expand_file_name(USES_REGS1) {
|
|
Term t = Deref(ARG1);
|
|
const char *text, *text2;
|
|
|
|
if (IsVarTerm(t)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t, "argument to true_file_name unbound");
|
|
return FALSE;
|
|
}
|
|
text = Yap_TextTermToText(t, NULL, 0);
|
|
if (!text)
|
|
return false;
|
|
if (!(text2 = PlExpandVars(text, NULL, NULL)))
|
|
return false;
|
|
freeBuffer(text);
|
|
bool rc = Yap_unify(ARG2, Yap_MkTextTerm(text2, t));
|
|
freeBuffer(text2);
|
|
return rc;
|
|
}
|
|
|
|
static Int true_file_name3(USES_REGS1) {
|
|
Term t = Deref(ARG1), t2 = Deref(ARG2);
|
|
char *root = NULL;
|
|
|
|
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;
|
|
}
|
|
root = RepAtom(AtomOfTerm(t2))->StrOfAE;
|
|
}
|
|
if (!Yap_findFile(RepAtom(AtomOfTerm(t))->StrOfAE, NULL, root,
|
|
LOCAL_FileNameBuf, false, YAP_PL, false, false))
|
|
return FALSE;
|
|
return Yap_unify(ARG3, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf)));
|
|
}
|
|
|
|
/* Executes $SHELL under Prolog */
|
|
/** @pred sh
|
|
|
|
|
|
Creates a new shell interaction.
|
|
|
|
|
|
*/
|
|
static Int p_sh(USES_REGS1) { /* sh */
|
|
#ifdef HAVE_SYSTEM
|
|
char *shell;
|
|
shell = (char *)getenv("SHELL");
|
|
if (shell == NULL)
|
|
shell = "/bin/sh";
|
|
if (system(shell) < 0) {
|
|
#if HAVE_STRERROR
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil, "%s in sh/0",
|
|
strerror(errno));
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil, "in sh/0");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
#else
|
|
#ifdef MSH
|
|
register char *shell;
|
|
shell = "msh -i";
|
|
system(shell);
|
|
return (TRUE);
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"sh not available in this configuration");
|
|
return (FALSE);
|
|
#endif /* MSH */
|
|
#endif
|
|
}
|
|
|
|
/** shell(+Command:text, -Status:integer) is det.
|
|
|
|
Run an external command and wait for its completion.
|
|
*/
|
|
static Int p_shell(USES_REGS1) { /* '$shell'(+SystCommand) */
|
|
const char *cmd;
|
|
Term t1 = Deref(ARG1);
|
|
if (IsAtomTerm(t1))
|
|
cmd = RepAtom(AtomOfTerm(t1))->StrOfAE;
|
|
else if (IsStringTerm(t1))
|
|
cmd = StringOfTerm(t1);
|
|
else
|
|
return FALSE;
|
|
#if _MSC_VER || defined(__MINGW32__)
|
|
{
|
|
int rval = system(cmd);
|
|
|
|
return rval == 0;
|
|
}
|
|
|
|
return true;
|
|
#else
|
|
#if HAVE_SYSTEM
|
|
char *shell;
|
|
register int bourne = FALSE;
|
|
|
|
shell = (char *)getenv("SHELL");
|
|
if (!strcmp(shell, "/bin/sh"))
|
|
bourne = TRUE;
|
|
if (shell == NIL)
|
|
bourne = TRUE;
|
|
/* Yap_CloseStreams(TRUE); */
|
|
if (bourne)
|
|
return system(cmd) == 0;
|
|
else {
|
|
int status = -1;
|
|
int child = fork();
|
|
|
|
if (child == 0) { /* let the children go */
|
|
if (!execl(shell, shell, "-c", cmd, NULL)) {
|
|
exit(-1);
|
|
}
|
|
exit(TRUE);
|
|
}
|
|
{ /* put the father on wait */
|
|
int result = child < 0 ||
|
|
/* vsc:I am not sure this is used, Stevens say wait returns
|
|
an integer.
|
|
#if NO_UNION_WAIT
|
|
*/
|
|
wait((&status)) != child ||
|
|
/*
|
|
#else
|
|
wait ((union wait *) (&status)) != child ||
|
|
#endif
|
|
*/
|
|
status == 0;
|
|
return result;
|
|
}
|
|
}
|
|
#else /* HAVE_SYSTEM */
|
|
#ifdef MSH
|
|
register char *shell;
|
|
shell = "msh -i";
|
|
/* Yap_CloseStreams(); */
|
|
system(shell);
|
|
return TRUE;
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"shell not available in this configuration");
|
|
return FALSE;
|
|
#endif
|
|
#endif /* HAVE_SYSTEM */
|
|
#endif /* _MSC_VER */
|
|
}
|
|
|
|
/** system(+Command:text).
|
|
|
|
Run an external command.
|
|
*/
|
|
|
|
static Int p_system(USES_REGS1) { /* '$system'(+SystCommand) */
|
|
const char *cmd;
|
|
Term t1 = Deref(ARG1);
|
|
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "argument to system/1 unbound");
|
|
return FALSE;
|
|
} else if (IsAtomTerm(t1)) {
|
|
cmd = RepAtom(AtomOfTerm(t1))->StrOfAE;
|
|
} else if (IsStringTerm(t1)) {
|
|
cmd = StringOfTerm(t1);
|
|
} else {
|
|
if (!Yap_GetName(LOCAL_FileNameBuf, YAP_FILENAME_MAX, t1)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, "argument to system/1");
|
|
return false;
|
|
}
|
|
cmd = LOCAL_FileNameBuf;
|
|
}
|
|
/* Yap_CloseStreams(TRUE); */
|
|
#if _MSC_VER || defined(__MINGW32__)
|
|
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
// Start the child process.
|
|
if (!CreateProcess(NULL, // No module name (use command line)
|
|
(LPSTR)cmd, // Command line
|
|
NULL, // Process handle not inheritable
|
|
NULL, // Thread handle not inheritable
|
|
FALSE, // Set handle inheritance to FALSE
|
|
0, // No creation flags
|
|
NULL, // Use parent's environment block
|
|
NULL, // Use parent's starting directory
|
|
&si, // Pointer to STARTUPINFO structure
|
|
&pi) // Pointer to PROCESS_INFORMATION structure
|
|
) {
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, ARG1, "CreateProcess failed (%d).\n",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
// Wait until child process exits.
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
// Close process and thread handles.
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
#elif HAVE_SYSTEM
|
|
#if _MSC_VER
|
|
_flushall();
|
|
#endif
|
|
if (system(cmd)) {
|
|
#if HAVE_STRERROR
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, t1, "%s in system(%s)",
|
|
strerror(errno), cmd);
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, t1, "in system(%s)", cmd);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
#else
|
|
#ifdef MSH
|
|
register char *shell;
|
|
shell = "msh -i";
|
|
/* Yap_CloseStreams(); */
|
|
system(shell);
|
|
return (TRUE);
|
|
#undef command
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "sh not available in this machine");
|
|
return (FALSE);
|
|
#endif
|
|
#endif /* HAVE_SYSTEM */
|
|
}
|
|
|
|
static Int p_mv(USES_REGS1) { /* rename(+OldName,+NewName) */
|
|
#if HAVE_LINK
|
|
int r;
|
|
char *oldname, *newname;
|
|
Term t1 = Deref(ARG1);
|
|
Term t2 = Deref(ARG2);
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "first argument to rename/2 unbound");
|
|
} else if (!IsAtomTerm(t1)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, "first argument to rename/2 not atom");
|
|
}
|
|
if (IsVarTerm(t2)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t2, "second argument to rename/2 unbound");
|
|
} else if (!IsAtomTerm(t2)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t2, "second argument to rename/2 not atom");
|
|
} else {
|
|
oldname = (RepAtom(AtomOfTerm(t1)))->StrOfAE;
|
|
newname = (RepAtom(AtomOfTerm(t2)))->StrOfAE;
|
|
if ((r = link(oldname, newname)) == 0 && (r = unlink(oldname)) != 0)
|
|
unlink(newname);
|
|
if (r != 0) {
|
|
#if HAVE_STRERROR
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, t2, "%s in rename(%s,%s)",
|
|
strerror(errno), oldname, newname);
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, t2, "in rename(%s,%s)", oldname,
|
|
newname);
|
|
#endif
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"rename/2 not available in this machine");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
#ifdef MAC
|
|
|
|
void Yap_SetTextFile(name) char *name;
|
|
{
|
|
#ifdef MACC
|
|
SetFileType(name, 'TEXT');
|
|
SetFileSignature(name, 'EDIT');
|
|
#else
|
|
FInfo f;
|
|
FInfo *p = &f;
|
|
GetFInfo(name, 0, p);
|
|
p->fdType = 'TEXT';
|
|
#ifdef MPW
|
|
if (mpwshell)
|
|
p->fdCreator = 'MPS\0';
|
|
#endif
|
|
#ifndef LIGHT
|
|
else
|
|
p->fdCreator = 'EDIT';
|
|
#endif
|
|
SetFInfo(name, 0, p);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/* return YAP's environment */
|
|
static Int p_getenv(USES_REGS1) {
|
|
#if HAVE_GETENV
|
|
Term t1 = Deref(ARG1), to;
|
|
char *s, *so;
|
|
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "first arg of getenv/2");
|
|
return (FALSE);
|
|
} else if (!IsAtomTerm(t1)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, "first arg of getenv/2");
|
|
return (FALSE);
|
|
} else
|
|
s = RepAtom(AtomOfTerm(t1))->StrOfAE;
|
|
if ((so = getenv(s)) == NULL)
|
|
return (FALSE);
|
|
to = MkAtomTerm(Yap_LookupAtom(so));
|
|
return (Yap_unify_constant(ARG2, to));
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"getenv not available in this configuration");
|
|
return (FALSE);
|
|
#endif
|
|
}
|
|
|
|
/* set a variable in YAP's environment */
|
|
static Int p_putenv(USES_REGS1) {
|
|
#if HAVE_PUTENV
|
|
Term t1 = Deref(ARG1), t2 = Deref(ARG2);
|
|
char *s, *s2, *p0, *p;
|
|
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "first arg to putenv/2");
|
|
return (FALSE);
|
|
} else if (!IsAtomTerm(t1)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t1, "first arg to putenv/2");
|
|
return (FALSE);
|
|
} else
|
|
s = RepAtom(AtomOfTerm(t1))->StrOfAE;
|
|
if (IsVarTerm(t2)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "second arg to putenv/2");
|
|
return (FALSE);
|
|
} else if (!IsAtomTerm(t2)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, t2, "second arg to putenv/2");
|
|
return (FALSE);
|
|
} else
|
|
s2 = RepAtom(AtomOfTerm(t2))->StrOfAE;
|
|
while (!(p0 = p = Yap_AllocAtomSpace(strlen(s) + strlen(s2) + 3))) {
|
|
if (!Yap_growheap(FALSE, MinHeapGap, NULL)) {
|
|
Yap_Error(RESOURCE_ERROR_HEAP, TermNil, LOCAL_ErrorMessage);
|
|
return FALSE;
|
|
}
|
|
}
|
|
while ((*p++ = *s++) != '\0')
|
|
;
|
|
p[-1] = '=';
|
|
while ((*p++ = *s2++) != '\0')
|
|
;
|
|
if (putenv(p0) == 0)
|
|
return TRUE;
|
|
#if HAVE_STRERROR
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil, "in putenv(%s)",
|
|
strerror(errno), p0);
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_OPERATING_SYSTEM, TermNil, "in putenv(%s)", p0);
|
|
#endif
|
|
return FALSE;
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
|
|
"putenv not available in this configuration");
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static Int p_host_type(USES_REGS1) {
|
|
Term out = MkAtomTerm(Yap_LookupAtom(HOST_ALIAS));
|
|
return (Yap_unify(out, ARG1));
|
|
}
|
|
|
|
static Int p_yap_home(USES_REGS1) {
|
|
Term out = MkAtomTerm(Yap_LookupAtom(YAP_ROOTDIR));
|
|
return (Yap_unify(out, ARG1));
|
|
}
|
|
|
|
static Int p_yap_paths(USES_REGS1) {
|
|
Term out1, out2, out3;
|
|
const char *env_destdir = getenv("DESTDIR");
|
|
char destdir[YAP_FILENAME_MAX + 1];
|
|
|
|
if (env_destdir) {
|
|
strncat(destdir, env_destdir, YAP_FILENAME_MAX);
|
|
strncat(destdir, "/" YAP_LIBDIR, YAP_FILENAME_MAX);
|
|
out1 = MkAtomTerm(Yap_LookupAtom(destdir));
|
|
} else {
|
|
out1 = MkAtomTerm(Yap_LookupAtom(YAP_LIBDIR));
|
|
}
|
|
if (env_destdir) {
|
|
strncat(destdir, env_destdir, YAP_FILENAME_MAX);
|
|
strncat(destdir, "/" YAP_SHAREDIR, YAP_FILENAME_MAX);
|
|
out2 = MkAtomTerm(Yap_LookupAtom(destdir));
|
|
} else {
|
|
out2 = MkAtomTerm(Yap_LookupAtom(YAP_SHAREDIR));
|
|
}
|
|
if (env_destdir) {
|
|
strncat(destdir, env_destdir, YAP_FILENAME_MAX);
|
|
strncat(destdir, "/" YAP_BINDIR, YAP_FILENAME_MAX);
|
|
out3 = MkAtomTerm(Yap_LookupAtom(destdir));
|
|
} else {
|
|
out3 = MkAtomTerm(Yap_LookupAtom(YAP_BINDIR));
|
|
}
|
|
return (Yap_unify(out1, ARG1) && Yap_unify(out2, ARG2) &&
|
|
Yap_unify(out3, ARG3));
|
|
}
|
|
|
|
static Int p_log_event(USES_REGS1) {
|
|
Term in = Deref(ARG1);
|
|
Atom at;
|
|
|
|
if (IsVarTerm(in))
|
|
return FALSE;
|
|
if (!IsAtomTerm(in))
|
|
return FALSE;
|
|
at = AtomOfTerm(in);
|
|
#if DEBUG
|
|
if (IsWideAtom(at))
|
|
fprintf(stderr, "LOG %S\n", RepAtom(at)->WStrOfAE);
|
|
else if (IsBlob(at))
|
|
return FALSE;
|
|
else
|
|
fprintf(stderr, "LOG %s\n", RepAtom(at)->StrOfAE);
|
|
#endif
|
|
if (IsWideAtom(at) || IsBlob(at))
|
|
return FALSE;
|
|
LOG(" %s ", RepAtom(at)->StrOfAE);
|
|
return TRUE;
|
|
}
|
|
|
|
static Int p_env_separator(USES_REGS1) {
|
|
#if defined(_WIN32)
|
|
return Yap_unify(MkIntegerTerm(';'), ARG1);
|
|
#else
|
|
return Yap_unify(MkIntegerTerm(':'), ARG1);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* This is responsable for the initialization of all machine dependant
|
|
* predicates
|
|
*/
|
|
void Yap_InitSysbits(int wid) {
|
|
CACHE_REGS
|
|
#if __simplescalar__
|
|
{
|
|
char *pwd = getenv("PWD");
|
|
strncpy(GLOBAL_pwd, pwd, YAP_FILENAME_MAX);
|
|
}
|
|
#endif
|
|
Yap_InitWTime();
|
|
Yap_InitRandom();
|
|
/* let the caller control signals as it sees fit */
|
|
Yap_InitOSSignals(worker_id);
|
|
}
|
|
|
|
static Int p_unix(USES_REGS1) {
|
|
#ifdef unix
|
|
return TRUE;
|
|
#else
|
|
#ifdef __unix__
|
|
return TRUE;
|
|
#else
|
|
#ifdef __APPLE__
|
|
return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
static Int p_win32(USES_REGS1) {
|
|
#ifdef _WIN32
|
|
return TRUE;
|
|
#else
|
|
#ifdef __CYGWIN__
|
|
return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
static Int p_ld_path(USES_REGS1) {
|
|
return Yap_unify(ARG1, MkAtomTerm(Yap_LookupAtom(YAP_LIBDIR)));
|
|
}
|
|
|
|
static Int p_address_bits(USES_REGS1) {
|
|
#if SIZEOF_INT_P == 4
|
|
return Yap_unify(ARG1, MkIntTerm(32));
|
|
#else
|
|
return Yap_unify(ARG1, MkIntTerm(64));
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
/* This code is from SWI-Prolog by Jan Wielemaker */
|
|
|
|
#define wstreq(s, q) (wcscmp((s), (q)) == 0)
|
|
|
|
static HKEY reg_open_key(const wchar_t *which, int create) {
|
|
HKEY key = HKEY_CURRENT_USER;
|
|
DWORD disp;
|
|
LONG rval;
|
|
|
|
while (*which) {
|
|
wchar_t buf[256];
|
|
wchar_t *s;
|
|
HKEY tmp;
|
|
|
|
for (s = buf; *which && !(*which == '/' || *which == '\\');)
|
|
*s++ = *which++;
|
|
*s = '\0';
|
|
if (*which)
|
|
which++;
|
|
|
|
if (wstreq(buf, L"HKEY_CLASSES_ROOT")) {
|
|
key = HKEY_CLASSES_ROOT;
|
|
continue;
|
|
} else if (wstreq(buf, L"HKEY_CURRENT_USER")) {
|
|
key = HKEY_CURRENT_USER;
|
|
continue;
|
|
} else if (wstreq(buf, L"HKEY_LOCAL_MACHINE")) {
|
|
key = HKEY_LOCAL_MACHINE;
|
|
continue;
|
|
} else if (wstreq(buf, L"HKEY_USERS")) {
|
|
key = HKEY_USERS;
|
|
continue;
|
|
}
|
|
|
|
if (RegOpenKeyExW(key, buf, 0L, KEY_READ, &tmp) == ERROR_SUCCESS) {
|
|
RegCloseKey(key);
|
|
key = tmp;
|
|
continue;
|
|
}
|
|
|
|
if (!create)
|
|
return NULL;
|
|
|
|
rval =
|
|
RegCreateKeyExW(key, buf, 0, L"", 0, KEY_ALL_ACCESS, NULL, &tmp, &disp);
|
|
RegCloseKey(key);
|
|
if (rval == ERROR_SUCCESS)
|
|
key = tmp;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
#define MAXREGSTRLEN 1024
|
|
|
|
static void recover_space(wchar_t *k, Atom At) {
|
|
if (At->WStrOfAE != k)
|
|
Yap_FreeCodeSpace((char *)k);
|
|
}
|
|
|
|
static wchar_t *WideStringFromAtom(Atom KeyAt USES_REGS) {
|
|
if (IsWideAtom(KeyAt)) {
|
|
return KeyAt->WStrOfAE;
|
|
} else {
|
|
int len = strlen(KeyAt->StrOfAE);
|
|
int sz = sizeof(wchar_t) * (len + 1);
|
|
char *chp = KeyAt->StrOfAE;
|
|
wchar_t *kptr, *k;
|
|
|
|
k = (wchar_t *)Yap_AllocCodeSpace(sz);
|
|
while (k == NULL) {
|
|
if (!Yap_growheap(FALSE, sz, NULL)) {
|
|
Yap_Error(RESOURCE_ERROR_HEAP, MkIntegerTerm(sz),
|
|
"generating key in win_registry_get_value/3");
|
|
return FALSE;
|
|
}
|
|
}
|
|
kptr = k;
|
|
while ((*kptr++ = *chp++))
|
|
;
|
|
return k;
|
|
}
|
|
}
|
|
|
|
static Int p_win_registry_get_value(USES_REGS1) {
|
|
DWORD type;
|
|
BYTE data[MAXREGSTRLEN];
|
|
DWORD len = sizeof(data);
|
|
wchar_t *k, *name;
|
|
HKEY key;
|
|
Term Key = Deref(ARG1);
|
|
Term Name = Deref(ARG2);
|
|
Atom KeyAt, NameAt;
|
|
|
|
if (IsVarTerm(Key)) {
|
|
Yap_Error(INSTANTIATION_ERROR, Key,
|
|
"argument to win_registry_get_value unbound");
|
|
return FALSE;
|
|
}
|
|
if (!IsAtomTerm(Key)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, Key, "argument to win_registry_get_value");
|
|
return FALSE;
|
|
}
|
|
KeyAt = AtomOfTerm(Key);
|
|
if (IsVarTerm(Name)) {
|
|
Yap_Error(INSTANTIATION_ERROR, Key,
|
|
"argument to win_registry_get_value unbound");
|
|
return FALSE;
|
|
}
|
|
if (!IsAtomTerm(Name)) {
|
|
Yap_Error(TYPE_ERROR_ATOM, Key, "argument to win_registry_get_value");
|
|
return FALSE;
|
|
}
|
|
NameAt = AtomOfTerm(Name);
|
|
|
|
k = WideStringFromAtom(KeyAt PASS_REGS);
|
|
if (!(key = reg_open_key(k, FALSE))) {
|
|
Yap_Error(EXISTENCE_ERROR_KEY, Key, "argument to win_registry_get_value");
|
|
recover_space(k, KeyAt);
|
|
return FALSE;
|
|
}
|
|
name = WideStringFromAtom(NameAt PASS_REGS);
|
|
|
|
if (RegQueryValueExW(key, name, NULL, &type, data, &len) == ERROR_SUCCESS) {
|
|
RegCloseKey(key);
|
|
switch (type) {
|
|
case REG_SZ:
|
|
recover_space(k, KeyAt);
|
|
recover_space(name, NameAt);
|
|
((wchar_t *)data)[len] = '\0';
|
|
return Yap_unify(MkAtomTerm(Yap_LookupMaybeWideAtom((wchar_t *)data)),
|
|
ARG3);
|
|
case REG_DWORD:
|
|
recover_space(k, KeyAt);
|
|
recover_space(name, NameAt);
|
|
{
|
|
DWORD *d = (DWORD *)data;
|
|
return Yap_unify(MkIntegerTerm((Int)d[0]), ARG3);
|
|
}
|
|
default:
|
|
recover_space(k, KeyAt);
|
|
recover_space(name, NameAt);
|
|
return FALSE;
|
|
}
|
|
}
|
|
recover_space(k, KeyAt);
|
|
recover_space(name, NameAt);
|
|
return FALSE;
|
|
}
|
|
|
|
char *Yap_RegistryGetString(char *name) {
|
|
DWORD type;
|
|
BYTE data[MAXREGSTRLEN];
|
|
DWORD len = sizeof(data);
|
|
HKEY key;
|
|
char *ptr;
|
|
int i;
|
|
|
|
#if SIZEOF_INT_P == 8
|
|
if (!(key =
|
|
reg_open_key(L"HKEY_LOCAL_MACHINE/SOFTWARE/YAP/Prolog64", FALSE))) {
|
|
return NULL;
|
|
}
|
|
#else
|
|
if (!(key = reg_open_key(L"HKEY_LOCAL_MACHINE/SOFTWARE/YAP/Prolog", FALSE))) {
|
|
return NULL;
|
|
}
|
|
#endif
|
|
if (RegQueryValueEx(key, name, NULL, &type, data, &len) == ERROR_SUCCESS) {
|
|
RegCloseKey(key);
|
|
switch (type) {
|
|
case REG_SZ:
|
|
ptr = malloc(len + 2);
|
|
if (!ptr)
|
|
return NULL;
|
|
for (i = 0; i <= len; i++)
|
|
ptr[i] = data[i];
|
|
ptr[len + 1] = '\0';
|
|
return ptr;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
void Yap_InitSysPreds(void) {
|
|
Yap_InitCPred("log_event", 1, p_log_event, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("sh", 0, p_sh, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$shell", 1, p_shell, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("system", 1, p_system,
|
|
SafePredFlag | SyncPredFlag | UserCPredFlag);
|
|
Yap_InitCPred("$rename", 2, p_mv, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$yap_home", 1, p_yap_home, SafePredFlag);
|
|
Yap_InitCPred("$yap_paths", 3, p_yap_paths, SafePredFlag);
|
|
Yap_InitCPred("$dir_separator", 1, p_dir_sp, SafePredFlag);
|
|
Yap_InitCPred("libraries_directories", 2, libraries_directories, 0);
|
|
Yap_InitCPred("system_library", 1, system_library, 0);
|
|
Yap_InitCPred("commons_library", 1, commons_library, 0);
|
|
Yap_InitCPred("$getenv", 2, p_getenv, SafePredFlag);
|
|
Yap_InitCPred("$putenv", 2, p_putenv, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$host_type", 1, p_host_type, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$env_separator", 1, p_env_separator, SafePredFlag);
|
|
Yap_InitCPred("$unix", 0, p_unix, SafePredFlag);
|
|
Yap_InitCPred("$win32", 0, p_win32, SafePredFlag);
|
|
Yap_InitCPred("$ld_path", 1, p_ld_path, SafePredFlag);
|
|
Yap_InitCPred("$address_bits", 1, p_address_bits, SafePredFlag);
|
|
Yap_InitCPred("$expand_file_name", 2, p_expand_file_name, SyncPredFlag);
|
|
Yap_InitCPred("expand_file_name", 3, expand_file_name3, SyncPredFlag);
|
|
Yap_InitCPred("expand_file_name", 2, expand_file_name, SyncPredFlag);
|
|
Yap_InitCPred("working_directory", 2, working_directory, SyncPredFlag);
|
|
Yap_InitCPred("prolog_to_os_filename", 2, prolog_to_os_filename,
|
|
SyncPredFlag);
|
|
Yap_InitCPred("absolute_file_system_path", 2, absolute_file_system_path, 0);
|
|
Yap_InitCPred("real_path", 2, prolog_realpath, 0);
|
|
Yap_InitCPred("true_file_name", 2, true_file_name, SyncPredFlag);
|
|
Yap_InitCPred("true_file_name", 3, true_file_name3, SyncPredFlag);
|
|
#ifdef _WIN32
|
|
Yap_InitCPred("win_registry_get_value", 3, p_win_registry_get_value, 0);
|
|
#endif
|
|
Yap_InitCPred("rmdir", 2, p_rmdir, SyncPredFlag);
|
|
Yap_InitCPred("make_directory", 1, make_directory, SyncPredFlag);
|
|
}
|