/* * CL_ResolveMasterAddress */ static void CL_ResolveMasterAddress( const char *master, netadr_t *adr ) { trie_error_t err; masteradrcache_t *cache; // check memory cache err = Trie_Find( serverlist_masters_trie, master, TRIE_EXACT_MATCH, (void **)&cache ); if( err == TRIE_OK ) { if( adr ) *adr = cache->adr; return; } // send a unicast packet cache = Mem_ZoneMalloc( sizeof( *cache ) ); NET_StringToAddress( master, &cache->adr ); if( adr ) *adr = cache->adr; cache->next = serverlist_masters_head; serverlist_masters_head = cache; Trie_Insert( serverlist_masters_trie, master, (void *)cache ); }
/* * ML_AddMap * Handles assigning memory for map and adding it to the list * in alphabetical order */ static void ML_AddMap( const char *filename, const char *fullname ) { mapinfo_t *map; char *buffer; char fullname_[MAX_CONFIGSTRING_CHARS]; if( !ML_ValidateFilename( filename ) ) return; if( !strcmp(filename, "ui") ) return; if( !fullname ) { ML_GetFullnameFromMap( filename, fullname_, sizeof( fullname_ ) ); fullname = fullname_; } if( !ML_ValidateFullname( fullname ) && *fullname ) // allow empty fullnames return; if( !strcmp(fullname, "ui") ) return; ml_flush = true; // tell everyone that maplist has changed buffer = ( char* )Mem_ZoneMalloc( sizeof( mapinfo_t ) + strlen( filename ) + 1 + strlen( fullname ) + 1 ); map = ( mapinfo_t * )buffer; buffer += sizeof( mapinfo_t ); map->filename = buffer; strcpy( map->filename, filename ); COM_StripExtension( map->filename ); buffer += strlen( filename ) + 1; map->fullname = buffer; strcpy( map->fullname, fullname ); COM_RemoveColorTokens( map->fullname ); Q_strlwr( map->fullname ); Trie_Insert( mlist_filenames_trie, map->filename, map ); Trie_Insert( mlist_fullnames_trie, map->fullname, map ); map->next = maplist; maplist = map; }
/* ## FT.SUGGADD key string score [INCR] [PAYLOAD {payload}] Add a suggestion string to an auto-complete suggestion dictionary. This is disconnected from the index definitions, and leaves creating and updating suggestino dictionaries to the user. ### Parameters: - key: the suggestion dictionary key. - string: the suggestion string we index - score: a floating point number of the suggestion string's weight -INCR: if set, we increment the existing entry of the suggestion by the given score, instead of replacing the score. This is useful for updating the dictionary based on user queries in real time - PAYLOAD: Add a payload to the suggestion string that will be used as additional information. ### Returns: Integer reply: the current size of the suggestion dictionary. */ int RSSuggestAddCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc < 4 || argc > 7) { return RedisModule_WrongArity(ctx); } int incr = 0, rv = AC_OK; RSPayload payload = {0}; ArgsCursor ac = {0}; ArgsCursor_InitRString(&ac, argv + 4, argc - 4); while (!AC_IsAtEnd(&ac)) { const char *s = AC_GetStringNC(&ac, NULL); if (!strcasecmp(s, "INCR")) { incr = 1; } else if (!strcasecmp(s, "PAYLOAD")) { if ((rv = AC_GetString(&ac, (const char **)&payload.data, &payload.len, 0)) != AC_OK) { return RMUtil_ReplyWithErrorFmt(ctx, "Invalid payload: %s", AC_Strerror(rv)); } } else { return RMUtil_ReplyWithErrorFmt(ctx, "Unknown argument `%s`", s); } } RedisModule_AutoMemory(ctx); /* Use automatic memory management. */ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); int type = RedisModule_KeyType(key); if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != TrieType) { return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); } RedisModuleString *val = argv[2]; double score; if ((RedisModule_StringToDouble(argv[3], &score) != REDISMODULE_OK)) { return RedisModule_ReplyWithError(ctx, "ERR invalid score"); } /* Create an empty value object if the key is currently empty. */ Trie *tree; if (type == REDISMODULE_KEYTYPE_EMPTY) { tree = NewTrie(); RedisModule_ModuleTypeSetValue(key, TrieType, tree); } else { tree = RedisModule_ModuleTypeGetValue(key); } /* Insert the new element. */ Trie_Insert(tree, val, score, incr, &payload); RedisModule_ReplyWithLongLong(ctx, tree->size); RedisModule_ReplicateVerbatim(ctx); return REDISMODULE_OK; }
/* * CL_ResolveMasterAddress */ static void CL_ResolveMasterAddress( const char *master ) { netadr_t adr, *padr; if( master && *master ) { NET_StringToAddress( master, &adr ); QMutex_Lock( resolveLock ); padr = ( netadr_t * )malloc( sizeof( adr ) ); *padr = adr; Trie_Insert( serverlist_masters_trie, master, padr ); QMutex_Unlock( resolveLock ); } }
dynvar_t *Dynvar_Create( const char *name, qboolean console, dynvar_getter_f getter, dynvar_setter_f setter ) { assert( dynvar_trie ); if( name && getter && setter ) { dynvar_t *dynvar = Dynvar_NewDynvar( name, console, getter, setter ); if( Trie_Insert( dynvar_trie, name, dynvar ) == TRIE_OK ) return dynvar; else Dynvar_FreeDynvar( dynvar ); } return NULL; }
/* * Cvar_Get * Creates the variable if it doesn't exist. * If the variable already exists, the value will not be set * The flags will be or'ed and default value overwritten in if the variable exists. */ cvar_t *Cvar_Get( const char *var_name, const char *var_value, cvar_flag_t flags ) { cvar_t *var; if( !var_name || !var_name[0] ) return NULL; if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) || Cvar_FlagIsSet( flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( var_name, qtrue ) ) { Com_Printf( "invalid info cvar name\n" ); return NULL; } } assert( cvar_trie ); Trie_Find( cvar_trie, var_name, TRIE_EXACT_MATCH, (void **)&var ); if( var ) { assert( var_value ); if( !var->dvalue || strcmp( var->dvalue, var_value ) ) { if( var->dvalue ) Mem_ZoneFree( var->dvalue ); // free the old default value string var->dvalue = ZoneCopyString( (char *) var_value ); } #ifdef PUBLIC_BUILD if( Cvar_FlagIsSet( flags, CVAR_READONLY ) || Cvar_FlagIsSet( flags, CVAR_DEVELOPER ) ) { #else if( Cvar_FlagIsSet( flags, CVAR_READONLY ) ) { #endif if( !var->string || strcmp( var->string, var_value ) ) { if( var->string ) Mem_ZoneFree( var->string ); var->string = ZoneCopyString( (char *) var_value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); } var->flags = flags; } if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) && !Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) ) userinfo_modified = qtrue; // transmit at next oportunity Cvar_FlagSet( &var->flags, flags ); return var; } if( !var_value ) return NULL; if( Cvar_FlagIsSet( flags, CVAR_USERINFO ) || Cvar_FlagIsSet( flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( var_value, qfalse ) ) { Com_Printf( "invalid info cvar value\n" ); return NULL; } } var = Mem_ZoneMalloc( (int)( sizeof( *var ) + strlen( var_name ) + 1 ) ); var->name = (char *)( (qbyte *)var + sizeof( *var ) ); strcpy( var->name, var_name ); var->dvalue = ZoneCopyString( (char *) var_value ); var->string = ZoneCopyString( (char *) var_value ); Cvar_SetModified( var ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); var->flags = flags; Trie_Insert( cvar_trie, var_name, var ); return var; } /* * Cvar_Set2 */ static cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { cvar_t *var = Cvar_Find( var_name ); if( !var ) { // create it return Cvar_Get( var_name, value, 0 ); } if( Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) || Cvar_FlagIsSet( var->flags, CVAR_SERVERINFO ) ) { if( !Cvar_InfoValidate( value, qfalse ) ) { Com_Printf( "invalid info cvar value\n" ); return var; } } if( !force ) { #ifdef PUBLIC_BUILD if( Cvar_FlagIsSet( var->flags, CVAR_NOSET ) || Cvar_FlagIsSet( var->flags, CVAR_READONLY ) || Cvar_FlagIsSet( var->flags, CVAR_DEVELOPER ) ) { #else if( Cvar_FlagIsSet( var->flags, CVAR_NOSET ) || Cvar_FlagIsSet( var->flags, CVAR_READONLY ) ) { #endif Com_Printf( "%s is write protected.\n", var_name ); return var; } if( Cvar_FlagIsSet( var->flags, CVAR_CHEAT ) && strcmp( value, var->dvalue ) ) { if( !Cvar_CheatsAllowed() ) { Com_Printf( "%s is cheat protected.\n", var_name ); return var; } } if( Cvar_FlagIsSet( var->flags, CVAR_LATCH ) || Cvar_FlagIsSet( var->flags, CVAR_LATCH_VIDEO ) || Cvar_FlagIsSet( var->flags, CVAR_LATCH_SOUND ) ) { if( var->latched_string ) { if( !strcmp( value, var->latched_string ) ) return var; Mem_ZoneFree( var->latched_string ); } else { if( !strcmp( value, var->string ) ) return var; } if( Com_ServerState() ) { Com_Printf( "%s will be changed upon restarting.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else { if( Cvar_FlagIsSet( var->flags, CVAR_LATCH_VIDEO ) ) { Com_Printf( "%s will be changed upon restarting video.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else if( Cvar_FlagIsSet( var->flags, CVAR_LATCH_SOUND ) ) { Com_Printf( "%s will be changed upon restarting sound.\n", var->name ); var->latched_string = ZoneCopyString( (char *) value ); } else { if( !strcmp( var->name, "fs_game" ) ) { FS_SetGameDirectory( value, qfalse ); return var; } Mem_ZoneFree( var->string ); // free the old value string var->string = ZoneCopyString( value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); Cvar_SetModified( var ); } } return var; } } else { if( var->latched_string ) { Mem_ZoneFree( var->latched_string ); var->latched_string = NULL; } } if( !strcmp( value, var->string ) ) return var; // not changed Cvar_SetModified( var ); if( Cvar_FlagIsSet( var->flags, CVAR_USERINFO ) ) userinfo_modified = qtrue; // transmit at next oportunity Mem_ZoneFree( var->string ); // free the old value string var->string = ZoneCopyString( (char *) value ); var->value = atof( var->string ); var->integer = Q_rint( var->value ); return var; } /* * Cvar_ForceSet * Set the variable even if NOSET or LATCH */ cvar_t *Cvar_ForceSet( const char *var_name, const char *value ) { return Cvar_Set2( var_name, value, qtrue ); } /* * Cvar_Set * Create the variable if it doesn't exist */ cvar_t *Cvar_Set( const char *var_name, const char *value ) { return Cvar_Set2( var_name, value, qfalse ); } /* * Cvar_FullSet */ cvar_t *Cvar_FullSet( const char *var_name, const char *value, cvar_flag_t flags, qboolean overwrite_flags ) { cvar_t *var; var = Cvar_Find( var_name ); if( !var ) return Cvar_Get( var_name, value, flags ); if( overwrite_flags ) { var->flags = flags; } else { Cvar_FlagSet( &var->flags, flags ); } // if we overwrite the flags, we will also force the value return Cvar_Set2( var_name, value, overwrite_flags ); }
/* * L10n_ParsePOFile * * Doesn't allocate memory, writes to input buffer, which * should NOT be freed after calling this function. */ static trie_t *L10n_ParsePOFile( const char *filepath, char *buffer, int length ) { int linenum = 0; char *start = buffer, *end = buffer + length; char *cur, *eol; qboolean have_msgid, have_msgstr, error; char *msgid, *msgstr, *instr, *outstr; size_t str_length; trie_t *dict; trie_error_t tr_err; tr_err = Trie_Create( TRIE_CASE_SENSITIVE, &dict ); if( tr_err != TRIE_OK ) { return NULL; } have_msgid = have_msgstr = qfalse; instr = outstr = buffer; msgid = msgstr = buffer; eol = end; for( cur = start; cur >= start && cur < end; cur = eol + 1 ) { if( !*cur ) { break; } linenum++; // skip whitespaces while( *cur == ' ' || *cur == '\t' ) { cur++; } // find the end of line eol = strchr( cur, '\n' ); if( eol ) { char *prev = eol - 1; *eol = '\0'; if( *prev == '\r' ) { *prev = '\0'; } } if( *cur == '#' ) { continue; } if( !*cur ) { // empty line continue; } parse_cmd: // search for msgid "id" if( !strncmp( cur, "msgid ", 6 ) ) { if( have_msgstr ) { Trie_Insert( dict, msgid, ( void * )msgstr ); have_msgid = have_msgstr = qfalse; } have_msgid = qtrue; instr = cur + 6; outstr = cur + 5; msgid = outstr; *msgid = '\0'; } else if( have_msgid && !strncmp( cur, "msgstr ", 7 ) ) { have_msgstr = qtrue; instr = cur + 7; outstr = cur + 6; msgstr = outstr; *msgstr = '\0'; } else { // multiline? if( have_msgid || have_msgstr ) { if( *cur != '"' || !strrchr( cur+1, '"') ) { if( have_msgstr ) { Trie_Insert( dict, msgid, ( void * )msgstr ); } // no have_msgid = have_msgstr = qfalse; goto parse_cmd; } // yes instr = cur; } else { continue; } } // parse single line of C-style string str_length = L10n_ParsePOString( instr, outstr, &error ); if( !str_length ) { have_msgid = have_msgstr = qfalse; if( error ) { Com_Printf( S_COLOR_YELLOW "Error parsing line %i of %s: syntax error near '%s'\n", linenum, filepath, instr ); } } else { // shift the output buffer so that in case multiline string // is ecountered it'll be properly appended outstr += str_length; } } if( have_msgstr ) { Trie_Insert( dict, msgid, ( void * )msgstr ); } return dict; }