XYplorer-

Index

Binary Numbers

Boolean Constants

Boolean Operators

Commands and Functions

Comments

Comparisons

Compound Assignment Operators

Control Structures

If/ElseIf/Else Blocks

While Loops

Foreach Loops

Switch Statements

Dereference Operator

General Command Syntax

Heredoc and Nowdoc Syntax

Hex Numbers

Include Statement

Include_once Statement

Math

Multi-line Scripts and Multi-Scripts

Nested Expressions

Operator Precedence

Quick Scripting

Remote Control

Script Files

Script Files for the Advanced

Scripting and User-Defined Commands

Scripting by Numbers

Step Mode: Stepping Through Scripts

Ternary Conditionals

User-Defined Functions

Using Quotes in Scripting

Variables

Variables Scope and Lifetime: Local, Global, and Permanent Variables

Introduction

XYplorer Scripting, introduced with version 7.0, can truly be seen as the ultimate in file management efficiency. Roll your own custom commands, combine them to scripts, wrap them in an XYplorer Script file (XYS), or a User-Defined Command, and trigger them by just a click or a keystroke. You may share scripts with colleagues, or download them from the internet. Just drop a script file into your app folder and fresh plug-in commands are at your finger tips.

Without doubt, scripting is an advanced feature that only pays off if you take the time to dive into it and explore the ways and possibilities. However, you will eventually find out that it ain't rocket science at all.

More information, downloads, and a growing pool of examples is available here:

https://www.xyplorer.com/

Warming Up

To get you started let's try something easy:

(1) Select menu Scripting | Run Script...

(2) Paste msg "Hello world!" into the edit box.

(3) Click OK.

You should see a "Hello world!" message box now. Well done, you just wrote your first XYplorer script!

Okay, now for something a little bit more interesting:

(1)Try msg %temp%. You should see a message box that displays your TEMP path. %temp% is a standard Windows environment variable.
(2)Try msg "XYplorer.exe runs from <xypath>". <xypath> is a native XYplorer variable that resolves to XYplorer's application path.
(3)Try msg "Press OK to copy the time!"; copytext "<date hh:nn:ss>". When the message box is OKed, the second command copytext is immediately executed and the current time is copied to the clipboard.
(4)Try set $a, "<curpath>"; msg $a. You should see a message box displaying the current path. First the variable $a is set to the current path, then it is used in the msg command.
(5)Try $a = "Year " . "<date yyyy>"; msg $a. You should see a message box displaying "Year 2009" (or whatever the year might be when you try this). First the variable $a is set to two strings, one literal and one variable, concatenated by a dot, then it is used in the msg command.

General Command Syntax

(1)There are commands consisting of a function name like msg or copytext, and arguments that can contain literals like "Hello!", and variables like %temp% (environment), <curpath> (XYplorer), or $a (user-defined).
(2)An argument can have more than one part. The parts are concatenated by dots ( . ).
(3)A command can have more than one argument. The arguments are separated by commas ( , ).
(4)A script can have more than one command. The commands are separated by semi-colons ( ; ).
(5)Arguments are identified either by position, or by a prefixed number denoting their position (see Numbered Arguments below).

Examples

This little script will rename all currently selected items by appending the current date:

rename b, "*-<datem yyyymmdd>"

This script goes to the Desktop folder (ensuring that the listing is unfiltered), sorts the list by date modified (descending), selects the first item, and moves the focus to the list:

goto "Desktop|"; sortby m, d; sel 1; focus List; 

Numbered Arguments

Instead of counting commas you now can prefix the position of the argument to the argument itself. The separator is ":=", the first position is 0 (zero).

For example, instead of this:

text popupmenu("A,B,C", , , , , , ",");

You can do this:

text popupmenu("A,B,C", 6:=",");

You can even do this (reversed or arbitrary order):

text popupmenu(6:=",", 0:="A,B,C");

Or this (processing is from left to right, the last mapping wins):

text popupmenu("a,b", 6:=";", 6:="|", 6:=",", 0:="A,B,C");

Concatenation

Strings and variables can be concatenated by dots. Any number of blanks surrounding the concatenator are ignored. The following scripts are identical:

msg "Hi there!"

msg "Hi "."there!"

msg "Hi " . "there!"

msg "Hi "   .  "there!"

msg "Hi"." "."there!"

Using Quotes in Scripting

It's strongly recommended that you (double- or single-) quote your strings! While the script engine is currently still permissive with unquoted strings (msg Hi! works) this might not be so in the future, so you better do msg "Hi!" right away!

Here's the basic laws of quoting:

(1)Everything is either in double-quotes, or in single-quotes, or outside of any quotes.
(2)To have double-quotes inside double-quotes they must be doubled.
(3)To have single-quotes inside single-quotes they must be doubled.
(4)Variables are resolved in double-quotes and outside of any quotes, but not in single-quotes.

Commands and Functions

There are two types of commands: commands (proper) and functions. Contrary to commands (e.g. echo), functions (e.g. quote()) return an in-place value.

In the first example, the quoting is achieved by doubled double-quotes. The only command in the statement is echo. In the second example, the quoting is achieved through the function quote():

echo """Hi!""";    //"Hi!"

echo quote("Hi!"); //"Hi!"

Remarks on Functions

(1)Function names are not case-sensitive: QUOTE() = quote().
(2)Even without any argument -- e.g. quote() -- the parentheses are mandatory, else a function is not recognized.
(3)You can call a function without caring for the return argument (but you need the parentheses!):
renameitem("John", , , "-01");
Optionally you can use the dummy command call:
call renameitem("John", , , "-01");
(4)Functions are not resolved (interpolated, see below) when inside double-quotes.

Command Prefixes

Now you can add a prefix to each command to modify its behavior. Currently one prefix is implemented:

 e = skip the big error debugging dialog

The prefix is separated from the command by | (pipe). For example, when you run this command in the drives listing:

rename , '*-<datem yyyymmdd>';      //shows error dialog

e|rename , '*-<datem yyyymmdd>';    //skips error dialog

Quick Scripting

Quick Scripting means: Scripts, when prefixed with "::" (double-colon), can be executed directly (i.e. quickly) through any interface in XYplorer that can process locations: Address Bar, Go To, Favorites, Catalog etc. This gives you a lot of choices for usage and storage of scripts.

Let's try:

Paste ::msg "Hello world!" into the Address Bar and press Enter. You should see a "Hello world!" message box.

Now, for mouse users, the Catalog is a very good place for scripts. Using the "::" prefix, scripts can be simply entered into the Location field of a catalog item. They are executed on a single click.

For example:

(1)Add a new category "Scripts" and add a new item to it.
(2)Set item's Location field to ::#1026 and save it. The icon turns into the script symbol.
(3)Now click the item. The Find Files tab on the Info Panel is opened, all search filters are reset, and the cursor is placed into the Name field. Nice!

But how did this work? And what is #1026? Read on...

Note: From version 9.70 onwards the "::" prefix is not necessary anymore when you end your script line with a trailing ";" (appended comments after the ";" are allowed). This behavior is enabled by the INI setting ScriptSmartDetect=1.

Scripting by Numbers

In XYplorer almost every function has a fixed number, the function ID, by which it can be referred to in a script. ID #1026 happens to refer to "Miscellaneous / Find Files / Open Find Files and Reset". Open the Customize Keyboard Shortcuts dialog (menu Tools) and find this function in category Miscellaneous. At the bottom of the dialog you'll see a button showing the function's ID. Clicking this button will copy the function's ID to the clipboard, making it easy to use it in a script.

You can execute almost any function in XY in a script by referring to its function ID. E.g. #230 will pop up the submenu "New" of menu Edit.

Step Mode: Stepping Through Scripts

Suppose you have an older script #230, and you forgot what #230 refers to. Or you downloaded a script from the internet, and don't know exactly what it does. What now? Very simple, enter Step Mode:

(1)Open the Scripting menu and select Step Mode.
(2)Now execute your mysterious script.

A small window, the Step Dialog, will pop up and tell you what is about to happen. You can now decide whether to execute the command, or skip it, or cancel the whole script. In stepping mode you are on the safe side. It is highly recommended when writing or debugging scripts!

There's also a toolbar button for toggling the stepping mode. When pressed (stepping is ON) its color changes to red to make the current state very clear.

Error Messaging and Risk Classes

The Step Dialog also tells you what went wrong where, and it informs you about the potential risk associated with the command to be executed. There are the following risk classes:

#3Potentially harmful because the function ID might refer to some risky process which is unknown at this point (either an internal command or a User-Defined Command): #[function ID]
#2Potentially harmful because files or folders are affected: backupto, copyto, delete, download, moveto, new, open, openwith, rename, rotate, run, setkey, swapnames, timestamp
#1Potentially harmful because Step Mode is terminated: unstep
#0Harmless: (all others)

Class #3, #2, and #1 are marked with a yellow "warning" icon, class #0 with a blue marble (think "cool") icon.

Script Context

The first two lines in the Step Dialog display (1) the current script resource,  and (2) the current script caption. Valuable information when writing and debugging scripts.

How Functions are Stepped

Functions are individually stepped. The current script line is marked green when a contained function is stepped as opposed to the main command of the line. You can even skip (button Skip) functions individually, in which case the function name is returned with the resolved arguments. For example:

msg quote(chr(64));

·If you continue both functions the result is: "@"
·If you skip chr() and continue quote() the result is: "chr(64)"
·If you continue chr() and skip quote() the result is: quote(@)
·If you skip both functions the result is: quote(chr(64))

When you "Continue without Stepping" on a function, the stepping is only suspended for all functions in the current script line / command.

Variables... (Button)

Click the Variables... button to display all currently assigned variables with their current values. Within the new "Variables on Stack" dialog you can double-click any listed variable to show its current value.

Right-click that button for further options:

Show User Functions will list all currently declared user functions. Within the new "User Functions" dialog you can double-click any listed function to show its code.

Scripting and User-Defined Commands

Now, for passionate keyboarders, there are User-Defined Commands (UDCs). Using the "::" prefix, scripts can be simply entered into the Location field of a UDC Go To item, which then can be assigned a keyboard shortcut to.

For example:

(1)Click menu User | Manage Commands...
(2)Select the category Go To, and click the New button.
(3)Enter ::text "<clipboard>" into the Location field.
(4)Assign a keyboard shortcut, say Ctrl+Alt+3.
(5)Click OK.

Now press Ctrl+Alt+3. You should see a small window displaying the current textual contents of the clipboard.

Of course, you don't have to abuse the UDC Go To for scripts. There's also the UDC Run Script which accepts scripts without a prefixed "::", e.g. text "<clipboard>".

Run Script can also handle more advanced stuff like multi-line scripts, and multi-scripts, the rules and possibilities of which will be further explained below under "XYplorer Script Files".

Multi-line Scripts and Multi-Scripts

A script can have more than one line (multi-line script), and a script resource can have more than one script (multi-script). There is one important formatting rule for multi-line scripts:

In a multi-line script all lines apart from the first line have to be indented by at least one space.

Each non-indented line is interpreted as the first line of a separate script, and if there are more than one scripts in a loaded script resource (i.e. a multi-script) then a menu is popped where you can select the script to run.

For example, this is a multi-script containing two multi-line scripts. In the first script, the script caption (which is used as the menu caption) forms the first line:

"Go to C:\"
 goto "C:\";
goto "%winsysdir%";
 selectitems "calc.exe";

Comments are an exception: Any number of non-indented comments can be prefixed to a multi-line script. Actually non-indented comments can be inserted anywhere. This script is functionally identical to the above one:

// comment 1
// comment 2
"Go to C:\"
// comment 3
 goto "C:\";
// comment 4
goto "%winsysdir%";
 selectitems "calc.exe";
// comment 5

Initialize and Terminate

You can define two special-named scripts within multi-scripts, "_Initialize" and "_Terminate". They can be placed anywhere in the multi-script, and they are not shown in the popup menu. The script called "_Initialize" will be auto-processed before the menu is popped. The script called "_Terminate" will be auto-processed after the script selected from the menu has been processed (or after the menu has been canceled).

Note: If a script within a multi-script is called directly (SCs Sub or Load), then "_Initialize"/"_Terminate" are NOT called.

For example, this multi-script defines a permanent variable (which is also global by definition), then offers various scripts in a popup menu, then finally removes the variable from memory:

"_Initialize"
 // if variable already exists it is NOT reset here but keeps it current value
 perm $p_a;
 // explicitly initialize it to zero
 $p_a = 0;
"_Terminate"
 unset $p_a;
 
"Show Variable"
 echo $p_a;
"Plus One"
 $p_a = $p_a + 1;
 echo $p_a;
"Minus One"
 $p_a = $p_a - 1;
 echo $p_a;
"Load Plus One"
 // will NOT call "_Initialize"/"_Terminate"
 Load "*", "Plus One";
 // WILL call "_Initialize"/"_Terminate"
 Load "*", "*";
"Sub Plus One"
 // will NOT call "_Initialize"/"_Terminate"
 Sub "Plus One";

Script Files

Here we are talking popup menus that are user-defined by a text file. Let's make one:

Create a new text file in any editor.

Paste the following multi-line script (see above):

// some little test scripts
"Go to C:\"
 goto "C:\"
"Go to System Folder"
 goto "%winsysdir%"
"Go to XYplorer Folder"
 goto "<xypath>"

Save the file as "test.xys" (XYplorer Script File) in XYplorer's Scripts folder. In case you don't know that path, use menu Scripting | Go to Scripts Folder to go there.

Now, in XYplorer, click menu Scripting | Load Script Files... and open "test.xys". The following menu should pop up at your mouse cursor:

Go to C:\

Go to System Folder

Go to XYplorer Folder

Now you can choose where you want to go.

A script file is basically a library of scripts. It is nothing more than a simple text file, which can contain one or more scripts. You will be able to either call one of those scripts directly, or simply load the entire file. In such case, XY will create a menu based on the contained scripts in that file and pop it up, allowing you to choose which script to execute.

The syntax for the scripts themselves within script files is exactly the same as for scripts anywhere else in XY since this is just another way to store and execute scripts.

Syntax rules for XYplorer Script Files

