UInt completion_rnam ( Char * name, UInt len ) { const Char * curr; const Char * next; UInt i, k; const UInt countRNam = LEN_PLIST(NamesRNam); next = 0; for ( i = 1; i <= countRNam; i++ ) { curr = CONST_CSTR_STRING( NAME_RNAM( i ) ); for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ; if ( k < len || curr[k] <= name[k] ) continue; if ( next != 0 ) { for ( k = 0; curr[k] != '\0' && curr[k] == next[k]; k++ ) ; if ( k < len || next[k] < curr[k] ) continue; } next = curr; } if ( next != 0 ) { for ( k = 0; next[k] != '\0'; k++ ) name[k] = next[k]; name[k] = '\0'; } return next != 0; }
static void ReadBytesNativeString(void * addr, UInt size) { Obj str = MODULE_STATE(Serialize).obj; UInt max = GET_LEN_STRING(str); UInt off = MODULE_STATE(Serialize).index; if (off + size > max) DeserializationError(); memcpy(addr, CONST_CSTR_STRING(str) + off, size); MODULE_STATE(Serialize).index += size; }
/**************************************************************************** ** *F iscomplete( <name>, <len> ) . . . . . . . . find the completions of name *F completion( <name>, <len> ) . . . . . . . . find the completions of name */ UInt iscomplete_rnam ( Char * name, UInt len ) { const Char * curr; UInt i, k; const UInt countRNam = LEN_PLIST(NamesRNam); for ( i = 1; i <= countRNam; i++ ) { curr = CONST_CSTR_STRING( NAME_RNAM( i ) ); for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ; if ( k == len && curr[k] == '\0' ) return 1; } return 0; }
/**************************************************************************** ** *F RNamObj(<obj>) . . . . . . . . . . . convert an object to a record name ** ** 'RNamObj' returns the record name corresponding to the object <obj>, ** which currently must be a string or an integer. */ UInt RNamObj ( Obj obj ) { /* convert integer object */ if ( IS_INTOBJ(obj) ) { return RNamIntg( INT_INTOBJ(obj) ); } /* convert string object (empty string may have type T_PLIST) */ else if ( IsStringConv(obj) && IS_STRING_REP(obj) ) { return RNamName( CONST_CSTR_STRING(obj) ); } /* otherwise fail */ else { Obj err; err = ErrorReturnObj( "Record: '<rec>.(<obj>)' <obj> must be a string or an integer", 0L, 0L, "you can replace <obj> via 'return <obj>;'" ); return RNamObj( err ); } }
static UInt GetNumber(Int readDecimalPoint) { UInt symbol = S_ILLEGAL; UInt i = 0; Char c; UInt seenADigit = 0; UInt seenExp = 0; UInt seenExpDigit = 0; STATE(ValueObj) = 0; c = PEEK_CURR_CHAR(); if (readDecimalPoint) { STATE(Value)[i++] = '.'; } else { // read initial sequence of digits into 'Value' while (IsDigit(c)) { i = AddCharToValue(i, c); seenADigit = 1; c = GET_NEXT_CHAR(); } // maybe we saw an identifier character and realised that this is an // identifier we are reading if (IsIdent(c) || c == '\\') { // if necessary, copy back from STATE(ValueObj) to STATE(Value) if (STATE(ValueObj)) { i = GET_LEN_STRING(STATE(ValueObj)); GAP_ASSERT(i >= MAX_VALUE_LEN - 1); memcpy(STATE(Value), CONST_CSTR_STRING(STATE(ValueObj)), MAX_VALUE_LEN); STATE(ValueObj) = 0; } // this looks like an identifier, scan the rest of it return GetIdent(i); } // Or maybe we saw a '.' which could indicate one of two things: a // float literal or S_DOT, i.e., '.' used to access a record entry. if (c == '.') { GAP_ASSERT(i < MAX_VALUE_LEN - 1); // If the symbol before this integer was S_DOT then we must be in // a nested record element expression, so don't look for a float. // This is a bit fragile if (STATE(Symbol) == S_DOT || STATE(Symbol) == S_BDOT) { symbol = S_INT; goto finish; } // peek ahead to decide which if (PEEK_NEXT_CHAR() == '.') { // It was '.', so this looks like '..' and we are probably // inside a range expression. symbol = S_INT; goto finish; } // Now the '.' must be part of our number; store it and move on i = AddCharToValue(i, '.'); c = GET_NEXT_CHAR(); } else { // Anything else we see tells us that the token is done symbol = S_INT; goto finish; } } // When we get here we have read possibly some digits, a . and possibly // some more digits, but not an e,E,d,D,q or Q // read digits while (IsDigit(c)) { i = AddCharToValue(i, c); seenADigit = 1; c = GET_NEXT_CHAR(); } if (!seenADigit) SyntaxError("Badly formed number: need a digit before or after the " "decimal point"); if (c == '\\') SyntaxError("Badly formed number"); // If we found an identifier type character in this context could be an // error or the start of one of the allowed trailing marker sequences if (IsIdent(c) && c != 'e' && c != 'E' && c != 'd' && c != 'D' && c != 'q' && c != 'Q') { // Allow one letter on the end of the numbers -- could be an i, C99 // style if (IsAlpha(c)) { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } // independently of that, we allow an _ signalling immediate conversion if (c == '_') { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); // After which there may be one character signifying the // conversion style if (IsAlpha(c)) { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } } // Now if the next character is alphanumerical, or an identifier type // symbol then we really do have an error, otherwise we return a result if (IsIdent(c) || IsDigit(c)) { SyntaxError("Badly formed number"); } else { symbol = S_FLOAT; goto finish; } } // If the next thing is the start of the exponential notation, read it now. if (IsAlpha(c)) { if (!seenADigit) SyntaxError("Badly formed number: need a digit before or after " "the decimal point"); seenExp = 1; i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); if (c == '+' || c == '-') { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } } // Either we saw an exponent indicator, or we hit end of token deal with // the end of token case if (!seenExp) { if (!seenADigit) SyntaxError("Badly formed number: need a digit before or after " "the decimal point"); // Might be a conversion marker if (IsAlpha(c) && c != 'e' && c != 'E' && c != 'd' && c != 'D' && c != 'q' && c != 'Q') { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } // independently of that, we allow an _ signalling immediate conversion if (c == '_') { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); // After which there may be one character signifying the // conversion style if (IsAlpha(c)) i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } // Now if the next character is alphanumerical, or an identifier type // symbol then we really do have an error, otherwise we return a result if (!IsIdent(c) && !IsDigit(c)) { symbol = S_FLOAT; goto finish; } SyntaxError("Badly formed number"); } // Here we are into the unsigned exponent of a number in scientific // notation, so we just read digits while (IsDigit(c)) { i = AddCharToValue(i, c); seenExpDigit = 1; c = GET_NEXT_CHAR(); } // Look out for a single alphabetic character on the end // which could be a conversion marker if (seenExpDigit) { if (IsAlpha(c)) { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); symbol = S_FLOAT; goto finish; } if (c == '_') { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); // After which there may be one character signifying the // conversion style if (IsAlpha(c)) { i = AddCharToValue(i, c); c = GET_NEXT_CHAR(); } symbol = S_FLOAT; goto finish; } } // Otherwise this is the end of the token if (!seenExpDigit) SyntaxError( "Badly formed number: need at least one digit in the exponent"); symbol = S_FLOAT; finish: i = AddCharToValue(i, '\0'); if (STATE(ValueObj)) { // flush buffer AppendBufToString(STATE(ValueObj), STATE(Value), i - 1); } return symbol; }
UInt RNamNameWithLen(const Char * name, UInt len) { Obj rnam; /* record name (as imm intobj) */ UInt pos; /* hash position */ Char namx [1024]; /* temporary copy of <name> */ Obj string; /* temporary string object <name> */ Obj table; /* temporary copy of <HashRNam> */ Obj rnam2; /* one element of <table> */ UInt i; /* loop variable */ UInt sizeRNam; if (len > 1023) { // Note: We can't pass 'name' here, as it might get moved by garbage collection ErrorQuit("Record names must consist of at most 1023 characters", 0, 0); } /* start looking in the table at the following hash position */ const UInt hash = HashString( name, len ); #ifdef HPCGAP HPC_LockNames(0); /* try a read lock first */ #endif /* look through the table until we find a free slot or the global */ sizeRNam = LEN_PLIST(HashRNam); pos = (hash % sizeRNam) + 1; while ( (rnam = ELM_PLIST( HashRNam, pos )) != 0 && !EqString( NAME_RNAM( INT_INTOBJ(rnam) ), name, len ) ) { pos = (pos % sizeRNam) + 1; } if (rnam != 0) { #ifdef HPCGAP HPC_UnlockNames(); #endif return INT_INTOBJ(rnam); } #ifdef HPCGAP if (!PreThreadCreation) { HPC_UnlockNames(); /* switch to a write lock */ HPC_LockNames(1); /* look through the table until we find a free slot or the global */ sizeRNam = LEN_PLIST(HashRNam); pos = (hash % sizeRNam) + 1; while ( (rnam = ELM_PLIST( HashRNam, pos )) != 0 && !EqString( NAME_RNAM( INT_INTOBJ(rnam) ), name, len ) ) { pos = (pos % sizeRNam) + 1; } } if (rnam != 0) { HPC_UnlockNames(); return INT_INTOBJ(rnam); } #endif /* if we did not find the global variable, make a new one and enter it */ /* (copy the name first, to avoid a stale pointer in case of a GC) */ memcpy( namx, name, len ); namx[len] = 0; string = MakeImmString(namx); const UInt countRNam = PushPlist(NamesRNam, string); rnam = INTOBJ_INT(countRNam); SET_ELM_PLIST( HashRNam, pos, rnam ); /* if the table is too crowded, make a larger one, rehash the names */ if ( sizeRNam < 3 * countRNam / 2 ) { table = HashRNam; sizeRNam = 2 * sizeRNam + 1; HashRNam = NEW_PLIST( T_PLIST, sizeRNam ); SET_LEN_PLIST( HashRNam, sizeRNam ); #ifdef HPCGAP /* The list is briefly non-public, but this is safe, because * the mutex protects it from being accessed by other threads. */ MakeBagPublic(HashRNam); #endif for ( i = 1; i <= (sizeRNam-1)/2; i++ ) { rnam2 = ELM_PLIST( table, i ); if ( rnam2 == 0 ) continue; string = NAME_RNAM( INT_INTOBJ(rnam2) ); pos = HashString( CONST_CSTR_STRING( string ), GET_LEN_STRING( string) ); pos = (pos % sizeRNam) + 1; while ( ELM_PLIST( HashRNam, pos ) != 0 ) { pos = (pos % sizeRNam) + 1; } SET_ELM_PLIST( HashRNam, pos, rnam2 ); } } #ifdef HPCGAP HPC_UnlockNames(); #endif /* return the record name */ return INT_INTOBJ(rnam); }
static inline int EqString(Obj str, const Char * name, UInt len) { if (GET_LEN_STRING(str) != len) return 0; return memcmp(CONST_CSTR_STRING(str), name, len) == 0; }