Scripts |
Top Previous Next |
Scripts are mostly a list of multiple expressions for performing more complex calculations, with a couple extra flow control capabilities built in. Scripts can be called like a function from another expression, so they're similar to defining functions in C or procedures in Visual Basic or Pascal.
If you just need to do simple iterations like adding up transaction amounts, or just need to execute a couple separate expressions at the same time, then you can probably do it without a Script by using the "Flow" functions like LoopSum( ) or Eval( ). For more complex tasks, though, a Script will allow more flexibility and will also result in a little "program" that's easier to read and modify than a large expression.
In many cases, a Script might also be more efficient because its flow control allows skipping the parsing & execution of expressions that aren't used. So even though you could probably do the same thing with carefully nested IIF and Loop functions, they might not be as fast.
Scripts Setup
To create a Script, go to Maintenance / Advanced Customizations / Scripts. This opens the Scripts Setup dialog, which lists all current Scripts and has the typical functions for adding, editing, etc. Note that while there are functions to Move Up and Move Down, a Script's position in the list does not affect any other functionality -- it's mainly for your own preferences. However if you have many Scripts defined, it may help the speed of your expressions a tiny bit to put the most speed-critical ones nearer the top, since they are searched in this order.
You can also Export one or more Scripts to a text file, or Import Scripts. This is primarily for you to import Scripts created by the software provider, though it can also be used to transfer Scripts between multiple databases.
Some sample Scripts are included with Campground Master which are used by the sample forms. While these have specific uses for the sample forms, you can also look at them as examples. Click the Import scripts button, and you'll get a typical Windows file dialog labelled "Import Scripts". You need to locate the samples folder, which is typically in C:\Program Files\Campground Master\Samples (most likely you just need to double-click the "Samples" folder to get there). Now select the appropriate "Sample Script" file, and click Open. Once the sample is imported, you'll see it appear in the list.
Note that the import/export files use the "CSV" file extension (e.g. Sample.csv), which means it's a comma-separated-value text file. Windows may recognize this file extension as something another program can open like Excel, but these are in a special format for importing records to Campground Master and should not be used in other functions. Also avoid opening different kinds of samples which use the same extension (e.g. don't open a Form sample from an Import Script function).
Be aware that Scripts should not have duplicate names (or else the CallScript function would just use the first one encountered by that name). If you make a Copy, text like "(copy 1)" will be added to the name to make it unique. If imported Scripts have duplicate names, the imported names are automatically changed to avoid duplication. This might affect the expressions where the Scripts are used, so a warning will be shown and indicate which Scripts name(s) were changed.
Script names are not case-sensitive, so "My Script" will appear to be the same as "my script".
Editing Script Definitions
When editing a Script, an Edit Script dialog is shown with each line of the script (each line being a single expression), and also a place to enter the Script Name (which is used to invoke the Script in an expression), and the Description (which is shown if the Script is selected in the Expression Elements dialog).
Creating a Script is simply a matter of adding one line (expression) after another, just like writing a program. Of course you can Insert lines, move and copy lines, etc. as needed. Each time you Add, Insert, or Edit an expression line, the Expression Creator dialog is used. Thus you can test-calculate each line, look up functions, etc. like anywhere else.
Adding/Inserting Multiple Lines
Special functions are available Add Multiple Lines and Insert Multiple Lines. These open a multi-line text window where you can enter as many lines as you want, all at once. This is usually faster than entering them separately, since you can work with several lines at once in free-form fashion. More importantly, it lets you copy/paste the lines from somewhere else, e.g. if you prefer using a different editor for programming. Just make sure that each expression has a "line feed" or "return" after it (long expressions will wrap but should not have the line feeds in them). Once you've entered or pasted what you want, click Save. Each line will be added as a separate line, either at the bottom of the Script (for Add) or inserted above the line you selected (Insert).
Tip: If you have a bunch of lines in the script that need to be edited, select them all, use copy (Ctrl-C), click Add Multiple Lines, and paste (Ctrl-V). Make your edits, Save, and then you can delete the originals and move the new ones into place.
Save & Test Script Results
This function simply uses the Expression Creator dialog, with a CallScript function already inserted to call the script you're working on. Press Calculate to execute the script to check for errors. Of course, like any other expression, it won't necessarily have all of the context information needed or variables defined to successfully execute the script, but you may be able to catch some of the basic problems with the script format, like mismatched IF/ELSE/ENDIF sets or WHILE/ENDWHILE pairs.
Using Scripts in Expressions
To invoke a Script, you use the function CallScript( ). Note that the only argument is the script name itself (in quotes of course, since it's a text argument).
CallScript("MyScript")
Note: Script names are not case-sensitive. "MyScript" is the same as "MYscript".
There are no optional arguments available to be passed into the Script. If you need information passed into the Script, you can use variables (see below).
Scripts can be called within other Scripts -- even the same Script can be called recursively.
Script Return Value
Each Script has a single return value, just like any other expression (technically this becomes the return value of the CallScript function). To return a value from a script, simply make sure that value is the result of the last line of the script. Remember that script lines are just expressions executed one after another. So the "value" of the last line of the script will be the returned value -- often times this is simply a variable name, if the Script sets the variable to the desired value.
The return type can be any type of value. Note that if the Script is used within a more complex expression, you might need to use a type-conversion function so the parser knows what type it's expected to return. For instance, if you know the Script will return a number but the parser gives an error that it's an unknown or mismatched type, use the "N" function to force it to text form. For example: N( Script( "JanReceipts" )) + N( Script( "FebReceipts" )).
Script Variables
It was mentioned before that you can pass information into a Script using variables. You can also pass information out of a Script through variables, for instance if you need more than just the single return value. While using a Global variable is one way to do this, you can also do it with local variables (to keep the "context" more tightly controlled). Here are the rules for using local variables for Scripts:
•Local variables are created with SetVar( ) function -- they do not exist in the current expression's execution space before that.
•Local variables exist as long as you're within the same Expression execution cycle where they're created, or at any level of CallScript, Macro, Eval, etc. executed within that same Expression. They are unique to that Expression -- e.g. a local variable created in a Query's Data expression will not exist for any other expression executed separately such as the Query's Filter expression (and thus will also not conflict with local variables by the same name in other Expression spaces).
•Any local variable that exists before the Script is invoked with CallScript is copied into the Script, and its value is also copied back out (it can be changed inside the Script).
•Any local variable that does not exist before the CallScript but is created within the Script is destroyed before CallScript returns. It will exist for the life of the Script, since each Expression line is parsed and executed within the same execution space.
•These rules apply for any depth level of script calling -- e.g. every CallScript creates a new level of variable scope, with any existing variables copied into it and back out of it.
Script Flow Control
There are two directives available for flow control -- IF and WHILE. Script lines starting with these are specially handled (pre-parsed), not just executed as an expression. Any text following the IF or WHILE directive (separated by a space) is parsed and executed as an expression, and must have a boolean result value. The result of course determines whether the lines following the IF or WHILE are executed.
Both of these directives must be followed in the Script by a line containing ENDIF or ENDWHILE, respectively. In the case of IF, you can also have an ELSE directive before the ENDIF. There is not an ENDELSE -- the ENDIF is used to terminate both the original IF prior to the ELSE directive.
These may be nested to any level, but each directive set must be properly nested. Any directive set that's not properly nested will result in an error.
These directives are not case-sensitive (e.g. "if" or "If" may be used), but we suggest using upper-case for ease of script readability. See the examples below.
Indentation & Spacing
Leading spaces in front of any text in line are ignored, so you can put spaces in front of any expression (including comments and flow control directives). We recommend indenting each level of IF or WHILE nesting by at least 3 spaces to improve readability. You can also insert blank lines to separate sections. The excerpts below show a couple examples of nesting and the use of flow control directives, and comments in scripts.
SetVar( "nResv", NumTran( ThisResv() ) )
SetVar( "bFound", .F. )
SetVar( "r", 1)
; Verify that this reservation contains this transaction
WHILE r <= nResv AND !bFound
IF ResvTran(r) = ThisTran()
SetVar( "bFound", .T.)
ENDIF
SetVar( "r", r+1)
ENDWHILE
....... Here's an example of looping through all reservations in the database:
SetVar("nRec", 1)
SetVar("nRecs", TableNumRecs("Reservations"))
WHILE (nRec <= nRecs)
SetVar("pRec", TableRecAt("Reservations", nRec))
// .... do something with pRec, e.g. check last night....
IF FieldDate(pRec, "Resv_Last_Date") = Today()
MessageBox("Found one ending today!")
ENDIF
SetVar("nRec", nRec + 1)
ENDWHILE
....... multi-level IF/ENDIF nesting example:
IF CCNum != ""
REM always need at least 2 lines
SetVar("nLines", 2)
IF C(Macro("TranCCAuth", "ThisTran()")) = "Y"
SetVar("nLines", nLines+1)
ENDIF
// Need more lines if a signature is shown
IF SettingLocalBool("Print", "PrintShowCCSigLine")
SetVar("nLines", nLines+7)
ELSE
SetVar("nLines", nLines+2)
ENDIF
ENDIF
Script Comments
It's a good idea to include comments in a complex Script, so you can understand it later. Any "expression" line starting with a double-backslash ("//") or a semicolon (";") is considered a comment. You can also use "REM " like in Basic (there must be a space after "rem", but it doesn't have to be upper-case). Don't worry that you're using the same Expression Creator to ener comments -- just enter the text the way you want it as if it's an expression. A comment cannot be on the same line as an expression.
Additional Topics:
Advanced Customizations Overview & other topics