This week we will be examining how to use SDK functions to read and write structured “parameter-value” pairs and how they can be used to access information from menu functions. Our main example will show how to open a file in the application desktop, perform EDGAR validation and get the results.
Friday, December 23. 2016
Legato Developers Corner #14: Processing Parameters with Strings and Arrays
Introduction
Certain data can be provided in string form as one or more parameter-value pairs. Conventionally, a parameter is followed by a colon and the value. When more than one parameter is provided, each pair is delimited either by a semicolon or a line return. A good example of where parameter pairs are used extensively is CSS declarations. For example:
font-family: Sans-Serif; font-size: 10pt; color: blue
In CSS, the above could be part of a declaration or inline properties. Each pair consists of a CSS property name and an associated value. For CSS, the properties are separated by a semicolon. Property names are well known and will not contain special characters, such as a semicolon or colon. Values, on the other hand, could potentially contain such characters. When this is the case, those characters must be escaped or encapsulated.
Parameters may also be passed to other scripts, stored, or transported to interchange data with other programs. They are frequently used in various forms within the Legato SDK as we shall see in an example later.
Legato supports reading and writing parameter lists both on a primitive level and a high level. In this article, we will also discuss some of the tools that can be used to move numeric and non-string data into and out of string form.
Key Names as Array Indices
Parameter arrays use key names to identify array entries. A key name is a short unique string used as a substitute for a numerical index. Legato automatically manages the key names and will sequentially add them to each dimensional variable as required. Many SDK functions employ key names as a way to identify elements of an array without being concerned about a fixed index or array position. For example, it is easier to refer to an array position as “color” as opposed to the fourth entry in the list.
There are some restrictions with respect to key names. For example, they cannot be larger than 64 characters and they are case sensitive. When the key name is to be used as a parameter name, it cannot contain a semicolon or colon.
Support for Parameter Lists
Let us begin our parameter discussion with two simple yet powerful functions alluded to in our previous article about exploding strings: the ParametersToArray and ArrayToParameters functions. These functions are similar to the explode and implode functions except they are meant to work with structured lists and key names.
To quickly parse a parameter list, we can use the ParametersToArray function:
string[] = ParametersToArray ( string data, [string delimiter] );
The function returns a string array. If the function fails, the array will have zero entries. If it works, each parameter value is placed in the array with the entry key name being equal to the parameter name. Let’s look at this example:
string s1; string items[]; int ix, size; s1 = "font-family: Sans-Serif; font-size: 10pt; color: blue"; items = ParametersToArray(s1); size = ArrayGetAxisDepth(items); while (ix < size) { s1 = ArrayGetKeyName(items, ix); AddMessage("%2d %-12s is '%s'", ix, s1, items[ix]); ix++; }
creates the following in the default log:
0 font-family is 'Sans-Serif' 1 font-size is '10pt' 2 color is 'blue'
Notice the ArrayGetKeyName function is used to retrieve the key name. The key name could also be used to access the value, (replace items[ix] with items[s1] in the above example).
The ParameterstoArray function also accepts an optional delimiter parameter. If the delimiter parameter is not specified, the function will treat a return character (0x0D/0x0A or various combinations) or a semicolon as a delimiter. For certain well structured information such as CSS data, not specifying the delimiter parameter is fine. In other circumstances, it is a good idea to specify it.
To go the other way, we can add the following code to the above function:
AddMessage("Change font-size and add padding:"); items["font-size"] = "12pt"; items["padding"] = "3pt"; s1 = ArrayToParameters(items, "; "); AddMessage(s1);
When run, the new log will display:
0 font-family is 'Sans-Serif' 1 font-size is '10pt' 2 color is 'blue' Change font-size and add padding: font-family: Sans-Serif; font-size: 12pt; color: blue; padding: 3pt
The ArrayToParameters function prototype is as follows:
string = ArrayToParameters ( string[] data, [string delimiter] );
Information in the data parameter must be well formatted. For example, the key names cannot contain specific characters such as colon. The delimiter function parameter specifies what goes between each array entry. This is similar to the glue in the ImplodeArray function. If omitted, line returns are used. For this CSS example, we added a semicolon and a space character to make the result look pretty.
Other Parameter Functions
Additional functions are available to read parameter information. The GetParameter function is useful as it allows a single parameter value to be picked out of a string of many parameters.
string = GetParameter ( string data, string name, [string delimiter] );
The return value will contain the parameter value, if found. Use the GetLastError function to determine if the value is an empty string or not found. In many cases, the error state does not matter. The data parameter contains a string of information similar to the above example. The name parameter specifies the exact parameter name to match. The optional delimiter specifies the delimiter, and, like the ParametersToArray function, is either line endings or semicolons if omitted. An example:
string s1; string color, family; s1 = "font-family: Sans-Serif; font-size: 10pt; color: blue"; color = GetParameter(s1, "color"); family = GetParameter(s1, "font-family"); AddMessage("Color is : %s", color); AddMessage("Family is : %s", family);
yields the following in the log:
Color is : blue Family is : Sans-Serif
If the parameter-value pair is broken out as a single entry, the functions GetParameterName and GetParameterValue can be used to capture the left and right components, respectively. Finally, while in a different syntax, the GetParameterEqualName and GetParameterEqualValue functions work with strings using the “parameter=value” pair syntax.
The RunMenuFunction Function and Parameter-Value Pairs
In the following example, we will use the GetParameter function to retrieve a window handle from a menu function. The RunMenuFunction function accepts parameter-pairs to direct menu functions. Many menu functions will return a list of structured parameters indicating the result of the operation. This example will open a sample file (as an edit window) from the application samples, perform an EDGAR validation on the content, get the resulting log, close everything, and report the number of validation errors to the user.
handle hInfoView, hLog; string s1, s2; int rc; s1 = GetApplicationExecuteFolder() + "Samples\\ASCII\\practice reflowing text.txt"; s1 = "Filename: " + s1; rc = RunMenuFunction("FILE_OPEN", s1); if (IsError(rc)) { MessageBox('x', "Error %08X on open", rc); exit; } rc = RunMenuFunction("EDGAR_VALIDATE", "Silent: TRUE"); if (IsError(rc)) { MessageBox('x', "Error %08X on validate", rc); exit; } s1 = GetMenuFunctionResponse(); s2 = GetParameter(s1, "InfoViewTab"); hInfoView = MakeHandle(s2); if (hInfoView == NULL_HANDLE) { MessageBox('x', "Error getting InfoView handle"); exit; } hLog = InfoViewGetLogObject(hInfoView); InfoViewCloseTab(hInfoView); rc = RunMenuFunction("FILE_CLOSE"); if (IsError(rc)) { MessageBox('x', "Error %08X on close", rc); exit; } rc = LogGetMessageCount(hLog); MessageBox("The validation had %d errors", rc);
Starting with the variable declarations, we have two handles, one for an Information View tab and one for a log. We are also declaring a couple of strings and a return code. While we could employ the array based parameter function in this example, it is not really necessary considering how few parameters we need to create and access.
The script begins by creating a qualified name for our sample located in the samples folder of program files. If you do not have permission to read and write the program files folder, you may have to copy the file to your desktop or another location and adjust the path as required. Next, we will manually build the parameter list for the FILE_OPEN menu function. See Appendix A of the GoFiler Script Reference for information on the actual functions, parameter names, and values.
In the example, each RunMenuFunction call is followed by an error check which will report an error and then leave the script. Using the exit statement is okay in this unstructured script. For others, we would want to use the return statement. Note that when we run the EDGAR ‘validate’, it will not return results in the return error code, but it will report its findings to the Information View in the form of advisories, warnings, and errors. So, upon completion of the menu function, the response information can be retrieved using the GetMenuFunctionResponse function, which returns certain data in the form of a parameter list.
The FILE_OPEN menu function will open the file. It also makes the new window the active window and returns the window handle in the response. We don’t need that handle because subsequent calls will operate on active window by default, so the response is not needed.
Next we will validate the file with the added parameter “Silent: TRUE”. The parameter stops the validation function from reporting the error results to the user in the form of a message box. As part of the process, an Information View tab is created. We retrieve the handle as a parameter string and then convert that string to an actual handle value using the GetParameter and MakeHandle functions. Next, we get a copy of the Information View tab in the form of a Log Object. The view tab and the edit window are then closed.
With the log handle, we can examine the errors or, as above, just get the message count using the LogGetMessageCount function. By default the LogGetMessageCount function will count fatal, general errors, and warnings. This way we can report how many validation errors are in the log to the user via a message box.
Some menu functions, such as Table Polish, will accept dozens of parameters. Other functions may report many parameters in the response, such as when exporting XBRL. In those cases it may make sense to use array based parameter-pair functions.
Converting String Data
As shown above, once we have retrieved data from a parameter, we may want to take action not based on a string but on a more complex data type. There are many string conversion functions. Let’s take a look at a few:
int = AlphaToInteger ( string value );
int = CardinalToInteger ( string value );
int = CellAddressGetColumn ( string value );
int = CellAddressGetRow ( string value );
int [] = CellAddressToIndex ( string value );
dword = ColorToRGB ( string value );
long = DecimalToInteger ( string value );
qword = HexToInteger ( string value );
qword = OctalToInteger ( string value );
int = RomanToInteger ( string value );
PVALUE = SGMLStringToValue ( string value );
long = TextToInteger ( string value );
All of the functions take a string and convert it into a numeric value. The AlphaToInteger function takes strings such as ‘c’ or ‘aa’ and converts them to a numeric equivalent. The CardinalToInteger function converts cardinal a string such as ‘thirteen” to an integer. The cell functions CellAddressGetColumn, CellAddressGetRow, and CellAddressToIndex convert spreadsheet style addresses, such as ‘B12’, to row and column values. The ColorToRGB function converts a conventional color name or RGB specification to a 24-bit color value. The DecimalToInteger function converts a basic decimal whole number to an integer and rips out commas and other common information. The HexToInteger and OctalToInteger functions convert computer oriented values to unsigned numbers. The RomanToInteger function converts a limited set of roman numerals to an integer. The SGMLStringToValue function converts complex values such as “12pt” or “1.55cm” to formatted PVALUE types. Finally, the TextToInteger function converts a simple decimal, octal, or hexadecimal value to a number.
Many of the above functions have analogs to make strings, and of course the FormatString function can be used to format numeric data into a string.
Dates can also be converted using:
qword = StringToDate ( string source, [int format] );
int = UnixToDate ( qword value );
The StringToDate function converts a string to a fine resolution date-time value while the UnixToDate function converts the string to a Unix or Epoch based date-time number.
Finally, in our menu function example, a hexadecimal string value can be passed as a window handle. However, handle values are a special data type so using the HexToInteger function will not work. The MakeHandle function will convert the value and type it as a handle:
handle = MakeHandle ( string value | int value );
The handle value can then be used with appropriate SDK functions to perform tasks such as window management.
Conclusion
In the next article on strings, we will discuss general functions to convert and parse string data.
Scott Theis is the President of Novaworks and has been involved in the EDGAR industry for over thirty years. He has worked with the EDGAR system at multiple levels: as a financial printer, a member of the EDGAR design team, and as a software developer. He has extensive expertise with EDGAR, HTML, XBRL, and other programming languages. |
Additional Resources
Quicksearch
Categories
Calendar
November '24 | ||||||
---|---|---|---|---|---|---|
Mo | Tu | We | Th | Fr | Sa | Su |
Tuesday, November 19. 2024 | ||||||
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |