Log in | Back to darenet.org

Guide to mIRC Debugging

(New page: == Why am I Here? == If you've come wandering upon this document it is likely that you are having trouble with a script that you wrote. It is probably fully written, but doesn't seem to w...)
 
Line 219: Line 219:
''Orginally Written by argv[0]. Last edit by: argv[0] at 2007-08-30 19:02:05''  
''Orginally Written by argv[0]. Last edit by: argv[0] at 2007-08-30 19:02:05''  
-
[[Category:Documentation]]
+
[[Category:Technical]]

Current revision as of 08:06, 26 October 2007

In This Guide:

Why am I Here?

If you've come wandering upon this document it is likely that you are having trouble with a script that you wrote. It is probably fully written, but doesn't seem to work as it should, for one reason or another. The purpose of this document is therefore to teach you how to debug your own scripts, making the coding process easier and more efficient. Don't get discouraged, debugging is not hard. Debugging is a logical process that can be easily learned and applied if you follow the steps involved.

If you happen to already know enough about debugging, but just can't seem to figure out what is going wrong with a script you wrote, you should take a look at section 5, in which some Common Scripting Pitfalls are discussed.

The Basics of Debugging

If a script does not work, the logical process is to find out why, so that it may be fixed. DO NOT take for granted the first step I mentioned, in which you must find out why your script does not work. When first dealing with any bugged script, your frame of mind should never be, "this needs to be fixed". Instead you should first be asking the question "why does this not work?" Once you answer that question you can move on to fixing it and the fix is usually much simpler than the debugging process itself. Think of debugging similar to a medical situation. Before you treat a patient, you must always diagnose him or her first. This concept applies the same way in debugging.

A lot of people asking for help on IRC or in forums are basically just asking for other people to debug their scripts, instead of helping them with something the person asking doesn't understand. Don't expect much respect if you ask people to bugfix for you.

The Steps of Debugging

Practically speaking, to diagnose a bugged script you should follow the set of steps which I will now begin explaining.

Narrow it Down!

"Narrow it down" is probably one of the best phrases to keep in mind when debugging a script. Often a scripter will ask for help with a script that doesn't seem to trigger, but he will paste his entire script, which happens to be 100 or so lines of code. The truth is that it is rarely necessary to look at more than 5-10 lines of code at a time. While debugging you should constantly be narrowing down which lines of code the bug is affecting, or which lines of code simply do not work.

But don't stop there; a line of code can easily become too general still. Continue to narrow down your search as much as possible. Sometimes it will be necessary to narrow things down to the smallest character (this has definitely been the source of many bugs I've seen in the past). Remember that sometimes a bug can be as simple as a typo or spelling mistake.

The question you are probably asking is how exactly you "narrow down" a search for a bug? "What should I be looking for?" There are many things to look for; here are some methods you can use to find out which part of your script is not functioning properly:

Look for Error Messages

Sometimes if mIRC breaks a script errantly it will echo the error information locally. This is usually found in the status window of your active connection id (unless your command explicitly used another connection id). If you get such an error it might inform you of the line it halted execution on. This is very useful to narrow your bug search to a certain line. If no line is mentioned you will most likely get the command, which is also very helpful. You can then go look up each time you used that command in your script.

Be Verbose

Verbose means to be audible. In the context of mIRC scripting it means to /echo data to the screen. Usually a debugger should try to echo as much information as often as possible.

If you have a variable that does not have the right value, it is best to echo that variable right after you set it to find out what value it took on. This can easily narrow your code down to a line in one simple step.

Another possibility is that a line of code isn't being executed at all (how do I know this, you ask? Well if it's a command such as /kick it is very easy to tell if it executes or not, however if it is a silent command, try tacking on a /echo inside the command itself to see if it executes). In such a case it is a good idea to drop in /echo commands along your code flow, regardless of what it actually echoes.

Consider the following example:

alias function_name {
    echo -a Started execution
    if (a == a) {
        echo -a Got to first level if
        if (b == b) {
            ; mIRC should get here, 
            ; but lets find out
            echo -a Got to second level
            ; Imagine this next if is a typo
            if (defcon == defdcon) {
                echo -a Got to third level
            }
        }
    }
    echo -a Ending function
}

Output:
Started execution
Got to first level if
Got to second level
Ending function

From this it should be clear that mIRC did not reach the last nested if-statement. You can now do further tests to find out why your if statement failed. In our case it was a typo, we really meant to say 'defcon' instead of 'defdcon'.

Another way to use echo is echo'ing big or complicated identifiers, or even entire commands, to see if they actually parse into what you want them to be.

Check Brackets and Syntax

This may seem trivial, but it is always important to make sure your script has as many open brackets as close brackets and also follow mIRC's basic syntax rules. I will outline some basic syntax rules that mIRC uses:

Basic Syntax Rules

Braces {} must always be spaced out and never touch any other character. There is one exception to this rule, but if you always space your braces out you should not have a problem. This also applies to the pipe | character used for dealing with multiple commands.

Multiple commands should generally be surrounded by braces. It is not necessary to use a new line for each command, but keep in mind the multiple command structure:

On one line:

ALIAS/EVENT { command 1 | command 2 | command 3 }

On multiple lines:

ALIAS/EVENT {
    command 1
    command 2
    command 3
}

On both multiple and single lines:

ALIAS/EVENT {
    command 1 | command 2
    command 3
    command 4
}

Note that the opening brace can never be on its own on a line. Consider the following:

ALIAS/EVENT
{
    command
}

Some languages allow the above syntax. This is not valid in mIRC. The opening brace can never begin a line.

The If control structure is command based in mIRC. As such, it must be properly spaced just like all commands. Some languages allow the use of:

if(condition)

This is also not valid in mIRC. In such a case, you would actually be performing the command of /if(condition), which most likely does not exist. The condition (including the brackets) in mIRC if statements is a parameter, and must follow the if statement with a space.

As far as braces go (the { } characters), mIRC can check this automatically in the script editor by clicking the "{ }" button. If mIRC says you have a mismatch, fix it before going further; it is likely that this is the cause of your bug.

When dealing with if statements it is always important to make sure you have the same amount of opening brackets as closing brackets. Sometimes mIRC will not report this error and will automatically fail the if statement and continue execution. If you read section 3.3 you may have used the echo method to find out which if statement is not being triggered. In such a case, the first thing you should do is count the brackets and look at general syntax as described above.

Check for Proper Code Alignment

If you have checked and found the bracket count and general syntax is correct, and the script is still not parsing correctly another thing you can look for is proper nesting. One method to see if things are nested properly is to look at the alignment down the page. For example with an if statement all nested "if's" and "elseifs" etc, Within the original "if statment" will go diagonally right when you press the "{}" button on the top right hand corner of the mirc scripts editor.

Note This isn't the case 100% of the time. Depending on the exact placement of the brackets (For example if you put a close bracket on the same line as the "command" versus on the next line as shown below then your alignment might not be perfect yet the script will still work).

The contradicting "else" or "elseif" for the original "if statement" should be vertically aligned with its original. If you notice that the "elseif" is not aligned with the corresponding "if statement" its possible while you may have the correct amount of brackets that you didn't nest them properly. Check to make sure all the brackets for nested "ifs" (Nested Ifs are if/elseif/else statements that fall within another if/elseif/else statement) are closed before the elseif for the original if it is corresponding to.

See the example below:

Note how the first "if statement" is aligned with the corresponding "elseif statement" for condition 1 and 2. Also note how all the nested "if statements" within the first are going diagonally to the right.

alias somealias {
  if (Condition1 == Condition2) {
    echo -a Condition 1 is the same as condition 2 
    if (Condition3 != Condition4) {
      echo -a Condition 3 is not the same as condition 4
      if (Condition5 isin Condition6) {
        echo -a Condition5 is within Condition 6
      }
      elseif (Condition5 !isin Condition6) {
        echo -a Condition 5 is not within Condition 6
      }
    }
  }
  Elseif (Condition1 != Condition2) {
    echo -a Condition 1 and 2 not equal, halting.
  }
}

