This article is part of my series Custom Function Vault. Here I describe custom functions for managing (script) parameters.
param( key; value )param.get( key; params )
Working with Script Parameters
FileMaker knows only one script parameter. To pass multiple values to a script, you have to look for a different way. Using table fields or global variables might be possible, but the former idea eliminates a generic solution, the latter will not work across modules and could create other problems.
FileMaker Pro Help suggest multiline values for complex parameters:
Complex parameters, such as a list of names or other values, can also be used. Complex parameters that are separated by carriage returns can be parsed using the LeftValues function, MiddleValues function, and RightValues function. These functions return the beginning, middle, and ending values from lists that are separated by carriage returns. Complex parameters separated by other characters can be parsed as text using functions such as Left function, Middle function, and Right function.
(Source: FileMaker Pro Help; Perform Script and script parameter example; )
This solution might work with simple values, but it will fail when you have to deal with more complex parameters. If one parameter itself is a multiline text, this solution will fail.
I use a different approach. With the help of custom functions I create and manage encapsulated named parameters. This technique is known in many programming languages, for example the associative arrays in PHP. Encapsulated named parameters have multiple advantages:
- The order in which the parameters are passed is irrelevant.
- It allows the use of optional parameters.
- Parameter values may include carriage returns.
- Encapsulated parameters are cascadable.
Basically I have two custom functions, one to encode the parameter and the second function to decode it.
CF param( key; value )
The first custom function will encapsulate the parameter. It takes the name of the parameter (key) and combines it with the parameter value. The result is a single-line text that can be concatenated with other parameters and used as a script parameter.
Substitute( key; [ "="; "^=" ]; [ "\¶"; "^\¶" ]; [ ¶; "\¶\¶" ] ) & "==" & Substitute( value; [ "="; "^=" ]; [ "\¶"; "^\¶" ]; [ ¶; "\¶\¶" ] ) & ¶
What is it doing?
First, the function escapes certain characters within key and parameter value. Special characters are the equal sign (=), the paragraph sign (¶), and carriage return. To create a paragraph sign within the FileMaker’s function editor, the paragraph sign has to be escaped, using FileMaker’s escape character (backslash): \¶. The carriage return in FileMaker is represented by the unescaped paragraph sign (¶).
To escape these characters, I use a circumflex (^). I choose this character, because it is rarely used in everyday text. Interestingly, a circumflex itself does not need to be escaped.
The second step the custom function is doing is combining the (escaped) key and value with two equal signs in between (key==value) plus adding a carriage return at the very end. Why using two equal signs? In most cases this would be sufficient enough. But in the very weird case key contains an equal sign, retrieving the parameter value would fail. Alternative the function could substitute any equal sign into something different, but that would add another character to the special character list required to be escaped.
Example
The following example encodes three parameter values:
param( "firstname"; "Arnold" ) & param( "lastname"; "Kegebein" ) & param( "city"; "Hamburg" )
The result is:
firstname==Arnold lastname==Kegebein city==Hamburg
CF param.get( key; params )
This is the counter part to the previous function. It retrieves a parameter value from a parameter list.
If( IsEmpty( key ) or IsEmpty( params );
"";
// Else
Let( [
_params = ¶ & params & ¶;
_key = ¶ & Substitute( key; [ "="; "^=" ]; [ "\¶"; "^\¶" ]; [ ¶; "\¶\¶" ] ) & "==";
_pos = Position( _params; _key; 1; 1 )
];
If( _pos = 0;
"";
// Else
Let( [
_start = _pos + Length( _key );
_end = Position( _params; ¶; _start; 1 )
];
Substitute( Middle( _params; _start; _end - _start ); [ "\¶\¶"; ¶ ]; [ "^\¶"; "\¶" ]; [ "^="; "=" ] )
)
)
)
)
What is it doing?
If key or params is empty, an empty string is returned. Otherwise special characters in key are escaped and then the key is searched in params. If nothing is found, an empty string is returned. Otherwise the related parameter value is retrieved and decoded. This reverts the encoding from function param.
Example
param.get( "firstname==Arnold¶lastname==Kegebein¶city==Hamburg"; "lastname" )
returns
Kegebein
Looking for an unknown parameter will return an empty string:
param.get( "firstname==Arnold¶lastname==Kegebein¶city==Hamburg"; "username" )
Script Parameter
With these two custom functions it is easy to pass multiple parameters to a script. Each parameter is encoded with the function param. Each parameter is then concatenated with the ampersand (&).
Inside the script, the script parameter is encoded like this:
Set Variable [$name; Value: param.get( "name"; Get( ScriptParameter ) )] Set Variable [$city; Value: param.get( "city"; Get( ScriptParameter ) )] ...
More benefits
These two custom functions will handle complexe script parameters. But they are not restricted to script parameters. I created a custom function, that manages as many timers as you like. It is using these functions to store the timer values. In a later blog I will write about this timer function.
Mikhail_Edoshin
I ended up with a similar suite of functions (http://edoshin.skeletonkey.com/2006/02/options.html) (I even used circumflex for the same reason
but I like your variant more, because in the wrapped form it is more readable than mine.
There’s also a similar solution somewhere in SixFriedRice blog (http://sixfriedrice.com/wp/blog/)
By the way, technically there’s more FileMaker-native way to first Quote() a string and then Evaluate() it. E.g. the param wrapper like that would be:
Quote( List( Quote(key), Quote(value) ) )
and then a similar sequence of Evaluate() steps to fetch a value by a key. It looks that this variant can be made type-aware, but when I test this I get weird results. Besides, this variant loses text formatting, while the Substitute-based one does not.
More Fun with Parameters – Gallimaufry
[...] my previous entry I described two customs functions for managing parameters: param and param.get. They encode and [...]
Arnold Kegebein
@Mikhail
Thank you for the links. I knew about them already. And as you can see in my newest entry, I consider you and your blog as an inspiration for my ideas working with parameters.
I was working with an Evaluate/Quote solution myself, but were running in some problems too. But I am using evaluation in other CFs, because it can make life so much easier.
I wonder, what you think about my other functions. I am on vacation right now, using the time to add some content to my blog. Expect more from my Custom Function Vault soon.
Unlimited Timer « Gallimaufry
[...] from my library. I have described two of them – param and param.get – already in the post Manage Parameters. The third – param.delete – is used to remove a parameter from the parameter [...]