VPL Language Reference (0.90alpha4)
===================================

Introduction
============

I haven't managed to write a help file yet, but here is a quick reference
(quick? It's over 900 lines long!! - a dissatisfied user ;) to the commands and
functions currently available in VPL.

What is VPL?
------------

VPL is ViRC's programming language. VPL programs allow you to totally customize
the way ViRC works, or implement new features, for example. VPL is rather
similar to ircII, so, if you have done script programming with ircII before,
you should find VPL very simple.

Aliases and events
==================

Aliases
-------

Aliases are effectively user-defined IRC commands, written in VPL. Aliases are
defined in VPL in an alias code block. To begin an alias definition, use:

        alias name {

To end an alias definition, use:

}

This is best illustrated by use of an example.

        alias test {
              /echo Hello, $0.
        }

If the user types:

        /test MeGALiTH

The following will be displayed in the server notices window:

        Hello, MeGALiTH.

All the parameters passed to the alias are supplied in the pseudo-variables
$0-$8. $0 represents the first parameter (in the example, MeGALiTH) and $8
represents the ninth parameters. If the pseudo-variable is suffixed with a -
(hyphen), it means "that parameter and all others afterwards". So, for example,
$0- would mean $0 $1 $2 $3 $4 ... as many parameters are specified. $1- would
mean all the parameters except the first, and so on. The main difference
between these pseudo-variables and other variables (say, $C) is that
pseudo-variables are automatically evaluated. With other variables, the line
must be prefixed with EVAL in order for the variables to be evaluated.

Event handlers
--------------

Writing event handlers is similar to defining aliases. You begin with an
event statement:

        event category name {

And end with that ircII-style closing parenthesis:

}

The category field is a number from 0-7, and corresponds directly with the
event tab that would be used if the event were to be defined manually with the
Event Editor.

        0 - In:Server  - responses received directly from the server
        1 - In:CTCP    - CTCPs received
        2 - In:RCTCP   - CTCP replies received
        3 - In:DCC     - DCC requests received
        4 - Out:Server - outgoing server requests (limited support at present)
        5 - Out:CTCP   - outgoing CTCPs (limited support at present)
        6 - Out:RCTCP  - outgoing CTCP replies (limited support at present)
        7 - Out:DCC    - outgoing DCC requests (limited support at present)

The name field is simply the name of the event. For example, if you want to
play DING.WAV whenever someone joins the channel, you could use the following
VPL fragment:

event 0 JOIN {
      /mplay d:\windows\ding.wav
}

Of course, you can put full VPL code in the event handler, If you want DING.WAV
to play whenever you join a new channel, for example, you could use:

event 0 JOIN {
      if ([$0] = [$N])
         /mplay d:\windows\ding.wav
      endif
}

To make a custom version reply, you could use a VPL fragment such as:

event 1 VERSION {
      /rctcp $0 Running Visual IRC 0.90alpha4 ...
}

If the given event doesn't exist, it is created automatically, unlike property
setting, which requires the event to exist already. This will change before
final release, and property setting will be able to create events too.
Currently, you need a fragment such as this to make a new event and set
properties.

setprop event:0->123.Where = 1
setprop event:0->123.Text = Event 123: $0-

event 0 123 {
}

Note that it doesn't matter whether the setprop commands are located before or
after the empty event handler. ViRC searches through your VPL code to locate
event handlers anywhere.

VPL statements
==============

VPL only has a few statements, but they are very powerful.

IF and ENDIF statements
-----------------------

Usage: if (condition) [&|] (condition) [&|] ...
          ...
       endif

Executes a block of code only if a given condition is true. Multiple conditions
can be specified, and are separated with & (boolean AND) or | (boolean OR)
operators. A number of different operators are supported. Here are some
examples.

       Condition              | Result
      ------------------------+--------
       (3 = 3)                | True
       (hello = hello)        | False (string operations must be in []'s)
       ([hello] = [hello])    | True
       ([hello] = [HELLO])    | True (string comparisons are case-insensitive)
       (5 > 3)                | True
       (4 >= 5)               | False
       (4 <= 5)               | True
       (10 < 4)               | False
       (10 > 4) & (7 > 3)     | True
       (10 > 4) | (1 > 2)     | True
       (0 = 1) | (1 = 2)      | False
       ((2 * 3) = 6)          | True
       ((2 ^ 8) = 256)        | True
       ((10 / 2) = 5)         | True
       ((18 + 4) = 20)        | False
       ((12.6 - 18.2) = -5.4) | True

IF can be used to compare numeric expressions or string expressions. All string
expressions must be enclosed in []'s, just as in ircII.

Numeric expression example:

        if (2+3 = 5)
           print Of course it does!!
        endif

String expression example:

        if ([hello] = [goodbye])
           print Not unless the laws of physics have changed.
        endif

Functions may be included in IF statements:

        if ([$left(3 test))] = [tes])
           print What do you think?
        endif

Boolean operators may also be used. & = and, | = or.

        if (2+3 = 5) & (4*2 = 8) then
           print Naturally.
        endif

Note that spaces are not required (they are ignored by the parser), but may be
included for clarity. For example:

        if (2+3=5)&(10*17=170)&((5>=2)|(9=16))

That's perfectly correct, but impossible to read ;). Adding spaces makes the
statement far clearer:

        if (2+3 = 5) & (10*17 = 170) & ((5 >= 2) | (9 = 16))

See also: BREAK statement

FOR statement
-------------

Usage: for (initial variable setting) (loop condition) (increment set)
           ...
       endfor

The FOR statement executes a block of code while the loop condition is true.
As such, the FOR statement in VPL is very powerful, and integrates the
functionality of for, while, and do/loop constructions present in many other
languages into a single statement.

Usage of the FOR statement is best illustrated with a simple example.

        for ($i = 1) ($i <= 5) ($i = $i + 1)
            eval print $i
        endfor

Will print:

1
2
3
4
5

This is the equivalent of the BASIC code:

        for i = 1 to 5
          print i
        next

And the C code:

        for (int i = 1; i <= 5; i++)
          printf("%d", i);

As can be seen, VPL's FOR statement is very similar to C's, and, like C,
multiple variables and increments can be set in a single FOR statement, for
example:

        for ($x = 1, $y = 5) ($x <= 5) ($x = $x + 1, $y = $y - 1)
            eval print $x $y
        endfor

Would display:

1 5
2 4
3 3
4 2
5 1

This behaviour makes VPL's FOR statement one of the most powerful in any
language.

See also: BREAK statement

BREAK statement
---------------

Usage: break [if (condition)]

The BREAK statement exits from the current level of scope. A level of scope is
defined as:

        (1) The block of code executing due to an IF statement returning true
        (2) The block of code executing due to a FOR statement in progress

If neither an IF statement or a FOR statement are active when the BREAK
statement is issued, execution of code terminates at that point.

Optionally, a condition may be specified. If this is the case, the break only
occurs if the given condition returns true.

Examples:

1. Execution halts at the BREAK statement if no IF or FOR block is currently
active.

        print You should see this.
        break
        print You shouldn't see this.

2. Although the FOR loop is set to go up to 10, it only reaches 5 because of
the conditional BREAK statement.

        for ($i = 1) ($i <= 10) ($i = $i + 1)
            eval print $i
            break if ($i = 5)
        endfor
        print Exited from FOR loop.

See also: IF statement, FOR statement

EVAL statement
--------------

Usage: eval command

Evalutes all variables and functions before executing command. This is best
demonstrated by this example:

        @ $i = 1
        print The value of i is $i.

Will display:

The value of i is $i.

Which is obviously not the desired effect. However:

        @ $i = 1
        eval print The value of i is $i.

Will display:

The value of i is 1.

Which is correct. But what if you wanted to display:

The value of $i is 1.

How do you prevent the first $i from being evaluated? Simple, use $$i instead
of $i. $$ always evaluates to $. So, when the command is evaluated, $$i will be
evaluated to $i, and $i will be evaluated to 1, which is the desired effect.

        @ $i = 1
        eval print The value of $$i is $i.

Evaluting this string twice (a double evaluation)

        @ $i = 1
        eval eval print The value of $$i is $i.

Will print:

The value of 1 is 1.

Because the string is first evaluated from "The value of $$i is $i." to "The
value of $i is 1.", and is then evaluted again to "The value of 1 is 1.".
Double evaluation is useful for arrays.

@ statement
-----------

Usage: @ variable = value

The @ statement makes up in power what it loses in complexity of name. =] It
assigns value to variable. Value is evaluated and then assigned to variable.
For example:

        @ $test = hello
        @ $test = $upper(hello)
        @ $x = 19.6