It is possible to have an else on the same line as a }, but it has to be preceeded by an |, i.e.

alias checkcondition {
  if (Condition7 isin Contition8)
    echo -a Condition7 is within Condition8
    } | elseif (Condition7 isin Condition9) {
    echo -a Condition7 is within Condition9
    } | else {
    echo -a Condition7 is not within Condition8 or Condition9
  }
}

As can be seen, this confuses the indentation.

Simplify Complicated and Suspicious Code

If you were unsuccessful in tracking down your bug using any of the other methods mentioned above, try looking for suspicious code. If you wrote a line of code that you just aren't sure about, try looking closer at that line. Similarly, if you have a very complex line of code in your script, try looking at that one first. A good way to handle a situation like this is to change the line to something very simple, and see if it works. If it does then you know that your problem lies in the code that you changed. If not then you can be certain that the bug you're looking for does not lie in your complex code. (Although be aware that you shouldn't now automatically trust it completely, as there may still be issues with it which won't be apparent until the current bug is fixed, for example.)

Final Notes

Remember that when you're debugging a script it is more important to find out why your script is failing than to fix it. An mIRC support channel can easily aid a scripter solve his problem when it is clear what the problem is. In essence, if you cannot solve a problem it is important that you at least understand what problem it is that you're having, that way you can get the help you need from an outside source. That is the purpose of debugging a script; not to directly fix, but to set yourself on a course to implement such a fix.

Common Scripting Pitfalls

You Cannot Trigger Your Own Text or Action Events

Like the name implies, mIRC will not allow you to trigger your own ON TEXT (or ON ACTION) events by typing in a channel (though it will work if you message yourself privately). To capture your own text in a channel, use ON INPUT, but keep in mind that in many case you don't actually want to do that.

Conflicting Event Matching

In the following snippet of code, the second ON TEXT event will never fire:

on 1:TEXT:*:#: { commands }
on 1:TEXT:!trigger *:#: { commands }

The reason that the !trigger event is not working is that mIRC goes downwards through a script file finding the first event that matches, at which point it stops processing that file. Since the '*' match overshadows the '!trigger *' match, mIRC will not reach the second event. To fix this, you must either reverse the order which these events appear in the file (most specific to least specific match), or put the !trigger in a new script file, so that mIRC will execute process both files (and both events).

* Note: this also occurs for any other events that have matchtext fields for the same input

Using " " In Filenames

Always use " " when dealing with files and directories, to make sure mIRC understands directories with spaces in the name. It's a good habit to always use them, even when you aren't expecting any spaces.

/rename c:\Program Files\Half-life\hl.exe c:\Program Files\Half-Life\hl2.exe

This won't work.

/rename "c:\Program Files\Half-life\hl.exe" "c:\Program Files\Half-Life\hl2.exe"

This will.

Remember That Some Commands Have Delays

Not all commands are completed the moment you start them. Some command require you to wait. this pretty much counts for every command that requires a reply from the server or from other clients or connections. For example, this won't work:

on *:DEOP:#:{
    if ($opnick == $me) {
        ;check if we are being deopped
        msg BOTNICK op $chan
        ;requesting op
        kick $chan $nick Don't deop me!
        ;kick the person that deopped you
    }
}

It won't work because when you ask for op status, there is a delay between the time that you ask it and the time that you actually get it. Even if it's just a few milliseconds, the script goes too fast for it. There are two ways to solve it; either put the kick command in a timer or use a separate on op event for the kick.

Using $read With The s Flag

When you use $read with the s flag to scan for a line starting with a certain word, keep in mind that the result will NOT include the word you were searching for itself! It returns everything after the word you scanned with.

So if you had a textfile with a line that said "Mommy is the greatest!" and you used $read(textfile.txt,s,Mommy), it would return "is the greatest!".

Orginally Written by argv[0]. Last edit by: argv[0] at 2007-08-30 19:02:05