(1)Lines starting with // are ignored and can be used for comments.
(2)One script can run over multiple lines. Simply indent the lines after the first line using any number of space or tab characters.
(3)You can have more than one script inside a script file. In that case, loading the script file will pop up a menu presenting all scripts inside the script file by their captions.
(4)To set a script caption simply prefix the desired caption to the script, and wrap it in quotes.
(5)Within a caption you may define a label that allows you to execute a script from a file directly.
(6)Using the command sub in a script file you can execute other scripts inside the same file.
(7)You may hide scripts by prefixing an underscore (_) to their caption.

To Load a Script File do one of the following:

(1)Use menu Scripting | Load Script File...
(2)Use a User-Defined Command from category "Load Script File".
(3)Use the script command load [scriptfile].

The existence of a command load, of course, means that one script file can load another. You will get an idea of the potential of scripting by now...

Drop on a Script File

You can drop files onto XYS-files. The dropped files are referred to in the dropped-on script by <get drop>.

This can get pretty cool in Dual Pane mode. You can have a folder with assorted script files in one pane, and your working folder in the other pane. Now you just drag-and-drop files onto the scripts for automated processing.

Primitive example script in a file "drop_on_me.xys":

text <get drop>;

Even cooler: You can also drop on multi-scripts. In that case you get the usual popup menu of choices, and the <get drop> will be available in each of the scripts.

Primitive example script in file "drop_on_me_2.xys":

"Text"
 text <get drop>;
"Echo"
 echo <get drop>;

Notes:

·If more than one file is dropped <get drop> returns one per line. Alternatively you can pass a separator like this:
text <get drop |>;
·The <get drop> variable is cleared after the script is processed, so it cannot be used after the drop event is completed.
·<drop> is a synonym for <get drop>.
·If the script contains no <get drop> variable it is run nevertheless just as if you loaded the script file.
·You can as well drop files on shortcuts (LNK) to XYS-files.
·You can also drop text onto XYS-files (and LNKs to XYS-files), e.g. selected text from a webpage. Just like with dropped files, the dropped text can be referred to in the dropped-on script by <get drop>.

Script Files for the Advanced

Labels

By using labels you can execute a script inside a file directly, avoiding the popup menu. The label is attached to the caption, separated by " : " (space-colon-space).  For example:

// some little test scripts, using labels
"Go to C:\ : croot"
 goto "C:\"
"Go to System Folder : system"
 goto "%winsysdir%"
"Go to XYplorer Folder : xy"
 goto "<xypath>"

If the above is saved to a file called "test.xys" in application data path then the following command will directly bring you to the System folder: load "test.xys", "system".

You may as well specify a list of labels, by which you can easily control which scripts are displayed in the popup menu, and in which order. See load for the details.

Wildcard catch-all label: The label "*" matches all load calls if more than one label is stated. The third command will be shown on load "test.xys", "croot;system":

// some little test scripts, using labels
"Go to C:\ : croot"
 goto "C:\"
"Go to System Folder : system"
 goto "%winsysdir%"
"Go to XYplorer Folder : *"
 goto "<xypath>"

Hiding scripts inside a script file

Hidden scripts can be executed but are not shown in the script file's popup menu. To hide a script simply prefix an underscore to the caption or label (a hidden script does not need a caption anyway). For example, create a script file "date.xys" in application data path with the following contents:

// this is in script file "date.xys"
"_date"
 msg "<date yyyy-mm-dd>"
"_time"
 msg "<date hh:nn:ss>"
"Show Date : date"
 sub "_date";
"Show Date && Time : datetime"
 sub "_date";
 sub "_time"

Now execute the script load "date.xys". The popup menu will show only two of the four contained scripts. Select either and see what happens.

Now run the script load "date.xys", "date". The script with the label "date" will be executed directly. It has only one command: sub "_date";. The sub command is a special command to call a script inside the same script file. In this case the hidden script with the label "_date" is called and executed. Its command msg "<date yyyy-mm-dd>" produces the message box showing the current date.

Variables in Captions

The captions of scripts in multi-script resources may contain XYplorer native variables. They are resolved in the moment the menu is popped up. For example, paste this into the Try Script box:

"Go to <xypath>"
 goto "<xypath>";
"Is it <date hh:nn:ss>?"
 msg "It's <date hh:nn:ss>!";

The 2nd script will show two different times if you wait longer than a second before you click the menu item.

Also Environment Variables and Permanent Variables are supported in captions.

Icons, States, and Levels

You can optionally define an icon and a state for each menu item.

Syntax:

"Caption|Icon|State|Level : Label" Script
 where
State Default = 1
State Checked = 2
State Disabled = 4

Examples for States

"Go C:|C:|1" goto "C:\";  //shown bold
"Go D:|D:|2" goto "D:\";  //shown checked
"Go E:|E:|3" goto "E:\";  //shown bold and checked

Icon can be any file or folder, and its small system icon (the one you see in Details View) will be used for the menu, or a PNG, JPG, GIF, BMP, or TIF file. XY variables and environment variables are supported. The path defaults to the XY icon path <xyicons>.

You can as well use XYplorer's internal toolbar icons using the button key, e.g.:

"Funny Script|Icons\fun.ico" echo "Ha!";
"Say Ho!|iexplore / 12" echo "Ho!";
"Recent Locations|:mru" button "mru"
"Hotlist|:hotlist" button "hotlist"

Note that the icon specification in a multi-script resource supports permanent global variables.

You can as well use generic file icons in the multi-script menus by passing the generic extension as "*.ext":

"Megan|*.png"  echo 'hello';
"Betty|*.jpg"  echo 'hello';

You can as well pass * as placeholder to use the caption as icon pointer:

"C:\|*" goto "C:\";
"C:\Windows|*" goto "C:\Windows";

Levels: Multi-Scripts support nesting. The level is simply stated by the number denoting its depth, first level is 0 (zero), which is also the default, of course. Up to 256 levels are possible. For example:

"C:|*"
"Go to C:\|||1"
 goto "C:\";
"|||1" goto "%winsysdir%";
 selectitems "calc.exe";
"D:|*"
"Go to D:\|||1"
 goto "D:\";

Relative Levels: Multi-script nesting can be defined with relative levels. This can be useful when building menus from local resources by use of the Include statement.

Syntax: A relative level is marked by a prefixed "+" character. The number following "+" is added to the last defined absolute level.

For example, the following two code samples create identical nested multi-scripts:

"A" echo "A";
"B|||1" echo "B";
"C|||2" echo "C";
"D|||1" echo "D";
"B|||2" echo "B";
"C|||3" echo "C";

"A" echo "A";
"B|||+1" echo "B";
"C|||+2" echo "C";
"D|||1" echo "D";
"B|||+1" echo "B";
"C|||+2" echo "C";

However, the second sample uses relative levels which allows it to re-use the same part of code twice:

"B|||+1" echo "B";
"C|||+2" echo "C";

So this part of code could be outsourced to a file say "IncludedMenuBC.xys" and then be included like this:

"A" echo "A";
include "IncludedMenuBC.xys"
"D|||1" echo "D";
include "IncludedMenuBC.xys"

The Goto-Shorthand

