Originally Posted By: Loki12583
Taking in user input in such a way can be dangerous, I had to use the $safe alias to guard against injection when evaluating the subcommand. Make sure to understand everything on this page if you're handling unknown content: http://en.wikichip.org/wiki/mirc/msl_injection

Here I've used a regex which captures a command and its arguments, if the arguments also match the regex I make a recursive call. The regex is designed such that empty or missing brackets are also acceptable: @command@ or @command@[]. Limiting character classes may help guard against invalid input depending on your preference. Reading back over your examples maybe I've misunderstood that subsequent text should be evaluated rather than the arguments in [], but you'll need to provide a more exact syntax if that's the case. I think trying to allow both would create an ambiguous syntax or complicate the code on a per-command basis.
Okay to clear it up some, let's say I make a command called !kick where you specify a name and then the bot does "/me kicks (name)" The command would be "/me kicks @target@[1]" and @target@[1] would be replaced by the first 'token' of input after the command. (Tokens being items separated by spaces.) Commands wouldn't be evaluated items, thus injections wouldn't really be a concern.


Originally Posted By: Loki12583
Code:
alias processcommand {
  var %regex = /^@(\S+?)@(?:\[(.*)\])?(.*)$/iS

  if (!$regex($1-,%regex)) return

  var %command = $regml(1)
  var %args = $regml(2)
  var %text = $regml(3)

  if (%args != $null) && ($regex(%args,%regex)) {
    %args = $recurse($!processcommand( $safe(%args) ))
  }

  if (%command == lower) {
    return $lower(%args)
  }
  if (%command == target) {
    return $gettok(%text,%args,32)
  }
  elseif (%command == bold) {
    return  $+ %args
  }
  elseif (%command == underline) {
    return  $+ %args
  }
  elseif (%command == beep) {
    beep | return beep
  }
  elseif (%command == echo) {
    echo -ag %args | return echo
  }

}

alias recurse { if ($isid) return $($1-,2) | else $1- }
alias safe return $!decode( $encode($1,m) ,m)
For the commands I was using aliases (to add a new command, just make a new alias). The 'trick' is in trying to make it so it parses the deepest first and works its way out, but without parsing stuff that's either meant to be 'as is' (like stuff in quotes) or stuff that is the result of parsing. Of course, maybe that's getting a bit complex.

Here's what I'm using at the moment...
Code:
alias twitch.cmd.process@ {
  if ( !$0 || !$regex($1-,/(@[^@\s]+@)/g ) ) { return $1- }
  var %return = $1-, %tokens, %break = 25
  var %regexes = /(@[^@\s]+@(?:\[("?)[^\[\]]+\2\]))/g±/(@[^@\s]+@)/g

  while ( %regexes ) {
    while ( $regex( %return, $gettok( %regexes, 1, 177 ) ) ) {
      dec %break
      if ( %break < 1 ) { echo -tgs $scriptline BREAK $1- | break }
      %return = $twitch.cmd.@subprocess(%return)
    }
    %regexes = $deltok(%regexes,1,177)
  }
  return %return
}
alias twitch.cmd.@subprocess {
  var %x = $regml(0), %tokens, %return = $1-

  while ( %x > 0 ) {
    if ( $len($regml(%x)) > 2 ) { %tokens = $addtok(%tokens,$+($regml(%x).pos,:,$regml(%x)),1) }
    dec %x
  }

  while ( %tokens ) {
    var %x = $gettok(%tokens,1,1), %var = $deltok(%x,1,58), %tokens = $deltok(%tokens,1,1), %pos = $calc( $gettok(%x,1,58) - 1 )
    var %reg = $regex(%var,/^(@[^@\s]+@)(?:\[("?)([^\[\]]+)\2\])?$/), %cmd = $+(twitch.val.,$regml(1))

    if ( $isalias(%cmd) ) { %cmd $iif($regml(3),$twitch.cmd.process@( $ifmatch ) ) }
    else { twitch.val.catchall@ %var }

    if ( $len($result) ) {
      var %new = $result, %offset = $calc( %pos + $len(%var) + 1 )
      var %return = $+($left(%return,%pos),%new,$mid(%return,%offset))
    }
  }
  return %return
}

alias twitch.val.@target@ { return [ [ $+(%,target,$iif($int($1),$ifmatch)) ] ] }
alias twitch.val.@lower@ { return $lower($1-) }
alias twitch.val.@upper@ { return $upper($1-) }

The original regex's I had weren't working right, what I've pasted above seems to be working SO FAR, but I'm sure it can be fine tuned some and I'm sure there's a better way of accomplishing my goal.


Just to mention this, but twitch doesn't support bold/underline/inverse/color codes, they get stripped (server side, not client). I know your code was just to show an example, but thought I'd mention it as a tidbit of info. Could be useful since on the client side, any codes will still echo properly, just won't make it past the server.