In order to numerically evaluate value, it must be enclosed in $( and ), as
follows.

        @ $test = 2+3

Would assign the string "2+3" to $test, but:

        @ $test = $(2+3)

Would assign the string "5" to $test.

See also: @u statement

@u statement
------------

Usage: @u variable

The direct opposite of @, @u unassigns a variable. This is best illustrated as
follows:

        @ $test = hello
        eval print Momma says $test.
        @u $test
        eval print Momma says $test.

The above code will print:

Momma says hello.
Momma says $test.

$test is not evaluated in the second line printed because ... uhh ... it no
longer exists. =]

& statement
-----------

Usage: & (condition) {what to display if condition is not met}

The & command (great command, shame about the name ;) is used right at the
beginning of a VPL program to ensure, usually, that the user is running a high
enough version of ViRC for it to work correctly. If the condition fails, a
messagebox is displayed containing the text in {}'s, and the loading of the VPL
program is halted.

If your script requires ViRC 0.90alpha3 or higher, you would use:

& ($ver >= 0.90) & ($rev >= 3) {This script requires ViRC 0.90alpha3 or higher.}

Executing IRC commands
----------------------

Usage: /command ...

Of course, the main purpose of VPL is to execute IRC commands. ;) IRC commands
can be executed by preceeding them with a /, just as if they were typed from
the keyboard. The / is REQUIRED to tell ViRC that what follows is an IRC
command (to send to the IRC parser) rather than a VPL statement (to send to the
VPL parser)