In a multi-script resource you can pass a plain path/file spec as a shorthand for a well-formed goto script. Such a line will be auto-converted to a valid goto command including the appropriate icon in the generated popup menu.

Long version using well-formed goto scripts with captions:

"C:\|C:\" goto "C:\";
"C:\Windows|C:\Windows" goto "C:\Windows";
"C:\WINDOWS\SoundMan.exe|*" goto "C:\WINDOWS\SoundMan.exe";

Equivalent shorthand version:

C:\
C:\Windows
C:\WINDOWS\SoundMan.exe

The goto-shorthand additionally supports environment and native variables, Quick Searches, and visual filters. For example:

Desktop
%tmp%
<xydata>
C:\WINDOWS\system.ini
C:\WINDOWS\system32
C:\WINDOWS\system32?a*
C:\WINDOWS\system32?:a* or b*
C:\WINDOWS\system32?:a* | b*
C:\WINDOWS\system32?lbl:blue
C:\WINDOWS\system32|a*

Comments

Two types of comments are supported, line end comments, and block comments.

Line End Comments

Line end comments begin with a double-forward slash (outside of any quotes) and end at

the end of the line:

$a = "<xypath>"; assert $a=="<xypath>"; //should not fail

$a = "<xypath>";            //assign XY path
 assert $a=="<xypath>";  //should not fail

"get CountSelected" // comment
 $count = get("CountSelected");  // comment
 assert $count!=0,     // comment
 "You must select a file before running this script!"

Block Comments

Block comments (aka C-style comments) start with /* (outside of any quotes) and end with the next */ (outside of any quotes) and can span any number of lines:

/* This is
a multi-line
block comment
*/ msg "hi!";

msg /*they can be inserted anywhere!*/ "hi!" /* anytime */;

Remarks on Comments

(1) Line-end and block comments overwrite each other:

msg "Hi!"; // /*this is not a block comment starting...
msg /* //this is not a line end comment starting... */ "Hi!";

(2) Make sure you don't nest block comments. It is easy to make

this mistake if you are trying to comment out a large block of

code:

/*
msg 'This is a test'; /* Will cause a problem */
*/

This, however, will work since // overwrites the /* */ comment:

//msg 'This is a test'; /* This comment is NO problem */

Variables

Advancing in script writing, you will soon feel the need for variables. XYplorer allows you to define and use as many variables as you want, using a number of commands like set, input, replace, etc. The script set $a, "Hi!"; msg $a; will define a new variable $a and assign the string "Hi!" (without the quotes) to it; then a message box will display "Hi!". The same can be achieved using the assignment operator  (=):

$a = "Hi!"; msg $a;

Interpolation

Variables are resolved wherever they are found in the arguments of all subsequent commands of the script, even if they are found inside double-quoted strings (see below, Interpolation); for example:

$name = "Ted"; msg "Hi, I'm uncle $name!";

will display the message "Hi, I'm uncle Ted!".

Format and Scope

Variables have to conform to the following rules:

(1)Variables are represented by a dollar sign ($) followed by the name of the variable.
(2)Names start with a letter or underscore, followed by any number of letters, numbers, or underscores.
(3)Letters are a-z and A-Z.

Good variables: $a, $ABC, $good_variable, $a1, $a_, $_a, $_

Bad variables: a, ABC, $1, a$, $ä, $., $

Variable names are case-sensitive.

The scope and lifetime of a variable begins and ends with the script where it has been defined.

Using the equal-operator (=)

To assign a value to a variable you can simply use the following syntax (as an alternative for the set command):

$a = "b"; or $a="b"; (spaces are ignored)

For the additional "reprocess" operand see description of the set command.

Increment Syntax (++/--)

The common increment syntax using the ++ (--) operator is supported.

$i=5; $i++; msg $i; //6

$i=5; $i--; msg $i; //4

$i++; msg $i; //1

You can also use $i++/$i-- as an argument. The value is incremented/decremented after it is passed to the function*:

$i = 1; echo $i++; echo $i;     //1; 2

$i = 1; echo 1 + $i++; echo $i; //2; 2

$i = 1; echo $i++ + 1; echo $i; //2; 2

$i = 1; echo $i++ . $i++ . $i;  //123

Note in the following that the left operand is incremented before the right operand is added. Finally, after the addition, the right operand is incremented:

$i = 1; echo $i++ + $i++; echo $i; //3; 3 

* Note that before v14.30.0100 the value was incremented/decremented before it was passed to the function!

Interpolation

Interpolation means that variables that are embedded in double-quoted or unquoted strings are resolved (replaced with their corresponding value). Examples:

$name = "Ted"; msg "Hi, I'm uncle " . $name . "!";

Displays "Hi, I'm uncle Ted!". The variable is concatenated with literal strings.

$name = "Ted"; msg "Hi, I'm uncle $name!";

Displays "Hi, I'm uncle Ted". The variable is interpolated inside double-quoted literal strings.

$name = "Ted"; msg "Hi, I'm " . uncle $name!;

Displays "Hi, I'm uncle Ted". The variable is interpolated inside non-quoted literal string uncle $name!. Note that using non-quoted literal strings is not recommended and might even be deprecated in a future version!

You can block interpolation by using single-quotes:

$name = "Ted"; msg 'Hi, I''m uncle $name!';

Displays "Hi, I'm uncle $name!". The variable is not interpolated inside single-quoted literal strings. Note that single-quotes embedded in single-quotes have to be doubled (I''m).

msg '%TMP% = ' . %TMP%;

Displays "%TMP% = C:\Temp". The first %TMP% is blocked from interpolation by being embedded in single-quotes.

$date = "<date>"; msg '$date = ' . $date;

Displays "$date = 28.08.2008 12:23:12".

Variables Scope and Lifetime: Local, Global, and Permanent Variables

Local Variables

By default, all variables in XY scripting are local, i.e. they are not shared between called and calling scripts. In other words, whenever one script calls another script (e.g. using commands "sub" or "load"), a new local namespace is created by the called script and pushed on the stack.

Global Variables

Generally, global variables are shared between scripts. This can make scripts hard to maintain. However, the mechanism of "globalization" -- (almost) identical to the one used in PHP -- used by XY scripting gives you maximum control over what is shared and where. Global variables are implemented by means of the command global.

Permanent Variables

The lifetime of local and global variables ends with the current script or script stack. Permanent variables, however, stay alive in memory for the whole XYplorer session, or even across sessions if configured like this (Configuration | Refresh, Icons, History | Remember permanent variables). Hence permanent variables can be easily shared between scripts. Permanent variables are implemented by means of the command perm.

Permanent Variables created / modified in a called script are immediately visible / updated in the calling script when the called script returns.

Note the scripting commands writepv and readpv by which you can read and write permanent variables from/to file. This allows for some interesting use as portable data storage.

To release all permanent variables from memory use the command releaseglobals. You can as well unset them individually via menu Scripting | Permanent Variables directly from the right-click menu in the variable list.

To view the current permanent variables use menu Scripting | Permanent Variables.

Initial Values

Local variables that have never been set to a value return their name as value (strictly speaking they aren't variables but normal strings). Global and permanent variables that have never been set to a value are initialized to "" when they are declared by global or perm:

msg $a;     // displays "$a" if $a is has not set to any value before, and has not been declared as global or permanent.

global $b;  // declare global variable

msg $b;     // displays "" if $b has not been set to any other value before.

perm $c;    // declare permanent variable

msg $c;     // displays "" if $c has not been set to any other value before.

Nested Expressions

You can nest expressions using parentheses, aka round brackets: ( ). There's no practical limit to nesting depth and superfluous parentheses are silently removed.

Examples where parentheses are merely decor:

msg "a" . "b";

msg ("a" . "b");

msg ("a") . ("b");

msg (("a") . ("b"));

msg ((("a") . ("b")));

msg "a" . "b" . ();

= ab

msg "a" . ("b" . "c");

msg ("a" . "b") . "c";

= abc

msg "a" == "a" . "a" == "b";

msg ("a" == "a") . ("a" == "b");

= 10 ("1" . "0")

Examples where parentheses actually make a difference:

msg "a" == "a" . "a";

msg ("a" == "a") . "a";

= 1a

msg "a" == ("a" . "a");

= 0

Examples for nesting errors:

msg ("a" . "b"; // ')' missing!

= ("a" . "b"

msg "a" . "b"); // '(' missing!

= a"b")

Math

Scripting can do basic calculation using math operators +-*/, and also \ (integer division), % (modulo), and ^ (exponentiation). Fractions and parentheses are supported. Also unary operators + and - are supported.

Examples

echo 1 + 1;

echo 1 - 2 - 3;   // -4

echo 1 - (2 - 3); //  2

echo 1/3 + 1/3;

echo 1 + 2 * 3;

echo (1 + 2) * 3;

echo 1/0;  // ERROR: division by zero

$a=3; $b=2; echo $a / $b; // 1.5

$fraction = 1.5; echo $fraction == 3/2; // true

echo 1.2 + 2.1; // 3.3

echo 1 + --1; //2

echo --(1 * ----2); //2

echo 5 \ 2; //2 (integer division)

echo 5 / 2; //2.5

echo 5 % 2; //1 (modulo)

echo 2 ^ 3;   //8

echo 4 ^ 0.5; //2

echo 4 ^ -1;  //0.25

Remarks

(1)Strings are converted to numbers as possible (just like in comparisons).
$a=""; $b="2"; echo $a + $b; // = 2
$a="1a"; $b="2b"; echo $a + $b; // = 3
(2)The decimal separator is NOT locale specific (e.g. dot in US, comma in Germany) but hard-coded to dot (period). This way scripts are interchangeable between regions.
(3)Calculation uses 8-byte floating point numbers with the following ranges:
negative: -1.79769313486232E308   to -4.94065645841247E-324
positive:  4.94065645841247E-324  to  1.79769313486232E308
Floating point arithmetic has its natural shortcomings so don't expect too much in terms of precise accuracy down to the 12th digit. A file manager is not a scientific calculator.
(4)The operator precedence is  ^ > (*,/) > (\,%) > (+,-)  meaning that * and /,  \ and %,  + and - are of equal weight.
Processing of math terms is from left to right:
echo 36 / 4 * 3;  // 27!   (not 3)
(5)With integer division (the portion of the result after the decimal point is lost) and modulo (the remainder of integer division) the operands are rounded before the operation!
echo 5.9 \ 2.1; //3!
echo 7.9 % 2.5; //2! (8 % 3 = 2)
echo 7.9 \ 0.4; //ERROR: Division by zero.
echo 7.9 % 0.4; //ERROR: Division by zero.
(6)Fractional numbers should be stated with a dot as decimal separator, or alternatively in quotes with the local decimal separator:
echo 7.5 / 2.5;       //3 -- works under each locale
echo "7,5" / "2,5";   //3 -- works only where comma is the decimal separator
Internally decimal separator are stored and processed according to the system locale:
$n = 2.5; echo $n;    //$n is "2,5" internally where comma is the decimal separator

Hex Numbers

The parser recognizes the common prefix 0x (zero-x) for hexadecimal values. Supported are up to 4 bytes per number, i.e. 8 hex digits. The hex digits are case-insensitive (the prefix is not).

Here for some examples; hex values are automatically resolved to decimal values:

echo 0xa; //10

echo 0xA; //10

echo 0xFFFFFF;   //16777215

echo 0xFFFFFFFF; //-1

echo 0x7FFFFFFF; // 2147483647

echo 0x80000000; //-2147483648

echo 0xA + 0xA; //20

The following are examples for invalid hex strings; they are returned unresolved:

echo 0xG;           //0xG (invalid value)

echo 0x;            //0x  (no value)

echo 0XA;           //0XA (wrong prefix)

echo 0x123456789;   //0x123456789 (too many characters)

echo "0x12345678";  //0x12345678 (quoted)

Tip: To convert HTML #RRGGBB colors to color decimals use this formula:

0xBBGGRR

Binary Numbers

The parser recognizes the common prefix 0b (zero-b) for binary values. Supported are up to 4 bytes per number, i.e. 32 binary digits. Here for some examples:

echo 0b0; //0

echo 0b1; //1

echo 0b11; //3

echo 0b10000000; //128

echo 0b11111111; //255

echo 0b100000000; //256

echo 0b00000000000000000000000000000001; //1

echo 0b10000000000000000000000000000000; //-2147483648

echo 0b11111111111111111111111111111111; //-1

The following are examples for invalid binary strings; they are returned unresolved:

echo 0b2;           //0b2 (invalid value)

echo 0b;            //0b  (no value)

echo 0B1;           //0B1 (wrong prefix)

echo 0b110000000000000000000000000000000; //0b110000000000000000000000000000000 (too many characters)

echo "0b1";         //0b1 (quoted)

Comparisons

Comparisons of two values are evaluated in-place. The "comparison" has the general form

   "a" operator "b"

where "a" and "b" are string expressions, and "operator" can be one of the following:

   ==  Equal

   !=  Not Equal

   <   Less than

   >   Greater than

   <=  Less than or Equal to

   >=  Greater than or Equal to

 Like  Matches Pattern (case-sensitive)

LikeI  Matches Pattern (case-insensitive)

UnLike  Does not match Pattern (case-sensitive)

UnLikeI Does not match Pattern (case-insensitive)

If the comparison evaluates as True it is set to "1", else it is set to "0".

Examples

msg "a" == "a";

= shows '1'

msg ("a" == "a") . ("a" == "b");

= shows '10'

$r = ("a" == "a"); $r = ($r?"True":"False"); msg $r;

= shows 'True'

$comparison = "a == a"; assert $comparison == "a == a";

= no assertion error

$minver = "7.60.0009"; assert "<xyver>" >= $minver, "This script needs at least XY $minver!"

= no assertion error if XY version is >= 7.60.0009

Strings and Numbers

If you compare two numerical strings, they are compared as integers:

msg ("2" < "10"); // -> true! (both parts are numeric)

msg ("2" < "10a"); // -> false! (only one parts numeric)

msg ("2a" < "10a"); // -> false! (both parts are non-numeric)

The Like (LikeI) and UnLike (UnLikeI) operators

General form:

 String Like Pattern   (case-sensitive)

 String LikeI Pattern  (case-insensitive)

Where string is any string expression and Pattern may contain the usual wildcards and special chars used in XY patterns (*?#[]). Note that exact capitalization matters: "Unlike" or "unlike" won't work. These operators must be surrounded by spaces.

Examples:

echo "abc" Like "a*"; //1

echo "Abc" Like "a*"; //0!

echo "Abc" LikeI "a*"; //1!

echo "abc" UnLike "a*"; //0

echo "Abc" UnLike "a*"; //1!

echo "Abc" UnLikeI "a*"; //0!

echo "Abc" LikeI "abC"; //1 (no wildcard!)

echo "It's " . ("<date yyyy>" Like "20??"?:"not ") ."the 21st century";

Boolean Operators

Scripting supports Boolean operators in the following order of precedence (see also Operator Precedence):

!            NOT    (unary operator)

&&   AND

||   OR

and  AND    (case-insensitive: AND, And...)

xor  XOR    (case-insensitive: xOR, Xor, XOR...)

or   OR     (case-insensitive: OR, Or...)

Examples

echo not 1; // 0

echo not 0; // 1

echo ! 1; // 0

echo !1; // 0

echo !!!1; // 0

echo !(1 and 0); // 1

// parsed as: (TRUE and FALSE) or (TRUE and TRUE);
 echo TRUE and FALSE or TRUE and TRUE; //1

// will show "1", then "done"
 $i = 1;
 while ($i < 2 && $i > 0) {
   echo $i;
   $i++;
 }
 echo "done";

Boolean Constants

The Boolean constants TRUE and FALSE (case is ignored) are recognized if they are used unquoted.

TRUE is resolved to 1.

FALSE is resolved to 0.

Examples

echo TRUE and TRUE;   // 1

echo TRUE and FALSE;  // 0

echo TRUE and false;  // 0 (constants are case-insensitive)

echo TRUE and "false";  // 1! (quoted "false" is NOT a constant)

echo (1==1) == TRUE;  // 1

echo (0==1) == FALSE; // 1

echo (1==1) != FALSE; // 1

Note that in a Boolean context the values "" and "0" evaluate to 0 (FALSE). All other values evaluates to 1 (TRUE):

echo "dog" and TRUE;  // 1  (TRUE and TRUE)(Boolean context)

echo "dog" == TRUE;   // 0  ("dog" == "1") (no Boolean context)

echo "0" == FALSE;    // 1  ("0" == "0")(same strings)

echo "" == FALSE;     // 0  ("" == "0") (no Boolean context)

echo "" XOR TRUE;     // 1  (FALSE XOR TRUE)

echo "0" XOR TRUE;    // 1  (FALSE XOR TRUE)

echo "dog" XOR TRUE;  // 0  (TRUE XOR TRUE)

Note that "0" and 0 ("1" and 1) are the same in XY scripting, so:

echo 0 == FALSE;      // 1  (0 == 0)

echo 0 XOR TRUE;      // 1  (FALSE XOR TRUE)

Ternary Conditionals

Scripting knows so-called "ternary conditionals" as used in many other programming languages. The logic is this:

 if (condition) {

   variable = value-if-true;

 } else {

   variable = value-if-false;

 }

As ternary conditional the same can be written like follows:

 variable = (condition) ? value-if-true : value-if-false;

The parentheses and the blanks are optional, so these are identical:

 variable = (condition) ? value-if-true : value-if-false;

 variable = (condition)? value-if-true: value-if-false;

 variable = condition?value-if-true:value-if-false;

The part "condition" has the form

   "a" operator "b"

where "a" and "b" are string expressions and "operator" can be one of the following:

   ==  Equal

   !=  Not Equal

   <   Less than

   >   Greater than

   <=  Less than or Equal to

   >=  Greater than or Equal to

(none) True if expression is not 0 and not ""

The parts "value-if-true" and "value-if-false" are string expressions.

Examples

$a = "<date hh>" >= "12"? "afternoon": "morning"; msg "Good $a!";

$a = ("<date mm-dd>" == "12-24")? "": "not "; msg "It's $a"."X-mas!";

You can employ ternary conditionals in any argument or part of argument:

msg "Good " . ("<date hh>" >= "12"? "afternoon": "morning") . "!";

msg "It's " . ("<date mm-dd>" == "12-24"? "": "not") . " X-mas!";

Compound Assignment Operators

The Compound Assignment Operators .=, +=, -=, *=, /=, \=  can be used to shortcut operations of two variables where the result is set to one of the variables. For example, both lines below are functionally identical; the latter one uses one of the Compound Assignment Operators:

$a = $a . "b";

$a .= "b";

More examples:

$a = "a"; $a .= "b"; echo $a;   //ab

$a = 1;   $a += 1; echo $a;     //2

$a = 1;   $a -= 1; echo $a;     //0

$a = 2;   $a *= 3; echo $a;     //6

$a = 5;   $a /= 2; echo $a;     //2.5

$a = 5;   $a \= 2; echo $a;     //2

Control Structures

Scripting offers various Control Structures by which you can control the order in which the individual statements are executed. Within these structures blocks of statements are grouped by encapsulating them with curly braces.

·If/ElseIf/Else Blocks
·While Loops
·Foreach Loops

If/ElseIf/Else Blocks

General syntax:

if (expression) {
 statement;
}
elseif (expression) {
 statement;
}
else {
 statement;
}

If expression evaluates to TRUE, the following statement block is executed and the other blocks are ignored. If expression evaluates to FALSE the following statement block is ignored and processing continues with the next Elseif or Else block.

Remarks

·Parentheses around the expression are mandatory.
·Curly braces around the statement block are mandatory (even if there is only one statement).
·The Elseif block(s) and Else block are optional. There can be only one Else block and it must be the last block in the whole control structure.

Examples

if (1 == 1) {echo "Hi!"}

// shows "Relax."
 if (1 == 2) {
   echo "Help!";
 }
 else {
   echo "Relax.";
 }

// shows "else", "elseif", "if"
 $i = 1;
 while ($i) {
   if ($i == 3) {
     echo "if";
     break 2;
   }
   elseif ($i == 2) {
     echo "elseif";
   }
   else {
     echo "else";
   }
   $i++;
 }

While Loops

General syntax:

while (expression) {
 statement;
}

The nested statement(s) are executed repeatedly, as long as the while expression evaluates to TRUE. The value of the expression is checked each time at the beginning of the loop. If the while expression evaluates to FALSE from the very beginning, the nested statement(s) won't even be run once.

Remarks

·Parentheses around the expression are mandatory.
·Curly braces around the statement block are mandatory (even if there is only one statement).

Examples

// will show 1, then 2, then terminate the script
 while ($i < 2) {$i++; echo $i;};

// will show 1, 2, 3, then terminate the script
 $x = 3;
 $i = 1;
 while ($i <= $x) {
   echo $i;
   $i++;
 }

// nested while blocks are okay
 $x = 3;
 $i = 1;
 while ($i <= $x) {
   $w = "Word";
   while ($w != "") {
     echo "$w No. $i";
     $w = "";
   }
   $i++;
}

// expression is FALSE, message will never show
 while (1 == 2) {echo "Help!"};

Foreach Loops

General syntax:

foreach($variable, ListOfTokens, [separator="|"], [flags], [MsgOnEmpty]) {
 statement(s);
}

Remarks

·$variable is the variable which receives the value of the next token in each round of the loop. You can use a new variable or an already used one, it does not matter.
·The last value of $variable remains even after the foreach loop.
·ListOfTokens is a string of tokens, separated by a separator.
·The separator defaults to "|" (pipe), but can be set to anything, also multi-character strings.
Passing an empty separator will tokenize the ListOfTokens by letter.
·Surrounding spaces are not trimmed off on each side of the tokens.
·flags can be either empty (default) or set to "r" for "reverse direction", or "e" to skip empty items in the list of tokens.
·In MsgOnEmpty you can state an error message for the case that ListOfTokens is empty. If MsgOnEmpty is given (even as empty string "") the loop will not be executed at all.
·SC break and SC continue are supported.

Examples

// returns 3 strings (moon, sun, venus):
 foreach($token, "moon,sun,venus", ",") {
   echo $token;
 }

// flag r: returns 3 strings in reversed order (venus, sun, moon):
 foreach($token, "moon,sun,venus", ",", "r") {
   echo $token;
 }

// flag e: returns 2 strings ("moon", "venus"); empty items are skipped:
 foreach($token, "moon,,venus,", ",", "e") {
   echo $token;
 }

// nested foreach loops
 foreach($token, "a|b|c") {
   foreach($token2, "1,2,3", ",") {
     echo $token . $token2;
   }
 }

// selected list items
 foreach($token, <get selecteditemspathnames |>) {
   echo $token;
 }

// shows "No files selected!" if no files are selected, and skips the loop
 foreach($item, <get selecteditemspathnames>, <crlf>, , "No files selected!") {
   echo $item;
 }

// passing an empty separator = tokenize by letter
 $string = 'string';
 foreach($letter, $string, '') {
   echo $letter;
 }

Switch Statements

The switch statement is similar to a series of IF statements on the same expression. In many occasions, you may want to compare the same variable (or expression) with many different values, and execute a different piece of code depending on which value it equals to. This is exactly what the switch statement is for.

In a switch statement, the condition is evaluated only once and the result is compared to each case statement. In an elseif statement, the condition is evaluated again. If your condition is more complicated than a simple compare and/or is in a tight loop, a switch may be faster.

General syntax:

switch (n) {
   case label1:
      code to be executed if n=label1;
       break;
   case label2:
      code to be executed if n=label2;
       break;
   case label3:
      code to be executed if n=label3;
       break;
   ...
   default:
      code to be executed if n is different from all labels;
}

Remarks

·The case statements are checked from top to bottom until a match is found.
·Each case should be closed by a break statement.
·It's possible to use a semicolon instead of a colon after a case.
·A special case is the default case. This case matches anything that wasn't matched by the other cases.

Examples

// switch
 $favcolor = "blue";
 switch ($favcolor) {
   case "red":
       echo "Your favorite color is red!";
       break;
   case "blue":
       echo "Your favorite color is blue!";
       break;
   default:
       echo "Your favorite color is neither red nor blue but $favcolor!";
 }
 echo "Switch done!";

The switch and case arguments can also be more complex expressions:

$a = 3; $b = 7; $c = 10.5; $d = 2;
 switch ($a * $b) {
   case $c * $d:
       echo "The result equals $c * $d = " . $c * $d;
       break;
   default:
       echo "The result is something else.";
 }

Usually each case should be closed by a break statement. Else processing continues with the next case (sometimes though this can be desired). Here is an example where omitting break statements makes sense. Also shows that the default case also accepts a break statement (although is totally superfluous here). Also shows that semicolons after the cases are an acceptable alternative to colons:

$beer = 'Kirin';
 switch($beer) {
     case 'Asahi';
     case 'Kirin';
     case 'Sapporo';
         echo 'Good choice';
         break;
     default;
         echo 'Please make a new selection...';
         break;
 }

The case statements don't have to be in their own line. This example also shows that using the return command within a function you can spare the break command:

function getChineseZodiac($year){
     switch ($year % 12) {
         case  0: return 'Monkey';  // Years 0, 12, 1200, 2004...
         case  1: return 'Rooster';
         case  2: return 'Dog';
         case  3: return 'Boar';
         case  4: return 'Rat';
         case  5: return 'Ox';
         case  6: return 'Tiger';
         case  7: return 'Rabbit';
         case  8: return 'Dragon';
         case  9: return 'Snake';
         case 10: return 'Horse';
         case 11: return 'Lamb';
     }
 }
 echo getChineseZodiac(2016);
 
 // BTW, user functions work in switch and in case:
 switch (getChineseZodiac(2016)) {
   case getChineseZodiac(2015): echo "2015"; break;
   case getChineseZodiac(2016): echo "2016"; break;
   case getChineseZodiac(2017): echo "2017"; break;
 }

Also note this somehow perverted use of a switch:

$a = "Kirin";
 switch (true){
   case $a=="Kirin":   echo "first choice"; break;
   case $a=="Sapporo": echo "second choice"; break;
 }

Heredoc and Nowdoc Syntax

Heredoc, using the <<< operator, is a way to define multi-line strings "as is" without the need to escape quotes etc.

The rules follow the PHP rules for Heredoc:

(1)After the <<< operator, an identifier (your free choice) is provided, then a new line. The string itself follows, and then the same identifier again to close the quotation. The closing identifier must begin in the *first* column of the line (no indent!). The line with the closing identifier must contain no other characters, except possibly a semicolon (;) directly after the identifier.
(2)Heredocs overwrite comments, and comments overwrite heredocs, depending on who comes first.

Within the Heredoc section:

(3)Line feeds, empty lines, and all kinds of comments survive.
(4)Lines are not trimmed (leading and trailing spaces are preserved).
(5)Quoting is handled automatically (no need to add outer quotes or to double inner quotes).
(6)Variables are resolved.

Example

A multiline script using Heredoc. Note that the Heredoc block is not indented, that comments are not removed, that quotes are not doubled, and that the variables are resolved (the only difference to Nowdoc), even within comments.

Basic example:

$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
 echo $str;

More complex example, with variables and comments:

$name = "Bond";
 text <<<FOO
My name is $name, "James $name". // line end comment: $name
 
Follow /* note: there's one space after me, */ me,
FOO
 ."please!";

Output:

My name is Bond, "James Bond". // line end comment: Bond
 
Follow /* note: there's one space after me, */ me, please!

Alternative Heredoc Syntax

A more radical parsing where the ending identifier can be anywhere is enabled when the identifier starts with a "#". These examples show two ways to code the same script.

$isOk = Confirm (<<<#FOO
Blah
BlahFOO#FOO); echo $isOk;

With the old-school parsing the ending identifier must be on its own line:

$isOk = Confirm (<<<FOO
Blah
BlahFOO
FOO
 ); echo $isOk;

Nowdoc Syntax

A special variety of Heredoc is the Nowdoc, that is a Heredoc without interpolation. Quoting from PHP Documentation:

"Nowdocs are to single-quoted strings what heredocs are to double-quoted strings. A nowdoc is specified similarly to a heredoc, but no parsing is done inside a nowdoc. The construct is ideal for embedding PHP code or other large blocks of text without the need for escaping. It shares some features in common with the SGML <![CDATA[ ]]> construct, in that it declares a block of text which is not for parsing.

A nowdoc is identified with the same <<< sequence used for heredocs, but the identifier which follows is enclosed in single quotes, e.g. <<<'EOT'. All the rules for heredoc identifiers also apply to nowdoc identifiers, especially those regarding the appearance of the closing identifier."

Example:

$var = "syntax";
 $str = <<<'EOD'
Example of string
spanning multiple lines
using nowdoc $var.
EOD;
 echo $str;

Output (note that $var has not been resolved):

Example of string
spanning multiple lines
using nowdoc $var.

Nowdoc also accepts the alternative radical option (see above) enabled by prefixing the identifier with '#' (within the quotes).

Dereference Operator

You can use the dereference operator * (asterisk) with all variables. Usage: Helpful when dynamically creating variables.

Examples

$var = '$a';        *$var = "TEST"; echo $a;  //TEST

$var = '$a';   perm *$var = "TEST"; echo $a;  //TEST

$var = '$a'; global *$var = "TEST"; echo $a;  //TEST

$var = '$a'; *$var = "TEST"; echo "*$var, $a!";  //TEST, TEST!

If the dereferenced variable is not defined, then the variable itself is used (as if there was no dereference operator):

*$undefined = "TEST"; echo $undefined; //TEST

Note that also unset and incr support the dereference operator:

$var = '$a';  *$var = "TEST"; unset *$var; echo $a; //$a

$var = '$a';  *$var = 1; incr *$var; echo $a; //2

$var = '$a';  *$var = 1; *$var++; echo $a; //2

$var = '$a';  *$var = 1; *$var--; echo $a; //0

$var = '$a'; *$var = 1; echo 1 + *$var++; echo *$var; //2; 2

Not in Interpolation

Dereferencing does not take place in interpolation. Compare the following scripts. Only in the last one $a is dereferenced:

$a = '$b'; $b = "Test"; echo "*$a!";  //*$b!

$a = '$b'; $b = "Test"; echo *$a!;    //*$b!

$a = '$b'; $b = "Test"; echo "*$a";   //*$b

$a = '$b'; $b = "Test"; echo *$a;     //Test

Also in these scripts using HEREDOC $a is not dereferenced but resolved to "$b":

$a = '$b'; $b = "Test"; echo <<<FOO
*$a!
FOO

$a = '$b'; $b = "Test"; echo <<<FOO
*$a
FOO

Operator Precedence

The precedence of an operator specifies how "tightly" it is connected to its surrounding operands. For example, in the expression 1 + 2 * 3, the answer is 7 and not 9 because the multiplication ("*") operator has a higher precedence than the addition ("+") operator. Parentheses may be used to force precedence, if necessary. For instance: (1 + 2) * 3 evaluates to 9.

The following table lists the precedence of operators with the highest-precedence operators listed at the top of the table. Operators on the same line are evaluated from left to right (3 - 2 + 1 evaluates to 2, not 0):

Operators     Additional Information

-------------------------------------------

++ --         Math: Increment, Decrement

! Not         Boolean: NOT

+ -           Math: Unary Plus, Unary Minus (operator is prefixed to a number)

* / *= /=     Math: Multiply, Divide

%             Math: Modulo

\ \=          Math: Integer division

+ - += -=     Math: Add, Subtract

. .=          String concatenator

< <= > >= == !=             Comparison

Like LikeI UnLike UnLikeI   Comparison

&&            Boolean: AND

||            Boolean: OR

And           Boolean: AND

Xor           Boolean: XOR

Or            Boolean: OR

? :           Ternary

=             Set

Remote Control

*** For software developers only ***

You can run an XYplorer script from an external program using the WM_COPYDATA command with XYplorer's hWnd. This means if you are a programmer you can fully remote control XYplorer.

·cds.dwData: 4194305 (0x00400001)
·cds.lpData: The syntax is identical to the one of the command line switch /script=<script resource>, so you can either pass the path to a script file (commonly called *.xys), or pass the script directly (must be preceded by ::).

User-Defined Functions

Like other aspects of XYplorer scripting also user-defined functions are closely modeled after PHP.

A user-defined function (or simply "user function") is a block of statements that can be used repeatedly in a program. It can return a value (using the command "return"). The function declaration starts with the word "function", then a space, then the name of the function:

General form:

function functionName() {
 code to be executed;
}

Alternative formatting:

function functionName() { code to be executed; }

Example with 2 arguments and a return value:

function sum($x, $y) {
 $z = $x + $y;
 return $z;
}

·User function names can only consist of letters (a-z, A-Z), numbers, and underscores, and must not start with a number.
·User function names are NOT case-sensitive.
·The first line of user function declarations can be left-bound or indented. It does not matter.
·User functions can be defined anywhere in a script resource, before or after the main script, and as many as you want.
·A user function will not execute immediately when a script is loaded. It has to be called just like native functions.
·All user functions have global scope.
·User functions overwrite native functions of the same name.
·If two or more user functions share the same name, the *first* one declared will be used, all other ones ignored.
·User functions do not support function overloading, nor is it possible to undefine or redefine previously-declared functions.
·User functions can call each other.
·It is possible to call recursive user functions, but be aware that too many recursions can smash the stack and cause a termination of the current script.
·Variables are by default passed by value, not by reference (so the function cannot modify the variables in the caller's scope).
·To pass variables by reference (so the function can modify the variables in the caller's scope) prefix them with & in the function declaration.
·All arguments are optional. Default values for missing arguments can be set. If no default value is set a missing argument is initialized to "".
·XYplorer native variables (e.g. <crlf>) and environment variables (e.g. %tmp%) are allowed in function argument default parameters. They are resolved if they are unquoted or double-quoted. They are NOT resolved if they are single-quoted.

Example 1: Arguments and Returns

echo multiply(3, 4) . <crlf> . sum(11,12);
function multiply($x, $y) { return $x * $y; }
function sum($x, $y) {
 $z = $x + $y;
 return $z;
}

Example 2: Argument by Value

$a = 1; add_one($a); echo $a; //1
function add_one($a) {
 $a++;
}

Example 3: Argument by Reference

$a = 1; add_one($a); echo $a; //2
function add_one(&$a) {
 $a++;
}

Example 4: Argument with Default Value

echo multiplyDefaults(2); //8 (2 * 4)
function multiplyDefaults($x = 3, $y = 4) {
 return $x * $y;
}

Include Statement

The "include" statement lets you include the content of a file at the place where the "include" statement was found. That way you can include e.g. function libraries into your script resources.

Note that the "include" statement is evaluated unconditionally when a script resource is loaded and before anything else is done.

Syntax

include file;

  file: Path, if not fully stated, is resolved relative to <xyscripts>.

         Extension defaults to ".xys".

         Quotes are optional (they are totally function-less here, but might look better to some folks including me).

         Note that you cannot use any script variables for file. However, XYplorer variables and environment variables are supported.

Remarks

You may end any include statement line with the usual instruction terminator ";". However, you must not append other instructions in the same line. The include statement needs to have its own line.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值