• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, February 03. 2017

LDC #20: Running a Script From a Command-Line

Like many programs, the GoFiler application can be run from a command-line or shell command. By learning some basics, you can run and control the application directly from a command prompt or shell execute. Further, by using some script code you can do much more than just open a file.


Like most applications, GoFiler will accept command-line parameters or options. The source of the command-line parameters is not important. What matters is that they are passed to the application as part of the startup.


It is important to note that while the GoFiler can be run from a command-line console like cmd.exe, it is not a console application. This means it cannot easily communicate with the conventional console, including shell pipes, standard input, output, and errors (stdio or conventional pipes). It also means that depending on how that application is run, the calling shell may not wait for execution to complete. For example, when running the application from the Windows command prompt, the command prompt will run the application asynchronously as a separate process and therefore return the user immediately to the prompt. Certain programming environments such as Perl, Python or even Legato have options to wait for and be signaled when the program executing the shell terminates. These issues become important when a command-line action is used to run scripts as part of a larger system.


Command-line options are delimited by forward slashes (‘/’) or plain dashes (‘-’). There is no difference in their meaning. By default, most command-line options are not case sensitive but that can depend on the section of the application receiving the specified options.


For the GoFiler application, command-line data is considered to be a series of unrelated options. The options not understood by the application are assumed to belong to other scripts and tasks. What this means is well-formed but unknown options will not necessarily generate an error. So be careful typing. The first item, if not preceded by a slash or a dash, is assumed to be a filename specification to open by the application desktop.


To get a list of options for the application, just go to Windows Start, Run cmd.exe (command prompt), and make sure you have the path for GoFiler or are in the GoFiler program folder. Type:


    gofiler /?

The result will be a dump to the console of the application’s options:


Command Line Help - GoFiler Complete
-----------------

Form:

   app.exe filename /option:data .....

Where:

   filename           Name to open on the application desktop.

   /CommandFile       Specifies a file which contains parameters to process as
                      a command line. After being processed, the command line
                      parsing will continue from the start of the file.
   /NewInstance       Starts a new instance of the application or starts
                      normally if no application is open.
   /NoGUI             Indicates whether to start the Graphics User Interface
                      (desktop). When used with RunScript, the script is run
                      during the application startup sequence.
   /OpenFile          Opens the specified file(s).
   /OpenInfoFile      Opens the specified file as an Information View log.
   /OpenProjectFile   Opens the specified specifically as a project file.
   /Parameters        Specifies individual parameter "name: value;" pairs.
   /ParameterFile     Specifies a file to use instead of the default parameters.
   /RunScript         Runs the specified script file either as a startup script
                      or as applications desktop script depending on the NoGUI
                      parameter.
   /ScriptParams      Specifies parameters to pass to the script specified with
                      the RunScript Command

As and API shell call (see API documentation):

   /InFile            Specifies one or more input files to apply to the API
                      verb.
   /OutFile           Output File
   /Preferences       Specifies a file that will override one or more
                      application preferences.
   /Project           Specifies the project file to use or create during API
   /Result            Specifies destination file for command line API verb
                      processing. This must be provided to have an API
                      verb be processed.
   /..verb...         See the API reference for the application for a list
                      of verbs.

If an option’s value contains spaces, place double quotes around the value data. While it may seem obvious, GoFiler is a ‘window’ application, not a ‘console’ application. In this article, we will be concerning ourselves with those items related to scripts and using the command line to pass a script to GoFiler for execution.


Running a Script


The first option we will discuss is ‘/RunScript’, which runs a specified script. By default, when the application runs the script, it is executed in the first instance of the application found on the computer desktop. If a version of the application is already running and the ‘/NewInstance’ option is not specified, the script location is sent to the currently running application and then executed. Note that this can get a bit ugly since the script will be executed even if dialogs are open in the current application instance. It is up to the script to determine whether it is appropriate to perform designated operations without conflicting with already running tasks. One tool, the IsDialogOpen Legato function, can be used to see if any dialogs are open.


An example of ensuring the script is run in a new instance:


   gofiler /runscript:"z:\myscripts\test.ls" /newinstance

When the script is run in the GUI (Graphics User Interface or the application desktop), the desktop will return to its previous state upon completion. The ExitApplication function can be used to force the application to quit.


Keep in mind that files specified in the command-line should have qualified path names. In our examples, the path for the gofiler.exe (or other product name) is omitted for brevity.


