GoFiler Legato Script Reference
Legato v 1.5b Application v 5.24b
|
Table of Contents | < < Previous | Next >> |
Chapter Two — Language Overview
This chapter illustrates some basic Legato programs to provide a quick overview of Legato’s operation and structure. While some of the examples have little or nothing to do with text processing or EDGAR, they demonstrate basic program structure and give the developer a flavor of program operation.
This section covers script examples at a generalized level while the following sections provide a brief description of Legato variables, flow control, and program operation. If the reader is familiar with structured language concepts, the manner in which these example programs function will be apparent. For those not familiar with such concepts, these examples give an overview of how simple programs operate in a structured environment. All of these examples can be copied and pasted into the application and run. Please note that if the plain text is copied to a text window, instead of a Legato IDE window, the application will not consider the text a Legato script and will therefore not run it. The functions employed in these scripts can be located in chapters 5 and 6.
Generally, Legato operates within the confines of the desktop application such as GoFiler. However, Legato can operate as a console application, in which case, the default interface is the console interface. In console mode, many high-level functions, such a those relating to edit windows, are not available.
The following is a simple program to convert Fahrenheit temperatures to Celsius:
// // Create Simple Fahrenheit to Celsius Table // // Based on K&R // int fahr, celsius; // Working values int lower, upper; // Limits int step; // Step amount lower = 0; // Set the lower limit upper = 300; // Set the upper limit step = 5; // Step amount 5 deg Fahrenheit fahr = lower; // Set starting position while (fahr <= upper) { // Loop until end upper limit celsius = 5 * (fahr - 32) / 9; // Basic conversion AddMessage("Fahr %d Cel %d", fahr, celsius); fahr += step; // Move forward on steps } // Continue
To use this program in GoFiler, copy it to the clipboard. Within the application, press File | New, then select Legato Script (at the bottom of the list). Paste the program and press F7 (run). A table will appear in the Information View under the Legato Log tab:
This table is the result of the script just run. In addition, the Legato Errors tab contains information about script execution, including errors and warnings. In the event of an error, the Legato Log tab may not appear. For more information about the Legato IDE, see Section 2.6 Integrated Development Environment (IDE).
The above script consists of three basic sections: variable declaration, initialization, and a calculation loop. In the declaration stage, all the of variables are declared as basic integers (32-bit signed values). This means that fractional amounts are automatically truncated (‘3.2’ becomes ‘3’). The initialization stage sets the range from 0 degrees to 300 degrees and a step value of 5 for creating the table. Finally, there is the loop that runs until the value of fahr exceeds the value of upper range.
Resulting data is formatted for presentation to the default log using the AddMessage function. C/C++ programmers will note the similarity to the printf statement for formatting strings.
Some notes of interest: All program statements are ended with a semicolon (‘;’) or the start of a block as denoted by an open brace (‘{’). Braces indicate a group of code to be executed together and must be started with an open brace and ended with a corresponding closing brace (‘}’). All variables must be declared. Finally, in the above case, there is no entry point. By default, if the script engine does not locate a ‘main’ or ‘entry’ routine, it starts running the first line of global code it encounters.
While temperature can be expressed as whole number values, temperature conversion might be better derived using real numbers. Integers can only represent whole numbers, but floating-point numbers contain real numbers and thus fractional values. To change the variables’ data types from int to float, simply alter the declarations as follows:
float fahr, celsius; // Working values float lower, upper; // Limits float step; // Step Amount
Since fractional values can now be printed, the output message should be changed to reflect this:
AddMessage("Fahr %3.0f Cel %1.1f", fahr, celsius);
This changes the %d to %f with a format modification. The %d translates the corresponding parameter to a decimal integer while the %f indicates the parameter is expected to be floating-point. The 3.0 indicates the whole number portion should be printed and the 1.1 indicates that the script should print out at least one leading digit and only one trailing digit. The output is now:
Fahr 0 Cel -17.8 Fahr 5 Cel -15.0 Fahr 10 Cel -12.2 Fahr 15 Cel -9.4 Fahr 20 Cel -6.7 Fahr 25 Cel -3.9 Fahr 30 Cel -1.1 Fahr 35 Cel 1.7 Fahr 40 Cel 4.4
In addition, using a convert subroutine simplifies the logic:
float convert (float); int main () { float fahr, celsius; // Working values float lower, upper; // Limits float step; // Step Amount lower = 0; // Set the lower limit upper = 300; // Set the upper limit step = 5; // Step amount 5 deg Fahrenheit fahr = lower; // Set staring position while (fahr <= upper) { // Loop until end upper limit celsius = convert(fahr); // Convert AddMessage("Fahr %3.0f Cel %1.1f", fahr, celsius); fahr = fahr + step; // Move forward on steps } // Continue } float convert(float f) { f = 5.0 * (f - 32.0) / 9.0; // '.0' to force float return f; }
In the above case, a subroutine or function was created that performs the conversion. In addition, for consistency, the main part of the program was moved into a function called main which is now the entry point. The short copy of the function name at the start of the program tells the script engine that convert is a function that expects to have passed to it a float parameter and returns a float parameter. Declaring a function like this is known as prototyping. Placing the conversion routine prior to its first reference makes prototyping unnecessary since the function is already declared by the time the engine encountered its first reference.
2.1.4 Display the Contents of a Folder
In this next example, the contents of a folder will be displayed in the log window. This not the most efficient way of performing this particular task but the verbose method helps illustrate a number of features and functions.
handle hEnum; string nTarget; string s1, s2, s3; int rc, files, folders; qword size, total, time, mt; // ----------------------------------------------------------- GetFirstFile s1 = GetScriptFilename(); s1 = GetFilePath(s1); nTarget = s1 + "*.*"; nTarget = "C:\\Windows\\*.*"; // something known hEnum = GetFirstFile(nTarget); if (hEnum == 0) { MessageBox('X', "Could not open path %s", s1); exit(); } AddMessage("Directory for %s", s1); AddMessage(""); AddMessage("-------Modified------- --Type-- ---Size--- --Name------------------------"); // ----------------------------------------------------------- Dump Folders s1 = GetName(hEnum); while (s1 != "") { s2 = GetFileAttributeString(hEnum); rc = InString(s2, "d"); if (rc > 0) { folders++; mt = GetFileModifiedTime(hEnum); s3 = FormatDate(mt, 0x02000031); AddMessage("%-22s %8s -- : [%s]", s3, s2, s1); } GetNextFile(hEnum); s1 = GetName(hEnum); } CloseFile(hEnum); // ----------------------------------------------------------- Dump Files hEnum = GetFirstFile(nTarget); s1 = GetName(hEnum); while (s1 != "") { s2 = GetFileAttributeString(hEnum); rc = InString(s2, "d"); if (rc < 0) { files++; size = GetFileSize(hEnum); total += size; mt = GetFileModifiedTime(hEnum); s3 = FormatDate(mt, 0x02000031); AddMessage("%-22s %8s %12a : %s", s3, s2, size, s1); } GetNextFile(hEnum); s1 = GetName(hEnum); } // ----------------------------------------------------------- Wrap Up AddMessage(""); AddMessage("Total %a file(s) for %a bytes and %a folder(s)", files, total, folders); CloseFile(hEnum);
Note the use of three new new data types: handle, string, and qword. A handle stores a unique identifier to an object and in this case, a FolderEnumeration object. A string contains chunks of text and a qword or ‘quad-word’ defines a 64-bit unsigned integer. The qword type is used to retrieve a date/time value which is measured in 100-nanosecond intervals from January 1, 1601, so it can be a very large number.
At the beginning of the script, the target path is developed. An extra line of code has been added to allow the script to be copied and pasted into the host application and still operate. Since copying the above code into an untitled window would result in an undefined script name (unless saved), the lines of code concerning retrieving the script name and path would not work. The string literal specifying the path for Windows contains double backslashes. The reason for this is that the backslash character has special meaning within a string literal so to use this character as part of the text, it must be escaped. Here “\\” actually means ‘\’. This is covered in more detail in the next chapter.
The main function in this example is the GetFirstFile function which takes the target path along with a wildcard mask (*.*) and enumerates any files and folders located at that specified point. Assuming something is found, a handle value to a FolderEnumeration object, which contains the results, will be returned. If not, the return value will be 0. Note that even empty locations will contain at least the folders ‘.’ and ‘..’. Once a valid handle is returned, the script loops through and dumps folders to the log. A second pass is made to enumerate the files.
During the enumeration process, the total files, folders, and bytes are collected to be printed at the end. The result might look something like:
Directory for C:\Windows\*.* -------Modified------- --Type-- ----Size---- --Name----------------------------- 03/26/2014 03:33:37 PM ---d---- -- : [.] 03/26/2014 03:33:37 PM ---d---- -- : [..] 07/14/2009 01:32:39 AM ---d---- -- : [addins] 07/13/2009 11:20:08 PM ---d---- -- : [AppCompat] . . . 03/30/2011 05:39:01 PM ----a--- 22,387 : Ascd_tmp.ini 09/14/2012 11:00:12 AM ----a--- 38,452 : atiogl.xml 03/30/2011 05:32:09 AM ----a--- 0 : ativpsrm.bin . . . 07/13/2009 09:39:57 PM ----a--- 10,240 : write.exe Total 50 file(s) for 8,659,644 bytes and 62 folder(s)
For brevity, only a few entries are shown.
The final example illustrates how Legato can be used to make a request to search a wiki page using a wiki API. The the script consists of a test jig and a function that makes the request and then parses the result to retrieve a page ID and name.
/****************************************/ /* ** Declarations */ int wiki_search (string ss); /* Prototype */ /* * Global Data */ string s1, s2, s3; /* General */ string r_page_id; /* Returned Page ID */ string r_title; /* Returned Title */ int rc; /* Return Code */ /****************************************/ /* ** Test Jig */ rc = wiki_search("MSFT"); /* Perform Search */ /* Result */ MessageBox('I', "Result %d:\r\r Page ID:%s\r Title: %s", rc, r_page_id, r_title); exit; /****************************************/ int wiki_search(string ss) { /* Query Wikipedia */ /****************************************/ handle hParse; /* Word Parse Handle */ string wq, wr; /* Query/Result */ string s1; /* General */ /* */ /* ** Perform Seach */ /* * Initialize */ r_page_id = ""; /* Clear the Page ID */ r_title = ""; /* Clear the Title */ /* * Build Query */ wq = "http://en.wikipedia.org/w/api.php?"; /* Main API query */ wq .= "format=json&action=query"; /* Main query */ wq .= "&titles=" + ss; /* Name */ /* * Perform Query */ wr = HTTPGetString(wq); /* Go back */ if (wr == "") { /* No good */ return 0; /* Not found */ } /* end empty */ if (IsInString(wr, "missing")) { /* No found */ return 0; /* Not found */ } /* end not found */ /* * Look At JASON */ hParse = WordParseCreate(3, wr); /* Add in the string, in program mode */ s1 = WordParseGetWord(hParse); /* Get the first item */ while (s1 != "") { /* Loop through */ if (s1 == "\"pageid\"") { /* * Page ID */ WordParseGetWord(hParse); /* Get the first item */ r_page_id = WordParseGetWord(hParse); /* Get the get item */ } /* end page ID */ if (s1 == "\"title\"") { /* * Page ID */ WordParseGetWord(hParse); /* Get the first item */ r_title = WordParseGetWord(hParse); /* Get the get item */ } /* end title */ s1 = WordParseGetWord(hParse); /* Get the first item */ } /* End Scan loop */ return 1; /* Found Item */ } /* end search */
This script introduces a couple of new items. First, this example contains both global and local variables. Until now, all variable declarations were global simply because they were placed outside of any function. A global variable is available and visible to the entire program. Local variables exist only while the function is running and are only visible to that specific function. If the function calls other functions, local variables still persist but can only be accessed within the scope of that specific function. In the above example, hParse, wq, wr, and s1 will be created and destroyed every time the wiki_search function is entered and exited. Note that the handle for the WordParse object is not closed, but since it is local variable, it is automatically closed on exit of the function.
A query is formed using the source string ss and creates the contents of the variable wq (wiki query). This is then sent out on the Internet using the HTTPGetString function, the results of which are placed into wr (wiki result). A series of simple tests are performed to determine if anything was returned or if the query resulted in a missing page. The wiki request was made with a format of JSON (JavaScript Object Notation). A positive reply looks something like this:
{"query":{"pages":{"778754":{"pageid":778754,"ns":0,"title":"MSFT"}}}}~
In this case, JSON was selected because of its predictable format. The remainder of the function parses the reply and fills the r_page_id and r_title global variables. The script then displays:
The script queried the string “MSFT”, which is Microsoft’s trading symbol. This example can be built upon. Perhaps a query could be made, the result turned into a URI, and then directed to Internet Explorer or another web browser.
Table of Contents | < < Previous | Next >> |
© 2012-2024 Novaworks, LLC. All rights reserved worldwide. Unauthorized use, duplication or transmission prohibited by law. Portions of the software are protected by US Patents 10,095,672, 10,706,221 and 11,210,456. GoFiler™ and Legato™ are trademarks of Novaworks, LLC. EDGAR® is a federally registered trademark of the U.S. Securities and Exchange Commission. Novaworks is not affiliated with or approved by the U.S. Securities and Exchange Commission. All other trademarks are property of their respective owners. Use of the features specified in this language are subject to terms, conditions and limitations of the Software License Agreement.