Author Topic: OnCommand/OnPlayerCommand Parser  (Read 2962 times)

0 Members and 1 Guest are viewing this topic.

Offline yexxle

  • Major(1)
  • Posts: 22
OnCommand/OnPlayerCommand Parser
« on: June 21, 2007, 10:52:15 am »
Script Name:
OnCommand/OnPlayerCommand Parser

Script Description:
Parses commands sent by admins and players. Allows for any parameter, such as those containing spaces or quotes. It's hard to explain exactly how it all works; I suggest you play with it by passing in different strings and seeing what you get back. :)

Original Author(s):
Nathan, yexxle@soldatforums

Core Version:
Coded on 1.4.1, BETA 2.6.1

Code:

Code: [Select]
{
    usage:
        parse_cmd(cmd: string; limit: byte) : array of string;
            cmd: the string with the command to parse (ex: /cmd arg1 arg2 "arg3 stillArg3")
            limit: number of arguments to return (the command entry (usually /xxx) is not included in the count).
                    So if you want command plus two arguments, pass the number 2, not 3. -1 means to return as
                    many arguments as given.

        var parsed := array of string;

        { simple split; -1 as limit parameter means no limit to how many parameters will be returned }
        { [ '/login', 'myname', 'mypass' ] }
        parsed := parse_cmd('/login myname mypass', -1);

        { quotes around text makes it a single argument }
        { [ '/login', 'my name', 'mypass' ] }
        parsed := parse_cmd('/login "my name" mypass', -1);

        { multiple quoted strings allowed }
        { [ '/login', 'my name', 'my pass' ] }
        parsed := parse_cmd('/login "my name" "my pass"', -1);

        { to get a double quote, you need to be within quotes and then double the quote }
        { [ '/login', 'myname', 'pass"with"quotes' ] }
        parsed := parse_cmd('/login myname "pass""with""quotes"', -1);

        { adding a limit parameter returns exactly that number of command arguments }
        { [ '/login', 'myname', 'my pass with spaces' ] }
        parsed := parse_cmd('/login myname my pass with spaces', 2);

        { about as complicated as it gets }
        { [ '/quote', '"To be, or not to be".', 'That was his question' ] }
        parsed := parse_cmd('/quote """To be, or not to be""." "That was his question"', -1);

        { if we ask for more arguments than are given in command, we get empty args back }
        { [ '/login', 'user', 'pass', '', '', '', '' ] }
        parsed := parse_cmd('/login user pass', 6);
}

function parse_cmd (cmd: string; limit: shortint): array of string;
var
args: array of string;
step, arg, cur, next: string;
len: byte;

begin
limit := limit + 1; {offsets cmd}
step := 'new';

while Length(cmd) > 0 do begin
cur := cmd[1];
Delete(cmd, 1, 1);

if Length(cmd) > 0 then
next := cmd[1]
else
next := '';

if step = 'new' then begin
if cur = ' ' then
continue
else if cur = '"' then
step := 'quoted'
else begin
arg := arg + cur;
step := 'unquoted';
end;
end
else if step = 'quoted' then begin
if cur = '"' then begin
if next = '"' then
step := 'quotedquote'
else begin
SetArrayLength(args, len + 1);
args[len] := arg;
len := len + 1;
arg := '';
step := 'new';
end;
end
else
arg := arg + cur;
end
else if step = 'quotedquote' then begin
arg := arg + cur;
step := 'quoted';
end
else if step = 'unquoted' then begin
if cur = '"' then begin
SetArrayLength(args, len + 1);
args[len] := arg;
len := len + 1;
arg := '';
step := 'new';
cmd := '"' + cmd;
end
else if (cur = ' ') and ( (limit <> len + 1) or (StrPos('"', cmd) > 0) ) then begin
SetArrayLength(args, len + 1);
args[len] := arg;
len := len + 1;
arg := '';
step := 'new';
end
else
arg := arg + cur;
end;
end;

if (arg <> '') or (step = 'quoted') then begin
SetArrayLength(args, len + 1);
args[len] := arg;
len := len + 1;
end;

while len < limit do begin
SetArrayLength(args, len + 1);
args[len] := '';
len := len + 1;
end;

if len = 0 then begin
SetArrayLength(args, 1);
args[0] := '';
end;

Result := args;
end;
« Last Edit: June 21, 2007, 01:13:23 pm by yexxle »

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: OnCommand/OnPlayerCommand Parser
« Reply #1 on: June 21, 2007, 12:53:55 pm »
Can't you just use GetPiece and split at spaces or commas?

Offline yexxle

  • Major(1)
  • Posts: 22
Re: OnCommand/OnPlayerCommand Parser
« Reply #2 on: June 21, 2007, 01:03:18 pm »
Can't you just use GetPiece and split at spaces or commas?
Ok, now say you need to pass in a space. Or maybe you need a comma in a parameter. I bet you then write new conditional statements for that specific command only. Point is, this lets you pass in multiple strings containing any characters. And it's consistent vs. what most people do by hacking the text for each different command. If you actually try it, it's written pretty well. It also catches the cases where the input isn't perfect but still makes sense. Not to mention being able to specify empty parameters and whatnot:

/cmd one two "" four  --> [ '/cmd', 'one', 'two', '', 'four' ]

Point is, it's simple. It's consistent. It doesn't break. Less headaches. Legible code. Consistent. Consistent. Period. :)

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: OnCommand/OnPlayerCommand Parser
« Reply #3 on: June 21, 2007, 01:37:59 pm »
What if you want to pass in multiple quotes inside of a quoted parameter?

Offline yexxle

  • Major(1)
  • Posts: 22
Re: OnCommand/OnPlayerCommand Parser
« Reply #4 on: June 21, 2007, 01:50:04 pm »
Double quote is the escape. It's in the examples, and yes, you can have as many quotes in a row as desired, so long as they're in proper pairs.

/cmd onecmd "two cmd" "third ""with"" quotes" fourth --> [ '/cmd', 'onecmd', 'two cmd', 'third "with" quotes', 'fourth' ]

/cmd "one long ""cmd"" with """"multiple"""" quotes" --> [ '/cmd', 'one long "cmd" with ""multiple"" quotes' ]

Offline zyxstand

  • Veteran
  • *****
  • Posts: 1106
  • Mother of all Bombs
Re: OnCommand/OnPlayerCommand Parser
« Reply #5 on: June 21, 2007, 03:21:08 pm »
why don't you do what windows does or w.e where you type \ in front of a character you'd want to be in the string.  like "hello, \"i'm quoted\" and this is not" "second cmd that contains a \\ (single backspace)"
Can't think of anything original to put here...

Offline yexxle

  • Major(1)
  • Posts: 22
Re: OnCommand/OnPlayerCommand Parser
« Reply #6 on: June 21, 2007, 03:24:36 pm »
Geez people, write your own functions then. I wrote this one the way I wanted it, and it works perfect.  ::)