Finally, since the application desktop may be opening, initialization tasks, such as RSS notifications and other application startup functions, will run. On a new instance execution, the script you specify is run as the last initialization operation. For an existing instance, the /RunScript is passed as a message to the existing frame window.


To GUI or Not to GUI


Unless directed otherwise, the GUI is displayed or the command-line is directed to another GUI instance. The ‘/NoGUI’ command-line option will stop the application from displaying the desktop and will direct it instead to enter menu/message mode.


When run in NoGUI mode, the application desktop is not available. Files cannot be opened in any edit views and any desktop or window-dependent functions will not operate. This includes running menu functions with the RunMenuFunction function. To test if the desktop is open, use the IsDesktopRunning function.


Dialog and message box functions are fully functional and, in fact, it is not an uncommon programming practice to use a dialog as a graphics user interface to perform functions.


Without a desktop, the application will immediately exit when the script execution has completed.  As mentioned earlier, depending on the execution or ‘shell’ method, the caller may not be waiting for execution to complete. As a result, programmers must determine the best method to signal or control the program that called the script via command-line.


The return value of the script is interpreted in three ways:


ERROR_CANCEL will cause the NoGUI operation to be aborted and the application desktop will load. This can be used as an opportunity to perform certain initialization prior to starting the app, such as a log-in.


ERROR_SOFT or any dword with the top bit set (0x80000000) will cause the application to exit with EXIT_FAILURE (1).


Any other code will cause the application to exit with EXIT_SUCCESS (0).


The failure or success code is returned to Windows and will be available to the calling program.


Getting Command-Line Data


There are essentially two methods of getting command-line data along with a variation. The GetCommandLine SDK function will return the entire command-line, less the name of the application executable. After retrieving the string, a script can then parse it as appropriate.


    gofiler /runscript:d:\data\commandline.ls /a /b /c:"My thing" /NoGUI

The content of ‘commandline.ls’ (location is your choice):


    MessageBox('i', GetCommandLine());

results in:


A screenshot of a Legato message box showing the command-line data


Another method is to use the GetCommandLineParameter function. This function is a little more sophisticated in that it uses the internal command-line class and allows parameters to be directly addressed. Changing the content of ‘commandline.ls’:


    MessageBox('i', GetCommandLineParameter("c"));

results in:


A screenshot of a Legato message box showing a command-line parameter


The GetCommandLine function takes no parameters while the GetCommandLineParameter function has the following structure:


string = GetCommandLineParameter ( string name, [int index] );

The name parameter is the name of the parameter to retrieve. Some predefined parameters, such as ‘/InFile’, allow for multiple entries, so the index parameter can be used to retrieve each sub item.


The variation to the above is to use the predefined ‘/Parameters’ or ‘/ParameterFile’ options to send script specific options. The GetCommandLineParameter function can be used to get the data, and the script can then parse them as needed.


Finally, Windows limits the amount of data that can be placed on a command line to about 4,000 bytes. The ‘/CommandFile’ option can be used with large amounts of data stored in command-line format in a file of up to 65K bytes. The command-line parser for the application will automatically load the data, which will only be available to the GetCommandLineParameter function.


Example #1 — Retrieving Company Information


Using the command-line and the ‘/NoGUI’ option, let us make a script to retrieve information from the public side EDGAR Company database:


    string    list[];
    string    cik, output, s1;
    int       rc;
	
    output = GetCommandLineParameter("output");
    if (output == "") { 
      return ERROR_CANCEL;  
      }

    cik = GetCommandLineParameter("cik");
    if (cik == "") {
      StringToFile("CIK Required", output);
      return ERROR_RANGE;
      }

    list = EDGARLookupCIK(cik);
    if (IsError()) {
      rc = GetLastError();
      s1 = FormatString("Error %08X looking up CIK %s", rc, cik);
      StringToFile(s1, output);
      return rc;
      }

    s1 = ArrayToParameters(list);
    StringToFile(s1, output);
    return ERROR_NONE;

This is a simple, unstructured script, that when run retrieves two options from the command-line: ‘/cik’ and ‘/output’. Assuming we get a valid filename from the /output option, errors can be reported back in the contents of the output file. Prior to that, if the script is called from a shell operation, the return value can be used to determine if an error occurred.


The first task is to get the ‘/output’ name and ‘/cik’ options as strings. Once we have those, the EDGARLookupCIK function can be used to get the data. The data is then converted from a keyed list to a parameter list and written to a file.


An example command-line (location is set as ‘d:\data\’):


    gofiler /runscript:d:\data\getcompanydata.ls /nogui /cik:320193 /output:d:\data\result.txt

Would result in the output file:


CompanyName: APPLE INC
CIK: 0000320193
IRSNumber: 942404110
FileNumber: 001-36743
EntityType: 
SIC: 3571
Address: ONE INFINITE LOOP
CUPERTINO, CALIFORNIA 95014
PhoneNumber: (408) 996-1010
SOI: CALIFORNIA
FYE: 0930
LastUpdate: 12/15/16

Note that if we open the result in Notepad, address lines one and two will not be split. A simple return (0x0D) is added to delimit the line in the ‘Address’ field (Notepad does not understand simple return codes). To fix this for our simple example, add the following code before the array is converted to a parameter string:


list["Address"] = ReplaceInString(list["Address"], "\r", ",");

Example #2 — Fetch all Registrant EDGAR Filings


Here is another example:


    string      list[];
    string      cik, output, s1;
    int	        rc;
    	
    output = GetCommandLineParameter("output");
    if (output == "") { 
      return ERROR_CANCEL;  
      }
    
    cik = GetCommandLineParameter("cik");
    if (cik == "") {
      StringToFile("CIK Required", output);
      return ERROR_RANGE;
      }
    
    list = EDGARFetchArchiveList(cik);
    if (IsError()) {
      rc = GetLastError();
      s1 = FormatString("Error %08X looking up CIK %s", rc, cik);
      StringToFile(s1, output);
      return rc;
      }
    
    s1 = ImplodeArray(list);
    StringToFile(s1, output);

    return ERROR_NONE;

The example command-line would be:


    gofiler /runscript:d:\data\getfilings.ls /nogui /cik:320193 /output:d:\data\result.txt

And this is the result placed into the output file (truncated):


http://www.sec.gov/Archives/edgar/data/320193/000162828017000312/0001628280-17-000312.txt
http://www.sec.gov/Archives/edgar/data/320193/000162828017000311/0001628280-17-000311.txt
http://www.sec.gov/Archives/edgar/data/320193/000021545717001275/0000215457-17-001275.txt
http://www.sec.gov/Archives/edgar/data/320193/000162828017000187/0001628280-17-000187.txt
http://www.sec.gov/Archives/edgar/data/320193/000119312517003764/0001193125-17-003764.txt
http://www.sec.gov/Archives/edgar/data/320193/000119312517003753/0001193125-17-003753.txt
http://www.sec.gov/Archives/edgar/data/320193/000162828016022242/0001628280-16-022242.txt
http://www.sec.gov/Archives/edgar/data/320193/000162828016022104/0001628280-16-022104.txt
http://www.sec.gov/Archives/edgar/data/320193/000162828016022047/0001628280-16-022047.txt
     . . .
http://www.sec.gov/Archives/edgar/data/320193/000095015094000392/0000950150-94-000392.txt
http://www.sec.gov/Archives/edgar/data/320193/000091898394000005/0000918983-94-000005.txt
http://www.sec.gov/Archives/edgar/data/320193/000091898394000004/0000918983-94-000004.txt
http://www.sec.gov/Archives/edgar/data/320193/000095015094000252/0000950150-94-000252.txt
http://www.sec.gov/Archives/edgar/data/320193/000032019394000002/0000320193-94-000002.txt
http://www.sec.gov/Archives/edgar/data/320193/000089161894000021/0000891618-94-000021.txt

Exmaple #3 — Get Series and Class Information


This example is a little more complex since we will be retrieving a table of information. This could be written out as a CSV table or perhaps as a cluster. For this example, we will convert it to plain text:


    string      list[][];
    string      cik, output, s1, s2;
    int         ix, size;
    int	        rc;
    	
    output = GetCommandLineParameter("output");
    if (output == "") { 
      return ERROR_CANCEL;  
      }
    
    cik = GetCommandLineParameter("cik");
    if (cik == "") {
      StringToFile("CIK Required", output);
      return ERROR_RANGE;
      }
    
    list = EDGARGetClassTable(cik);
    if (IsError()) {
      rc = GetLastError();
      s1 = FormatString("Error %08X looking up CIK %s", rc, cik);
      StringToFile(s1, output);
      return rc;
      }
    
    s1 = "IX  ------Key Name-------- : -SeriesID-  -ClassID-  --Ticker--  --Status--\r\n";
    size = ArrayGetAxisDepth(list, AXIS_ROW);

    while (ix < size) {
      s2 = ArrayGetKeyName(list, ix, AXIS_ROW);
      s1 += FormatString("%3d %-22s : %10s  %10s  %-10s  %-8s  %s\r\n", 
                         ix, s2, list[ix]["SeriesID"], list[ix]["ClassID"], 
                         list[ix]["Ticker"], list[ix]["Status"], list[ix]["Name"]);
      ix++;
      }

    StringToFile(s1, output);

    return ERROR_NONE;