Functions in VPL
================

UPPER function
--------------

Usage: $upper(text)

Returns text, with each letter converted to uppercase.

Example:

        eval print $upper(test)

Would print:

TEST

See also: LOWER function

LOWER function
--------------

Usage: $lower(text)

Returns text, with each letter converted to lowercase.

Example:

        eval print $lower(TeSt)

Would print:

test

See also: UPPER function

LEFT function
-------------

Usage: $left(x text)

Returns the first x characters in text, starting from the left.

Example:

        eval print $left(4 abc123)

Would print:

abc1

See also: RIGHT function, MID function

RIGHT function
--------------

Usage: $right(x text)

Returns the last x characters in text.

Example:

        eval print $right(4 abc123)

Would print:

c123

See also: LEFT function, MID function

MID function
------------

Usage: $mid(pos x text)

Returns the first x characters in text, starting from pos.

Example:

        eval print $mid(2 3 abc123)

Would print:

bc1

See also: LEFT function, RIGHT function

RANDOM function
---------------

Usage: $random(x)

Returns a random integer, such that 0<=return<x. In other words, the random
number returned can be anywhere between 0 and x-1.

Example:

        eval print $random(176)

Might print:

18

Or:

156

But never:

176

Or:

-41

LEN function
------------

Usage: $len(text)

Returns the length of text. Example:

        eval print $len(abcdefghijklmnopqrstuvwxyz)

Would return:

26

GETTOKEN function
-----------------

Usage: $gettoken(text char)

Returns everything to the left of the first occurrence of char in text,
starting from the left of the string.

Example:

        eval print $gettoken(jimc.demon.co.uk .)

Would print:

jimc

See also: INVGETTOKEN function, RGETTOKEN function, INVRGETTOKEN function

RGETTOKEN function
------------------

Usage: $gettoken(text char)

Returns everything to the right of the first occurrence of char in text,
starting from the right of the string.

Example:

        eval print $rgettoken(jimc.demon.co.uk .)

Would print:

uk

See also: GETTOKEN function, INVGETTOKEN function, INVRGETTOKEN function

INVGETTOKEN function
--------------------

Usage: $invgettoken(text char)

Returns everything to the right of the first occurrence of char in text,
starting from the left of the string.

