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);