/* cl_main.c */ /** * @brief Autocomplete function for some network functions * @sa Cmd_AddParamCompleteFunction * @todo Extend this for all the servers on the server browser list */ static int CL_CompleteNetworkAddress (const char *partial, const char **match) { int i, matches = 0; const char *localMatch[MAX_COMPLETE]; const char *adrStr; size_t len; len = strlen(partial); if (!len) { /* list them all if there was no parameter given */ for (i = 0; i < MAX_BOOKMARKS; i++) { adrStr = Cvar_VariableString(va("adr%i", i)); if (*adrStr) Com_Printf("%s\n", adrStr); } return 0; } localMatch[matches] = NULL; /* search all matches and fill the localMatch array */ for (i = 0; i < MAX_BOOKMARKS; i++) { adrStr = Cvar_VariableString(va("adr%i", i)); if (*adrStr && !Q_strncmp(partial, adrStr, len)) { Com_Printf("%s\n", adrStr); localMatch[matches++] = adrStr; if (matches >= MAX_COMPLETE) break; } } return Cmd_GenericCompleteFunction(len, match, matches, localMatch); } [...] Cmd_AddCommand("connect", CL_Connect_f, "Connect to given ip"); Cmd_AddParamCompleteFunction("connect", CL_CompleteNetworkAddress); Cmd_AddCommand("rcon", CL_Rcon_f, "Execute a rcon command - see rcon_password"); Cmd_AddParamCompleteFunction("rcon", CL_CompleteNetworkAddress); [...] /* cmd.c */ /** * @sa Cmd_AddParamCompleteFunction */ int Cmd_GenericCompleteFunction (size_t len, const char **match, int matches, const char **list) { static char matchString[MAX_QPATH]; char matchChar; int lenResult = 0; int i; switch (matches) { /* exactly one match */ case 1: *match = list[0]; break; /* no matches */ case 0: break; /* more than one match */ default: /* get the shortest matching string of the results */ lenResult = len; while (qtrue) { matchChar = list[0][lenResult]; for (i = 0; i < matches; i++) { if (matchChar != list[i][lenResult]) break; } lenResult++; if (i != matches) break; } /* len is >= 1 here */ if (len != lenResult) { if (lenResult >= MAX_QPATH) lenResult = MAX_QPATH - 1; /* j must be bigger than 0 here */ Q_strncpyz(matchString, list[0], lenResult); *match = matchString; matches = 1; } break; } return matches; } /** * @param[in] cmd_name The name the command we want to add the complete function * @param[in] function The complete function pointer * @sa Cmd_AddCommand * @sa Cmd_CompleteCommandParameters */ void Cmd_AddParamCompleteFunction (const char *cmd_name, int (*function)(const char *partial, const char **match)) { cmd_function_t *cmd; unsigned int hash; if (!cmd_name || !cmd_name[0]) return; hash = Com_HashKey(cmd_name, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (!Q_strcmp(cmd_name, cmd->name)) { cmd->completeParam = function; return; } } return; } /** * @brief Unix like tab completion for console commands parameters * @param[in] command The command we try to complete the parameter for * @param[in] partial The beginning of the parameter we try to complete * @sa Cvar_CompleteVariable * @sa Key_CompleteCommand */ int Cmd_CompleteCommandParameters (const char *command, const char *partial, const char **match) { cmd_function_t *cmd; unsigned int hash; /* check for partial matches in commands */ hash = Com_HashKey(command, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (!Q_strcasecmp(command, cmd->name)) { if (!cmd->completeParam) return 0; return cmd->completeParam(partial, match); } } return 0; } /* cl_keys. */ /** * @brief Console completion for command and variables * @sa Key_Console * @sa Cmd_CompleteCommand * @sa Cvar_CompleteVariable * @sa Sys_ConsoleCompleteCommand */ static void Key_CompleteCommand (void) { const char *cmd = NULL, *cvar = NULL, *use = NULL, *s; int cntCmd = 0, cntCvar = 0, cntParams = 0; char cmdLine[MAXCMDLINE] = ""; qboolean append = qtrue; char *tmp; s = key_lines[edit_line] + 1; if (*s == '\\' || *s == '/') s++; if (!*s || *s == ' ') return; /* don't try to search a command or cvar if we are already in the * parameter stage */ if (strstr(s, " ")) { tmp = cmdLine; while (*s != ' ') *tmp++ = *s++; /* terminate the string at whitespace position to seperate the cmd */ *tmp++ = '\0'; /* get rid of the whitespace */ s++; cntParams = Cmd_CompleteCommandParameters(cmdLine, s, &cmd); if (cntParams == 1) { /* append the found parameter */ Q_strcat(cmdLine, " ", sizeof(cmdLine)); Q_strcat(cmdLine, cmd, sizeof(cmdLine)); append = qfalse; use = cmdLine; } else if (cntParams > 1) { Com_Printf("\n"); } else return; } else { cntCmd = Cmd_CompleteCommand(s, &cmd); cntCvar = Cvar_CompleteVariable(s, &cvar); if (cntCmd == 1 && !cntCvar) use = cmd; else if (!cntCmd && cntCvar == 1) use = cvar; else Com_Printf("\n"); } if (use) { key_lines[edit_line][1] = '/'; Q_strncpyz(key_lines[edit_line] + 2, use, MAXCMDLINE - 2); key_linepos = strlen(use) + 2; if (append) { key_lines[edit_line][key_linepos] = ' '; key_linepos++; } key_lines[edit_line][key_linepos] = 0; return; } }