Example:

        eval print $invgettoken(jimc.demon.co.uk .)

Would print:

demon.co.uk

See also: GETTOKEN function, RGETTOKEN function, INVRGETTOKEN function

INVRGETTOKEN function
---------------------

Usage: $invrgettoken(text char)

Returns everything to the left of the first occurrence of char in text,
starting from the right of the string.

Example:

        eval print $invrgettoken(jimc.demon.co.uk .)

Would print:

jimc.demon.co

See also: GETTOKEN function, RGETTOKEN function, INVGETTOKEN function

READ function
-------------

Usage: $read(filename)

Returns a random line from filename. Example:

        eval print $read(d:\windows\win.ini)

Might print:

[386Enh]

Or:

device=Brother HL-6V,HPPCL5MS,LPT1:

NTIME function
--------------

Usage: $ntime()

Returns the number of seconds that have elapsed since midnight, accurate to 2
decimal places. This function is used in ping algorithms.

Example:

        eval print $ntime()

Might print:

74626.89

See also: TIME function, DATE function

TIME function
-------------

Usage: $time()

Returns the time in human-readable format.

Example:

        eval print The time is now $time().

Might print:

The time is now 18:06:54.

See also: NTIME function, DATE function

DATE function
-------------

Usage: $time()

Returns the date in human-readable format.

Example:

        eval print The date is $time().

Might print:

The date is 11/07/95.

See also: NTIME function, DATE function

INPUTBOX function
-----------------

Usage: $inputbox(text)

Prompts the user for a response, displaying text in the prompt dialog. Example:

        eval print You typed $inputbox(Type something!!)

See also: MSGBOX function

MSGBOX function
---------------

Usage: $msgbox(type text)

Prompts the user for an OK-style or yes/no-style response, displaying text in
the prompt dialog. type can be one of the following:

0       Display OK button only.
1       Display OK and Cancel buttons.
2       Display Abort, Retry, and Ignore buttons.
3       Display Yes, No, and Cancel buttons.
4       Display Yes and No buttons.
5       Display Retry and Cancel buttons.

16      Display a STOP icon.
32      Display a question mark icon.
48      Display an exclamation mark icon.
64      Display an "i" icon.

0       First button is default.
256     Second button is default.
512     Third button is default.

Multiple settings may be combined by adding their values together. For example,
if you wanted a message box that had Yes and No buttons, displayed a question
mark icon, and whose second button (No) was default, you would specify type as
292 (which is 4+32+256).

The value returned by this function depends on the button the user pressed:

1       OK button selected.
2       Cancel button selected.
3       Abort button selected.
4       Retry button selected.
5       Ignore button selected.
6       Yes button selected.
7       No button selected.

Example:

        @ $test = $msgbox(292 Press a button!!)
        if ($test = 6)
           print You clicked on the Yes button.
        endif
        if ($test = 7)
           print You clicked on the No button.
        endif

WILDMATCH function
------------------

Usage: $wildmatch(text1 text2)

Returns true if text1 and text2 are equivalent, expanding wildcards. Examples:

        $wildmatch(hello hello) = true
        $wildmatch(he* hello) = true
        $wildmatch(ell hell*) = false
        $wildmatch(*ello hubalubaloohello) = true

See also: MASKMATCH function

MASKMATCH function
------------------

Usage: $maskmatch(mask1 mask2)

Returns true if nick!user@host masks mask1 and mask2 are equivalent, expanding
wildcards. Examples:

        $maskmatch(MeGALiTH!~megalith@jimc.demon.co.uk *!*@*uk) = true
        $wildmatch(a!b@c *!*b@*c) = true
        $wildmatch(a!b@c b!c@a) = false

See also: WILDMATCH function

TDIFF function
--------------

Usage: $tdiff(x)

Expands the time x given in seconds to a more "human-friendly" form. Examples:

        eval print $tdiff(12368)
        eval print $tdiff(6481239128.96)
        eval print $tdiff(7201)
        eval print $tdiff(86400)
        eval print $tdiff(1)

Would print:

3 hours 26 minutes 8 seconds
75014 days 8 hours 12 minutes 8.96 seconds
2 hours 1 second
1 day
1 second

