Debugging

Contributed by blue-elf
Introduction
Script debugging means to find the bugs or the errors in your scripts. This is perhaps the most painful part in mIRC scripting or any programming language for that matter. Sometimes we think that we have scripted everything right and yet they don't trigger or work at all, or if they do work, they do not work correctly. But how do we know what's wrong? This lesson will present two ways of debugging scripts. This will give you ideas how to find what's wrong, and also where to find what needs to be fixed.
Using the /echo command
One of the oldest methods in finding out bugs is to use the /echo command. At first glance, it doesn't seem to make sense. Here's how you can use /echo to find bugs.

Supposing you have this in remotes:
ctcp +90:PASS:?:{ 
  writeini passwords.ini 90 $address($nick,3) $2- 
} 
In case the whole thing does not trigger, you can put the /echo just before the command. Thus, we modify the above example:
ctcp +90:PASS:?:{ 
  echo -s /writeini passwords.ini 90 $address($nick,3) $2- 
}
That way, you can see where the $null's are or which parameter is not filled in. It means that when you put the /echo command there, there should be three things after passwords.ini, and that would be, 90, the $address($nick,3), and the $2-. If, for example, you see that there is no address, then you can assume that you need to enable your Internal Address List.

In fact, you can put an echo just before any command. Instead of executing the command, make it echo.

You can extend the application of echo even in if-else statements.

Example:
on *:join:#:{ 
  if ($level($address($nick,3)) == 5) kick # $nick banned
  elseif ($level($address($nick,3) == 3) msg # welcome, $nick
  else return
}
Let's say the whole thing doesn't trigger, or if it does, it only triggers for level 3. You don't have to echo everything. What you can do is:
on *:join:#:{ 
  echo -a if ( $level($address($nick,3)) == 5 ) 
  if ($level($address($nick,3)) == 5) kick # $nick banned
  elseif ($level($address($nick,3) == 3) msg # welcome, $nick
  else return
} 
The first line attempts to echo the level of the user. Note that the parentheses are moved farther. The purpose of that is to force the identifier to be evaluated. Otherwise, the first line will just echo it as normal text. If nothing echos, then you would have known where the bug is. In fact you can just do this:
on *:join:#:{ 
  echo -a $nick 's userlevel is $level($address($nick,3))
  ; the rest goes here
}
Another method of evaluating identifiers, especially if they are within other identifiers, is to put an exclamation mark "!" after the identifier "$" sign. For example, $!ctime or $!me. Here is an example:
on *:text:*:#:{
  if ((*.edu iswm $fulladdress) && ($gettok($fulladdress,-2,46) == haverford)) kick # $nick
}
Using the method mentioned above, we can change the lines temporarily so that we will exactly know what is triggering the text event. Thus, we can make it look like the one below:
on @*:text:*:#:{
  echo -a debug: $!gettok( $fulladdress ,-2,46)
  ;if ((*.edu iswm $fulladdress) && ($gettok($fulladdress,-2,46) == haverford)) kick # $nick
}
If we do that, we can see what the $fulladdress identifier is being evaluated into before the $gettok evaluates it. This method is most useful when there are more than one identifier inside other identifiers. For example:
raw 302:*:{
  set %userhost.address $gettok($2-,2-,$asc($left($gettok($2-,2,61),1)))
}
Or..
raw 302:*:{
  set %userhost.address $gettok($replace($remove($2-,*),=-,!,=+,!),1,33)
}
In these two raw examples (raw 302 is the /userhost reply), try changing them around like below to see what each one does:
set %userhost.address $!gettok( $2- , 2- , $asc($left($gettok($2-,2,61),1)) )

set %userhost.address $!gettok($2-,2-,$asc( $left($gettok($2-,2,61),1) ) )

set %userhost.address $!gettok($2-,2-,$asc($left( $gettok($2-,2,61),1 )) )
Here is the second set of examples:
set %userhost.address $gettok($replace($remove($2-,*),=-,!,=+,!),1,33)

set %userhost.address $!gettok($replace( $remove($2-,*) ,=-,!,=+,!),1,33)
These examples might not be for very new scripters, but for the intermediate scripters, it should give them an idea how to use this method in finding bugs.
Using $script and $scriptline
Two more useful identifiers that can work well with the /echo command is the $script and the $scriptline. The $script identifier will return the actual filename being used when an alias or script is being executed. For example:
aecho {
  echo -a *** Now executing alias /aecho from $script
  var %i = 1
  while ($chan(%i)) {
    echo $ifmatch $$1 $2-
    inc %i
  }
  %i = 1
  while ($query(%i)) {
    echo $ifmatch $$1 $2-
    inc %i
  }
}
The above alias will echo to the active window that it is going to execute itself, and it will tell you what file it is in. And then it will continue to echo the parameters that you supplied in all channel windows and all query windows that are open.

Using the same alias, let us insert the $scriptline identifier to see how it can be of use to us. Take note that $scriptline has been introduced only in mIRC 5.8 and does not work for earlier versions.
aecho {
  echo -a *** Now executing alias /aecho from $script
  var %i = 1
  while ($chan(%i)) {
    echo $ifmatch $$1 $2-
    echo -a *** You are now in line number $scriptline of $script
    inc %i
  }
  %i = 1
  while ($query(%i)) {
    echo $ifmatch $$1 $2-
    inc %i
  }
  echo -a *** You are now in line number $scriptline of $script
  echo -a *** The alias will end now.
}
Try to copy and paste the alias in a clean mIRC and test it out. $scriptline is most useful when it comes to figuring out which script or event stops working, and where exactly your alias fails, or your events fail, and so on. There are so many possibilities in this one.

Also, if you have noticed, you can actually use $script even when the file is loaded as an alias. And similarly, $scriptline also works even if the file is not a remote script.
Debugging and Variable Setting
Another way of debugging is using the -s switch in the /set command. Sometimes variables are not set to anything. And we might not notice this all the time. With the -s switch, we can attempt to take a peek into what variable is being set to what.

Example:
alias k {
  set -su %blah $iif($2 != $null,$2-,bye)
  .quote kick # $1 : $+ %blah
}
When the variable %blah is set, mIRC will show something like:

*** Set %blah to bye

You can also use /set -s in remotes or even popups. But it does not work all the time. For instance, if you're attempting a /set -s and the active window is a picture window, it will only show when the variable is unset and not when it is being set. Take note that the -s also works for /inc /dec /unset and /unsetall commands.

In cases where a /set -s is not possible, you could resort to the /echo command after setting variables. For example:
menu @window {
  dclick:{
    set %var $mouse.x $mouse.y
    echo -s % $+ var is being set to %var
  }
}
In that way, if the variable doesn't echo anything, we would have known that there is in fact something wrong.

Similarly, with the /var command, the -s switch is also available. This has been added in mIRC version 5.8. The usage is the same like the /set command. The only difference is, the variables being set by the /var command is local and not global. For example:
alias viewscripts {
  var -s %count = 1
  while ($script(%count)) {
    echo -a $ifmatch
    inc %count
  }
}
In the above example, mIRC will tell you that %count is being set to "1" when you first use the alias. And, as mentioned above, the variable will be local only - it will have no effect with other aliases or scripts that we have even if our other scripts or aliases have a variable with the name %count in them. And after executing that alias (viewscripts), the %count variable which was set in it automatically ceases to exist (or 'unset').
Hints and tips
Most of the time, bugs are caused by simple typographical errors, or syntactical errors. In other words, scripts stop working because of small mistakes. For example, a little typo, the wrong variable used, a variable instead of an identifier is used or vice-versa, and so on.

For the newbie scripter, mistakes also range from remotes not being enabled, or conflicting remotes. What this means is, when you are trying to script remotes (or the so-called ON events like ON TEXT), the remotes need to be on via the /remote on command. And also, bear in mind that the so-called ON events conflict with each other. If there is an ON TEXT event and it is not working, check if there is another ON TEXT event above it. Are they conflicting? Do they trigger the same event? Things like that should be taken into consideration.

And yet another common mistake is trying to use $address or other related address identifiers while the Internal Address List (IAL) is not enabled. Always remember to enable it with the /ial on command.

Testing your scripts is very important. For those who have many files loaded, it is best to test one alias at a time in a clean mIRC first before attempting to code a full-blown alias or script along with your other scripts. In this manner, you can identify where exactly your script fails thus making it easier to fix.

Also, when testing scripts, try to use a comment as you have seen in the examples above. This will prevent you from getting more errors.
Conclusion
These are just simple examples and they can be done in a better way. But hopefully, you will get better ideas out of it.
All content is copyright by mircscripts.org and cannot be used without permission. For more details, click here.