RUN

The RUN instruction executes the command passed as argument.

Syntax

RUN command
  [ IN {FORM|LINE} MODE ]
  [ RETURNING variable | WITHOUT WAITING ]
  1. command is a string expression with the command to be executed.
  2. variable is an integer variable receiving the execution status of the command.

Understanding the RUN command

The RUN instruction hands the argument command to the command interpreter.

The IN FORM MODE or IN LINE MODE clause can be used to define if the command is interactive or is silent. This has an impact in TUI mode. See IN LINE MODE and IN FORM MODE.

The RETURNING clause can be used to get the result status of the command. See Catching the execution status

If the WITHOUT WAITING clause is not specified with the RUN instruction, the calling process waits for the command termination. When the WITHOUT WAITING clause is specified, the calling process continues just after starting the command. See Waiting for the subprocess.

RUN and GUI resources

When executing in GUI mode, resources such as images may be sent asynchroneously by fglrun to the front-end, typically at the beginning of the program execution.

If a RUN command is executed at this time, it will suspend the parent program execution and block the resource transfers.

Consider starting child programs with the RUN command, when the parent program is alive for a couple of seconds, to make sure that all GUI resources have been transmitted to the front-end.

RUN is not supported with mobile apps

When running an embedded app on a mobile device (or emulator), the RUN cmd and RUN cmd WITHOUT WAITING instructions are not supported. To implement apps running on a server, see the runOnServer front call.

Defining the command execution shell

In order to execute the command line, the RUN instruction uses the OS-specific shell defined in the environment of the current user:
  • On UNIX™, the shell program is defined by the SHELL environment variable.
  • On Windows®, the shell program is defined by COMSPEC environment variable, and this program must support the /c option (hardcoded).

Passing command-line arguments

The command provided to the RUN instruction can use arguments.

The next example will pass the -l option and 3 file names to the ls command:
RUN "ls -l file1 file2 file3"
In order to pass arguments containing blanks, use the single or double-quote argument delimiters. These delimiters can have different semantics depending on the used OS shell:
RUN 'ls -l "file name with spaces" '
On Windows, when using the (default) COMSPEC CMD.EXE command interpreter, special consideration needs to be taken with double quotes in the command string. Depending on several conditions, the first and the last " quotation marks will be removed before executing the command string. This can lead to command execution failure, when arguments using space characters need to be enclosed in double quotes:
RUN '"C:\\Program Files\\Tools\\bin\\cleanup.exe" "C:\\tmp\\my dir"'
Above instruction will actually try to execute the following command:
C:\Program Files\Tools\bin\cleanup.exe" "C:\tmp\my dir
A typical workaround (on Windows only) is to surround the whole command again in double quotes:
RUN '" "C:\\Program Files\\Tools\\bin\\cleanup.exe" "C:\\tmp\\my dir" "'
See MSDN documentation for CMD.EXE details.

Using OS shell features

The command provided to the RUN instruction can use any possibilities supported by the OS shell, such as output redirection, chaining commands, etc:
RUN "grep -h name *.txt | sort -u > zz"

Waiting for the subprocess

By default, the RUN instruction waits for the end of the execution of the command, suspending the execution of the current program. After executing the command, the display of the parent program is restored.

If you specify WITHOUT WAITING, the command line is executed as a background process, and must not affect the visual display. This clause can be used when the command takes some time to execute, and the parent program does not need the result to continue. It is also typically used in GUI mode to start another program. Do not use this clause in TUI mode when the sub-program displays forms, otherwise both programs would run simultaneously on the same terminal.

Catching the execution status

The RETURNING clause saves the termination status code of the command that RUN executes in a program variable of type SMALLINT. Examine the variable after execution to determine the next action to take. A status code of zero usually indicates that the command has terminated normally. A non-zero exit status indicates an error.

The execution status provided by the RETURNING clause is platform-dependent:
  • On UNIX systems, the value is composed of two bytes having different meanings: The lower byte (x mod 256) of the return status defines the termination status of the RUN command. The higher byte (x / 256) of the return status defines the execution status of the program.
  • On Windows platforms, the execution status is zero for success, or a non-zero value if an error occurred: The value of the return status only defines the execution status of the program.
Example on UNIX platform:
MAIN
    IF arg_val(1)=="child" THEN
       DISPLAY SFMT("Child: EXIT PROGRAM %1", arg_val(2))
       EXIT PROGRAM arg_val(2)
    ELSE
       IF arg_val(1) IS NULL THEN
          CALL run_cmd("invalid-command")
       ELSE
          CALL run_cmd(SFMT("fglrun run child %1",arg_val(1)))
       END IF
    END IF
END MAIN

