Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346/****************************************************************************1**2*W gvars.c GAP source Martin Schönert3**4**5*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany6*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland7*Y Copyright (C) 2002 The GAP Group8**9** This file contains the functions of the global variables package.10**11** The global variables package is the part of the kernel that manages12** global variables, i.e., the global namespace. A global variable binds an13** identifier to a value.14**15** A global variable can be automatic. That means that the global variable16** binds the identifier to a function and an argument. When the value of17** the global variable is needed, the function is called with the argument.18** This function call should, as a side-effect, execute an assignment of a19** value to the global variable, otherwise an error is signalled.20**21** A global variable can have a number of internal copies, i.e., C variables22** that always reference the same value as the global variable.23** It can also have a special type of internal copy (a fopy) only used for24** functions, where the internal copies25** only reference the same value as the global variable if it is a function.26** Otherwise the internal copies reference functions that signal an error.27*/28#include "system.h" /* Ints, UInts */293031#include "gasman.h" /* garbage collector */32#include "objects.h" /* objects */3334#include "scanner.h" /* scanner */3536#include "gap.h" /* error handling, initialisation */3738#include "code.h" /* coder */3940#include "gvars.h" /* global variables */4142#include "calls.h" /* generic call mechanism */4344#include "records.h" /* generic records */45#include "precord.h" /* plain records */4647#include "lists.h" /* generic lists */4849#include "plist.h" /* plain lists */50#include "string.h" /* strings */5152#include "bool.h" /* booleans */5354#include "tls.h" /* thread-local storage */55#include "thread.h" /* threads */56#include "aobjects.h" /* atomic objects */5758/****************************************************************************59**60*V ValGVars . . . . . . . . . . . . . . . . . . values of global variables61*V PtrGVars . . . . . . . . . . . . . pointer to values of global variables62**63** 'ValGVars' is the bag containing the values of the global variables.64**65** 'PtrGVars' is a pointer to the 'ValGVars' bag. This makes it faster to66** access global variables.67**68** Since a garbage collection may move this bag around, the pointer69** 'PtrGVars' must be revalculated afterwards. This should be done by a70** function in this package, but is still done in 'VarsAfterCollectBags'.71*/72Obj ValGVars;7374Obj * PtrGVars;757677/****************************************************************************78**79*F VAL_GVAR(<gvar>) . . . . . . . . . . . . . . . value of global variable80**81** 'VAL_GVAR' returns the value of the global variable <gvar>. If <gvar>82** has no assigned value, 'VAL_GVAR' returns 0. In this case <gvar> might83** be an automatic global variable, and one should call 'ValAutoGVar', which84** will return the value of <gvar> after evaluating <gvar>-s expression, or85** 0 if <gvar> was not an automatic variable.86**87** 'VAL_GVAR' is defined in the declaration part of this package as follows88**89#define VAL_GVAR(gvar) PtrGVars[ (gvar) ]90*/919293/****************************************************************************94**95*V NameGVars . . . . . . . . . . . . . . . . . . . names of global variables96*V WriteGVars . . . . . . . . . . . . . writable flags of global variables97*V ExprGVars . . . . . . . . . . expressions for automatic global variables98*V CopiesGVars . . . . . . . . . . . . . internal copies of global variables99*V FopiesGVars . . . . . . . . internal function copies of global variables100*V CountGVars . . . . . . . . . . . . . . . . . number of global variables101*/102Obj NameGVars;103Obj WriteGVars;104Obj ExprGVars;105Obj CopiesGVars;106Obj FopiesGVars;107UInt CountGVars;108109110/****************************************************************************111**112*V TableGVars . . . . . . . . . . . . . . hashed table of global variables113*V SizeGVars . . . . . . . current size of hashed table of global variables114*/115Obj TableGVars;116UInt SizeGVars;117118119/****************************************************************************120**121*V ErrorMustEvalToFuncFunc . . . . . . . . . function that signals an error122*F ErrorMustEvalToFuncHandler(<self>,<args>) . handler that signals an error123**124** 'ErrorMustEvalToFuncFunc' is a (variable number of args) function that125** signals the error ``Function: <func> be a function''.126**127** 'ErrorMustEvalToFuncHandler' is the handler that signals the error128** ``Function: <func> must be a function''.129*/130Obj ErrorMustEvalToFuncFunc;131132Obj ErrorMustEvalToFuncHandler (133Obj self,134Obj args )135{136ErrorQuit(137"Function Calls: <func> must be a function",1380L, 0L );139return 0;140}141142143/****************************************************************************144**145*V ErrorMustHaveAssObjFunc . . . . . . . . . function that signals an error146*F ErrorMustHaveAssObjHandler(<self>,<args>) . handler that signals an error147**148** 'ErrorMustHaveAssObjFunc' is a (variable number of args) function that149** signals the error ``Variable: <<unknown>> must have an assigned value''.150**151** 'ErrorMustHaveAssObjHandler' is the handler that signals the error152** ``Variable: <<unknown>> must have an assigned value''.153*/154Obj ErrorMustHaveAssObjFunc;155156Obj ErrorMustHaveAssObjHandler (157Obj self,158Obj args )159{160ErrorQuit(161"Variable: <<unknown>> must have an assigned value",1620L, 0L );163return 0;164}165166167/****************************************************************************168**169*F AssGVar(<gvar>,<val>) . . . . . . . . . . . . assign to a global variable170**171** 'AssGVar' assigns the value <val> to the global variable <gvar>.172*/173174static Obj REREADING; /* Copy of GAP global variable REREADING */175176void AssGVar (177UInt gvar,178Obj val )179{180Obj cops; /* list of internal copies */181Obj * copy; /* one copy */182UInt i; /* loop variable */183Obj onam; /* object of <name> */184185/* make certain that the variable is not read only */186while ( (REREADING != True) &&187(ELM_PLIST( WriteGVars, gvar ) == INTOBJ_INT(0)) ) {188ErrorReturnVoid(189"Variable: '%s' is read only",190(Int)CSTR_STRING( ELM_PLIST(NameGVars,gvar) ), 0L,191"you can 'return;' after making it writable" );192}193194/* assign the value to the global variable */195VAL_GVAR(gvar) = val;196CHANGED_BAG( ValGVars );197198/* if the global variable was automatic, convert it to normal */199SET_ELM_PLIST( ExprGVars, gvar, 0 );200201/* assign the value to all the internal copies */202cops = ELM_PLIST( CopiesGVars, gvar );203if ( cops != 0 ) {204for ( i = 1; i <= LEN_PLIST(cops); i++ ) {205copy = (Obj*) ELM_PLIST(cops,i);206*copy = val;207}208}209210/* if the value is a function, assign it to all the internal fopies */211cops = ELM_PLIST( FopiesGVars, gvar );212if ( cops != 0 && val != 0 && TNUM_OBJ(val) == T_FUNCTION ) {213for ( i = 1; i <= LEN_PLIST(cops); i++ ) {214copy = (Obj*) ELM_PLIST(cops,i);215*copy = val;216}217}218219/* if the values is not a function, assign the error function */220else if ( cops != 0 && val != 0 /* && TNUM_OBJ(val) != T_FUNCTION */ ) {221for ( i = 1; i <= LEN_PLIST(cops); i++ ) {222copy = (Obj*) ELM_PLIST(cops,i);223*copy = ErrorMustEvalToFuncFunc;224}225}226227/* if this was an unbind, assign the other error function */228else if ( cops != 0 /* && val == 0 */ ) {229for ( i = 1; i <= LEN_PLIST(cops); i++ ) {230copy = (Obj*) ELM_PLIST(cops,i);231*copy = ErrorMustHaveAssObjFunc;232}233}234235/* assign name to a function */236if ( val != 0 && TNUM_OBJ(val) == T_FUNCTION && NAME_FUNC(val) == 0 ) {237onam = CopyToStringRep(NameGVarObj(gvar));238RESET_FILT_LIST( onam, FN_IS_MUTABLE );239NAME_FUNC(val) = onam;240CHANGED_BAG(val);241}242}243244245/****************************************************************************246**247*F ValAutoGVar(<gvar>) . . . . . . . . value of a automatic global variable248**249** 'ValAutoGVar' returns the value of the global variable <gvar>. This will250** be 0 if <gvar> has no assigned value. It will also cause a function251** call, if <gvar> is automatic.252*/253Obj ValAutoGVar (254UInt gvar )255{256Obj func; /* function to call for automatic */257Obj arg; /* argument to pass for automatic */258259/* if this is an automatic variable, make the function call */260if ( VAL_GVAR(gvar) == 0 && ELM_PLIST( ExprGVars, gvar ) != 0 ) {261262/* make the function call */263func = ELM_PLIST( ELM_PLIST( ExprGVars, gvar ), 1 );264arg = ELM_PLIST( ELM_PLIST( ExprGVars, gvar ), 2 );265CALL_1ARGS( func, arg );266267/* if this is still an automatic variable, this is an error */268while ( VAL_GVAR(gvar) == 0 ) {269ErrorReturnVoid(270"Variable: automatic variable '%s' must get a value by function call",271(Int)CSTR_STRING( ELM_PLIST(NameGVars,gvar) ), 0L,272"you can 'return;' after assigning a value" );273}274275}276277/* return the value */278return VAL_GVAR(gvar);279}280281282/****************************************************************************283**284*F NameGVar(<gvar>) . . . . . . . . . . . . . . . name of a global variable285**286** 'NameGVar' returns the name of the global variable <gvar> as a C string.287*/288Char * NameGVar (289UInt gvar )290{291return CSTR_STRING( ELM_PLIST( NameGVars, gvar ) );292}293294Obj NameGVarObj ( UInt gvar )295{296return ELM_PLIST( NameGVars, gvar );297}298299#define NSCHAR '@'300301Obj CurrNamespace = 0;302303Obj FuncSET_NAMESPACE(Obj self, Obj str)304{305TLS(CurrNamespace) = str;306return 0;307}308309Obj FuncGET_NAMESPACE(Obj self)310{311return TLS(CurrNamespace);312}313314/****************************************************************************315**316*F GVarName(<name>) . . . . . . . . . . . . . . global variable for a name317**318** 'GVarName' returns the global variable with the name <name>.319*/320UInt GVarName (321const Char * name )322{323Obj gvar; /* global variable (as imm intval) */324Char gvarbuf[1024]; /* temporary copy for namespace */325Char * cns; /* Pointer to current namespace */326UInt pos; /* hash position */327Char namx [1024]; /* temporary copy of <name> */328Obj string; /* temporary string value <name> */329Obj table; /* temporary copy of <TableGVars> */330Obj gvar2; /* one element of <table> */331const Char * p; /* loop variable */332UInt i; /* loop variable */333Int len; /* length of name */334335/* First see whether it could be namespace-local: */336cns = CSTR_STRING(TLS(CurrNamespace));337if (*cns) { /* only if a namespace is set */338len = strlen(name);339if (name[len-1] == NSCHAR) {340strlcpy(gvarbuf, name, 512);341strlcat(gvarbuf, cns, sizeof(gvarbuf));342name = gvarbuf;343}344}345346/* start looking in the table at the following hash position */347pos = 0;348for ( p = name; *p != '\0'; p++ ) {349pos = 65599 * pos + *p;350}351pos = (pos % SizeGVars) + 1;352353/* look through the table until we find a free slot or the global */354while ( (gvar = ELM_PLIST( TableGVars, pos )) != 0355&& strncmp( NameGVar( INT_INTOBJ(gvar) ), name, 1023 ) ) {356pos = (pos % SizeGVars) + 1;357}358359/* if we did not find the global variable, make a new one and enter it */360/* (copy the name first, to avoid a stale pointer in case of a GC) */361if ( gvar == 0 ) {362CountGVars++;363gvar = INTOBJ_INT(CountGVars);364SET_ELM_PLIST( TableGVars, pos, gvar );365strlcpy(namx, name, sizeof(namx));366C_NEW_STRING_DYN(string, namx);367368RESET_FILT_LIST( string, FN_IS_MUTABLE );369GROW_PLIST( ValGVars, CountGVars );370SET_LEN_PLIST( ValGVars, CountGVars );371SET_ELM_PLIST( ValGVars, CountGVars, 0 );372GROW_PLIST( NameGVars, CountGVars );373SET_LEN_PLIST( NameGVars, CountGVars );374SET_ELM_PLIST( NameGVars, CountGVars, string );375CHANGED_BAG( NameGVars );376GROW_PLIST( WriteGVars, CountGVars );377SET_LEN_PLIST( WriteGVars, CountGVars );378SET_ELM_PLIST( WriteGVars, CountGVars, INTOBJ_INT(1) );379GROW_PLIST( ExprGVars, CountGVars );380SET_LEN_PLIST( ExprGVars, CountGVars );381SET_ELM_PLIST( ExprGVars, CountGVars, 0 );382GROW_PLIST( CopiesGVars, CountGVars );383SET_LEN_PLIST( CopiesGVars, CountGVars );384SET_ELM_PLIST( CopiesGVars, CountGVars, 0 );385GROW_PLIST( FopiesGVars, CountGVars );386SET_LEN_PLIST( FopiesGVars, CountGVars );387SET_ELM_PLIST( FopiesGVars, CountGVars, 0 );388PtrGVars = ADDR_OBJ( ValGVars );389}390391/* if the table is too crowed, make a larger one, rehash the names */392if ( SizeGVars < 3 * CountGVars / 2 ) {393table = TableGVars;394SizeGVars = 2 * SizeGVars + 1;395TableGVars = NEW_PLIST( T_PLIST, SizeGVars );396SET_LEN_PLIST( TableGVars, SizeGVars );397for ( i = 1; i <= (SizeGVars-1)/2; i++ ) {398gvar2 = ELM_PLIST( table, i );399if ( gvar2 == 0 ) continue;400pos = 0;401for ( p = NameGVar( INT_INTOBJ(gvar2) ); *p != '\0'; p++ ) {402pos = 65599 * pos + *p;403}404pos = (pos % SizeGVars) + 1;405while ( ELM_PLIST( TableGVars, pos ) != 0 ) {406pos = (pos % SizeGVars) + 1;407}408SET_ELM_PLIST( TableGVars, pos, gvar2 );409}410}411412/* return the global variable */413return INT_INTOBJ(gvar);414}415416/****************************************************************************417**418419*V Tilde . . . . . . . . . . . . . . . . . . . . . . . . global variable '~'420**421** 'Tilde' is the global variable '~', the one used in expressions such as422** '[ [ 1, 2 ], ~[1] ]'.423**424** Actually when such expressions appear in functions, one should probably425** use a local variable. But for now this is good enough.426*/427UInt Tilde;428429430/****************************************************************************431**432*F MakeReadOnlyGVar( <gvar> ) . . . . . . make a global variable read only433*/434void MakeReadOnlyGVar (435UInt gvar )436{437SET_ELM_PLIST( WriteGVars, gvar, INTOBJ_INT(0) );438CHANGED_BAG(WriteGVars)439}440441442/****************************************************************************443**444*F MakeReadOnlyGVarHandler(<self>,<name>) make a global variable read only445**446** 'MakeReadOnlyGVarHandler' implements the function 'MakeReadOnlyGVar'.447**448** 'MakeReadOnlyGVar( <name> )'449**450** 'MakeReadOnlyGVar' make the global variable with the name <name> (which451** must be a GAP string) read only.452*/453Obj MakeReadOnlyGVarHandler (454Obj self,455Obj name )456{457/* check the argument */458while ( ! IsStringConv( name ) ) {459name = ErrorReturnObj(460"MakeReadOnlyGVar: <name> must be a string (not a %s)",461(Int)TNAM_OBJ(name), 0L,462"you can return a string for <name>" );463}464465/* get the variable and make it read only */466MakeReadOnlyGVar(GVarName(CSTR_STRING(name)));467468/* return void */469return 0;470}471472473/****************************************************************************474**475*F MakeReadWriteGVar( <gvar> ) . . . . . . make a global variable read write476*/477void MakeReadWriteGVar (478UInt gvar )479{480SET_ELM_PLIST( WriteGVars, gvar, INTOBJ_INT(1) );481CHANGED_BAG(WriteGVars)482}483484485/****************************************************************************486**487*F MakeReadWriteGVarHandler(<self>,<name>) make a global variable read write488**489** 'MakeReadWriteGVarHandler' implements the function 'MakeReadWriteGVar'.490**491** 'MakeReadWriteGVar( <name> )'492**493** 'MakeReadWriteGVar' make the global variable with the name <name> (which494** must be a GAP string) read and writable.495*/496Obj MakeReadWriteGVarHandler (497Obj self,498Obj name )499{500/* check the argument */501while ( ! IsStringConv( name ) ) {502name = ErrorReturnObj(503"MakeReadWriteGVar: <name> must be a string (not a %s)",504(Int)TNAM_OBJ(name), 0L,505"you can return a string for <name>" );506}507508/* get the variable and make it read write */509MakeReadWriteGVar(GVarName(CSTR_STRING(name)));510511/* return void */512return 0;513}514515/****************************************************************************516**517*F IsReadOnlyGVar( <gvar> ) . . . . . . return status of a global variable518*/519Int IsReadOnlyGVar (520UInt gvar )521{522return !INT_INTOBJ(ELM_PLIST(WriteGVars, gvar));523}524525526/****************************************************************************527**528*F FuncIsReadOnlyGVar( <name> ) . . .handler for GAP function529**530*/531532static Obj FuncIsReadOnlyGVar (533Obj self,534Obj name )535{536/* check the argument */537while ( ! IsStringConv( name ) ) {538name = ErrorReturnObj(539"IsReadOnlyGVar: <name> must be a string (not a %s)",540(Int)TNAM_OBJ(name), 0L,541"you can return a string for <name>" );542}543544/* get the answer */545return IsReadOnlyGVar(GVarName(CSTR_STRING(name))) ? True : False;546}547548549/****************************************************************************550**551*F AUTOHandler() . . . . . . . . . . . . . make automatic global variables552**553** 'AUTOHandler' implements the internal function 'AUTO'.554**555** 'AUTO( <func>, <arg>, <name1>, ... )'556**557** 'AUTO' makes the global variables, whose names are given the strings558** <name1>, <name2>, ..., automatic. That means that when the value of one559** of those global variables is requested, then the function <func> is560** called and the argument <arg> is passed. This function call should,561** cause the execution of an assignment to that global variable, otherwise562** an error is signalled.563*/564Obj AUTOFunc;565566Obj AUTOHandler (567Obj self,568Obj args )569{570Obj func; /* the function to call */571Obj arg; /* the argument to pass */572Obj list; /* function and argument list */573Obj name; /* one name (as a GAP string) */574UInt gvar; /* one global variable */575UInt i; /* loop variable */576577/* check that there are enough arguments */578if ( LEN_LIST(args) < 2 ) {579ErrorQuit(580"usage: AUTO( <func>, <arg>, <name1>... )",5810L, 0L );582return 0;583}584585/* get and check the function */586func = ELM_LIST( args, 1 );587while ( TNUM_OBJ(func) != T_FUNCTION ) {588func = ErrorReturnObj(589"AUTO: <func> must be a function (not a %s)",590(Int)TNAM_OBJ(func), 0L,591"you can return a function for <func>" );592}593594/* get the argument */595arg = ELM_LIST( args, 2 );596597/* make the list of function and argument */598list = NEW_PLIST( T_PLIST, 2 );599SET_LEN_PLIST( list, 2 );600SET_ELM_PLIST( list, 1, func );601SET_ELM_PLIST( list, 2, arg );602603/* make the global variables automatic */604for ( i = 3; i <= LEN_LIST(args); i++ ) {605name = ELM_LIST( args, i );606while ( ! IsStringConv(name) ) {607name = ErrorReturnObj(608"AUTO: <name> must be a string (not a %s)",609(Int)TNAM_OBJ(name), 0L,610"you can return a string for <name>" );611}612gvar = GVarName( CSTR_STRING(name) );613SET_ELM_PLIST( ValGVars, gvar, 0 );614SET_ELM_PLIST( ExprGVars, gvar, list );615CHANGED_BAG( ExprGVars );616}617618/* return void */619return 0;620}621622623/****************************************************************************624**625*F iscomplete( <name>, <len> ) . . . . . . . . find the completions of name626*F completion( <name>, <len> ) . . . . . . . . find the completions of name627*/628UInt iscomplete_gvar (629Char * name,630UInt len )631{632Char * curr;633UInt i, k;634635for ( i = 1; i <= CountGVars; i++ ) {636curr = NameGVar( i );637for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;638if ( k == len && curr[k] == '\0' ) return 1;639}640return 0;641}642643UInt completion_gvar (644Char * name,645UInt len )646{647Char * curr;648Char * next;649UInt i, k;650651next = 0;652for ( i = 1; i <= CountGVars; i++ ) {653/* consider only variables which are currently bound for completion */654if ( VAL_GVAR( i ) || ELM_PLIST( ExprGVars, i )) {655curr = NameGVar( i );656for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;657if ( k < len || curr[k] <= name[k] ) continue;658if ( next != 0 ) {659for ( k = 0; curr[k] != '\0' && curr[k] == next[k]; k++ ) ;660if ( k < len || next[k] < curr[k] ) continue;661}662next = curr;663}664}665666if ( next != 0 ) {667for ( k = 0; next[k] != '\0'; k++ )668name[k] = next[k];669name[k] = '\0';670}671672return next != 0;673}674675676/****************************************************************************677**678*F FuncIDENTS_GVAR( <self> ) . . . . . . . . . . idents of global variables679*/680Obj FuncIDENTS_GVAR (681Obj self )682{683/*QQ extern Obj NameGVars; */684Obj copy;685UInt i;686687copy = NEW_PLIST( T_PLIST+IMMUTABLE, LEN_PLIST(NameGVars) );688for ( i = 1; i <= LEN_PLIST(NameGVars); i++ ) {689SET_ELM_PLIST( copy, i, ELM_PLIST( NameGVars, i ) );690}691SET_LEN_PLIST( copy, LEN_PLIST(NameGVars) );692return copy;693}694695Obj FuncIDENTS_BOUND_GVARS (696Obj self )697{698/*QQ extern Obj NameGVars; */699Obj copy;700UInt i, j;701702copy = NEW_PLIST( T_PLIST+IMMUTABLE, LEN_PLIST(NameGVars) );703for ( i = 1, j = 1; i <= LEN_PLIST(NameGVars); i++ ) {704if ( VAL_GVAR( i ) || ELM_PLIST( ExprGVars, i )) {705SET_ELM_PLIST( copy, j, ELM_PLIST( NameGVars, i ) );706j++;707}708}709SET_LEN_PLIST( copy, j - 1 );710return copy;711}712713/****************************************************************************714**715*F FuncASS_GVAR( <self>, <gvar>, <val> ) . . . . assign to a global variable716*/717Obj FuncASS_GVAR (718Obj self,719Obj gvar,720Obj val )721{722/* check the argument */723while ( ! IsStringConv( gvar ) ) {724gvar = ErrorReturnObj(725"READ: <gvar> must be a string (not a %s)",726(Int)TNAM_OBJ(gvar), 0L,727"you can return a string for <gvar>" );728}729730AssGVar( GVarName( CSTR_STRING(gvar) ), val );731return 0L;732}733734735/****************************************************************************736**737*F FuncISB_GVAR( <self>, <gvar> ) . . check assignment of a global variable738*/739Obj FuncISB_GVAR (740Obj self,741Obj gvar )742{743UInt gv;744/* check the argument */745while ( ! IsStringConv( gvar ) ) {746gvar = ErrorReturnObj(747"ISB_GVAR: <gvar> must be a string (not a %s)",748(Int)TNAM_OBJ(gvar), 0L,749"you can return a string for <gvar>" );750}751752gv = GVarName( CSTR_STRING(gvar) );753return ( VAL_GVAR( gv ) ||754ELM_PLIST( ExprGVars, gv )) ? True : False;755}756757758/****************************************************************************759**760*F FuncVAL_GVAR( <self>, <gvar> ) . . contents of a global variable761*/762763Obj FuncVAL_GVAR (764Obj self,765Obj gvar )766{767Obj val;768/* check the argument */769while ( ! IsStringConv( gvar ) ) {770gvar = ErrorReturnObj(771"VAL_GVAR: <gvar> must be a string (not a %s)",772(Int)TNAM_OBJ(gvar), 0L,773"you can return a string for <gvar>" );774}775776/* get the value */777val = ValAutoGVar( GVarName( CSTR_STRING(gvar) ) );778779while (val == (Obj) 0)780val = ErrorReturnObj("VAL_GVAR: No value bound to %s",781(Int)CSTR_STRING(gvar), (Int) 0,782"you can return a value" );783return val;784}785786/****************************************************************************787**788*F FuncUNB_GVAR( <self>, <gvar> ) . . unbind a global variable789*/790791Obj FuncUNB_GVAR (792Obj self,793Obj gvar )794{795/* check the argument */796while ( ! IsStringConv( gvar ) ) {797gvar = ErrorReturnObj(798"UNB_GVAR: <gvar> must be a string (not a %s)",799(Int)TNAM_OBJ(gvar), 0L,800"you can return a string for <gvar>" );801}802803/* */804AssGVar( GVarName( CSTR_STRING(gvar) ), (Obj)0 );805return (Obj) 0;806}807808809810/****************************************************************************811**812813*F * * * * * * * * * * * * * copies and fopies * * * * * * * * * * * * * * *814*/815816817/****************************************************************************818**819820*V CopyAndFopyGVars . . . . . . kernel table of kernel copies and "fopies"821**822** This needs to be kept inside the kernel so that the copies can be updated823** after loading a workspace.824*/825typedef struct {826Obj * copy;827UInt isFopy;828const Char * name;829} StructCopyGVar;830831#ifndef MAX_COPY_AND_FOPY_GVARS832#define MAX_COPY_AND_FOPY_GVARS 30000833#endif834835static StructCopyGVar CopyAndFopyGVars[MAX_COPY_AND_FOPY_GVARS];836static Int NCopyAndFopyGVars;837838839/****************************************************************************840**841*F InitCopyGVar( <name>, <copy> ) . . declare C variable as copy of global842**843** 'InitCopyGVar' makes the C variable <cvar> at address <copy> a copy of844** the global variable named <name> (which must be a kernel string).845**846** The function only registers the information in <CopyAndFopyGVars>. At a847** latter stage one has to call 'UpdateCopyFopyInfo' to actually enter the848** information stored in <CopyAndFopyGVars> into a plain list.849**850** This is OK for garbage collection, but a real problem for saving in any851** event, this information does not really want to be saved because it is852** kernel centred rather than workspace centred.853**854** Accordingly we provide two functions `RemoveCopyFopyInfo' and855** `RestoreCopyFopyInfo' to remove or restore the information from the856** workspace. The Restore function is also intended to be used after857** loading a saved workspace858*/859void InitCopyGVar (860const Char * name ,861Obj * copy )862{863/* make a record in the kernel for saving and loading */864if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {865Pr( "Panic, no room to record CopyGVar\n", 0L, 0L );866SyExit(1);867}868CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;869CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 0;870CopyAndFopyGVars[NCopyAndFopyGVars].name = name;871NCopyAndFopyGVars++;872}873874875/****************************************************************************876**877*F InitFopyGVar( <name>, <copy> ) . . declare C variable as copy of global878**879** 'InitFopyGVar' makes the C variable <cvar> at address <copy> a (function)880** copy of the global variable <gvar>, whose name is <name>. That means881** that whenever the value of <gvar> is a function, then <cvar> will882** reference the same value (i.e., will hold the same bag identifier). When883** the value of <gvar> is not a function, then <cvar> will reference a884** function that signals the error ``<func> must be a function''. When885** <gvar> has no assigned value, then <cvar> will reference a function that886** signals the error ``<gvar> must have an assigned value''.887*/888void InitFopyGVar (889const Char * name,890Obj * copy )891{892/* make a record in the kernel for saving and loading */893if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {894Pr( "Panic, no room to record FopyGVar\n", 0L, 0L );895SyExit(1);896}897CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;898CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 1;899CopyAndFopyGVars[NCopyAndFopyGVars].name = name;900NCopyAndFopyGVars++;901}902903904/****************************************************************************905**906*F UpdateCopyFopyInfo() . . . . . . . . . . convert kernel info into plist907*/908static Int NCopyAndFopyDone;909910void UpdateCopyFopyInfo ( void )911{912Obj cops; /* copies list */913UInt ncop; /* number of copies */914UInt gvar;915const Char * name; /* name of the variable */916Obj * copy; /* address of the copy */917918/* loop over new copies and fopies */919for ( ; NCopyAndFopyDone < NCopyAndFopyGVars; NCopyAndFopyDone++ ) {920name = CopyAndFopyGVars[NCopyAndFopyDone].name;921copy = CopyAndFopyGVars[NCopyAndFopyDone].copy;922gvar = GVarName(name);923924/* get the copies list and its length */925if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) {926if ( ELM_PLIST( FopiesGVars, gvar ) != 0 ) {927cops = ELM_PLIST( FopiesGVars, gvar );928}929else {930cops = NEW_PLIST( T_PLIST, 0 );931SET_ELM_PLIST( FopiesGVars, gvar, cops );932CHANGED_BAG(FopiesGVars);933}934}935else {936if ( ELM_PLIST( CopiesGVars, gvar ) != 0 ) {937cops = ELM_PLIST( CopiesGVars, gvar );938}939else {940cops = NEW_PLIST( T_PLIST, 0 );941SET_ELM_PLIST( CopiesGVars, gvar, cops );942CHANGED_BAG(CopiesGVars);943}944}945ncop = LEN_PLIST(cops);946947/* append the copy to the copies list */948GROW_PLIST( cops, ncop+1 );949SET_LEN_PLIST( cops, ncop+1 );950SET_ELM_PLIST( cops, ncop+1, (Obj)copy );951CHANGED_BAG(cops);952953/* now copy the value of <gvar> to <cvar> */954if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) {955if ( VAL_GVAR(gvar) != 0 && IS_FUNC(VAL_GVAR(gvar)) ) {956*copy = VAL_GVAR(gvar);957}958else if ( VAL_GVAR(gvar) != 0 ) {959*copy = ErrorMustEvalToFuncFunc;960}961else {962*copy = ErrorMustHaveAssObjFunc;963}964}965else {966*copy = VAL_GVAR(gvar);967}968}969}970971972/****************************************************************************973**974*F RemoveCopyFopyInfo() . . . remove the info about copies of gvars from ws975*/976void RemoveCopyFopyInfo( void )977{978UInt i, l;979980l = LEN_PLIST(CopiesGVars);981for ( i = 1; i <= l; i++ )982SET_ELM_PLIST( CopiesGVars, i, 0 );983l = LEN_PLIST(FopiesGVars);984for ( i = 1; i <= l; i++ )985SET_ELM_PLIST( FopiesGVars, i, 0 );986NCopyAndFopyDone = 0;987return;988}989990991/****************************************************************************992**993*F RestoreCopyFopyInfo() . . . restore the info from the copy in the kernel994*/995void RestoreCopyFopyInfo( void )996{997NCopyAndFopyDone = 0;998UpdateCopyFopyInfo();999}100010011002/****************************************************************************1003**10041005*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *1006*/100710081009/****************************************************************************1010**10111012*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export1013*/1014static StructGVarFunc GVarFuncs [] = {10151016{ "MakeReadOnlyGVar", 1, "name",1017MakeReadOnlyGVarHandler, "src/gap.c:MakeReadOnlyGVar" },10181019{ "MakeReadWriteGVar", 1, "name",1020MakeReadWriteGVarHandler, "src/gap.c:MakeReadWriteGVar" },10211022{ "IsReadOnlyGVar", 1, "name",1023FuncIsReadOnlyGVar, "src/gap.c:IsReadOnlyGVar" },10241025{ "AUTO", -1, "args",1026AUTOHandler, "src/gap.c:AUTO" },10271028{ "IDENTS_GVAR", 0L, "",1029FuncIDENTS_GVAR, "src/gap.c:IDENTS_GVAR" },10301031{ "IDENTS_BOUND_GVARS", 0L, "",1032FuncIDENTS_BOUND_GVARS, "src/gap.c:IDENTS_BOUND_GVARS" },10331034{ "ISB_GVAR", 1L, "gvar",1035FuncISB_GVAR, "src/gap.c:ISB_GVAR" },10361037{ "ASS_GVAR", 2L, "gvar, value",1038FuncASS_GVAR, "src/gap.c:ASS_GVAR" },10391040{ "VAL_GVAR", 1L, "gvar",1041FuncVAL_GVAR, "src/gap.c:VAL_GVAR" },10421043{ "UNB_GVAR", 1L, "gvar",1044FuncUNB_GVAR, "src/gap.c:UNB_GVAR" },10451046{ "SET_NAMESPACE", 1L, "str",1047FuncSET_NAMESPACE, "src/gvars.c:SET_NAMESPACE" },10481049{ "GET_NAMESPACE", 0L, "",1050FuncGET_NAMESPACE, "src/gvars.c:GET_NAMESPACE" },10511052{ 0 }10531054};105510561057/****************************************************************************1058**10591060*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures1061*/1062static Int InitKernel (1063StructInitInfo * module )1064{1065ValGVars = (Obj) 0;1066NCopyAndFopyGVars = 0;1067NCopyAndFopyDone = 0;1068InitHandlerRegistration();10691070/* init global bags and handler */1071InitGlobalBag( &ErrorMustEvalToFuncFunc,1072"src/gvars.c:ErrorMustEvalToFuncFunc" );1073InitGlobalBag( &ErrorMustHaveAssObjFunc,1074"src/gvars.c:ErrorMustHaveAssObjFunc" );1075InitGlobalBag( &ValGVars,1076"src/gvars.c:ValGVars" );1077InitGlobalBag( &NameGVars,1078"src/gvars.c:NameGVars" );1079InitGlobalBag( &WriteGVars,1080"src/gvars.c:WriteGVars" );1081InitGlobalBag( &ExprGVars,1082"src/gvars.c:ExprGVars" );1083InitGlobalBag( &CopiesGVars,1084"src/gvars.c:CopiesGVars" );1085InitGlobalBag( &FopiesGVars,1086"src/gvars.c:FopiesGVars" );1087InitGlobalBag( &TableGVars,1088"src/gvars.c:TableGVars" );1089InitGlobalBag( &CurrNamespace,1090"src/gvars.c:CurrNamespace" );10911092InitHandlerFunc( ErrorMustEvalToFuncHandler,1093"src/gvars.c:ErrorMustEvalToFuncHandler" );1094InitHandlerFunc( ErrorMustHaveAssObjHandler,1095"src/gvars.c:ErrorMustHaveAssObjHandler" );10961097/* init filters and functions */1098InitHdlrFuncsFromTable( GVarFuncs );10991100/* Get a copy of REREADING */1101ImportGVarFromLibrary("REREADING", &REREADING);110211031104/* return success */1105return 0;1106}110711081109/****************************************************************************1110**1111*F PostRestore( <module> ) . . . . . . . . . . . . . after restore workspace1112*/11131114static Int PostRestore (1115StructInitInfo * module )1116{1117/* make the lists for global variables */1118CountGVars = LEN_PLIST( ValGVars );1119PtrGVars = ADDR_OBJ( ValGVars );1120SizeGVars = LEN_PLIST( TableGVars );11211122/* create the global variable '~' */1123Tilde = GVarName( "~" );112411251126/* update fopies and copies */1127UpdateCopyFopyInfo();11281129/* return success */1130return 0;1131}11321133/****************************************************************************1134**1135*F PreSave( <module> ) . . . . . . . . . . . . . before save workspace1136*/1137static Int PreSave (1138StructInitInfo * module )1139{1140RemoveCopyFopyInfo();1141return 0;1142}11431144/****************************************************************************1145**1146*F PostSave( <module> ) . . . . . . . . . . . . . aftersave workspace1147*/1148static Int PostSave (1149StructInitInfo * module )1150{1151UpdateCopyFopyInfo();1152return 0;1153}115411551156/****************************************************************************1157**1158*F InitLibrary( <module> ) . . . . . . . initialise library data structures1159*/1160static Int InitLibrary (1161StructInitInfo * module )1162{1163/* make the error functions for 'AssGVar' */1164ErrorMustEvalToFuncFunc = NewFunctionC(1165"ErrorMustEvalToFunc", -1,"args", ErrorMustEvalToFuncHandler );11661167ErrorMustHaveAssObjFunc = NewFunctionC(1168"ErrorMustHaveAssObj", -1L,"args", ErrorMustHaveAssObjHandler );11691170/* make the lists for global variables */1171ValGVars = NEW_PLIST( T_PLIST, 0 );1172SET_LEN_PLIST( ValGVars, 0 );11731174NameGVars = NEW_PLIST( T_PLIST, 0 );1175SET_LEN_PLIST( NameGVars, 0 );11761177WriteGVars = NEW_PLIST( T_PLIST, 0 );1178SET_LEN_PLIST( WriteGVars, 0 );11791180ExprGVars = NEW_PLIST( T_PLIST, 0 );1181SET_LEN_PLIST( ExprGVars, 0 );11821183CopiesGVars = NEW_PLIST( T_PLIST, 0 );1184SET_LEN_PLIST( CopiesGVars, 0 );11851186FopiesGVars = NEW_PLIST( T_PLIST, 0 );1187SET_LEN_PLIST( FopiesGVars, 0 );11881189/* make the list of global variables */1190SizeGVars = 997;1191TableGVars = NEW_PLIST( T_PLIST, SizeGVars );1192SET_LEN_PLIST( TableGVars, SizeGVars );11931194/* Create the current namespace: */1195TLS(CurrNamespace) = NEW_STRING(0);1196SET_LEN_STRING(TLS(CurrNamespace),0);11971198/* fix C vars */1199PostRestore( module );12001201/* init filters and functions */1202InitGVarFuncsFromTable( GVarFuncs );12031204/* return success */1205return 0;1206}120712081209/****************************************************************************1210**1211*F CheckInit( <module> ) . . . . . . . . . . . . . . . check initialisation1212*/1213static Int CheckInit (1214StructInitInfo * module )1215{1216Int success = 1;12171218if ( NCopyAndFopyGVars != NCopyAndFopyDone ) {1219success = 0;1220Pr( "#W failed to updated copies and fopies\n", 0L, 0L );1221}12221223/* return success */1224return ! success;1225}122612271228/****************************************************************************1229**1230*F InitInfoGVars() . . . . . . . . . . . . . . . . . table of init functions1231*/1232static StructInitInfo module = {1233MODULE_BUILTIN, /* type */1234"gvars", /* name */12350, /* revision entry of c file */12360, /* revision entry of h file */12370, /* version */12380, /* crc */1239InitKernel, /* initKernel */1240InitLibrary, /* initLibrary */1241CheckInit, /* checkInit */1242PreSave, /* preSave */1243PostSave, /* postSave */1244PostRestore /* postRestore */1245};12461247StructInitInfo * InitInfoGVars ( void )1248{1249return &module;1250}125112521253/****************************************************************************1254**12551256*E gvars.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here1257*/125812591260