📄 cmd.pas
字号:
procedure Cmd_Echo_f; cdecl;
var
i: Integer;
begin
for i := 1 to Cmd_Argc - 1 do
Com_Printf('%s ', [Cmd_Argv(i)]);
Com_Printf(#10, []);
end;
(*
===============
Cmd_Alias_f
Creates a new command that executes a command string (possibly ; seperated)
===============
*)
procedure Cmd_Alias_f; cdecl;
var
a: cmdalias_p;
cmd: array[0..1023] of Char;
i, c: Integer;
s: PChar;
begin
if Cmd_Argc = 1 then
begin
Com_Printf('Current alias commands:'#10, []);
a := cmd_alias;
while a <> nil do
begin
Com_Printf('%s : %s'#10, [a^.name, a^.value]);
a := a^.next;
end;
Exit;
end;
s := Cmd_Argv(1);
if strlen(s) >= MAX_ALIAS_NAME then
begin
Com_Printf('Alias name is too long'#10, []);
Exit;
end;
// if the alias already exists, reuse it
a := cmd_alias;
while a <> nil do
begin
if strcmp(s, @a^.name) = 0 then
begin
Z_Free(a^.value);
break;
end;
a := a^.next;
end;
if a = nil then
begin
a := Z_Malloc(SizeOf(cmdalias_t));
a^.next := cmd_alias;
cmd_alias := a;
end;
strcpy(@a^.name, s);
// copy the rest of the command line
cmd[0] := #0;
c := Cmd_Argc;
for i := 2 to c - 1 do
begin
StrCat(cmd, Cmd_Argv(i));
if i <> (c - 1) then
StrCat(cmd, ' ');
end;
StrCat(cmd, #10);
a^.value := CopyString(cmd);
end;
(*
=============================================================================
COMMAND EXECUTION
=============================================================================
*)
type
cmd_function_p = ^cmd_function_s;
cmd_function_s = packed record
next: cmd_function_p;
name: PChar;
function_: tcdeclproc;
end;
cmd_function_t = cmd_function_s;
var
cmd_argc_: Integer;
cmd_argv_: array[0..MAX_STRING_TOKENS - 1] of PChar;
cmd_null_string: PChar = '';
cmd_args_: array[0..MAX_STRING_CHARS - 1] of Char;
cmd_functions: cmd_function_p;
(*
============
Cmd_Argc
============
*)
function Cmd_Argc: Integer; cdecl;
begin
Result := cmd_argc_;
end;
(*
============
Cmd_Argv
============
*)
function Cmd_Argv(arg: Integer): PChar;
begin
if arg >= cmd_argc_ then
Result := cmd_null_string
else
Result := Cmd_Argv_[arg];
end;
(*
============
Cmd_Args
Returns a single string containing argv(1) to argv(argc()-1)
============
*)
function Cmd_Args: PChar;
begin
Result := cmd_args_;
end;
(*
======================
Cmd_MacroExpandString
======================
*)
function Cmd_MacroExpandString(text_: PChar): PChar;
const
expanded: array[0..MAX_STRING_CHARS - 1] of Char = #0;
var
i, j, count, len: Integer;
inquote: qboolean;
scan: PChar;
temporary: array[0..MAX_STRING_CHARS - 1] of Char;
token, start: PChar;
label CONTINUE_;
begin
inquote := False;
scan := text_;
len := strlen(scan);
if len >= MAX_STRING_CHARS then
begin
Com_Printf('Line exceeded %d chars, discarded.'#10, [MAX_STRING_CHARS]);
Result := nil;
Exit;
end;
count := 0;
i := 0;
while (i < len) do begin
if scan[i] = '"' then
inquote := not inquote;//inquote := inquote xor 1;
if inquote then
goto CONTINUE_; // don't expand inside quotes
if scan[i] <> '$' then
goto CONTINUE_;
// scan out the complete macro
start := scan + i + 1;
token := COM_Parse(start);
if start <> nil then
goto CONTINUE_;
token := Cvar_VariableString(token);
j := strlen(token);
Inc(len, j);
if len >= MAX_STRING_CHARS then
begin
Com_Printf('Expanded line exceeded %d chars, discarded.', [MAX_STRING_CHARS]);
Result := nil;
Exit;
end;
strncpy(temporary, scan, i);
strcpy(temporary + i, token);
strcpy(temporary + i + j, start);
strcpy(expanded, temporary);
scan := expanded;
Dec(i);
Inc(count);
if count = 100 then
begin
Com_Printf('Macro expansion loop, discarded.'#10, []);
Result := nil;
Exit;
end;
CONTINUE_:
Inc(i);
end;
if inquote then
begin
Com_Printf('Line has unmatched quote, discarded.'#10, []);
Result := nil;
Exit;
end;
Result := scan;
end;
(*
============
Cmd_TokenizeString
Parses the given string into command line tokens.
$Cvars will be expanded unless they are in a quoted token
============
*)
procedure Cmd_TokenizeString(text_: PChar; macroExpand: qboolean);
var
i: Integer;
com_token: PChar;
l: Integer;
begin
// clear the args from the last string
for i := 0 to cmd_argc_ - 1 do
Z_Free(cmd_argv_[i]);
cmd_argc_ := 0;
cmd_args[0] := #0;
// macro expand the text
if macroExpand then
text_ := Cmd_MacroExpandString(text_);
if text_ = nil then
Exit;
while True do
begin
// skip whitespace up to a /n
while (text_^ <> #0) and (text_^ <= ' ') and (text_^ <> #10) do
Inc(text_);
if text_^ = #10 then
begin // a newline seperates commands in the buffer
Inc(text_);
Break;
end;
if text_^ = #0 then
Exit;
// set cmd_args to everything after the first arg
if cmd_argc_ = 1 then
begin
strcpy(cmd_args_, text_);
// strip off any trailing whitespace
l := strlen(cmd_args_) - 1;
while l >= 0 do
begin
if cmd_args_[l] <= ' ' then
cmd_args_[l] := #0
else
Break;
Dec(l);
end;
end;
com_token := COM_Parse(text_);
if text_ = nil then
Exit;
if cmd_argc_ < MAX_STRING_TOKENS then
begin
cmd_argv_[cmd_argc_] := Z_Malloc(strlen(com_token) + 1);
strcpy(cmd_argv_[cmd_argc_], com_token);
Inc(cmd_argc_);
end;
end;
end;
(*
============
Cmd_AddCommand
============
*)
procedure Cmd_AddCommand(cmd_name: PChar; function_: tcdeclproc); cdecl;
var
cmd: cmd_function_p;
begin
// fail if the command is a variable name
if Cvar_VariableString(cmd_name)[0] <> #0 then
begin
Com_Printf('Cmd_AddCommand: %s already defined as a var'#10, [cmd_name]);
Exit;
end;
// fail if the command already exists
cmd := cmd_functions;
while cmd <> nil do
begin
if strcmp(cmd_name, cmd^.name) = 0 then
begin
Com_Printf('Cmd_AddCommand: %s already defined'#10, [cmd_name]);
Exit;
end;
cmd := cmd^.next;
end;
cmd := Z_Malloc(SizeOf(cmd_function_t));
cmd^.name := cmd_name;
cmd^.function_ := function_;
cmd^.next := cmd_functions;
cmd_functions := cmd;
end;
(*
============
Cmd_RemoveCommand
============
*)
procedure Cmd_RemoveCommand(cmd_name: PChar); cdecl;
type
cmd_function_pp = ^cmd_function_p;
var
cmd: cmd_function_p;
back: cmd_function_pp;
begin
back := @cmd_functions;
while True do
begin
cmd := back^;
if cmd = nil then
begin
Com_Printf('Cmd_RemoveCommand: %s not added'#10, [cmd_name]);
Exit;
end;
if strcmp(cmd_name, cmd^.name) = 0 then
begin
back^ := cmd^.next;
Z_Free(cmd);
Exit;
end;
back := @cmd^.next;
end;
end;
(*
============
Cmd_Exists
============
*)
function Cmd_Exists(cmd_name: PChar): qboolean;
var
cmd: cmd_function_p;
begin
cmd := cmd_functions;
while cmd <> nil do
begin
if strcmp(cmd_name, cmd^.name) = 0 then
begin
Result := True;
Exit;
end;
cmd := cmd^.next;
end;
Result := False;
end;
(*
============
Cmd_CompleteCommand
============
*)
function Cmd_CompleteCommand(partial: PChar): PChar;
var
cmd: cmd_function_p;
len: Integer;
a: cmdalias_p;
begin
len := strlen(partial);
if len = 0 then
begin
Result := nil;
Exit;
end;
// check for exact match
cmd := cmd_functions;
while cmd <> nil do
begin
if strcmp(partial, cmd^.name) = 0 then
begin
Result := cmd^.name;
Exit;
end;
cmd := cmd^.next;
end;
a := cmd_alias;
while a <> nil do
begin
if strcmp(partial, a^.name) = 0 then
begin
Result := a^.name;
Exit;
end;
a := a^.next;
end;
// check for partial match
cmd := cmd_functions;
while cmd <> nil do
begin
if strncmp(partial, cmd^.name, len) = 0 then
begin
Result := cmd^.name;
Exit;
end;
cmd := cmd^.next;
end;
a := cmd_alias;
while a <> nil do
begin
if strncmp(partial, a^.name, len) = 0 then
begin
Result := a^.name;
Exit;
end;
a := a^.next;
end;
Result := nil;
end;
(*
============
Cmd_ExecuteString
A complete command line has been parsed, so try to execute it
FIXME: lookupnoadd the token to speed search?
============
*)
procedure Cmd_ExecuteString(text_: PChar);
var
cmd: cmd_function_p;
a: cmdalias_p;
begin
Cmd_TokenizeString(text_, True);
// execute the command line
if Cmd_Argc() = 0 then
Exit; // no tokens
// check functions
cmd := cmd_functions;
while cmd <> nil do
begin
if Q_strcasecmp(cmd_argv_[0], cmd^.name) = 0 then
begin
if not Assigned(cmd^.function_) then
Cmd_ExecuteString(va('cmd %s', [text_])) // forward to server command
else
cmd^.function_;
Exit;
end;
cmd := cmd^.next;
end;
// check alias
a := cmd_alias;
while a <> nil do
begin
if Q_strcasecmp(cmd_argv_[0], a^.name) = 0 then
begin
Inc(alias_count);
if alias_count = ALIAS_LOOP_COUNT then
begin
Com_Printf('ALIAS_LOOP_COUNT'#10, []);
Exit;
end;
Cbuf_InsertText(a^.value);
Exit;
end;
a := a^.next;
end;
// check cvars
if Cvar_Command then
Exit;
// send it as a server command if we are connected
Cmd_ForwardToServer;
end;
(*
============
Cmd_List_f
============
*)
procedure Cmd_List_f; cdecl;
var
cmd: cmd_function_p;
i: Integer;
begin
i := 0;
cmd := cmd_functions;
while cmd <> nil do
begin
Com_Printf('%s'#10, [cmd^.name]);
Inc(i);
cmd := cmd^.next;
end;
Com_Printf('%d commands'#10, [i]);
end;
(*
============
Cmd_Init
============
*)
procedure Cmd_Init;
begin
//
// register our commands
//
Cmd_AddCommand('cmdlist', Cmd_List_f);
Cmd_AddCommand('exec', Cmd_Exec_f);
Cmd_AddCommand('echo', Cmd_Echo_f);
Cmd_AddCommand('alias', Cmd_Alias_f);
Cmd_AddCommand('wait', Cmd_Wait_f);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -