⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
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 + -