FUNCTION run_cmd(cmd STRING) RETURNS ()
    DEFINE s, rs, cs SMALLINT
    DISPLAY "\nCommand: ", cmd
    RUN cmd RETURNING s
    DISPLAY "RUN RETURNING result:"
    DISPLAY SFMT("   s           = %1", s)
    LET rs = s MOD 256
    DISPLAY SFMT("   s MOD 256   = %1", rs)
    LET cs = s / 256
    DISPLAY SFMT("   s / 256     = %1", cs)
END FUNCTION
Output:
$ fglcomp run.4gl && fglrun run

Command: invalid-command
sh: line 1: invalid-command: command not found
RUN RETURNING result:
   s           = 32512
   s MOD 256   = 0
   s / 256     = 127

$ fglcomp run.4gl && fglrun run 5

Command: fglrun run child 5
Child: EXIT PROGRAM 5
RUN RETURNING result:
   s           = 1280
   s MOD 256   = 0
   s / 256     = 5

GUI rendering of child programs

When starting a new child program in GUI mode, different rendering options can be used to show the application windows.

The windows/forms of each application can be displayed in a common window container or in a dedicated container window container. The window container is a desktop OS window frame with the desktop front-end (GDC), or a web browser tab with the Genero application server (GAS).

For more details, see Containers for program windows.

IN LINE MODE and IN FORM MODE

The IN {LINE|FORM} MODE clause of the RUN instruction defines how the dumb terminal behaves when running the child process. This clause has no particular impact on GUI front-ends, but should be considered when the same program can run in TUI or GUI mode.

The concept of line mode / form mode comes from the TUI and tty terminal raw mode / cooked mode concept.

No matter if you are in TUI or GUI mode, run silent (batch) programs in form mode, and if the program to run is interactive, or displays messages to the terminal, or if you don't known what it does, use the line mode.

If no LINE/FORM MODE clause is specified in the RUN command, it defaults to the last OPTIONS IN FORM/LINE MODE setting, which is by default IN LINE MODE. However, as many UI instructions (such as OPTIONS) take the program into form mode, typical interactive programs are actually in form mode most of the time (they start in line mode and after the first UI instruction, they are in form mode)

Executing an interactive Genero program with RUN … IN FORM MODE WITHOUT WAITING (or with RUN … WITHOUT WAITING and the FORM MODE is set by OPTIONS), can lead to unexpected behavior.

When the RUN statement specifies IN FORM MODE, the program remains in form mode, if it is currently in form mode, but it does not enter form mode if it is currently in line mode. When the prevailing RUN option specifies IN LINE MODE, the program remains in line mode if it is currently in line mode, and it switches to line mode, if it is currently in form mode. This also applies to the PIPE option of START REPORT.

To run another interactive program, you must use the line mode:
  • In TUI mode, the terminal is in the same state (in terms of tty options) as when the program began. Usually the terminal input is in cooked mode, with interrupts enabled and input not becoming available until after a newline character is typed.
  • In GUI mode, if the WITHOUT WAITING clause in used, the front-end is warned that a new interactive child program is started. If the RUN command waits for child termination (i.e. no WITHOUT WAITING clause is used), no particular action is taken by the parent fglrun to warn the front-end, and the new child fglrun will connect to the front-end.
To execute a subprocess running silently (batch program without output), you must use the form mode:
  • In TUI mode, the screen stays in form mode, if it was in form mode, which saves a clear / redraw of the screen. The form mode specifies the terminal raw mode, in which each character of input becomes available to the program as it is typed or read.
  • In GUI mode, no particular action is taken to warn the front-end (there is no need to warn the front-end for batch program execution).

Besides RUN, the OPTIONS, START REPORT and START REPORT... TO PIPE instructions can explicitly specify a screen mode. With START REPORT using PIPE specifications, the default screen mode is IN FORM MODE.

Example

MAIN
  DEFINE result SMALLINT
  CALL runApplication("app2 -p xxx")
  CALL runBatch("ls -l", FALSE) RETURNING result
  CALL runBatch("ls -l > /tmp/files", TRUE) RETURNING result
END MAIN

FUNCTION runApplication(pname)
  DEFINE pname, cmd STRING
  LET cmd = "fglrun " || pname
  IF fgl_getenv("FGLGUI") == 0 THEN
    RUN cmd
  ELSE
    RUN cmd WITHOUT WAITING
  END IF
END FUNCTION

FUNCTION runBatch(cmd, silent)
  DEFINE cmd STRING
  DEFINE silent STRING
  DEFINE result SMALLINT
  IF silent THEN
    RUN cmd IN FORM MODE RETURNING result
  ELSE
    RUN cmd IN LINE MODE RETURNING result
  END IF
  IF fgl_getenv("OS") MATCHES "Win*" THEN
    RETURN result
  ELSE
    RETURN ( result / 256 )
  END IF
END FUNCTION