Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions lib/package.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1862,19 +1862,19 @@
#F ExtendRootDirectories( <paths> )
##
InstallGlobalFunction( ExtendRootDirectories, function( rootpaths )
local i;

rootpaths:= Filtered( rootpaths, path -> not path in GAPInfo.RootPaths );
if not IsEmpty( rootpaths ) then
# 'DirectoriesLibrary' concatenates root paths with directory names.
for i in [ 1 .. Length( rootpaths ) ] do
if not EndsWith( rootpaths[i], "/" ) then
rootpaths[i]:= Concatenation( rootpaths[i], "/" );
fi;
od;
# Append the new root paths.
GAPInfo.RootPaths:= Immutable( Concatenation( GAPInfo.RootPaths,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've replaced this now with a loop that uses Add to add each path separately. Various reasons

  • the "skip paths already in the list" is more powerful if we do it after ensuring the trailing slash is there
  • for HPC-GAP compatibility we may have to switch GAPInfo.RootPaths from a plist to an atomic list, where Add is supported but not Append

Anyway this is of course also a natural place to turn relative paths in absolute ones, call realpath, etc. -- but that goes beyond the scope of this PR

rootpaths ) );
local path, changed;

changed:= false;

Check warning on line 1867 in lib/package.gi

View check run for this annotation

Codecov / codecov/patch

lib/package.gi#L1867

Added line #L1867 was not covered by tests
for path in rootpaths do
if not EndsWith( path, "/" ) then
path:= Concatenation( path, "/" );
fi;
if not path in GAPInfo.RootPaths then
Add( GAPInfo.RootPaths, path );
changed:= true;
fi;
od;

Check warning on line 1876 in lib/package.gi

View check run for this annotation

Codecov / codecov/patch

lib/package.gi#L1869-L1876

Added lines #L1869 - L1876 were not covered by tests
if changed then
# Clear the cache.
GAPInfo.DirectoriesLibrary:= AtomicRecord( rec() );
# Reread the package information.
Expand Down
2 changes: 2 additions & 0 deletions src/gap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,8 @@ static Int InitKernel (
InitGlobalBag( &WindowCmdString, "src/gap.c:WindowCmdString" );
InitGlobalBag( &KernelArgs, "src/gap.c:KernelArgs" );

InitGlobalBag( &SyGapRootPaths, "src/gap.c:SyGapRootPaths" ); // FIXME

// init filters and functions
InitHdlrFuncsFromTable( GVarFuncs );

Expand Down
10 changes: 4 additions & 6 deletions src/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,8 @@ Obj READ_AS_FUNC(TypInputFile * input)
*/
Int READ_GAP_ROOT ( const Char * filename )
{
char path[GAP_PATH_MAX];

// try to find the GAP file
SyFindGapRootFile(filename, path, sizeof(path));
Obj path = SyFindGapRootFile(filename);

// try to find compiled version of the GAP file
if (SyUseModule) {
Expand All @@ -378,7 +376,7 @@ Int READ_GAP_ROOT ( const Char * filename )
if (info) {
// found a matching statically linked module; if there is also
// a GAP file, compare their CRC
if (*path && info->crc != SyGAPCRC(path)) {
if (path && info->crc != SyGAPCRC(CSTR_STRING(path))) {
Pr("#W Static module %s has CRC mismatch, ignoring\n",
(Int)filename, 0);
}
Expand All @@ -395,7 +393,7 @@ Int READ_GAP_ROOT ( const Char * filename )
}

// not found?
if (*path == 0)
if (path == 0)
return 0;

#ifdef GAP_ENABLE_SAVELOAD
Expand All @@ -415,7 +413,7 @@ Int READ_GAP_ROOT ( const Char * filename )
}

TypInputFile input;
if (!OpenInput(&input, path))
if (!OpenInput(&input, CSTR_STRING(path)))
return 0;

GAP_TRY
Expand Down
193 changes: 76 additions & 117 deletions src/sysroots.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "sysroots.h"

#include "gaputils.h"
#include "listfunc.h"
#include "plist.h"
#include "stringobj.h"
#include "sysfiles.h"
Expand Down Expand Up @@ -47,34 +48,28 @@
** name of a library file 'strcat( SyGapRootPaths[i], "lib/init.g" );' must
** be a valid filename.
*/
enum { MAX_GAP_DIRS = 16 };
static Char SyGapRootPaths[MAX_GAP_DIRS][GAP_PATH_MAX];
Obj SyGapRootPaths;


/****************************************************************************
**
*F SyFindGapRootFile( <filename>, <buf>, <size> ) . find file in system area
*F SyFindGapRootFile( <filename> ) . . . . . . . . find file in system area
**
** <buf> must point to a buffer of at least <size> characters. This function
** then searches for a readable file with the name <filename> in the system
** area. If sich a file is found then its absolute path is copied into
** <buf>, and <buf> is returned. If no file is found or if <buf> is not big
** enough, then <buf> is set to an empty string and NULL is returned.
** This function searches for a readable file with the name <filename> in
** the system area. If such a file is found then its absolute path is
** returned as a string object. If no file is found then NULL is returned.
*/
Char * SyFindGapRootFile(const Char * filename, Char * buf, size_t size)
Obj SyFindGapRootFile(const Char * filename)
Copy link
Member Author

@fingolfin fingolfin Feb 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately changing SyFindGapRootFile to return a string object currently clashes with workspace restoring as it is called during that when restoring loaded compiled modules (including kernel extensions).

{
for (int k = 0; k < ARRAY_SIZE(SyGapRootPaths); k++) {
if (SyGapRootPaths[k][0]) {
if (gap_strlcpy(buf, SyGapRootPaths[k], size) >= size)
continue;
if (gap_strlcat(buf, filename, size) >= size)
continue;
if (SyIsReadableFile(buf) == 0) {
return buf;
}
int len = strlen(filename);
int npaths = LEN_PLIST(SyGapRootPaths);
for (int k = 1; k <= npaths; k++) {
Obj path = CopyToStringRep(ELM_PLIST(SyGapRootPaths, k));
AppendCStr(path, filename, len);
if (SyIsReadableFile(CSTR_STRING(path)) == 0) {
return path;
}
}
buf[0] = '\0';
return 0;
}

Expand All @@ -99,10 +94,12 @@
*/
void SySetGapRootPath(const Char * string)
{
const Char * p;
Char * q;
Int i;
Int n;
Int pos = 1;

if (SyGapRootPaths == 0) {
SyGapRootPaths = NEW_PLIST(T_PLIST_EMPTY, 0); // FIXME
}


// set string to a default value if unset
if (string == 0 || *string == 0) {
Expand All @@ -111,110 +108,79 @@

// check if we append, prepend or overwrite.
if (string[0] == ';') {
// Count the number of root directories already present.
n = 0;
while (SyGapRootPaths[n][0] != '\0')
n++;
// append
pos = LEN_PLIST(SyGapRootPaths) + 1;

Check warning on line 112 in src/sysroots.c

View check run for this annotation

Codecov / codecov/patch

src/sysroots.c#L112

Added line #L112 was not covered by tests

// Skip leading semicolon.
string++;
}
else if (string[strlen(string) - 1] == ';') {
// Count the number of directories in 'string'.
n = 0;
p = string;
while (*p)
if (*p++ == ';')
n++;

// Find last root path.
for (i = 0; i < MAX_GAP_DIRS; i++)
if (SyGapRootPaths[i][0] == '\0')
break;
i--;

#ifdef HPCGAP
n *= 2; // for each root <ROOT> we also add <ROOT/hpcgap> as a root
#endif

// Move existing root paths to the back
if (i + n >= MAX_GAP_DIRS)
return;
while (i >= 0) {
memcpy(SyGapRootPaths[i + n], SyGapRootPaths[i],
sizeof(SyGapRootPaths[i + n]));
i--;
}

n = 0;
// prepend
}
else {
// Make sure to wipe out all possibly existing root paths
for (i = 0; i < MAX_GAP_DIRS; i++)
SyGapRootPaths[i][0] = '\0';
n = 0;
SET_LEN_PLIST(SyGapRootPaths, 0);
RetypeBagSM(SyGapRootPaths, T_PLIST_EMPTY);
// TODO: also adjust filters...
}

// unpack the argument
p = string;
const Char * p = string;
while (*p) {
if (n >= MAX_GAP_DIRS)
return;

q = SyGapRootPaths[n];
while (*p && *p != ';') {
*q = *p++;

#ifdef SYS_IS_CYGWIN32
// change backslash to slash for Windows
if (*q == '\\')
*q = '/';
#endif
Obj path;

// locate next semicolon or string end
const Char * q = p;
while (*q && *q != ';') {
q++;
}
if (q == SyGapRootPaths[n]) {
strxcpy(SyGapRootPaths[n], "./", sizeof(SyGapRootPaths[n]));
}
else if (q[-1] != '/') {
*q++ = '/';
*q = '\0';
}
else {
*q = '\0';
}
if (*p) {
p++;

if (q == p) {
// empty string treated as ./
path = MakeString("./");

Check warning on line 139 in src/sysroots.c

View check run for this annotation

Codecov / codecov/patch

src/sysroots.c#L139

Added line #L139 was not covered by tests
// TODO: insert output of getcwd??
} else {
if (*p == '~') {
const char * userhome = getenv("HOME");

Check warning on line 143 in src/sysroots.c

View check run for this annotation

Codecov / codecov/patch

src/sysroots.c#L143

Added line #L143 was not covered by tests
if (!userhome)
userhome = "";
path = MakeString(userhome);
p++;
AppendCStr(path, p, q - p);

Check warning on line 148 in src/sysroots.c

View check run for this annotation

Codecov / codecov/patch

src/sysroots.c#L145-L148

Added lines #L145 - L148 were not covered by tests
}
else {
path = MakeStringWithLen(p, q - p);
}

Char * r = CSTR_STRING(path);
#ifdef SYS_IS_CYGWIN32
while (*r) {
// change backslash to slash for Windows
if (*r == '\\')
*r = '/';

Check warning on line 159 in src/sysroots.c

View check run for this annotation

Codecov / codecov/patch

src/sysroots.c#L159

Added line #L159 was not covered by tests
r++;
}
#endif

// ensure path ends with a slash
r = CSTR_STRING(path) + GET_LEN_STRING(path) - 1;
if (*r != '/') {
AppendCStr(path, "/", 1);
}
}
n++;

p = *q ? q + 1 : q;

AddPlist3(SyGapRootPaths, path, pos);
pos++;

#ifdef HPCGAP
// for each root <ROOT> to be added, we first add <ROOT/hpcgap> as a root
if (n < MAX_GAP_DIRS) {
gap_strlcpy(SyGapRootPaths[n], SyGapRootPaths[n - 1],
sizeof(SyGapRootPaths[n]));
}
strxcat(SyGapRootPaths[n - 1], "hpcgap/",
sizeof(SyGapRootPaths[n - 1]));
n++;
#endif
}
path = CopyToStringRep(path);
AppendCStr(path, "hpcgap/", 7);

// replace leading tilde ~ by HOME environment variable
// TODO; instead of iterating over all entries each time, just
// do this for the new entries
char * userhome = getenv("HOME");
if (!userhome || !*userhome)
return;
const UInt userhomelen = strlen(userhome);
for (i = 0; i < MAX_GAP_DIRS && SyGapRootPaths[i][0]; i++) {
const UInt pathlen = strlen(SyGapRootPaths[i]);
if (SyGapRootPaths[i][0] == '~' &&
userhomelen + pathlen < sizeof(SyGapRootPaths[i])) {
SyMemmove(SyGapRootPaths[i] + userhomelen,
// don't copy the ~ but the trailing '\0'
SyGapRootPaths[i] + 1, pathlen);
memcpy(SyGapRootPaths[i], userhome, userhomelen);
}
AddPlist3(SyGapRootPaths, path, pos);
pos++;
#endif
}
}

Expand All @@ -225,12 +191,5 @@
*/
Obj SyGetGapRootPaths(void)
{
Obj tmp = NEW_PLIST_IMM(T_PLIST, MAX_GAP_DIRS);
for (int i = 0; i < MAX_GAP_DIRS; i++) {
if (SyGapRootPaths[i][0]) {
PushPlist(tmp, MakeImmString(SyGapRootPaths[i]));
}
}
MakeImmutableNoRecurse(tmp);
return tmp;
return SyGapRootPaths;
}
31 changes: 23 additions & 8 deletions src/sysroots.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,24 @@
*/
extern char SyDefaultRootPath[GAP_PATH_MAX];

#include <stddef.h>

/****************************************************************************
**
*V SyGapRootPaths . . . . . . . . . . . . . . . . . . . array of root paths
**
** 'SyGapRootPaths' contains the names of the directories where the GAP
** files are located.
**
** It is modified by the command line option -l.
**
** It is copied into the GAP variable 'GAPInfo.RootPaths' and used by
** 'SyFindGapRootFile'.
**
** Each entry must end with the pathname separator, e.g. if 'init.g' is the
** name of a library file 'strcat( SyGapRootPaths[i], "lib/init.g" );' must
** be a valid filename.
*/
extern Obj SyGapRootPaths;


/****************************************************************************
Expand All @@ -45,15 +62,13 @@ void SySetGapRootPath(const Char * string);

/****************************************************************************
**
*F SyFindGapRootFile( <filename>, <buf>, <size> ) . find file in system area
*F SyFindGapRootFile( <filename> ) . . . . . . . . find file in system area
**
** <buf> must point to a buffer of at least <size> characters. This function
** then searches for a readable file with the name <filename> in the system
** area. If sich a file is found then its absolute path is copied into
** <buf>, and <buf> is returned. If no file is found or if <buf> is not big
** enough, then <buf> is set to an empty string and NULL is returned.
** This function searches for a readable file with the name <filename> in
** the system area. If such a file is found then its absolute path is
** returned as a string object. If no file is found then NULL is returned.
*/
Char * SyFindGapRootFile(const Char * filename, Char * buf, size_t size);
Obj SyFindGapRootFile(const Char * filename);


/****************************************************************************
Expand Down
Loading