This would be the command-line for this example:


    gofiler /runscript:d:\data\getseries.ls /nogui /cik:930667 /output:d:\data\result.txt

Note that our list is now a two-dimension table and we are iterating through the data to build the text output. The result in the output file would be like (truncated to fit):


IX  ------Key Name-------- : -SeriesID-  -ClassID-  -Ticker- -Status-
  0 S000004246             : S000004246                       Active  ... MSCI Australia ETF
  1 S000004246_C000011950  :             C000011950  EWA      Active  ... MSCI Australia ETF
  2 S000004247             : S000004247                       Active  ... MSCI Hong Kong ETF
  3 S000004247_C000011951  :             C000011951  EWH      Active  ... MSCI Hong Kong ETF
  4 S000004248             : S000004248                       Active  ... MSCI Italy Capped ETF
  5 S000004248_C000011952  :             C000011952  EWI      Active  ... MSCI Italy Capped ETF
         . . . 
139 S000049021_C000154544  :             C000154544  EMGF     Active  ... Edge MSCI Multifac...
140 S000051285             : S000051285                       Active  ... Edge MSCI Min Vol ...
141 S000051285_C000161697  :             C000161697  HEMV     Active  ... Edge MSCI Min Vol ...
142 S000054183             : S000054183                       Active  ... MSCI EM ESG Optimi...
143 S000054183_C000170244  :             C000170244  ESGE     Active  ... MSCI EM ESG Optimi...

Output like this could also easily be written to a CSV file using the CSVWriteTable function.


Putting it Together


To develop scripts that run from a command-line, it is a good idea to write and debug the code in the GoFiler IDE. Code can actually be made multi-purpose by using the GetScriptParent function to determine how to handle the input and output. The return value can be checked in the Legato IDE or with various command-line states. Working in the IDE also allows program stepping and variable inspection during debugging.


    string      list[];
    string      cik, output, s1;
    int	        rc;
    	
    if (GetScriptParent() == "LegatoIDE") {
      output = "D:\\Data\\MyOutput.txt";
      cik = "320193";
      }
    else {
      output = GetCommandLineParameter("output");
      if (output == "") { 
        return ERROR_CANCEL;  
        }
    
      cik = GetCommandLineParameter("cik");
      if (cik == "") {
        StringToFile("CIK Required", output);
        return ERROR_RANGE;
        }
      }
    
    list = EDGARLookupCIK(cik); 
    if (IsError()) {
      rc = GetLastError();
      s1 = FormatString("Error %08X looking up CIK %s", rc, cik);
      StringToFile(s1, output);
      return rc;
      }
    
    s1 = ArrayToParameters(list);
    StringToFile(s1, output);
    if (GetScriptParent() == "LegatoIDE") {
      ConsolePrint(s1);
      }

    return ERROR_NONE;

Using example #1, we can add the IDE test to the start of the script and load our variable manually. We can even dump the output to a console window. This make debugging much easier. The debug code can be later removed or left in place for future development.


In addition, since debugging scripts for command-line operation is essentially performed in the blind, the DebugTrace pragma can be used to place execution and debug data in a log. For example, adding the following to the start of the program:


#pragma DebugTrace mylog.log

will place trace data into ‘mylog.log’ in the user temporary file area (‘%temp%’). The application log (located in ‘%AppData%\Novaworks\’) can also be used to check the overall operation of the application.


Learning how to use the command-line can open a lot of alternatives to access EDGAR and other functions embedded in GoFiler.



 


Note: The CIK and associated companies used in the examples are not related to Novaworks and are intended only as a source of data for demonstration purposes.



 




Scott Theis is the President of Novaworks and the principal developer of the Legato scripting language. He has extensive expertise with EDGAR, HTML, XBRL, and other programming languages.


Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 



Posted by
Scott Theis
in Development at 10:26
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
The author does not allow comments to this entry

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Sunday, May 18. 2025
      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 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us