1 /****************************************************************************
2 **
3 **  This file is part of GAP, a system for computational discrete algebra.
4 **
5 **  Copyright of GAP belongs to its developers, whose names are too numerous
6 **  to list here. Please refer to the COPYRIGHT file for details.
7 **
8 **  SPDX-License-Identifier: GPL-2.0-or-later
9 **
10 **  This file implements APIs for GAP modules, including builtin modules,
11 **  or static and dynamic modules used by packages and end users to provide
12 **  kernel extensions.
13 */
14 
15 #include "modules.h"
16 
17 #include "ariths.h"
18 #include "bool.h"
19 #include "code.h"
20 #include "compstat.h"
21 #include "error.h"
22 #include "funcs.h"
23 #include "gap.h"
24 #include "gapstate.h"
25 #include "gvars.h"
26 #include "integer.h"
27 #include "intobj.h"
28 #include "io.h"
29 #include "lists.h"
30 #include "modules_builtin.h"
31 #include "opers.h"
32 #include "plist.h"
33 #include "saveload.h"
34 #include "streams.h"
35 #include "stringobj.h"
36 #include "sysfiles.h"
37 #include "sysopt.h"
38 
39 #ifdef HAVE_DLOPEN
40 #include <dlfcn.h>
41 #endif
42 
43 
44 /****************************************************************************
45 **
46 *F  Modules . . . . . . . . . . . . . . . . . . . . . . . . . list of modules
47 */
48 #ifndef MAX_MODULES
49 #define MAX_MODULES 1000
50 #endif
51 
52 
53 #ifndef MAX_MODULE_FILENAMES
54 #define MAX_MODULE_FILENAMES (MAX_MODULES * 50)
55 #endif
56 
57 static Char   LoadedModuleFilenames[MAX_MODULE_FILENAMES];
58 static Char * NextLoadedModuleFilename = LoadedModuleFilenames;
59 
60 typedef struct {
61 
62     // pointer to the actual StructInitInfo
63     StructInitInfo * info;
64 
65     // filename relative to GAP_ROOT or absolute
66     Char * filename;
67 
68     // true if the filename is GAP_ROOT relative
69     Int isGapRootRelative;
70 
71 } StructInitInfoExt;
72 
73 
74 static StructInitInfoExt Modules[MAX_MODULES];
75 static UInt       NrModules;
76 static UInt       NrBuiltinModules;
77 
78 
79 typedef struct {
80     const Char * name;
81     Obj *        address;
82 } StructImportedGVars;
83 
84 #ifndef MAX_IMPORTED_GVARS
85 #define MAX_IMPORTED_GVARS 1024
86 #endif
87 
88 static StructImportedGVars ImportedGVars[MAX_IMPORTED_GVARS];
89 static Int                 NrImportedGVars;
90 
91 static StructImportedGVars ImportedFuncs[MAX_IMPORTED_GVARS];
92 static Int                 NrImportedFuncs;
93 
94 static Int StateNextFreeOffset = 0; // Start of next free memory area (as offset into GAPState.StateSlots)
95 
RegisterModuleState(StructInitInfo * info)96 static void RegisterModuleState(StructInitInfo * info)
97 {
98     UInt size = info->moduleStateSize;
99     if (size == 0)
100         return;
101 
102     // using moduleStateSize without moduleStateOffsetPtr makes no sense
103     GAP_ASSERT(info->moduleStateOffsetPtr);
104 
105     // check that we have enough free space
106     assert((STATE_SLOTS_SIZE - StateNextFreeOffset) >= size);
107 
108     // record start offset of this module's state
109     *info->moduleStateOffsetPtr = StateNextFreeOffset;
110 
111     // ... and 'allocate' the requested amount of storage
112     StateNextFreeOffset += size;
113     StateNextFreeOffset = (StateNextFreeOffset + sizeof(Obj)-1) & ~(sizeof(Obj)-1);
114 }
115 
116 
117 /*************************************************************************
118 **
119 *F * * * * * * * * * functions for dynamical/static modules * * * * * * * * *
120 */
121 
122 
123 /****************************************************************************
124 **
125 *F  FuncGAP_CRC( <self>, <name> ) . . . . . . . create a crc value for a file
126 */
FuncGAP_CRC(Obj self,Obj filename)127 static Obj FuncGAP_CRC(Obj self, Obj filename)
128 {
129     /* check the argument                                                  */
130     RequireStringRep("GAP_CRC", filename);
131 
132     /* compute the crc value                                               */
133     return ObjInt_Int(SyGAPCRC(CONST_CSTR_STRING(filename)));
134 }
135 
136 
137 /****************************************************************************
138 **
139 *F  ActivateModule( <info> )
140 */
ActivateModule(StructInitInfo * info)141 void ActivateModule(StructInitInfo * info)
142 {
143     Int res = 0;
144 
145     RegisterModuleState(info);
146 
147     if (info->initKernel) {
148         res = info->initKernel(info);
149     }
150 
151     if (!SyRestoring) {
152         UpdateCopyFopyInfo();
153 
154         if (info->initLibrary) {
155             // Start a new executor to run the outer function of the module in
156             // global context
157             ExecBegin(STATE(BottomLVars));
158             res = res || info->initLibrary(info);
159             ExecEnd(res);
160         }
161     }
162 
163     if (res) {
164         Pr("#W  init functions returned non-zero exit code\n", 0L, 0L);
165     }
166 
167     if (info->initModuleState)
168         res = res || (info->initModuleState)();
169 }
170 
171 
172 /****************************************************************************
173 **
174 *F  SyLoadModule( <name>, <func> )  . . . . . . . . .  load a compiled module
175 **
176 **  This function attempts to load a compiled module <name>.
177 **  If successful, it returns 0, and sets <func> to a pointer to the init
178 **  function of the module. In case of an error, <func> is set to 0, and the
179 **  return value indicates which error occurred.
180 */
181 #ifdef HAVE_DLOPEN
SyLoadModule(const Char * name,InitInfoFunc * func)182 static Int SyLoadModule(const Char * name, InitInfoFunc * func)
183 {
184     void *          init;
185     void *          handle;
186 
187     *func = 0;
188 
189     handle = dlopen( name, RTLD_LAZY | RTLD_GLOBAL);
190     if ( handle == 0 ) {
191       Pr("#W dlopen() error: %s\n", (long) dlerror(), 0L);
192       return 1;
193     }
194 
195     init = dlsym( handle, "Init__Dynamic" );
196     if ( init == 0 )
197       return 3;
198 
199     *func = (InitInfoFunc) init;
200     return 0;
201 }
202 #endif
203 
204 
205 
206 /****************************************************************************
207 **
208 *F  FuncLOAD_DYN( <self>, <name>, <crc> ) . . .  try to load a dynamic module
209 */
FuncLOAD_DYN(Obj self,Obj filename,Obj crc)210 static Obj FuncLOAD_DYN(Obj self, Obj filename, Obj crc)
211 {
212     StructInitInfo * info;
213     Obj              crc1;
214     Int              res;
215     InitInfoFunc     init;
216 
217     /* check the argument                                                  */
218     RequireStringRep("LOAD_DYN", filename);
219     if (!IS_INTOBJ(crc) && crc != False) {
220         ErrorMayQuit(
221             "LOAD_DYN: <crc> must be a small integer or 'false' (not a %s)",
222             (Int)TNAM_OBJ(crc), 0);
223     }
224 
225     /* try to read the module                                              */
226 #ifdef HAVE_DLOPEN
227     res = SyLoadModule(CONST_CSTR_STRING(filename), &init);
228     if (res == 1)
229         ErrorQuit("module '%g' not found", (Int)filename, 0L);
230     else if (res == 3)
231         ErrorQuit("symbol 'Init_Dynamic' not found", 0L, 0L);
232 #else
233     /* no dynamic library support                                          */
234     if (SyDebugLoading) {
235         Pr("#I  LOAD_DYN: no support for dynamical loading\n", 0L, 0L);
236     }
237     return False;
238 #endif
239 
240     /* get the description structure                                       */
241     info = (*init)();
242     if (info == 0)
243         ErrorQuit("call to init function failed", 0L, 0L);
244 
245     // info->type should not be larger than kernel version
246     if (info->type / 10 > GAP_KERNEL_API_VERSION)
247         ErrorMayQuit("LOAD_DYN: kernel module built for newer "
248                      "version of GAP",
249                      0L, 0L);
250 
251     // info->type should not have an older major version
252     if (info->type / 10000 < GAP_KERNEL_MAJOR_VERSION)
253         ErrorMayQuit("LOAD_DYN: kernel module built for older "
254                      "version of GAP",
255                      0L, 0L);
256 
257     // info->type % 10 should be 0, 1 or 2, for the 3 types of module
258     if (info->type % 10 > 2)
259         ErrorMayQuit("LOAD_DYN: Invalid kernel module", 0L, 0L);
260 
261     /* check the crc value                                                 */
262     if (crc != False) {
263         crc1 = ObjInt_Int(info->crc);
264         if (!EQ(crc, crc1)) {
265             if (SyDebugLoading) {
266                 Pr("#I  LOAD_DYN: crc values do not match, gap ", 0L, 0L);
267                 PrintInt(crc);
268                 Pr(", dyn ", 0L, 0L);
269                 PrintInt(crc1);
270                 Pr("\n", 0L, 0L);
271             }
272             return False;
273         }
274     }
275 
276     ActivateModule(info);
277     RecordLoadedModule(info, 0, CONST_CSTR_STRING(filename));
278 
279     return True;
280 }
281 
282 
283 /****************************************************************************
284 **
285 *F  FuncLOAD_STAT( <self>, <name>, <crc> )  . . . . try to load static module
286 */
FuncLOAD_STAT(Obj self,Obj filename,Obj crc)287 static Obj FuncLOAD_STAT(Obj self, Obj filename, Obj crc)
288 {
289     StructInitInfo * info = 0;
290     Obj              crc1;
291     Int              k;
292 
293     /* check the argument                                                  */
294     RequireStringRep("LOAD_STAT", filename);
295     if (!IS_INTOBJ(crc) && crc != False) {
296         ErrorMayQuit(
297             "LOAD_STAT: <crc> must be a small integer or 'false' (not a %s)",
298             (Int)TNAM_OBJ(crc), 0);
299     }
300 
301     /* try to find the module                                              */
302     for (k = 0; CompInitFuncs[k]; k++) {
303         info = (*(CompInitFuncs[k]))();
304         if (info && !strcmp(CONST_CSTR_STRING(filename), info->name)) {
305             break;
306         }
307     }
308     if (CompInitFuncs[k] == 0) {
309         if (SyDebugLoading) {
310             Pr("#I  LOAD_STAT: no module named '%g' found\n", (Int)filename,
311                0L);
312         }
313         return False;
314     }
315 
316     /* check the crc value                                                 */
317     if (crc != False) {
318         crc1 = ObjInt_Int(info->crc);
319         if (!EQ(crc, crc1)) {
320             if (SyDebugLoading) {
321                 Pr("#I  LOAD_STAT: crc values do not match, gap ", 0L, 0L);
322                 PrintInt(crc);
323                 Pr(", stat ", 0L, 0L);
324                 PrintInt(crc1);
325                 Pr("\n", 0L, 0L);
326             }
327             return False;
328         }
329     }
330 
331     ActivateModule(info);
332     RecordLoadedModule(info, 0, CONST_CSTR_STRING(filename));
333 
334     return True;
335 }
336 
337 
338 /****************************************************************************
339 **
340 *F  FuncSHOW_STAT() . . . . . . . . . . . . . . . . . . . show static modules
341 */
FuncSHOW_STAT(Obj self)342 static Obj FuncSHOW_STAT(Obj self)
343 {
344     Obj              modules;
345     Obj              name;
346     StructInitInfo * info;
347     Int              k;
348     Int              im;
349 
350     /* count the number of install modules                                 */
351     for (k = 0, im = 0; CompInitFuncs[k]; k++) {
352         info = (*(CompInitFuncs[k]))();
353         if (info == 0) {
354             continue;
355         }
356         im++;
357     }
358 
359     /* make a list of modules with crc values                              */
360     modules = NEW_PLIST(T_PLIST, 2 * im);
361 
362     for (k = 0; CompInitFuncs[k]; k++) {
363         info = (*(CompInitFuncs[k]))();
364         if (info == 0) {
365             continue;
366         }
367         name = MakeImmString(info->name);
368 
369         PushPlist(modules, name);
370 
371         /* compute the crc value                                           */
372         PushPlist(modules, ObjInt_Int(info->crc));
373     }
374 
375     return modules;
376 }
377 
378 
379 /****************************************************************************
380 **
381 *F  FuncLoadedModules( <self> ) . . . . . . . . . . . list all loaded modules
382 */
FuncLoadedModules(Obj self)383 static Obj FuncLoadedModules(Obj self)
384 {
385     Int              i;
386     StructInitInfo * m;
387     Obj              str;
388     Obj              list;
389 
390     /* create a list                                                       */
391     list = NEW_PLIST(T_PLIST, NrModules * 3);
392     SET_LEN_PLIST(list, NrModules * 3);
393     for (i = 0; i < NrModules; i++) {
394         m = Modules[i].info;
395         if (IS_MODULE_BUILTIN(m->type)) {
396             SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'b']);
397             CHANGED_BAG(list);
398             str = MakeImmString(m->name);
399             SET_ELM_PLIST(list, 3 * i + 2, str);
400             SET_ELM_PLIST(list, 3 * i + 3, INTOBJ_INT(m->version));
401         }
402         else if (IS_MODULE_DYNAMIC(m->type)) {
403             SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'d']);
404             CHANGED_BAG(list);
405             str = MakeImmString(m->name);
406             SET_ELM_PLIST(list, 3 * i + 2, str);
407             CHANGED_BAG(list);
408             str = MakeImmString(Modules[i].filename);
409             SET_ELM_PLIST(list, 3 * i + 3, str);
410         }
411         else if (IS_MODULE_STATIC(m->type)) {
412             SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'s']);
413             CHANGED_BAG(list);
414             str = MakeImmString(m->name);
415             SET_ELM_PLIST(list, 3 * i + 2, str);
416             CHANGED_BAG(list);
417             str = MakeImmString(Modules[i].filename);
418             SET_ELM_PLIST(list, 3 * i + 3, str);
419         }
420     }
421     return list;
422 }
423 
424 
425 /****************************************************************************
426 **
427 *F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
428 */
429 
430 
431 /****************************************************************************
432 **
433 *F  InitBagNamesFromTable( <table> )  . . . . . . . . .  initialise bag names
434 */
InitBagNamesFromTable(const StructBagNames * tab)435 void InitBagNamesFromTable(const StructBagNames * tab)
436 {
437     Int i;
438 
439     for (i = 0; tab[i].tnum != -1; i++) {
440         SET_TNAM_TNUM(tab[i].tnum, tab[i].name);
441     }
442 }
443 
444 
445 /****************************************************************************
446 **
447 *F  InitClearFiltsTNumsFromTable( <tab> ) . . .  initialise clear filts tnums
448 */
InitClearFiltsTNumsFromTable(const Int * tab)449 void InitClearFiltsTNumsFromTable(const Int * tab)
450 {
451     Int i;
452 
453     for (i = 0; tab[i] != -1; i += 2) {
454         ClearFiltsTNums[tab[i]] = tab[i + 1];
455         ClearFiltsTNums[tab[i] | IMMUTABLE] = tab[i + 1] | IMMUTABLE;
456     }
457 }
458 
459 
460 /****************************************************************************
461 **
462 *F  InitHasFiltListTNumsFromTable( <tab> )  . . initialise tester filts tnums
463 */
InitHasFiltListTNumsFromTable(const Int * tab)464 void InitHasFiltListTNumsFromTable(const Int * tab)
465 {
466     Int i;
467 
468     for (i = 0; tab[i] != -1; i += 3) {
469         HasFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
470         HasFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] = tab[i + 2];
471     }
472 }
473 
474 
475 /****************************************************************************
476 **
477 *F  InitSetFiltListTNumsFromTable( <tab> )  . . initialise setter filts tnums
478 */
InitSetFiltListTNumsFromTable(const Int * tab)479 void InitSetFiltListTNumsFromTable(const Int * tab)
480 {
481     Int i;
482 
483     for (i = 0; tab[i] != -1; i += 3) {
484         SetFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
485         SetFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] =
486             tab[i + 2] | IMMUTABLE;
487     }
488 }
489 
490 
491 /****************************************************************************
492 **
493 *F  InitResetFiltListTNumsFromTable( <tab> )  initialise unsetter filts tnums
494 */
InitResetFiltListTNumsFromTable(const Int * tab)495 void InitResetFiltListTNumsFromTable(const Int * tab)
496 {
497     Int i;
498 
499     for (i = 0; tab[i] != -1; i += 3) {
500         ResetFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
501         ResetFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] =
502             tab[i + 2] | IMMUTABLE;
503     }
504 }
505 
ValidatedArgList(const char * name,int nargs,const char * argStr)506 static Obj ValidatedArgList(const char * name, int nargs, const char * argStr)
507 {
508     Obj args = ArgStringToList(argStr);
509     int len = LEN_PLIST(args);
510     if (nargs >= 0 && len != nargs)
511         fprintf(stderr,
512                 "#W %s takes %d arguments, but argument string is '%s'"
513                 " which implies %d arguments\n",
514                 name, nargs, argStr, len);
515     return args;
516 }
517 
518 /****************************************************************************
519 **
520 *F  InitGVarFiltsFromTable( <tab> ) . . . . . . . . . . . . . . . new filters
521 */
InitGVarFiltsFromTable(const StructGVarFilt * tab)522 void InitGVarFiltsFromTable(const StructGVarFilt * tab)
523 {
524     Int i;
525 
526     for (i = 0; tab[i].name != 0; i++) {
527         UInt gvar = GVarName(tab[i].name);
528         Obj  name = NameGVar(gvar);
529         Obj  args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
530         AssReadOnlyGVar(gvar, NewFilter(name, args, tab[i].handler));
531     }
532 }
533 
534 
535 /****************************************************************************
536 **
537 *F  InitGVarAttrsFromTable( <tab> ) . . . . . . . . . . . . .  new attributes
538 */
InitGVarAttrsFromTable(const StructGVarAttr * tab)539 void InitGVarAttrsFromTable(const StructGVarAttr * tab)
540 {
541     Int i;
542 
543     for (i = 0; tab[i].name != 0; i++) {
544         UInt gvar = GVarName(tab[i].name);
545         Obj  name = NameGVar(gvar);
546         Obj  args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
547         AssReadOnlyGVar(gvar, NewAttribute(name, args, tab[i].handler));
548     }
549 }
550 
551 /****************************************************************************
552 **
553 *F  InitGVarPropsFromTable( <tab> ) . . . . . . . . . . . . .  new properties
554 */
InitGVarPropsFromTable(const StructGVarProp * tab)555 void InitGVarPropsFromTable(const StructGVarProp * tab)
556 {
557     Int i;
558 
559     for (i = 0; tab[i].name != 0; i++) {
560         UInt gvar = GVarName(tab[i].name);
561         Obj  name = NameGVar(gvar);
562         Obj  args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
563         AssReadOnlyGVar(gvar, NewProperty(name, args, tab[i].handler));
564     }
565 }
566 
567 
568 /****************************************************************************
569 **
570 *F  InitGVarOpersFromTable( <tab> ) . . . . . . . . . . . . .  new operations
571 */
InitGVarOpersFromTable(const StructGVarOper * tab)572 void InitGVarOpersFromTable(const StructGVarOper * tab)
573 {
574     Int i;
575 
576     for (i = 0; tab[i].name != 0; i++) {
577         UInt gvar = GVarName(tab[i].name);
578         Obj  name = NameGVar(gvar);
579         Obj  args = ValidatedArgList(tab[i].name, tab[i].nargs, tab[i].args);
580         AssReadOnlyGVar(
581             gvar, NewOperation(name, tab[i].nargs, args, tab[i].handler));
582     }
583 }
584 
SetupFuncInfo(Obj func,const Char * cookie)585 static void SetupFuncInfo(Obj func, const Char * cookie)
586 {
587     // The string <cookie> usually has the form "PATH/TO/FILE.c:FUNCNAME".
588     // We check if that is the case, and if so, split it into the parts before
589     // and after the colon. In addition, the file path is cut to only contain
590     // the last two '/'-separated components.
591     const Char * pos = strchr(cookie, ':');
592     if (pos) {
593         Obj location = MakeImmString(pos + 1);
594 
595         Obj  filename;
596         char buffer[512];
597         Int  len = 511 < (pos - cookie) ? 511 : pos - cookie;
598         memcpy(buffer, cookie, len);
599         buffer[len] = 0;
600 
601         Char * start = strrchr(buffer, '/');
602         if (start) {
603             while (start > buffer && *(start - 1) != '/')
604                 start--;
605         }
606         else
607             start = buffer;
608         filename = MakeImmString(start);
609 
610         Obj body_bag = NewFunctionBody();
611         SET_FILENAME_BODY(body_bag, filename);
612         SET_LOCATION_BODY(body_bag, location);
613         SET_BODY_FUNC(func, body_bag);
614         CHANGED_BAG(body_bag);
615         CHANGED_BAG(func);
616     }
617 }
618 
619 /****************************************************************************
620 **
621 *F  InitGVarFuncsFromTable( <tab> ) . . . . . . . . . . . . . . new functions
622 */
InitGVarFuncsFromTable(const StructGVarFunc * tab)623 void InitGVarFuncsFromTable(const StructGVarFunc * tab)
624 {
625     Int i;
626 
627     for (i = 0; tab[i].name != 0; i++) {
628         UInt gvar = GVarName(tab[i].name);
629         Obj  name = NameGVar(gvar);
630         Obj  args = ValidatedArgList(tab[i].name, tab[i].nargs, tab[i].args);
631         Obj  func = NewFunction(name, tab[i].nargs, args, tab[i].handler);
632         SetupFuncInfo(func, tab[i].cookie);
633         AssReadOnlyGVar(gvar, func);
634     }
635 }
636 
637 
638 /****************************************************************************
639 **
640 *F  InitHdlrFiltsFromTable( <tab> ) . . . . . . . . . . . . . . . new filters
641 */
InitHdlrFiltsFromTable(const StructGVarFilt * tab)642 void InitHdlrFiltsFromTable(const StructGVarFilt * tab)
643 {
644     Int i;
645 
646     for (i = 0; tab[i].name != 0; i++) {
647         InitHandlerFunc(tab[i].handler, tab[i].cookie);
648         InitFopyGVar(tab[i].name, tab[i].filter);
649     }
650 }
651 
652 
653 /****************************************************************************
654 **
655 *F  InitHdlrAttrsFromTable( <tab> ) . . . . . . . . . . . . .  new attributes
656 */
InitHdlrAttrsFromTable(const StructGVarAttr * tab)657 void InitHdlrAttrsFromTable(const StructGVarAttr * tab)
658 {
659     Int i;
660 
661     for (i = 0; tab[i].name != 0; i++) {
662         InitHandlerFunc(tab[i].handler, tab[i].cookie);
663         InitFopyGVar(tab[i].name, tab[i].attribute);
664     }
665 }
666 
667 
668 /****************************************************************************
669 **
670 *F  InitHdlrPropsFromTable( <tab> ) . . . . . . . . . . . . .  new properties
671 */
InitHdlrPropsFromTable(const StructGVarProp * tab)672 void InitHdlrPropsFromTable(const StructGVarProp * tab)
673 {
674     Int i;
675 
676     for (i = 0; tab[i].name != 0; i++) {
677         InitHandlerFunc(tab[i].handler, tab[i].cookie);
678         InitFopyGVar(tab[i].name, tab[i].property);
679     }
680 }
681 
682 
683 /****************************************************************************
684 **
685 *F  InitHdlrOpersFromTable( <tab> ) . . . . . . . . . . . . .  new operations
686 */
InitHdlrOpersFromTable(const StructGVarOper * tab)687 void InitHdlrOpersFromTable(const StructGVarOper * tab)
688 {
689     Int i;
690 
691     for (i = 0; tab[i].name != 0; i++) {
692         InitHandlerFunc(tab[i].handler, tab[i].cookie);
693         InitFopyGVar(tab[i].name, tab[i].operation);
694     }
695 }
696 
697 
698 /****************************************************************************
699 **
700 *F  InitHdlrFuncsFromTable( <tab> ) . . . . . . . . . . . . . . new functions
701 */
InitHdlrFuncsFromTable(const StructGVarFunc * tab)702 void InitHdlrFuncsFromTable(const StructGVarFunc * tab)
703 {
704     Int i;
705 
706     for (i = 0; tab[i].name != 0; i++) {
707         InitHandlerFunc(tab[i].handler, tab[i].cookie);
708     }
709 }
710 
711 
712 /****************************************************************************
713 **
714 *F  ImportGVarFromLibrary( <name>, <address> )  . . .  import global variable
715 */
716 
717 
ImportGVarFromLibrary(const Char * name,Obj * address)718 void ImportGVarFromLibrary(const Char * name, Obj * address)
719 {
720     if (NrImportedGVars == 1024) {
721         Pr("#W  warning: too many imported GVars\n", 0L, 0L);
722     }
723     else {
724         ImportedGVars[NrImportedGVars].name = name;
725         ImportedGVars[NrImportedGVars].address = address;
726         NrImportedGVars++;
727     }
728     if (address != 0) {
729         InitCopyGVar(name, address);
730     }
731 }
732 
733 
734 /****************************************************************************
735 **
736 *F  ImportFuncFromLibrary( <name>, <address> )  . . .  import global function
737 */
738 
739 
ImportFuncFromLibrary(const Char * name,Obj * address)740 void ImportFuncFromLibrary(const Char * name, Obj * address)
741 {
742     if (NrImportedFuncs == 1024) {
743         Pr("#W  warning: too many imported Funcs\n", 0L, 0L);
744     }
745     else {
746         ImportedFuncs[NrImportedFuncs].name = name;
747         ImportedFuncs[NrImportedFuncs].address = address;
748         NrImportedFuncs++;
749     }
750     if (address != 0) {
751         InitFopyGVar(name, address);
752     }
753 }
754 
755 
756 /****************************************************************************
757 **
758 *F  FuncExportToKernelFinished( <self> )  . . . . . . . . . . check functions
759 */
FuncExportToKernelFinished(Obj self)760 static Obj FuncExportToKernelFinished(Obj self)
761 {
762     UInt i;
763     Int  errs = 0;
764     Obj  val;
765 
766     SyInitializing = 0;
767     for (i = 0; i < NrImportedGVars; i++) {
768         if (ImportedGVars[i].address == 0) {
769             val = ValAutoGVar(GVarName(ImportedGVars[i].name));
770             if (val == 0) {
771                 errs++;
772                 if (!SyQuiet) {
773                     Pr("#W  global variable '%s' has not been defined\n",
774                        (Int)ImportedFuncs[i].name, 0L);
775                 }
776             }
777         }
778         else if (*ImportedGVars[i].address == 0) {
779             errs++;
780             if (!SyQuiet) {
781                 Pr("#W  global variable '%s' has not been defined\n",
782                    (Int)ImportedGVars[i].name, 0L);
783             }
784         }
785         else {
786             MakeReadOnlyGVar(GVarName(ImportedGVars[i].name));
787         }
788     }
789 
790     for (i = 0; i < NrImportedFuncs; i++) {
791         if (ImportedFuncs[i].address == 0) {
792             val = ValAutoGVar(GVarName(ImportedFuncs[i].name));
793             if (val == 0 || !IS_FUNC(val)) {
794                 errs++;
795                 if (!SyQuiet) {
796                     Pr("#W  global function '%s' has not been defined\n",
797                        (Int)ImportedFuncs[i].name, 0L);
798                 }
799             }
800         }
801         else if (*ImportedFuncs[i].address == ErrorMustEvalToFuncFunc ||
802                  *ImportedFuncs[i].address == ErrorMustHaveAssObjFunc) {
803             errs++;
804             if (!SyQuiet) {
805                 Pr("#W  global function '%s' has not been defined\n",
806                    (Int)ImportedFuncs[i].name, 0L);
807             }
808         }
809         else {
810             MakeReadOnlyGVar(GVarName(ImportedFuncs[i].name));
811         }
812     }
813 
814     return errs == 0 ? True : False;
815 }
816 
817 
818 /****************************************************************************
819 **
820 *F  RecordLoadedModule( <module> )  . . . . . . . . store module in <Modules>
821 */
822 
RecordLoadedModule(StructInitInfo * info,Int isGapRootRelative,const Char * filename)823 void RecordLoadedModule(StructInitInfo * info,
824                         Int              isGapRootRelative,
825                         const Char *     filename)
826 {
827     UInt len;
828     if (NrModules == MAX_MODULES) {
829         Panic("no room to record module");
830     }
831     len = strlen(filename);
832     if (NextLoadedModuleFilename + len + 1 >
833         LoadedModuleFilenames + MAX_MODULE_FILENAMES) {
834         Panic("no room for module filename");
835     }
836     *NextLoadedModuleFilename = '\0';
837     memcpy(NextLoadedModuleFilename, filename, len + 1);
838     Modules[NrModules].info = info;
839     Modules[NrModules].filename = NextLoadedModuleFilename;
840     NextLoadedModuleFilename += len + 1;
841     Modules[NrModules].isGapRootRelative = isGapRootRelative;
842     NrModules++;
843 }
844 
845 
SaveModules(void)846 void SaveModules(void)
847 {
848     SaveUInt(NrModules - NrBuiltinModules);
849     for (UInt i = NrBuiltinModules; i < NrModules; i++) {
850         SaveUInt(Modules[i].info->type);
851         SaveUInt(Modules[i].isGapRootRelative);
852         SaveCStr(Modules[i].filename);
853     }
854 }
855 
LoadModules(void)856 void LoadModules(void)
857 {
858     Char buf[256];
859     UInt nMods = LoadUInt();
860     for (UInt i = 0; i < nMods; i++) {
861         UInt type = LoadUInt();
862         UInt isGapRootRelative = LoadUInt();
863         LoadCStr(buf, 256);
864         if (isGapRootRelative)
865             READ_GAP_ROOT(buf);
866         else {
867             StructInitInfo * info = NULL;
868             /* Search for user module static case first */
869             if (IS_MODULE_STATIC(type)) {
870                 UInt k;
871                 for (k = 0; CompInitFuncs[k]; k++) {
872                     info = (*(CompInitFuncs[k]))();
873                     if (info == 0) {
874                         continue;
875                     }
876                     if (!strcmp(buf, info->name)) {
877                         break;
878                     }
879                 }
880                 if (CompInitFuncs[k] == 0) {
881                     Pr("Static module %s not found in loading kernel\n",
882                        (Int)buf, 0L);
883                     SyExit(1);
884                 }
885             }
886             else {
887                 /* and dynamic case */
888                 InitInfoFunc init;
889 
890 #ifdef HAVE_DLOPEN
891                 int res = SyLoadModule(buf, &init);
892                 if (res != 0) {
893                     Panic("Failed to load needed dynamic module %s, error "
894                           "code %d\n",
895                           buf, res);
896                 }
897                 info = (*init)();
898                 if (info == 0) {
899                     Panic("Failed to init needed dynamic module %s, error "
900                           "code %d\n",
901                           buf, res);
902                 }
903 #else
904                 Panic("workspace require dynamic module %s, but dynamic "
905                       "loading not supported",
906                       buf);
907 #endif
908             }
909 
910             ActivateModule(info);
911             RecordLoadedModule(info, 0, buf);
912         }
913     }
914 }
915 
ModulesSetup(void)916 void ModulesSetup(void)
917 {
918     NrImportedGVars = 0;
919     NrImportedFuncs = 0;
920     NrModules = 0;
921     for (UInt i = 0; InitFuncsBuiltinModules[i]; i++) {
922         if (NrModules == MAX_MODULES) {
923             Panic("too many builtin modules");
924         }
925         StructInitInfo * info = InitFuncsBuiltinModules[i]();
926         Modules[NrModules++].info = info;
927         if (SyDebugLoading) {
928             fputs("#I  InitInfo(builtin ", stderr);
929             fputs(info->name, stderr);
930             fputs(")\n", stderr);
931         }
932 
933         RegisterModuleState(info);
934     }
935     NrBuiltinModules = NrModules;
936 }
937 
ModulesInitKernel(void)938 void ModulesInitKernel(void)
939 {
940     for (UInt i = 0; i < NrBuiltinModules; i++) {
941         StructInitInfo * info = Modules[i].info;
942         if (info->initKernel) {
943             if (SyDebugLoading) {
944                 fputs("#I  InitKernel(builtin ", stderr);
945                 fputs(info->name, stderr);
946                 fputs(")\n", stderr);
947             }
948             Int ret = info->initKernel(info);
949             if (ret) {
950                 Panic("InitKernel(builtin %s) returned non-zero value", info->name);
951             }
952         }
953     }
954 }
955 
ModulesInitLibrary(void)956 void ModulesInitLibrary(void)
957 {
958     for (UInt i = 0; i < NrBuiltinModules; i++) {
959         StructInitInfo * info = Modules[i].info;
960         if (info->initLibrary) {
961             if (SyDebugLoading) {
962                 fputs("#I  InitLibrary(builtin ", stderr);
963                 fputs(info->name, stderr);
964                 fputs(")\n", stderr);
965             }
966             Int ret = info->initLibrary(info);
967             if (ret) {
968                 Panic("InitLibrary(builtin %s) returned non-zero value", info->name);
969             }
970         }
971     }
972 }
973 
ModulesCheckInit(void)974 void ModulesCheckInit(void)
975 {
976     for (UInt i = 0; i < NrModules; i++) {
977         StructInitInfo * info = Modules[i].info;
978         if (info->checkInit) {
979             if (SyDebugLoading) {
980                 fputs("#I  CheckInit(builtin ", stderr);
981                 fputs(info->name, stderr);
982                 fputs(")\n", stderr);
983             }
984             Int ret = info->checkInit(info);
985             if (ret) {
986                 Panic("CheckInit(builtin %s) returned non-zero value", info->name);
987             }
988         }
989     }
990 }
991 
ModulesInitModuleState(void)992 void ModulesInitModuleState(void)
993 {
994     for (UInt i = 0; i < NrModules; i++) {
995         StructInitInfo * info = Modules[i].info;
996         if (info->initModuleState) {
997             if (SyDebugLoading) {
998                 fputs("#I  InitModuleState(", stderr);
999                 fputs(info->name, stderr);
1000                 fputs(")\n", stderr);
1001             }
1002             Int ret = info->initModuleState();
1003             if (ret) {
1004                 Panic("InitModuleState(builtin %s) returned non-zero value", info->name);
1005             }
1006         }
1007     }
1008 }
1009 
ModulesDestroyModuleState(void)1010 void ModulesDestroyModuleState(void)
1011 {
1012     for (UInt i = 0; i < NrModules; i++) {
1013         StructInitInfo * info = Modules[i].info;
1014         if (info->destroyModuleState) {
1015             if (SyDebugLoading) {
1016                 fputs("#I  DestroyModuleState(", stderr);
1017                 fputs(info->name, stderr);
1018                 fputs(")\n", stderr);
1019             }
1020             Int ret = info->destroyModuleState();
1021             if (ret) {
1022                 Panic("DestroyModuleState(builtin %s) returned non-zero value", info->name);
1023             }
1024         }
1025     }
1026 }
1027 
1028 
ModulesPreSave(void)1029 Int ModulesPreSave(void)
1030 {
1031     for (UInt i = 0; i < NrModules; i++) {
1032         StructInitInfo * info = Modules[i].info;
1033         if (info->preSave != NULL && info->preSave(info)) {
1034             Pr("Failed to save workspace -- problem reported in %s\n",
1035                (Int)info->name, 0L);
1036             // roll back all save preparations
1037             while (i--) {
1038                 info = Modules[i].info;
1039                 info->postSave(info);
1040             }
1041             return 1;
1042         }
1043     }
1044     return 0;
1045 }
1046 
ModulesPostSave(void)1047 void ModulesPostSave(void)
1048 {
1049     for (UInt i = 0; i < NrModules; i++) {
1050         StructInitInfo * info = Modules[i].info;
1051         if (info->postSave != NULL)
1052             info->postSave(info);
1053     }
1054 }
1055 
ModulesPostRestore(void)1056 void ModulesPostRestore(void)
1057 {
1058     for (UInt i = 0; i < NrModules; i++) {
1059         StructInitInfo * info = Modules[i].info;
1060         if (info->postRestore) {
1061             if (SyDebugLoading) {
1062                 fputs("#I  PostRestore(builtin ", stderr);
1063                 fputs(info->name, stderr);
1064                 fputs(")\n", stderr);
1065             }
1066             Int ret = info->postRestore(info);
1067             if (ret) {
1068                 Panic("PostRestore(builtin %s) returned non-zero value", info->name);
1069             }
1070         }
1071     }
1072 }
1073 
1074 
1075 /****************************************************************************
1076 **
1077 *V  GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
1078 */
1079 static StructGVarFunc GVarFuncs[] = {
1080     GVAR_FUNC(GAP_CRC, 1, "filename"),
1081     GVAR_FUNC(LOAD_DYN, 2, "filename, crc"),
1082     GVAR_FUNC(LOAD_STAT, 2, "filename, crc"),
1083     GVAR_FUNC(SHOW_STAT, 0, ""),
1084     GVAR_FUNC(LoadedModules, 0, ""),
1085     GVAR_FUNC(ExportToKernelFinished, 0, ""),
1086     { 0, 0, 0, 0, 0 }
1087 };
1088 
1089 
1090 /****************************************************************************
1091 **
1092 *F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
1093 */
InitKernel(StructInitInfo * module)1094 static Int InitKernel(StructInitInfo * module)
1095 {
1096     // init filters and functions
1097     InitHdlrFuncsFromTable(GVarFuncs);
1098 
1099     // return success
1100     return 0;
1101 }
1102 
1103 
1104 /****************************************************************************
1105 **
1106 *F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
1107 */
InitLibrary(StructInitInfo * module)1108 static Int InitLibrary(StructInitInfo * module)
1109 {
1110     // init filters and functions
1111     InitGVarFuncsFromTable(GVarFuncs);
1112 
1113     // return success
1114     return 0;
1115 }
1116 
1117 
1118 /****************************************************************************
1119 **
1120 *F  InitInfoModules() . . . . . . . . . . . . . . . . table of init functions
1121 */
1122 static StructInitInfo module = {
1123     // init struct using C99 designated initializers; for a full list of
1124     // fields, please refer to the definition of StructInitInfo
1125     .type = MODULE_BUILTIN,
1126     .name = "modules",
1127     .initKernel = InitKernel,
1128     .initLibrary = InitLibrary,
1129 };
1130 
InitInfoModules(void)1131 StructInitInfo * InitInfoModules(void)
1132 {
1133     return &module;
1134 }
1135