/** * @brief A complete command line has been parsed, so try to execute it * @todo lookupnoadd the token to speed search? */ void Cmd_ExecuteString (const char *text) { const cmd_function_t *cmd; const cmd_alias_t *a; const char *str; unsigned int hash; Com_DPrintf(DEBUG_COMMANDS, "ExecuteString: '%s'\n", text); Cmd_TokenizeString(text, qtrue); /* execute the command line */ if (!Cmd_Argc()) /* no tokens */ return; str = Cmd_Argv(0); /* check functions */ hash = Com_HashKey(str, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (!Q_strcasecmp(str, cmd->name)) { if (!cmd->function) { /* forward to server command */ Cmd_ExecuteString(va("cmd %s", text)); } else { cmd_userdata = cmd->userdata; cmd->function(); } return; } } /* check alias */ hash = Com_HashKey(str, ALIAS_HASH_SIZE); for (a = cmd_alias_hash[hash]; a; a = a->hash_next) { if (!Q_strcasecmp(str, a->name)) { if (++alias_count == ALIAS_LOOP_COUNT) { Com_Printf("ALIAS_LOOP_COUNT\n"); return; } Cbuf_InsertText(a->value); return; } } /* check cvars */ if (Cvar_Command()) return; /* send it as a server command if we are connected */ Cmd_ForwardToServer(); }
/* =========== Cvar_Get =========== */ cvar_t *Cvar_Get (const char *name, const char *string, int cvarflags) { cvar_t *var; int key; var = Cvar_Find(name); if (var) { var->flags &= ~CVAR_TEMP; var->flags |= cvarflags; return var; } // allocate a new cvar var = (cvar_t *) Q_malloc (sizeof(cvar_t)); // link it in var->next = cvar_vars; cvar_vars = var; key = Com_HashKey (name); var->hash_next = cvar_hash[key]; cvar_hash[key] = var; // Q_malloc returns unitialized memory, so make sure all fields // are initialized here var->name = Q_strdup (name); var->string = Q_strdup (string); var->flags = cvarflags | CVAR_DYNAMIC; var->value = Q_atof (var->string); var->OnChange = NULL; // FIXME, check userinfo/serverinfo return var; }
/* ================== S_AliasName ================== */ static sfx_t *S_AliasName (const char *aliasname, const char *truename) { sfx_t *sfx; int i; unsigned int hash; // find a free sfx for (i = 0; i < num_sfx; i++) { if (!known_sfx[i].name[0]) break; } if (i == num_sfx) { if (num_sfx == MAX_SFX) Com_Error (ERR_FATAL, "S_AliasName: out of sfx_t"); num_sfx++; } sfx = &known_sfx[i]; //memset (sfx, 0, sizeof(*sfx)); sfx->cache = NULL; strcpy(sfx->name, aliasname); sfx->registration_sequence = s_registration_sequence; sfx->truename = CopyString (truename, TAG_CL_SFX); hash = Com_HashKey(aliasname, SND_HASH_SIZE); sfx->hashNext = sfx_hash[hash]; sfx_hash[hash] = sfx; return sfx; }
/* ============ Cmd_AddCommand ============ */ void Cmd_AddCommand (const char *cmd_name, xcommand_t function) { cmd_function_t *cmd; int key; if (host_initialized) // because hunk allocation would get stomped Sys_Error ("Cmd_AddCommand after host_initialized"); // fail if the command is a variable name if (Cvar_Find(cmd_name)) { Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name); return; } key = Com_HashKey (cmd_name); // fail if the command already exists for (cmd=cmd_hash_array[key] ; cmd ; cmd=cmd->hash_next) { if (!strcasecmp (cmd_name, cmd->name)) { Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); return; } } cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t)); cmd->name = cmd_name; cmd->function = function; cmd->next = cmd_functions; cmd_functions = cmd; cmd->hash_next = cmd_hash_array[key]; cmd_hash_array[key] = cmd; }
cvar_t *Cvar_Create (char *name, char *string, int cvarflags) { cvar_t *v; int key; if ((v = Cvar_Find(name))) { v->flags &= ~CVAR_TEMP; v->flags |= cvarflags; return v; } v = (cvar_t *) Q_malloc(sizeof(cvar_t)); memset(v, 0, sizeof(cvar_t)); // Cvar doesn't exist, so we create it v->next = cvar_vars; cvar_vars = v; key = Com_HashKey (name) % VAR_HASHPOOL_SIZE; v->hash_next = cvar_hash[key]; cvar_hash[key] = v; v->name = Q_strdup(name); v->string = Q_strdup(string); v->defaultvalue = Q_strdup(string); v->flags = cvarflags | CVAR_USER_CREATED; v->value = Q_atof (v->string); v->integer = Q_atoi (v->string); StringToRGB_W(v->string, v->color); v->modified = true; #ifdef WITH_TCL TCL_RegisterVariable (v); #endif return v; }
/** * @brief Removes a command from script interface * @param[in] cmd_name The script interface function name to remove * @sa Cmd_AddCommand */ void Cmd_RemoveCommand (const char *cmd_name) { cmd_function_t *cmd, **back; unsigned int hash; hash = Com_HashKey(cmd_name, CMD_HASH_SIZE); back = &cmd_functions_hash[hash]; while (1) { cmd = *back; if (!cmd) { Com_Printf("Cmd_RemoveCommand: %s not added\n", cmd_name); return; } if (!Q_strcasecmp(cmd_name, cmd->name)) { *back = cmd->hash_next; break; } back = &cmd->hash_next; } back = &cmd_functions; while (1) { cmd = *back; if (!cmd) { Com_Printf("Cmd_RemoveCommand: %s not added\n", cmd_name); return; } if (Q_streq(cmd_name, cmd->name)) { *back = cmd->next; Mem_Free(cmd); return; } back = &cmd->next; } }
/** * @brief Returns the command description for a given command * @param[in] cmd_name Command id in global command array * @note never returns a NULL pointer * @todo - search alias, too */ const char* Cmd_GetCommandDesc (const char* cmd_name) { cmd_function_t *cmd; char *sep = NULL; unsigned int hash; char searchName[MAX_VAR]; /* remove parameters */ Q_strncpyz(searchName, cmd_name, sizeof(searchName)); sep = strstr(searchName, " "); if (sep) *sep = '\0'; /* fail if the command already exists */ hash = Com_HashKey(searchName, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (Q_streq(searchName, cmd->name)) { if (cmd->description) return cmd->description; else return ""; } } return ""; }
/** * @brief Add a new command to the script interface * @param[in] cmd_name The name the command is available via script interface * @param[in] function The function pointer * @param[in] desc A usually(?) one-line description of what the cmd does * @sa Cmd_RemoveCommand */ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc) { cmd_function_t *cmd; unsigned int hash; if (!cmd_name || !cmd_name[0]) return; /* fail if the command is a variable name */ if (Cvar_GetString(cmd_name)[0]) { Com_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); return; } /* fail if the command already exists */ hash = Com_HashKey(cmd_name, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (Q_streq(cmd_name, cmd->name)) { Com_DPrintf(DEBUG_COMMANDS, "Cmd_AddCommand: %s already defined\n", cmd_name); return; } } cmd = (cmd_function_t *)Mem_PoolAlloc(sizeof(*cmd), com_cmdSysPool, 0); cmd->name = cmd_name; cmd->description = desc; cmd->function = function; cmd->completeParam = NULL; HASH_Add(cmd_functions_hash, cmd, hash); cmd->next = cmd_functions; cmd_functions = cmd; }
/* ============ PR_FindDef Returns NULL if no matching def is found ============ */ def_t *PR_FindDef (char *name, def_t *scope) { int hash = Com_HashKey (name); if (scope) { // search local defs first for (def_t *def = pr.def_hash_head[hash].hash_next ; def ; def = def->hash_next) { if (def->visscope != scope) continue; // in a different function, or global if (strcmp(def->name, name)) continue; // found it return def; } } // search global defs for (def_t *def = pr.def_hash_head[hash].hash_next ; def ; def = def->hash_next) { if (def->visscope) continue; // a local def if (strcmp(def->name, name)) continue; // found it return def; } return NULL; }
/* ============== RE_GetSkinModel ============== */ qboolean RE_GetSkinModel( qhandle_t skinid, const char *type, char *name ) { int i; int hash; skin_t *skin; skin = tr.skins[ skinid ]; hash = Com_HashKey( ( char * ) type, strlen( type ) ); for ( i = 0; i < skin->numModels; i++ ) { if ( hash != skin->models[ i ]->hash ) { continue; } if ( !Q_stricmp( skin->models[ i ]->type, type ) ) { // (SA) whoops, should've been this way Q_strncpyz( name, skin->models[ i ]->model, sizeof( skin->models[ i ]->model ) ); return qtrue; } } return qfalse; }
/** * @brief Loads and registers a sound file for later use * @param[in] soundFile The name of the soundfile, relative to the sounds dir * @return The index of the loaded sample or 0 * @sa S_LoadSound */ int S_LoadSampleIdx (const char *soundFile) { Mix_Chunk *chunk; s_sample_t *sample; char name[MAX_QPATH]; unsigned hash; if (!s_env.initialized) return 0; Com_StripExtension(soundFile, name, sizeof(name)); sample = S_FindByName(name); if (sample) return sample->index; /* make sure the sound is loaded */ chunk = S_LoadSampleChunk(name); if (!chunk) return 0; /* couldn't load the sound's data */ hash = Com_HashKey(name, SAMPLE_HASH_SIZE); sample = (s_sample_t *)Mem_PoolAlloc(sizeof(*sample), cl_soundSysPool, 0); sample->name = Mem_PoolStrDup(name, cl_soundSysPool, 0); sample->chunk = chunk; sample->hashNext = sampleHash[hash]; sampleHash[hash] = sample; sampleIndex[++sampleIndexLast] = sample; sample->index = sampleIndexLast; return sample->index; }
/** * Register a property name-value to a global structure for all tests * @param name Name of the property * @param value Value of the property. Only the pointer of the value is used. Use it ONLY with stable memory. */ void TEST_RegisterProperty (const char* name, const char* value) { unsigned int hash; test_property_t* element; /* if the alias already exists, reuse it */ hash = Com_HashKey(name, PROPERTY_HASH_SIZE); for (element = test_property_hash[hash]; element; element = element->hash_next) { if (Q_streq(name, element->name)) { break; } } if (!element) { element = (test_property_t*) malloc(sizeof(*element)); Q_strncpyz(element->name, name, sizeof(element->name)); /** TODO maybe copy the value instead of copying the pointer of the value */ element->value = value; element->next = test_property; element->hash_next = test_property_hash[hash]; test_property_hash[hash] = element; test_property = element; Com_Printf("Register test property \"%s\" = \"%s\"\n", name, value); } }
/** * @brief Creates a new command that executes a command string (possibly ; separated) */ static void Cmd_Alias_f (void) { cmd_alias_t *a; char cmd[MAX_STRING_CHARS]; size_t len; unsigned int hash; int i, c; const char *s; if (Cmd_Argc() == 1) { Com_Printf("Current alias commands:\n"); for (a = cmd_alias; a; a = a->next) Com_Printf("%s : %s\n", a->name, a->value); return; } s = Cmd_Argv(1); len = strlen(s); if (len == 0) return; if (len >= MAX_ALIAS_NAME) { Com_Printf("Alias name is too long\n"); return; } /* if the alias already exists, reuse it */ hash = Com_HashKey(s, ALIAS_HASH_SIZE); for (a = cmd_alias_hash[hash]; a; a = a->hash_next) { if (Q_streq(s, a->name)) { Mem_Free(a->value); break; } } if (!a) { a = (cmd_alias_t *)Mem_PoolAlloc(sizeof(*a), com_aliasSysPool, 0); a->next = cmd_alias; /* cmd_alias_hash should be null on the first run */ a->hash_next = cmd_alias_hash[hash]; cmd_alias_hash[hash] = a; cmd_alias = a; } Q_strncpyz(a->name, s, sizeof(a->name)); /* copy the rest of the command line */ cmd[0] = 0; /* start out with a null string */ c = Cmd_Argc(); for (i = 2; i < c; i++) { Q_strcat(cmd, Cmd_Argv(i), sizeof(cmd)); if (i != (c - 1)) Q_strcat(cmd, " ", sizeof(cmd)); } if (Q_streq(Cmd_Argv(0), "aliasa")) a->archive = qtrue; a->value = Mem_PoolStrDup(cmd, com_aliasSysPool, 0); }
/** * @brief Init or return a cvar * @param[in] var_name The cvar name * @param[in] var_value The standard cvar value (will be set if the cvar doesn't exist) * @param[in] flags CVAR_USERINFO, CVAR_LATCH, CVAR_SERVERINFO, CVAR_ARCHIVE and so on * @param[in] desc This is a short description of the cvar (see console command cvarlist) * @note CVAR_ARCHIVE: Cvar will be saved to config.cfg when game shuts down - and * will be reloaded when game starts up the next time * @note CVAR_LATCH: Latched cvars will be updated at the next map load * @note CVAR_SERVERINFO: This cvar will be send in the server info response strings (server browser) * @note CVAR_NOSET: This cvar can not be set from the commandline * @note CVAR_USERINFO: This cvar will be added to the userinfo string when changed (network synced) * @note CVAR_DEVELOPER: Only changeable if we are in development mode * If the variable already exists, the value will not be set * The flags will be or'ed in if the variable exists. */ cvar_t* Cvar_GetOrCreate (const char* var_name, const char* var_value, int flags, const char* desc) { const unsigned hash = Com_HashKey(var_name, CVAR_HASH_SIZE); if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) { if (!Cvar_InfoValidate(var_name)) { Com_Printf("invalid info cvar name\n"); return nullptr; } } if (cvar_t* const var = Cvar_FindVar(var_name)) { if (!var->defaultString && (flags & CVAR_CHEAT)) var->defaultString = Mem_PoolStrDup(var_value, com_cvarSysPool, 0); var->flags |= flags; if (desc) { Mem_Free(var->description); var->description = Mem_PoolStrDup(desc, com_cvarSysPool, 0); } return var; } if (!var_value) return nullptr; if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) { if (!Cvar_InfoValidate(var_value)) { Com_Printf("invalid info cvar value '%s' of cvar '%s'\n", var_value, var_name); return nullptr; } } cvar_t* const var = Mem_PoolAllocType(cvar_t, com_cvarSysPool); var->name = Mem_PoolStrDup(var_name, com_cvarSysPool, 0); var->string = Mem_PoolStrDup(var_value, com_cvarSysPool, 0); var->oldString = nullptr; var->modified = true; var->value = atof(var->string); var->integer = atoi(var->string); if (desc) var->description = Mem_PoolStrDup(desc, com_cvarSysPool, 0); HASH_Add(cvarVarsHash, var, hash); /* link the variable in */ var->next = cvarVars; cvarVars = var; if (var->next) var->next->prev = var; var->flags = flags; if (var->flags & CVAR_CHEAT) var->defaultString = Mem_PoolStrDup(var_value, com_cvarSysPool, 0); for (CvarListeners::iterator i = cvarListeners.begin(); i != cvarListeners.end(); ++i) { (*i)->onCreate(var); } return var; }
/* ============ Cvar_Register Adds a freestanding variable to the variable list. If the variable already exists, the value will not be set The flags will be or'ed in if the variable exists. ============ */ EXTERNC void Cvar_Register (cvar_t *var) { char string[512]; int key; cvar_t *old; // first check to see if it has already been defined old = Cvar_Find (var->name); if (old && !(old->flags & CVAR_DYNAMIC)) { if (old == var) return; Com_Printf ("Can't register variable %s, already defined\n", var->name); return; } #if 0 // check for overlap with a command if (Cmd_Exists (var->name)) { Com_Printf ("Cvar_Register: %s is a command\n", var->name); return; } #endif if (old) { var->flags |= old->flags & ~(CVAR_DYNAMIC|CVAR_TEMP); strlcpy (string, old->string, sizeof(string)); Cvar_Delete (old->name); if (!(var->flags & CVAR_ROM)) var->string = Q_strdup (string); else var->string = Q_strdup (var->string); } else { // allocate the string on heap because future sets will Q_free it var->string = Q_strdup (var->string); } var->value = Q_atof (var->string); // link the variable in key = Com_HashKey (var->name); var->hash_next = cvar_hash[key]; cvar_hash[key] = var; var->next = cvar_vars; cvar_vars = var; #ifndef CLIENTONLY if (var->flags & CVAR_SERVERINFO) SV_ServerinfoChanged (var->name, var->string); #endif #ifndef SERVERONLY if (var->flags & CVAR_USERINFO) CL_UserinfoChanged (var->name, var->string); #endif }
static const char* CL_GetMessageID (const char* id) { const unsigned int hash = Com_HashKey(id, MAX_MSGIDHASH); for (msgid_t** anchor = &msgIDHash[hash]; *anchor; anchor = &(*anchor)->hash_next) { if (Q_streq(id, (*anchor)->id)) return (*anchor)->text; } return id; }
/** * @brief Find or allocate a bucket for an address */ static leakyBucket_t* SVC_BucketForAddress (struct net_stream& address, int burst, int period) { char node[64]; NET_StreamPeerToName(&address, node, sizeof(node), false); const long hash = Com_HashKey(node, MAX_HASHES); const int now = Sys_Milliseconds(); for (leakyBucket_t* bucket = bucketHashes[hash]; bucket; bucket = bucket->next) { if (!Q_streq(bucket->node, node)) continue; return bucket; } for (int i = 0; i < MAX_BUCKETS; i++) { leakyBucket_t* bucket = &buckets[i]; const int interval = now - bucket->lastTime; /* Reclaim expired buckets */ if (bucket->lastTime > 0 && (interval > (burst * period) || interval < 0)) { if (bucket->prev != nullptr) { bucket->prev->next = bucket->next; } else { bucketHashes[bucket->hash] = bucket->next; } if (bucket->next != nullptr) { bucket->next->prev = bucket->prev; } OBJZERO(*bucket); } if (Q_strnull(bucket->node)) { Q_strncpyz(bucket->node, node, sizeof(bucket->node)); bucket->lastTime = now; bucket->burst = 0; bucket->hash = hash; /* Add to the head of the relevant hash chain */ bucket->next = bucketHashes[hash]; if (bucketHashes[hash] != nullptr) { bucketHashes[hash]->prev = bucket; } bucket->prev = nullptr; bucketHashes[hash] = bucket; return bucket; } } /* Couldn't allocate a bucket for this address */ return nullptr; }
/** * @brief Searches the hash for a given sound file * @param name The soundfile (relative to the sound dir and without extension) * @return @c nullptr if not yet loaded */ static s_sample_t* S_FindByName (const char* name) { const unsigned hash = Com_HashKey(name, SAMPLE_HASH_SIZE); for (s_sample_t* sample = sampleHash[hash]; sample; sample = sample->hashNext) if (Q_streq(name, sample->name)) return sample; return nullptr; }
/** * @brief Get a node from child index * @return A child node by his name, else nullptr */ uiNode_t* UI_WindowNodeGetIndexedChild (uiNode_t* const node, const char* childName) { unsigned int hash = Com_HashKey(childName, INDEXEDCHILD_HASH_SIZE); for (node_index_t* a = EXTRADATA(node).index_hash[hash]; a; a = a->hash_next) { if (Q_streq(childName, a->node->name)) { return a->node; } } return nullptr; }
static void CL_ParseMessageID (const char* name, const char** text) { /* get it's body */ const char* token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseMessageID: msgid \"%s\" without body ignored\n", name); return; } /* search for game types with same name */ int i; for (i = 0; i < numMsgIDs; i++) if (Q_streq(token, msgIDs[i].id)) break; if (i == numMsgIDs) { msgid_t* msgid = &msgIDs[numMsgIDs++]; if (numMsgIDs >= MAX_MSGIDS) Sys_Error("CL_ParseMessageID: MAX_MSGIDS exceeded"); OBJZERO(*msgid); msgid->id = Mem_PoolStrDup(name, cl_msgidPool, 0); const unsigned int hash = Com_HashKey(msgid->id, MAX_MSGIDHASH); HASH_Add(msgIDHash, msgid, hash); do { const char* errhead = "CL_ParseMessageID: unexpected end of file (msgid "; token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; if (Q_streq(token, "text")) { /* found a definition */ token = Com_EParse(text, errhead, name, msgIDText, MSGIDSIZE); if (!*text) break; if (token[0] == '_') token++; if (token[0] != '\0') msgid->text = _(token); else msgid->text = token; if (msgid->text == token) { msgid->text = Mem_PoolStrDup(token, cl_msgidPool, 0); Com_Printf("no translation for %s\n", msgid->id); } } } while (*text); } else { Com_Printf("CL_ParseMessageID: msgid \"%s\" with same already exists - ignore the second one\n", name); Com_SkipBlock(text); } }
/** * @brief Searches for a cvar given by parameter * @param varName The cvar name as string * @return Pointer to cvar_t struct or @c nullptr if no cvar with the specified name was found * @sa Cvar_GetString * @sa Cvar_SetValue */ cvar_t* Cvar_FindVar (const char* varName) { const unsigned hash = Com_HashKey(varName, CVAR_HASH_SIZE); for (cvar_t* var = cvarVarsHash[hash]; var; var = var->hash_next) { if (Q_streq(varName, var->name)) return var; } return nullptr; }
/* ============ BaseCmd_Insert Add new typed base command to hashmap ============ */ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name ) { uint hash = Com_HashKey( name, HASH_SIZE ); base_command_hashmap_t *elem; elem = Z_Malloc( sizeof( base_command_hashmap_t ) ); elem->basecmd = basecmd; elem->type = type; elem->name = name; elem->next = hashed_cmds[hash]; hashed_cmds[hash] = elem; }
/* ============ Cvar_Find ============ */ cvar_t *Cvar_Find (const char *name) { cvar_t *var; int key; key = Com_HashKey (name); for (var=cvar_hash[key] ; var ; var=var->hash_next) if (!Q_stricmp (name, var->name)) return var; return NULL; }
/** * @brief Checks whether a function exists already * @param[in] cmd_name The script interface function name to search for */ qboolean Cmd_Exists (const char *cmd_name) { cmd_function_t *cmd; unsigned int hash; hash = Com_HashKey(cmd_name, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (Q_streq(cmd_name, cmd->name)) return qtrue; } return qfalse; }
/** * Get a property name from global test structure * @param name Name of the property * @return A property element, else nullptr if property not found. */ static const test_property_t* TEST_GetProperty (const char* name) { unsigned int hash; const test_property_t* element; hash = Com_HashKey(name, PROPERTY_HASH_SIZE); for (element = test_property_hash[hash]; element; element = element->hash_next) { if (!Q_strcasecmp(name, element->name)) { return element; } } return nullptr; }
char *Cmd_AliasString (char *name) { int key; cmd_alias_t *alias; key = Com_HashKey (name); for (alias = cmd_alias_hash[key] ; alias ; alias = alias->hash_next) { if (!Q_stricmp(name, alias->name)) return alias->value; } return NULL; }
cvar_t *Cvar_Find (const char *var_name) { cvar_t *var; int key = Com_HashKey (var_name) % VAR_HASHPOOL_SIZE; for (var = cvar_hash[key]; var; var = var->hash_next) { if (!strcasecmp (var_name, var->name)) { return var; } } return NULL; }
/* ============ Cmd_Exists ============ */ qbool Cmd_Exists (const char *cmd_name) { int key; cmd_function_t *cmd; key = Com_HashKey (cmd_name); for (cmd=cmd_hash_array[key] ; cmd ; cmd=cmd->hash_next) { if (!strcasecmp (cmd_name, cmd->name)) return true; } return false; }
/* ============ Cmd_FindCommand ============ */ cmd_function_t *Cmd_FindCommand (char *cmd_name) { int key; cmd_function_t *cmd; key = Com_HashKey (cmd_name); for (cmd=cmd_hash_array[key] ; cmd ; cmd=cmd->hash_next) { if (!Q_stricmp (cmd_name, cmd->name)) return cmd; } return NULL; }
/* =============== Cmd_Alias_f Creates a new command that executes a command string (possibly ; separated) =============== */ void Cmd_Alias_f (void) { cmd_alias_t *a; int key; char *name; if (Cmd_Argc() == 1) { Com_Printf ("alias <name> <command> : create or modify an alias\n"); Com_Printf ("aliaslist : list all aliases\n"); return; } name = Cmd_Argv(1); // see if there's already an alias by that name a = Cmd_FindAlias(name); if (a) { // reuse it Q_free (a->name); Q_free (a->value); } else { // allocate a new one a = Q_malloc (sizeof(cmd_alias_t)); a->flags = 0; // link it in a->next = cmd_alias; cmd_alias = a; key = Com_HashKey(name); a->hash_next = cmd_alias_hash[key]; cmd_alias_hash[key] = a; } a->name = Q_strdup(name); a->value = Q_strdup(Cmd_MakeArgs(2)); // copy the rest of the command line #ifndef SERVERONLY if (cbuf_current == &cbuf_svc) a->flags |= ALIAS_STUFFED; else a->flags &= ALIAS_STUFFED; #endif if (!Q_stricmp(Cmd_Argv(0), "aliasa")) a->flags |= ALIAS_ARCHIVE; }