Skip to content

Commit

Permalink
Add function to get and change current directory (#5585)
Browse files Browse the repository at this point in the history
* kernel: replace undocumented IsDir by IS_DIR

... which just returns a boolean. If we want a function that allows
detecting types of file system objects more generally, we can add
one in the future with a more appropriate name.

* kernel: add functions to get/change working dir

* Add ChangeDirectoryCurrent
  • Loading branch information
fingolfin authored Jan 14, 2024
1 parent 9d3fdea commit 5533cdb
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 51 deletions.
1 change: 1 addition & 0 deletions doc/ref/files.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
29 changes: 27 additions & 2 deletions lib/files.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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">
## <ManSection>
## <Func Name="ChangeDirectoryCurrent" Arg='path'/>
##
## <Description>
## Changes the current directory. Returns <K>true</K> on success and
## <K>fail</K> on failure.
## </Description>
## </ManSection>
## <#/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( <filename> ) . . . . . . . . . . . . . . . . create crc value
Expand Down
7 changes: 3 additions & 4 deletions lib/files.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
43 changes: 38 additions & 5 deletions src/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,17 +1037,48 @@ static Obj FuncRemoveDir(Obj self, Obj filename)

/****************************************************************************
**
*F FuncIsDir( <self>, <name> ) . . . . . check whether something is a dir
*F FuncIS_DIR( <self>, <path> ) . . . . . 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( <self> ) . . . . . . . . . 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( <self>, <path> ) . . . . 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;
}


/****************************************************************************
Expand Down Expand Up @@ -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),
Expand Down
55 changes: 34 additions & 21 deletions src/sysfiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -2949,38 +2949,51 @@ Int SyRmdir ( const Char * name )

/****************************************************************************
**
*F SyIsDir( <name> ) . . . . . . . . . . . . . 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( <path> )
**
** 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;
}


Expand Down
20 changes: 13 additions & 7 deletions src/sysfiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,13 +411,19 @@ Int SyRmdir(const Char * name);

/****************************************************************************
**
*F SyIsDir( <name> ) . . . . . . . . . . . . . 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( <path> )
**
** 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);


/****************************************************************************
Expand Down
24 changes: 12 additions & 12 deletions tst/testinstall/kernel/streams.tst
Original file line number Diff line number Diff line change
Expand Up @@ -169,32 +169,32 @@ gap> CreateDir(fail);
Error, CreateDir: <filename> must be a string (not the value 'fail')
gap> RemoveDir(fail);
Error, RemoveDir: <filename> must be a string (not the value 'fail')
gap> IsDir(fail);
Error, IsDir: <filename> must be a string (not the value 'fail')
gap> IS_DIR(fail);
Error, IS_DIR: <path> 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);
Expand Down

0 comments on commit 5533cdb

Please sign in to comment.