This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/os/files.c

806 lines
22 KiB
C
Raw Normal View History

2015-06-18 01:33:55 +01:00
/*************************************************************************
2017-10-02 08:58:51 +01:00
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: iopreds.c *
* Last rev: 5/2/88 *
* mods: *
* comments: Input/Output C implemented predicates *
* *
*************************************************************************/
2015-06-18 01:33:55 +01:00
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#endif
/*
* This file includes the definition of a miscellania of standard predicates
* for yap refering to: Files and GLOBAL_Streams, Simple Input/Output,
2015-06-18 01:33:55 +01:00
*
*/
2016-01-31 10:37:41 +00:00
#include "sysbits.h"
2017-11-21 15:44:43 +00:00
#include "yapio.h"
2016-01-31 10:37:41 +00:00
2018-06-07 18:05:45 +01:00
#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#if HAVE_DIRECT_H
#include <direct.h>
#endif
#if defined(__MINGW32__) || _MSC_VER
#include <io.h>
#include <windows.h>
#endif
#if _MSC_VER || defined(__MINGW32__)
2015-06-18 01:33:55 +01:00
#define SYSTEM_STAT _stat
#else
#define SYSTEM_STAT stat
#endif
2017-10-02 08:58:51 +01:00
const char *Yap_GetFileName(Term t USES_REGS) {
char *buf = Malloc(YAP_FILENAME_MAX + 1);
if (IsApplTerm(t) && FunctorOfTerm(t) == FunctorSlash) {
snprintf(buf, YAP_FILENAME_MAX, "%s/%s", Yap_GetFileName(ArgOfTerm(1, t)),
2018-07-15 13:40:01 +01:00
Yap_GetFileName(ArgOfTerm(2, t)));
}
if (IsAtomTerm(t)) {
return RepAtom(AtomOfTerm(t))->StrOfAE;
}
if (IsStringTerm(t)) {
return StringOfTerm(t);
2016-08-29 23:35:01 +01:00
}
2017-10-02 08:58:51 +01:00
return Yap_TextTermToText(t PASS_REGS);
2016-08-29 23:35:01 +01:00
}
2017-10-02 08:58:51 +01:00
/**
* @pred file_name_extension( ? BaseFile, ?Extension, ?FullNameO)
*
* Relate a file name with an extension. The extension is the filename's suffix
* and indicates the kind of the file.
*
* The predicate can be used to:
* - Given __FullName__, extract the extension as _Extension_, and the remainder
* as _BaseFile_. - Given _BaseFile_ and _?Extension_ obtain a _FullNameO_.
* ~~~~
* ~~~~
* Notice that:
* + if no suffix is found, file_name_extension/3 generates the empty
* suffu]kx, `''`. + the extension does not include the `,` separator; + the
* suffix may be longer thsn 3 characters + case should not matter in Windows
* and MacOS + paths may not correspond to valid file names.
*
* @return G
*/
static Int file_name_extension(USES_REGS1) {
2017-10-02 08:58:51 +01:00
Term t1;
Term t2;
2015-06-18 01:33:55 +01:00
Term t3 = Deref(ARG3);
2017-10-02 08:58:51 +01:00
int l = push_text_stack();
if (!IsVarTerm(t3)) {
// full path is given.
const char *f = Yap_GetFileName(t3);
const char *ext;
char *base;
bool rc = true;
seq_type_t typ = Yap_TextType(t3);
if (!f) {
pop_text_stack(l);
2015-06-18 01:33:55 +01:00
return false;
}
2017-10-02 16:04:34 +01:00
size_t len_b = strlen(f), lenb_b;
2017-10-02 08:58:51 +01:00
char *candidate = strrchr(f, '.');
char *file = strrchr(f, '/');
2018-07-15 13:40:01 +01:00
if (candidate && candidate > file) {
2017-10-02 16:04:34 +01:00
lenb_b = candidate - f;
2017-10-02 08:58:51 +01:00
ext = candidate + 1;
2016-08-30 14:26:14 +01:00
} else {
2017-10-02 08:58:51 +01:00
lenb_b = len_b;
ext = "";
2016-08-30 14:26:14 +01:00
}
2017-10-02 08:58:51 +01:00
base = Malloc(lenb_b + 1);
2018-06-30 14:33:32 +01:00
memmove(base, f, lenb_b);
2017-10-02 08:58:51 +01:00
base[lenb_b] = '\0';
if (IsVarTerm(t1 = Deref(ARG1))) {
// should always succeed
rc = Yap_unify(t1, Yap_MkTextTerm(base, typ));
2015-06-18 01:33:55 +01:00
} else {
2017-10-02 08:58:51 +01:00
char *f_a = (char *)Yap_GetFileName(t1 PASS_REGS);
2016-08-29 23:35:01 +01:00
#if __APPLE__ || _WIN32
2017-10-02 08:58:51 +01:00
rc = strcasecmp(f_a, base) == 0;
#else
2017-10-02 16:04:34 +01:00
rc = strcmp(f_a, base) == 0;
2016-08-29 23:35:01 +01:00
#endif
}
2017-10-02 08:58:51 +01:00
if (rc) {
if (IsVarTerm(t2 = Deref(ARG2))) {
// should always succeed
rc = Yap_unify(t2, Yap_MkTextTerm(ext, typ));
} else {
char *f_a = (char *)Yap_TextTermToText(t2 PASS_REGS);
if (f_a[0] == '.') {
f_a += 1;
}
2016-08-29 23:35:01 +01:00
#if __APPLE__ || _WIN32
2017-10-02 08:58:51 +01:00
rc = strcasecmp(f_a, ext) == 0;
#else
2017-10-02 16:04:34 +01:00
rc = strcmp(f_a, ext) == 0;
2016-08-29 23:35:01 +01:00
#endif
2015-06-18 01:33:55 +01:00
}
2016-08-29 23:35:01 +01:00
}
2017-10-02 08:58:51 +01:00
pop_text_stack(l);
return rc;
2016-08-29 23:35:01 +01:00
} else {
2017-10-02 08:58:51 +01:00
const char *f;
2016-08-29 23:35:01 +01:00
char *f2;
2017-10-02 08:58:51 +01:00
seq_type_t typ, typ1 = Yap_TextType((t1 = Deref(ARG1))),
typ2 = Yap_TextType((t2 = Deref(ARG2)));
if (typ1 == typ2) {
typ = typ1;
} else if (typ1 == YAP_STRING_ATOM || typ2 == YAP_STRING_ATOM) {
typ = YAP_STRING_ATOM;
} else {
typ = YAP_STRING_STRING;
}
if (!(f = Yap_TextTermToText(t1 PASS_REGS))) {
pop_text_stack(l);
2015-06-18 01:33:55 +01:00
return false;
}
2017-10-02 08:58:51 +01:00
if (!(f2 = (char *)Yap_TextTermToText(t2 PASS_REGS))) {
pop_text_stack(l);
2015-06-18 01:33:55 +01:00
return false;
}
2017-10-02 08:58:51 +01:00
if (f2[0] == '.') {
f2++;
2015-06-18 01:33:55 +01:00
}
2017-10-02 08:58:51 +01:00
size_t lenb_b = strlen(f);
char *o = Realloc((void *)f, lenb_b + strlen(f2) + 2);
o[lenb_b] = '.';
o += lenb_b + 1;
pop_text_stack(l);
return strcpy(o, f2) && (t3 = Yap_MkTextTerm(o, typ)) &&
Yap_unify(t3, ARG3);
2015-06-18 01:33:55 +01:00
}
}
static Int access_path(USES_REGS1) {
2015-06-18 01:33:55 +01:00
Term tname = Deref(ARG1);
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "access");
2016-04-12 16:04:33 +01:00
return false;
} else if (!IsAtomTerm(tname)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
2016-04-12 16:04:33 +01:00
return false;
2015-06-18 01:33:55 +01:00
} else {
2018-02-14 00:13:13 +00:00
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;
}
2015-06-18 01:33:55 +01:00
#if HAVE_STAT
struct SYSTEM_STAT ss;
2016-04-12 16:04:33 +01:00
char *file_name;
2015-06-18 01:33:55 +01:00
file_name = RepAtom(AtomOfTerm(tname))->StrOfAE;
if (SYSTEM_STAT(file_name, &ss) != 0) {
/* ignore errors while checking a file */
2016-04-12 16:04:33 +01:00
return true;
2015-06-18 01:33:55 +01:00
}
2016-04-12 16:04:33 +01:00
return true;
2015-06-18 01:33:55 +01:00
#else
2016-04-12 16:04:33 +01:00
return false;
2015-06-18 01:33:55 +01:00
#endif
}
}
static Int exists_file(USES_REGS1) {
2015-06-18 01:33:55 +01:00
Term tname = Deref(ARG1);
char *file_name;
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "access");
return FALSE;
} else if (!IsAtomTerm(tname)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
return FALSE;
} else {
2018-02-14 00:13:13 +00:00
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;
}
2015-06-18 01:33:55 +01:00
#if HAVE_STAT
struct SYSTEM_STAT ss;
file_name = RepAtom(AtomOfTerm(tname))->StrOfAE;
if (SYSTEM_STAT(file_name, &ss) != 0) {
/* ignore errors while checking a file */
2015-06-18 01:33:55 +01:00
return FALSE;
}
#if _MSC_VER
return ss.st_mode & S_IFREG;
#else
return S_ISREG(ss.st_mode);
#endif
2015-06-18 01:33:55 +01:00
#else
return FALSE;
#endif
}
}
static Int file_exists(USES_REGS1) {
Term tname = Deref(ARG1);
char *file_name;
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "access");
return FALSE;
} else if (!IsAtomTerm(tname)) {
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
return FALSE;
} else {
#if HAVE_STAT
struct SYSTEM_STAT ss;
file_name = RepAtom(AtomOfTerm(tname))->StrOfAE;
if (SYSTEM_STAT(file_name, &ss) != 0) {
if (errno == ENOENT)
return false;
PlIOError(SYSTEM_ERROR_OPERATING_SYSTEM, tname, "error %s",
strerror(errno));
return false;
}
return true;
#else
return FALSE;
#endif
}
}
static Int time_file(USES_REGS1) {
2015-06-18 01:33:55 +01:00
Term tname = Deref(ARG1);
2015-06-18 01:33:55 +01:00
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "access");
return FALSE;
} else if (!IsAtomTerm(tname)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "access");
return FALSE;
} else {
const char *n = RepAtom(AtomOfTerm(tname))->StrOfAE;
2018-02-14 00:13:13 +00:00
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));
}
2015-06-18 01:33:55 +01:00
#if __WIN32
2016-01-31 10:37:41 +00:00
FILETIME ft;
HANDLE hdl;
Term rc;
2016-04-18 01:09:10 +01:00
if ((hdl = CreateFile(n, 0, 0, NULL, OPEN_EXISTING, 0, 0)) == 0) {
Yap_WinError("in time_file");
2015-06-18 01:33:55 +01:00
return false;
2016-04-18 01:09:10 +01:00
}
if (GetFileTime(hdl, NULL, NULL, &ft) == 0) {
Yap_WinError("in time_file");
2015-06-18 01:33:55 +01:00
return false;
2016-04-18 01:09:10 +01:00
}
2015-06-18 01:33:55 +01:00
// Convert the last-write time to local time.
// FileTimeToSystemTime(&ftWrite, &stUTC);
// SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
CloseHandle(hdl);
ULONGLONG qwResult;
// Copy the time into a quadword.
qwResult = (((ULONGLONG)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
#if SIZEOF_INT_P == 8
rc = MkIntegerTerm(qwResult);
#elif USE_GMP
char s[64];
MP_INT rop;
snprintf(s, 64, "%I64d", (long long int)n);
mpz_init_set_str(&rop, s, 10);
2016-07-31 16:15:55 +01:00
rc = Yap_MkBigIntTerm((void *)&rop PASS_REGS);
#else
2016-01-31 10:37:41 +00:00
rc = MkIntegerTerm(ft.dwHighDateTime);
#endif
return Yap_unify(ARG2, rc);
2015-06-18 01:33:55 +01:00
#elif HAVE_STAT
struct SYSTEM_STAT ss;
2015-06-18 01:33:55 +01:00
if (SYSTEM_STAT(n, &ss) != 0) {
/* ignore errors while checking a file */
2015-06-18 01:33:55 +01:00
return FALSE;
}
return Yap_unify(ARG2, MkIntegerTerm(ss.st_mtime));
#else
return FALSE;
#endif
}
}
static Int file_size(USES_REGS1) {
2015-09-29 23:44:11 +01:00
int rc;
Int sno = Yap_CheckStream(
ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f),
"file_size/2");
2015-06-18 01:33:55 +01:00
if (sno < 0)
return (FALSE);
2018-02-14 00:13:13 +00:00
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))) {
// there
struct stat file_stat;
if ((rc = fstat(fileno(GLOBAL_Stream[sno].file), &file_stat)) < 0) {
UNLOCK(GLOBAL_Stream[sno].streamlock);
2015-09-29 23:44:11 +01:00
if (rc == ENOENT)
PlIOError(EXISTENCE_ERROR_SOURCE_SINK, ARG1, "%s in file_size",
strerror(errno));
2015-09-29 23:44:11 +01:00
else
PlIOError(PERMISSION_ERROR_INPUT_STREAM, ARG1, "%s in file_size",
strerror(errno));
return false;
}
// and back again
2015-06-19 10:10:02 +01:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
return Yap_unify_constant(ARG2, MkIntegerTerm(file_stat.st_size));
}
UNLOCK(GLOBAL_Stream[sno].streamlock);
2015-06-18 01:33:55 +01:00
return false;
}
2016-09-21 20:47:05 +01:00
static Int lines_in_file(USES_REGS1) {
Int sno = Yap_CheckStream(ARG1, (Input_Stream_f), "lines_in_file/2");
2016-09-21 20:47:05 +01:00
if (sno < 0)
return false;
FILE *f = GLOBAL_Stream[sno].file;
size_t count = 0;
int ch;
2016-09-21 20:47:05 +01:00
#if __ANDROID__
#define getw getc
#endif
if (!f)
return false;
while ((ch = getw(f)) >= 0) {
if (ch == '\n') {
count++;
2016-09-21 20:47:05 +01:00
}
}
return Yap_unify(ARG2, MkIntegerTerm(count));
2016-09-21 20:47:05 +01:00
}
static Int access_file(USES_REGS1) {
2015-06-18 01:33:55 +01:00
Term tname = Deref(ARG1);
Term tmode = Deref(ARG2);
2016-02-11 14:15:30 +00:00
char *ares;
2015-06-18 01:33:55 +01:00
Atom atmode;
if (IsVarTerm(tmode)) {
Yap_Error(INSTANTIATION_ERROR, tmode, "access_file/2");
return FALSE;
} else if (!IsAtomTerm(tmode)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "access_file/2");
return FALSE;
}
atmode = AtomOfTerm(tmode);
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "access_file/2");
return FALSE;
} else if (!IsAtomTerm(tname)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "access_file/2");
return FALSE;
} else {
if (atmode == AtomNone)
return TRUE;
if (!(ares = RepAtom(AtomOfTerm(tname))->StrOfAE))
2015-06-18 01:33:55 +01:00
return FALSE;
}
2018-02-14 14:17:57 +00:00
VFS_t *vfs;
if ((vfs = vfs_owner(ares))) {
vfs_stat o;
if (vfs->stat(vfs, ares, &o)) {
if (atmode == AtomExist)
return true;
else if (atmode == AtomExists)
return true;
else if (atmode == AtomWrite)
return o.st_mode & VFS_CAN_WRITE;
else if (atmode == AtomRead)
return o.st_mode & VFS_CAN_READ;
else if (atmode == AtomAppend)
return o.st_mode & VFS_CAN_WRITE;
else if (atmode == AtomCsult)
return o.st_mode & VFS_CAN_READ;
else if (atmode == AtomExecute)
return o.st_mode & VFS_CAN_EXEC;
else {
Yap_Error(DOMAIN_ERROR_IO_MODE, tmode, "access_file/2");
return FALSE;
}
} else {
return false;
2018-02-14 14:17:57 +00:00
}
}
2015-06-18 01:33:55 +01:00
#if HAVE_ACCESS
#if _WIN32
{
int mode;
2016-07-31 16:15:55 +01:00
if (atmode == AtomExist)
mode = 00;
else if (atmode == AtomExists)
mode = 00;
else if (atmode == AtomWrite)
mode = 02;
else if (atmode == AtomRead)
mode = 04;
else if (atmode == AtomAppend)
mode = 03;
else if (atmode == AtomCsult)
mode = 04;
else if (atmode == AtomExecute)
mode = 00; // can always execute?
else {
Yap_Error(DOMAIN_ERROR_IO_MODE, tmode, "access_file/2");
return FALSE;
}
if (access(ares, mode) < 0) {
/* ignore errors while checking a file */
return false;
}
return true;
}
#else
2015-06-18 01:33:55 +01:00
{
int mode;
2016-07-31 16:15:55 +01:00
if (atmode == AtomExist)
mode = F_OK;
else if (atmode == AtomExists)
mode = F_OK;
2015-06-18 01:33:55 +01:00
else if (atmode == AtomWrite)
mode = W_OK;
else if (atmode == AtomRead)
mode = R_OK;
else if (atmode == AtomAppend)
mode = W_OK;
else if (atmode == AtomCsult)
mode = R_OK;
else if (atmode == AtomExecute)
mode = X_OK;
else {
2016-02-11 14:15:30 +00:00
Yap_Error(DOMAIN_ERROR_IO_MODE, tmode, "access_file/2");
return FALSE;
2015-06-18 01:33:55 +01:00
}
if (access(ares, mode) < 0) {
/* ignore errors while checking a file */
2016-02-11 14:15:30 +00:00
return false;
2015-06-18 01:33:55 +01:00
}
2016-02-11 14:15:30 +00:00
return true;
2015-06-18 01:33:55 +01:00
}
#endif
2015-06-18 01:33:55 +01:00
#elif HAVE_STAT
{
struct SYSTEM_STAT ss;
if (SYSTEM_STAT(ares, &ss) != 0) {
/* ignore errors while checking a file */
2015-06-18 01:33:55 +01:00
return FALSE;
}
return TRUE;
}
#else
return FALSE;
#endif
}
static Int exists_directory(USES_REGS1) {
2015-06-18 01:33:55 +01:00
Term tname = Deref(ARG1);
char *file_name;
if (IsVarTerm(tname)) {
Yap_Error(INSTANTIATION_ERROR, tname, "exists_directory/1");
return FALSE;
} else if (!IsAtomTerm(tname)) {
2015-06-18 01:33:55 +01:00
Yap_Error(TYPE_ERROR_ATOM, tname, "exists_directory/1");
return FALSE;
} else {
2018-02-14 00:13:13 +00:00
VFS_t *vfs;
char *s = Yap_VF(RepAtom(AtomOfTerm(tname))->StrOfAE);
if (!s) return false;
if ((vfs = vfs_owner(s))) {
bool rc = true;
2018-02-14 14:17:57 +00:00
return vfs->isdir(vfs, s);
2018-02-14 00:13:13 +00:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
return rc;
}
2015-06-18 01:33:55 +01:00
#if HAVE_STAT
struct SYSTEM_STAT ss;
2017-12-01 10:42:10 +00:00
file_name = Yap_VF(RepAtom(AtomOfTerm(tname))->StrOfAE);
2015-06-18 01:33:55 +01:00
if (SYSTEM_STAT(file_name, &ss) != 0) {
/* ignore errors while checking a file */
2016-02-11 14:15:30 +00:00
return false;
2015-06-18 01:33:55 +01:00
}
return (S_ISDIR(ss.st_mode));
#else
return FALSE;
#endif
}
}
static Int is_absolute_file_name(USES_REGS1) { /* file_base_name(Stream,N) */
2015-06-18 01:33:55 +01:00
Term t = Deref(ARG1);
Atom at;
2016-05-30 11:24:40 +01:00
bool rc;
if (IsVarTerm(t)) {
2015-06-18 01:33:55 +01:00
Yap_Error(INSTANTIATION_ERROR, t, "file_base_name/2");
2016-05-30 11:24:40 +01:00
return false;
2015-06-18 01:33:55 +01:00
}
2017-09-26 15:15:15 +01:00
int l = push_text_stack();
2017-10-02 08:58:51 +01:00
const char *buf = Yap_TextTermToText(t PASS_REGS);
2016-02-13 03:11:25 +00:00
if (buf) {
2017-12-01 10:42:10 +00:00
rc = Yap_IsAbsolutePath(buf, true);
2016-02-13 03:11:25 +00:00
} else {
2017-10-02 08:58:51 +01:00
at = AtomOfTerm(t);
2016-05-30 11:24:40 +01:00
#if _WIN32
2017-10-02 08:58:51 +01:00
rc = PathIsRelative(RepAtom(at)->StrOfAE);
2016-05-30 11:24:40 +01:00
#else
2017-10-02 08:58:51 +01:00
rc = RepAtom(at)->StrOfAE[0] == '/';
2016-07-31 16:15:55 +01:00
#endif
2015-06-18 01:33:55 +01:00
}
2017-09-26 15:15:15 +01:00
pop_text_stack(l);
2016-07-31 16:15:55 +01:00
return rc;
2015-06-18 01:33:55 +01:00
}
static Int file_base_name(USES_REGS1) { /* file_base_name(Stream,N) */
2015-06-18 01:33:55 +01:00
Term t = Deref(ARG1);
Atom at;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR, t, "file_base_name/2");
return FALSE;
2015-06-18 01:33:55 +01:00
}
at = AtomOfTerm(t);
const char *c = RepAtom(at)->StrOfAE;
const char *s;
#if HAVE_BASENAME && 0 // DISABLED: Linux basename is not compatible with
// file_base_name in SWI and GNU
char c1[YAP_FILENAME_MAX + 1];
strncpy(c1, c, YAP_FILENAME_MAX);
s = basename(c1);
2015-06-18 01:33:55 +01:00
#else
Int i = strlen(c);
while (i && !Yap_dir_separator((int)c[--i]))
;
if (Yap_dir_separator((int)c[i])) {
i++;
2015-06-18 01:33:55 +01:00
}
s = c + i;
#endif
return Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(s)));
2015-06-18 01:33:55 +01:00
}
static Int file_directory_name(USES_REGS1) { /* file_directory_name(Stream,N) */
2015-06-18 01:33:55 +01:00
Term t = Deref(ARG1);
Atom at;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR, t, "file_directory_name/2");
return false;
2015-06-18 01:33:55 +01:00
}
at = AtomOfTerm(t);
const char *c = RepAtom(at)->StrOfAE;
#if HAVE_BASENAME && 0 // DISABLED: Linux basename is not compatible with
// file_base_name in SWI and GNU
const char *s;
char c1[YAP_FILENAME_MAX + 1];
strncpy(c1, c, YAP_FILENAME_MAX);
s = dirname(c1);
2015-06-18 01:33:55 +01:00
#else
char s[YAP_FILENAME_MAX + 1];
Int i = strlen(c);
strncpy(s, c, YAP_FILENAME_MAX);
while (--i) {
if (Yap_dir_separator((int)c[i]))
break;
2015-06-18 01:33:55 +01:00
}
2017-10-02 08:58:51 +01:00
if (i == 0) {
s[0] = '.';
i = 1;
}
s[i] = '\0';
#endif
return Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(s)));
2015-06-18 01:33:55 +01:00
}
2018-06-07 18:05:45 +01:00
/* Return a list of files for a directory */
static Int list_directory(USES_REGS1) {
Term tf = MkAtomTerm(Yap_LookupAtom("[]"));
yhandle_t sl = Yap_InitSlot(tf);
2018-06-27 16:38:17 +01:00
VFS_t *vfsp;
2018-06-07 18:05:45 +01:00
char *buf = (char *)AtomName(AtomOfTerm(ARG1));
2018-06-27 16:38:17 +01:00
if ((vfsp = vfs_owner(buf))) {
void *de;
const char *dp;
2018-06-07 18:05:45 +01:00
2018-06-27 16:38:17 +01:00
if ((de = vfsp->opendir(vfsp, buf)) == NULL) {
2018-06-14 11:27:43 +01:00
PlIOError(PERMISSION_ERROR_INPUT_STREAM, ARG1, "%s in list_directory",
strerror(errno));
2018-06-07 18:05:45 +01:00
}
2018-06-27 16:38:17 +01:00
while ((dp = vfsp->nextdir( de))) {
2018-06-15 13:55:31 +01:00
YAP_Term ti = MkAtomTerm(Yap_LookupAtom(dp));
Yap_PutInHandle(sl, MkPairTerm(ti, Yap_GetFromHandle(sl)));
2018-06-07 18:05:45 +01:00
}
2018-06-27 16:38:17 +01:00
vfsp->closedir( de);
} else {
#if defined(__MINGW32__) || _MSC_VER
struct _finddata_t c_file;
char bs[BUF_SIZE];
long hFile;
bs[0] = '\0';
#if HAVE_STRNCPY
strncpy(bs, buf, BUF_SIZE);
#else
strcpy(bs, buf);
2018-06-07 18:05:45 +01:00
#endif
2018-06-27 16:38:17 +01:00
#if HAVE_STRNCAT
strncat(bs, "/*", BUF_SIZE);
#else
strcat(bs, "/*");
#endif
if ((hFile = _findfirst(bs, &c_file)) == -1L) {
2018-09-26 01:14:14 +01:00
return (Yap_unify(ARG2, tf));
2018-06-27 16:38:17 +01:00
}
2018-09-26 01:14:14 +01:00
Yap_PutInSlot(sl, MkPairTerm(MkAtomTerm(Yap_LookupAtom(c_file.name)),
Yap_GetFromSlot(sl)));
2018-06-27 16:38:17 +01:00
while (_findnext(hFile, &c_file) == 0) {
2018-09-26 01:14:14 +01:00
Term ti = MkAtomTerm(Yap_LookupAtom(c_file.name));
Yap_PutInSlot(sl, MkPairTerm(ti, Yap_GetFromSlot(sl)));
2018-06-27 16:38:17 +01:00
}
_findclose(hFile);
#elif HAVE_OPENDIR
{
DIR *de;
struct dirent *dp;
2018-06-07 18:05:45 +01:00
2018-06-27 16:38:17 +01:00
if ((de = opendir(buf)) == NULL) {
PlIOError(PERMISSION_ERROR_INPUT_STREAM, ARG1, "%s in list_directory",
strerror(errno));
2018-06-14 11:27:43 +01:00
2018-06-27 16:38:17 +01:00
return false;
}
while ((dp = readdir(de))) {
Term ti = MkAtomTerm(Yap_LookupAtom(dp->d_name));
Yap_PutInSlot(sl, MkPairTerm(ti, Yap_GetFromSlot(sl)));
}
closedir(de);
}
2018-06-07 18:05:45 +01:00
#endif /* HAVE_OPENDIR */
2018-06-27 16:38:17 +01:00
}
2018-06-07 18:05:45 +01:00
tf = Yap_GetFromSlot(sl);
return Yap_unify(ARG2, tf);
}
static Int same_file(USES_REGS1) {
2015-06-18 01:33:55 +01:00
char *f1 = RepAtom(AtomOfTerm(Deref(ARG1)))->StrOfAE;
char *f2 = RepAtom(AtomOfTerm(Deref(ARG2)))->StrOfAE;
if (strcmp(f1, f2) == 0)
2015-06-18 01:33:55 +01:00
return TRUE;
#if HAVE_LSTAT
2015-06-18 01:33:55 +01:00
{
int out;
struct stat *b1, *b2;
while ((char *)HR + sizeof(struct stat) * 2 > (char *)(ASP - 1024)) {
if (!Yap_gcl(2 * sizeof(struct stat), 2, ENV, Yap_gcP())) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
2015-06-18 01:33:55 +01:00
}
}
b1 = (struct stat *)HR;
b2 = b1 + 1;
if (strcmp(f1, "user_input") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[0].file), b1) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (strcmp(f1, "user_output") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[1].file), b1) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (strcmp(f1, "user_error") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[2].file), b1) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (stat(f1, b1) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
}
if (strcmp(f2, "user_input") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[0].file), b2) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (strcmp(f2, "user_output") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[1].file), b2) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (strcmp(f2, "user_error") == 0) {
2015-06-18 01:33:55 +01:00
if (fstat(fileno(GLOBAL_Stream[2].file), b2) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
2015-06-18 01:33:55 +01:00
}
} else if (stat(f2, b2) == -1) {
/* file does not exist, but was opened? Return -1 */
return FALSE;
}
out = (b1->st_ino == b2->st_ino
#ifdef __LCC__
2017-10-02 08:58:51 +01:00
&& memcmp((const void *)&(b1->st_dev), (const void *)&(b2->st_dev),
sizeof(buf1.st_dev)) == 0
2015-06-18 01:33:55 +01:00
#else
&& b1->st_dev == b2->st_dev
2015-06-18 01:33:55 +01:00
#endif
2017-10-02 08:58:51 +01:00
);
2015-06-18 01:33:55 +01:00
return out;
}
#else
return (FALSE);
2015-06-18 01:33:55 +01:00
#endif
}
void Yap_InitFiles(void) {
Yap_InitCPred("file_base_name", 2, file_base_name, SafePredFlag);
Yap_InitCPred("file_directory_name", 2, file_directory_name, SafePredFlag);
Yap_InitCPred("is_absolute_file_name", 1, is_absolute_file_name,
SafePredFlag);
Yap_InitCPred("same_file", 2, same_file, SafePredFlag | SyncPredFlag);
Yap_InitCPred("$access_file", 2, access_file, SafePredFlag | SyncPredFlag);
2016-09-21 20:47:05 +01:00
Yap_InitCPred("$lines_in_file", 2, lines_in_file,
SafePredFlag | SyncPredFlag);
Yap_InitCPred("access", 1, access_path, SafePredFlag | SyncPredFlag);
Yap_InitCPred("exists_directory", 1, exists_directory,
SafePredFlag | SyncPredFlag);
Yap_InitCPred("exists_file", 1, exists_file, SafePredFlag | SyncPredFlag);
Yap_InitCPred("$file_exists", 1, file_exists, SafePredFlag | SyncPredFlag);
Yap_InitCPred("time_file64", 2, time_file, SafePredFlag | SyncPredFlag);
Yap_InitCPred("time_file", 2, time_file, SafePredFlag | SyncPredFlag);
Yap_InitCPred("file_size", 2, file_size, SafePredFlag | SyncPredFlag);
Yap_InitCPred("file_name_extension", 3, file_name_extension,
SafePredFlag | SyncPredFlag);
2018-06-14 11:27:43 +01:00
Yap_InitCPred("list_directory", 2, list_directory, SyncPredFlag);
2015-06-18 01:33:55 +01:00
}