diff --git a/doc/ref/files.xml b/doc/ref/files.xml
index 0c0c3c1351..2013360f88 100644
--- a/doc/ref/files.xml
+++ b/doc/ref/files.xml
@@ -108,6 +108,7 @@ for more information how to do this.
<#Include Label="Directory">
<#Include Label="DirectoryTemporary">
<#Include Label="DirectoryCurrent">
+<#Include Label="ChangeDirectoryCurrent">
<#Include Label="DirectoriesLibrary">
<#Include Label="DirectoriesSystemPrograms">
<#Include Label="DirectoryContents">
diff --git a/lib/files.gd b/lib/files.gd
index a3458c6deb..38d3a13ad0 100644
--- a/lib/files.gd
+++ b/lib/files.gd
@@ -497,7 +497,7 @@ DeclareGlobalFunction( "RemoveDirectoryRecursively" );
InstallAtExit( function()
local path;
for path in GAPInfo.DirectoriesTemporary do
- if IsDir(path) = 'D' then
+ if IS_DIR(path) then
RemoveDirectoryRecursively(path);
else
PRINT_TO("*errout*", "Temporary directory already removed: ", path, "\n");
@@ -522,12 +522,37 @@ InstallAtExit( function()
##
BIND_GLOBAL( "DirectoryCurrent", function()
if IsBool( GAPInfo.DirectoryCurrent ) then
- GAPInfo.DirectoryCurrent := Directory("./");
+ GAPInfo.DirectoryCurrent := Directory(GAP_getcwd());
fi;
return GAPInfo.DirectoryCurrent;
end );
+#############################################################################
+##
+#F ChangeDirectoryCurrent() . . . . . . . . . . . change current directory
+##
+## <#GAPDoc Label="ChangeDirectoryCurrent">
+##
+##
+##
+##
+## Changes the current directory. Returns true on success and
+## fail on failure.
+##
+##
+## <#/GAPDoc>
+##
+BIND_GLOBAL( "ChangeDirectoryCurrent", function( path )
+ if GAP_chdir(path) = true then
+ GAPInfo.DirectoryCurrent := Directory(GAP_getcwd());
+ return true;
+ else
+ return fail;
+ fi;
+end );
+
+
#############################################################################
##
#F CrcFile( ) . . . . . . . . . . . . . . . . create crc value
diff --git a/lib/files.gi b/lib/files.gi
index c4cd489017..936cb71b52 100644
--- a/lib/files.gi
+++ b/lib/files.gi
@@ -369,7 +369,7 @@ InstallGlobalFunction(RemoveDirectoryRecursively,
function(dirname)
# dirname must be a string
local Dowork;
- if not(IsDir(dirname) = 'D') then
+ if not IS_DIR(dirname) then
Error("dirname must be a directory");
return fail;
fi;
@@ -383,13 +383,12 @@ InstallGlobalFunction(RemoveDirectoryRecursively,
fi;
Dowork := function(pathname)
# pathname does not end in a / and is known to be a proper directory
- local c,f,fullname,what;
+ local c,f,fullname;
c := DirectoryContents(pathname);
for f in c do
if f <> "." and f <> ".." then
fullname := Concatenation(pathname,"/",f);
- what := IsDir(fullname);
- if what = 'D' then
+ if IS_DIR(fullname) then
Dowork(fullname);
else
RemoveFile(fullname);
diff --git a/src/streams.c b/src/streams.c
index 9517a8c173..7bb853c874 100644
--- a/src/streams.c
+++ b/src/streams.c
@@ -1037,17 +1037,48 @@ static Obj FuncRemoveDir(Obj self, Obj filename)
/****************************************************************************
**
-*F FuncIsDir( , ) . . . . . check whether something is a dir
+*F FuncIS_DIR( , ) . . . . . check whether something is a dir
*/
-static Obj FuncIsDir(Obj self, Obj filename)
+static Obj FuncIS_DIR(Obj self, Obj path)
{
- RequireStringRep(SELF_NAME, filename);
+ RequireStringRep(SELF_NAME, path);
// call the system dependent function
- return SyIsDir( CONST_CSTR_STRING(filename) );
+ return SyFileType(CONST_CSTR_STRING(path)) == 'D' ? True : False;
+}
+
+/****************************************************************************
+**
+*F FuncGAP_getcwd( ) . . . . . . . . . get working directory pathname
+*/
+static Obj FuncGAP_getcwd(Obj self)
+{
+ char * res;
+ char buf[GAP_PATH_MAX];
+
+ res = getcwd(buf, sizeof(buf));
+ if (res == NULL) {
+ SySetErrorNo();
+ return Fail;
+ }
+ return MakeImmString(buf);
}
+/****************************************************************************
+**
+*F FuncGAP_chdir( , ) . . . . change current working directory
+*/
+static Obj FuncGAP_chdir(Obj self, Obj path)
+{
+ RequireStringRep(SELF_NAME, path);
+ int res = chdir(CONST_CSTR_STRING(path));
+ if (res < 0) {
+ SySetErrorNo();
+ return Fail;
+ }
+ return True;
+}
/****************************************************************************
@@ -1682,7 +1713,9 @@ static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_1ARGS(RemoveFile, filename),
GVAR_FUNC_1ARGS(CreateDir, filename),
GVAR_FUNC_1ARGS(RemoveDir, filename),
- GVAR_FUNC_1ARGS(IsDir, filename),
+ GVAR_FUNC_1ARGS(IS_DIR, path),
+ GVAR_FUNC_0ARGS(GAP_getcwd),
+ GVAR_FUNC_1ARGS(GAP_chdir, path),
GVAR_FUNC_0ARGS(LastSystemError),
GVAR_FUNC_1ARGS(IsExistingFile, filename),
GVAR_FUNC_1ARGS(IsReadableFile, filename),
diff --git a/src/sysfiles.c b/src/sysfiles.c
index afc0936698..b6eaa7eeb8 100644
--- a/src/sysfiles.c
+++ b/src/sysfiles.c
@@ -2949,38 +2949,51 @@ Int SyRmdir ( const Char * name )
/****************************************************************************
**
-*F SyIsDir( ) . . . . . . . . . . . . . test if something is a dir
-**
-** Returns 'F' for a regular file, 'L' for a symbolic link and 'D'
-** for a real directory, 'C' for a character device, 'B' for a block
-** device 'P' for a FIFO (named pipe) and 'S' for a socket.
+*F SyFileType( )
+**
+** Return a character describing the filesystem object with the given path:
+** - 'F' for a regular file
+** - 'L' for a symbolic link
+** - 'D' for a directory
+** - 'C' for a character device
+** - 'B' for a block device
+** - 'P' for a FIFO (named pipe)
+** - 'S' for a socket
+** - `\0` if there was en error (e.g. invalid path, unknown type, etc.)
*/
-Obj SyIsDir ( const Char * name )
+char SyFileType(const Char * path)
{
- Int res;
- struct stat ourlstatbuf;
+ int res;
+ struct stat ourlstatbuf;
- res = lstat(name,&ourlstatbuf);
- if (res < 0) {
- SySetErrorNo();
- return Fail;
- }
- if (S_ISREG(ourlstatbuf.st_mode)) return ObjsChar['F'];
- else if (S_ISDIR(ourlstatbuf.st_mode)) return ObjsChar['D'];
- else if (S_ISLNK(ourlstatbuf.st_mode)) return ObjsChar['L'];
+ res = lstat(path, &ourlstatbuf);
+ if (res < 0) {
+ SySetErrorNo();
+ return 0;
+ }
+ if (S_ISREG(ourlstatbuf.st_mode))
+ return 'F';
+ if (S_ISDIR(ourlstatbuf.st_mode))
+ return 'D';
+ if (S_ISLNK(ourlstatbuf.st_mode))
+ return 'L';
#ifdef S_ISCHR
- else if (S_ISCHR(ourlstatbuf.st_mode)) return ObjsChar['C'];
+ if (S_ISCHR(ourlstatbuf.st_mode))
+ return 'C';
#endif
#ifdef S_ISBLK
- else if (S_ISBLK(ourlstatbuf.st_mode)) return ObjsChar['B'];
+ if (S_ISBLK(ourlstatbuf.st_mode))
+ return 'B';
#endif
#ifdef S_ISFIFO
- else if (S_ISFIFO(ourlstatbuf.st_mode)) return ObjsChar['P'];
+ if (S_ISFIFO(ourlstatbuf.st_mode))
+ return 'P';
#endif
#ifdef S_ISSOCK
- else if (S_ISSOCK(ourlstatbuf.st_mode)) return ObjsChar['S'];
+ if (S_ISSOCK(ourlstatbuf.st_mode))
+ return 'S';
#endif
- else return ObjsChar['?'];
+ return 0;
}
diff --git a/src/sysfiles.h b/src/sysfiles.h
index 2f7ac1b5af..50c56edcb4 100644
--- a/src/sysfiles.h
+++ b/src/sysfiles.h
@@ -411,13 +411,19 @@ Int SyRmdir(const Char * name);
/****************************************************************************
**
-*F SyIsDir( ) . . . . . . . . . . . . . test if something is a dir
-**
-** Returns 'F' for a regular file, 'L' for a symbolic link and 'D'
-** for a real directory, 'C' for a character device, 'B' for a block
-** device 'P' for a FIFO (named pipe) and 'S' for a socket.
-*/
-Obj SyIsDir(const Char * name);
+*F SyFileType( )
+**
+** Return a character describing the filesystem object with the given path:
+** - 'F' for a regular file
+** - 'L' for a symbolic link
+** - 'D' for a directory
+** - 'C' for a character device
+** - 'B' for a block device
+** - 'P' for a FIFO (named pipe)
+** - 'S' for a socket
+** - `\0` if there was en error (e.g. invalid path, unknown type, etc.)
+*/
+char SyFileType(const Char * path);
/****************************************************************************
diff --git a/tst/testinstall/kernel/streams.tst b/tst/testinstall/kernel/streams.tst
index 1f550dd6c0..e78c07cf52 100644
--- a/tst/testinstall/kernel/streams.tst
+++ b/tst/testinstall/kernel/streams.tst
@@ -169,32 +169,32 @@ gap> CreateDir(fail);
Error, CreateDir: must be a string (not the value 'fail')
gap> RemoveDir(fail);
Error, RemoveDir: must be a string (not the value 'fail')
-gap> IsDir(fail);
-Error, IsDir: must be a string (not the value 'fail')
+gap> IS_DIR(fail);
+Error, IS_DIR: must be a string (not the value 'fail')
#
gap> tmpdir := MakeImmutable(TmpDirectory());;
gap> subdir := MakeImmutable(Concatenation(tmpdir, "/subdir"));;
gap> CreateDir(subdir);
true
-gap> IsDir(subdir);
-'D'
+gap> IS_DIR(subdir);
+true
gap> RemoveDir(subdir);
true
-gap> IsDir(subdir);
-fail
+gap> IS_DIR(subdir);
+false
gap> CreateDir(subdir);
true
gap> FileString(Concatenation(subdir, "/file"), "data");
4
-gap> IsDir(subdir);
-'D'
+gap> IS_DIR(subdir);
+true
gap> RemoveDirectoryRecursively(tmpdir);
true
-gap> IsDir(subdir);
-fail
-gap> IsDir(tmpdir);
-fail
+gap> IS_DIR(subdir);
+false
+gap> IS_DIR(tmpdir);
+false
#
gap> IsExistingFile(fail);