User-defined functions
======================

You're not just limited to built-in functions. You can make your own functions
too. Making a function is just like creating an alias, the only difference
being that a function must set the value of a special variable,
function_return. Here's an example of a function that's more complex than an
example function should be. =] It strips all of the vowels out of the text
given.

alias novowels {
      @ $otext = $0-
      @ $ntext = $null
      for ($i = 1) ($i <= $len($otext)) ($i = $i + 1)
          @ $x = $mid($i 1 $otext)
          @ $ux = $upper($x)
          if (([$ux] <> [A]) & ([$ux] <> [E]) & ([$ux] <> [I]) & ([$ux] <> [O]) & ([$ux] <> [U]))
             @ $ntext = $ntext$x
          endif
      endfor
      @ $function_return = $ntext
}

Arrays
======

Arrays are not supported directly, but they can be implemented using a trick
known as "double evaluation". This is best demonstrated with the following
example:

        @ $numbers.0 = zero
        @ $numbers.1 = one
        @ $numbers.2 = two
        @ $numbers.3 = three
        @ $numbers.4 = four
        @ $numbers.5 = five
        @ $numbers.6 = six
        @ $numbers.7 = seven
        @ $numbers.8 = eight
        @ $numbers.9 = nine

        for ($i = 0) ($i < 10) ($i = $i + 1)
            eval eval print $$numbers.$random(10)
        endfor

This will print the verbal equivalents of 10 numbers from 0-9, picked at
random. The trick is as follows. The string:

        print $$numbers.$random(10)

Is evaluated twice, due to two EVAL statements being present. The first
evaluation might return:

        $numbers.7

The second evaluation would then cause the variable $numbers.7 to be evaluated,
and would therefore display:

        seven

On the screen. This trick can even be used to make arrays of arrays.

Properties
==========

What are properties?
--------------------

ViRC's property support, sort of similar to VB and Delphi, allows attributes of
objects to be set. Currently, the only "objects" supported are event objects,
but properties allow much flexibility.

Setting properties
------------------

Usage: setprop type:category->name.property = value

At the moment, the only type support is event. Category refers to the event
type, and is the same as the category field for event handlers. The name
property is the object's name, and for event handlers, is the name of the
event. The property field can be one of the following for event handlers:

   Where   - sets where the contents of the Text property is to be displayed
   LogType - sets the logtype (and hence colour) of Text when it is displayed
   Text    - sets the text to be displayed on reception of the event
   MMFile  - sets a multimedia file (WAV, MID, AVI) etc. to be played

Examples:

# Make all incoming channel text appear in the server notices window
setprop event:0->PRIVMSG:CHANNEL.Where = 1
# Make the displayed channel text have the form -=Nickname=- Text
setprop event:0->PRIVMSG:CHANNEL.Text = -=$nick=- $1-

If the given event doesn't exist, it is NOT created automatically, unlike event
handlers, which do not require the event to exist already. This will change
before final release, and new events will be able to be created by setting
properties as well. Currently, you need a fragment such as this to make a new
event and set properties.

setprop event:0->123.Where = 1
setprop event:0->123.Text = Event 123: $0-

event 0 123 {
}

Note that it doesn't matter whether the setprop commands are located before or
after the empty event handler. ViRC searches through your VPL code to locate
event handlers anywhere.

Getting properties
------------------

Getting the value of properties is done with the $getprop(property) function.

Example:

# Display the multimedia file played when someone joins a channel

/eval echo $getprop(event:0->JOIN.MMFile)

Example programs
================

The following VPL programs are included with 0.90alpha4.

  Name     | Function                             | Demonstrates ...
 ----------+--------------------------------------+----------------------------
  BAN      | Perform /ban, /unban, /fk etc.       | Aliases, events, if, goto
  CLEARBAN | Remove all bans set on you           | Aliases, events, properties
  COLTEXT  | Send text to chan. in random colours | Functions, for, &
  PING     | Accurate pings (built into 0.90)     | Functions, properties

If you've written something interesting in VPL and want to share it with the
world, send it to me, and I'll include it in a future version of ViRC. Of
course, it'll bring you instant fame, if not fortune. =]
