GIB Mark III Reference

Beta version


Basic Syntax


The syntax of GIB is mostly similar to the normal quake console:


command arg1 arg2 arg3 ...


However, there are a few differences when it comes to characters that surround tokens.  Double quotes work as you would expect:


echo "Hello, world!"


No processing is done to text inside double quotes.  If you want to use variables or function return values, you shouldn't use double quotes.  Within double quotes you may now use escape characters.  As of now, this allows you to use \" in place of a double quote and \n in place of the newline character.


echo "This token has two \"quotes\" and\na newline."


In addition to double quotes, you may now use curly braces to surround tokens.  Curly braces have one unique feature:  you may have line breaks within them:


echo {This token

has several

lines}


This is most useful with functions, loops, and if statements.  As with double quotes, no processing is done inside curly braces.  The final type of token is one surrounded by parentheses.  These enclose math expressions that will be evaluated before the command is executed:


echo (5*5-(1/(2+1)))


See the section on the math evaluator for more information.


Sometimes you will want to be able to combine tokens of different types into one token.  For instance, it might be useful to include a math expression inside a string that will be displayed.  You can use a comma (,) between two token to concatenate them:


echo "5 times 5 is ", (5*5), "."


GIB is fairly anal about malformed commands.  Unmatched braces, parentheses, and double quotes will generate errors and halt execution of your program.


Variables


Types


There are three types of variables in GIB: local, global, and console.  Local variables are visible only to the current function and are destroyed when that function completes.  Global variables are visible to all GIB functions and are never destroyed.  Console variables are not strictly part of GIB but can be manipulated and used by it.


Structure


Local and global variables differ from console variables in that they can be trees.  For instance, the following would all be part of the same variable:


foobar

foobar.1

foobar.2

foobar.2.string

foobar.3.string


If a variable is global, all branches of that variable are automatically global as well.


Substitution


Any place outside quotes, the following patterns will be replaced with the value of the variable they specify:


$variable

${variable}


In the first example, the end of a variable name is considered to be the first non-alphanumeric, non-underline character, for instance:


$var1*$var2


would be two different variables with a * between them


In the second example, everything within the braces ({ and }) is considered part of the variable name.  Braces MUST be used when substituting branches of variables:


${variable.branch.anotherbranch}


This makes assignment dynamically to a branch less cumbersome, because periods in variable names won't automatically get swallowed.  Variables can act as pointers to another variable by containing their name.  You can then access the named variable indirectly through the pointer:


$$pointer


You can use this to dynamically access branches as well:


${variable.$i.string}


You may trim the value of a variable down into a certain range of characters.  For instance:


$variable[2:5]


Will give you characters 2 through 5 of the variable.  Characters start at 0.  If you try to access characters outside the length of the variable, it will be clipped to the end of the variable.   A negative number counts backwards from the end of the variable, so -1 would mean the second from last character, -2 the third from the last, and so on.  To specify the last character, use a colon but don't specify a second number.  If you only want one character, you can omit the colon and second number.  Consider these examples:


h = "hello"

echo $h[0:1]  // Prints "he"

echo $h[:2]   // Prints "hel"

echo $h[2:]   // Prints "llo"

echo $h[1:-1] // Prints "ell"


Here is one thing that will not work:


${variable.$var[0:1].string} // Indexing only works at the top level


Variables will be checked in this order when substituting: Local, global, console.


Assignment


You assign to a GIB variable using the syntax:


variable = value


Assigning to a branch is simple:


variable.branch = value


If you want to dynamically assign to a branch, you can use:


variable.$i.string = value


where the variable i contains the name of the branch to assign to.  Note that if the period after $i were considered to be part of the variable name, this wouldn't work.  The number and level of branches is theoretically unlimited.


When assigning to a variable that doesn't exist, it is automatically created as a local.  If a local already exists, it is assigned to.  If a global already exists, it is assigned to.  If both a local and global exist with the same name, the local is assigned to.  You should declare your globals in the main body of your GIB script with the following syntax:


global varname


This ensures that the variable and all branches used later on will be persistent across different functions.


If you can't be certain that a variable you want to use as a local doesn't already exist as a global, you can use the following at the start of your functions:


local varname


This will ensure that all further operations on that variable will use a local version.  You will be sharing a namespace with any other loaded GIB scripts, so this is advised.  On the other hand, it is bad practice to use common variable names such as i as globals.  Consider created a single global variable with the name of your script and using branches of it to store global data.


Functions


Functions are like aliases of the normal quake console, with several differences:

- They execute in a new context

- They can take arguments

- They can return values

- They are normally not usable from the console.


You declare a function as follows:


function name program


In general, you will want to write functions like this:


function test {

echo "Hello, world!"

}


A function gets its own set of local variables whenever it is executed.  Each instance of a function gets a unique set.  When a function is executed, several local variables are set up for it.  These are argc, the number of arguments the function was called with, and the numbers 0 through argc-1, each containing and argument.  Argument 0 is the name of the function.  Therefore, even a function called with no arguments will get an argc of 1.  Consider the following example:


function test2 {

echo "The name of this function is ", $0

echo "My first argument is ", $1

}


You can use a "pointer" variable and argc to easily examine each argument passed to a function.  The following function prints each argument passed to it on a separate line:


function printargs {

local i

i = 1

while ($i < $argc) {

  echo $$i

  i = ($i + 1)

}

}


Functions can return a value to whatever called them at any time.  The syntax for return is as follows:


return value


If you omit the value, the function will cease execution but will not return anything.  Attempting to return a value where it isn't wanted (to a non-GIB buffer, or to a buffer that has not requested a return value, or at the top of the execution stack) will result in a warning, but execution will proceed as usual.  In order to use the return value of a function, you must substitute it into your command using backticks (` `).  This key is usually found above the tab key on most keyboards.  It usually is the same key with ~ on it.  Consider this example:


function hello {

return "Hello, world!"

}


echo `hello`


The function within the backticks is run, and the return value is substituted in its place.  This example would result in "Hello, world!" being printed.  Some built-in GIB commands can return values; backticks can be used with these as well.  Using backticks with something that does not result in a return value will cause an error.


Normally, GIB functions can only be called from other GIB functions.  However, the export command can be used to make a GIB function available to the console:


function test {

echo "Testing 1 2 3..."

}

export test


The ideal GIB script will export several functions for use in binds or at the console and keep the rest unexported as support functions.  This reduces namespace pollution.


Flow control


Several GIB commands are available for controlling the flow of a GIB program:


while

usage:  while condition program

example:


i = 0

while ($i < 10) {

i = ($i + 1)

}


notes:  While the condition statement evaluates to a non-zero number, the program will be continuously executed.  You can use the break command at any time inside a loop to end the loop prematurely.


for

usage: for variable in list program

example:


for i in "1 2 3 4 5" {

echo $i, " times 2 is ", ($i * 2)

}


notes: "for" iterates a local variable through each whitespace-separated token of a list.  To achieve this, the internal command "__for" is used at the start of each iteration.  Manual use of this command is highly discouraged.


if/ifnot

usage: if condition program [else program2]

example:


if $var1 {

echo "Var1 is true."

}


if $var1 {

echo "Var1 is true."

} else {

echo "Var1 is false."

}


if $var1 {

echo "Var1 is true."

} else if $var2 {

echo "Var2 is true."

} else {

echo "Var1 and var2 are false."

}


notes:  if executes program when condition evaluates to a non-zero number (true).  If the condition is false but else and a second program are present, it will be executed instead. If-else statements can be chained together.  If ifnot is used instead of if, the first program will be executed if the statement is false and the second if the statement is true.


Math Evaluator


The math evaluator supports common arithmetic and logical operators and respects order of operations.


!  Unary not

** Exponent

/  Division

-  Unary negation (to get negative numbers)

*  Multiplication

+  Addition

-  Subtraction

== Equality test

!= Not-equal test

>= Greater-than-or-equal-to test

>  Greater-then test

<= Less-than-or-equal-to test

<  Less-than test

|| Logical or

&& Logical and


Operations will be performed starting at the top of the list and moving down.  In addition to binary and unary operators, several functions are available:


sin  Sine

cos  Cosine

tan  Tangent

asin Inverse (arc) sine

acos Inverse (arc) cosine

atan Inverse (arc) tangent


A function should be used as follows:


echo "Twice the sin of 5 radians is ", (2 * sin (5)), "."


Note that all trigonometric functions operate in radians.


File access


GIB provides rudimentary file access to the current game directory (the directory where the currently-loaded mod resides, determined by the console variable gamedir).  All subdirectories of the current game directory are accessible, but attempts to escape higher into the file system via ".." will cause an access error.


file.read

usage: file.read file

Returns the contents of file.


file.write

usage: file.write file contents

Creates/overwrites file with contents


file.find

usage: file.find glob [subdir]

Returns a list suitable for use in a for loop of all files in the current game directory that match glob.  "*.cfg" and "file???.foo" are examples of globs.  If the optional subdir argument is provided, that directory will be searched instead of the root game directory.



Threads and callbacks


Threads are highly experimental at this point, and aren't true threads in that multitasking is not pre-emptive.  Threads must issue the wait command to relinquish control to the console and other threads.


Callbacks are functions registered to be started in a thread when a certain event is triggered in the client or server.  Currently, only a few events in qw-client can have callbacks associated with them, although more will be added.


thread.create

usage: thread.create program

Creates a new thread containing program.  Returns a unique ID number that should be saved for looping threads.


thread.kill

usage: thread.kill id

Immediately ends the thread with the ID id.


Game-play hooks


As of the 0.5.2 release of QuakeForge, qw-client provides several global variables and callbacks so that GIB can monitor player stats.  The "player" global tree variable is updated with information as follows:


player.health:  The player's health

player.armor:  The player's armor

player.armor.type:  The type (green, yellow, red, none) of armor the player is wearing.

player.ammo.(type)Ammo of (type) that is available.  (type) can be shells, nails, rockets, or cells.

player.weapon.(number):  1 if the weapon corresponding to (number) is available, 0 otherwise.

player.key.(number): 1 if the player has key or flag (number).  Number can be 1 or 2.


Several callbacks can be registered that will get called when one of these stats changes.  Simply set the global variable to the name of the function to be called:


player.health.callback:  Passed the new health value as an argument

player.armor.callback:  Passed the new armor value.

player.ammo.(type).callback:  Passed the new ammo value.

player.weapon.callback:  Called when available weapons change.

player.key.callback:  Called when any key is gained or lost.


Note that in the future these callbacks may get registered in a different way.  These hooks are currently for testing purposes only.


Miscellaneous built-in functions


function.get

usage: function.get function

Returns the program text of function.


string.equal

usage: string.equal string1 string2

Returns 1 if the two strings are the same, 0 otherwise.


string.length

usage: string.length string

Returns the length of string.


range

usage: range start end [step]

Returns a space-separated list of numbers between start and end.  If a step size isn't specified, 1 is used.  If end is less than start and a custom step size is specified, it must be negative.  step cannot be 0 either.  This command is best used with for loops.


Using GIB


GIB code should be placed in a file with the extension .gib.  You can then load it like any other script with the exec command:


exec script.gib


Scripts ending in .gib will be placed in a new buffer on the execution stack set to use the GIB interpreter rather than the normal quake console interpreter.  Note that all other scripts are simply copied into the current buffer.  This means ANY script run from GIB will be considered a GIB script.  Future versions of GIB will allow you to force a command to be run in a standard console buffer.