6.19. kink/PROCESS

Control the current process and subprocesses.

About exit statuses

In POSIX compliant systems, only the least 8 bits of the exit status can be usable [1]. To comply with that restriction, PROCESS.exit only accepts int nums in [0, 255].

In Windows API, the exit status is a 32bit unsigned integer [2]. To be able to handle that, the range of Process.wait is defined as [0, 4294967295]. Note that, although Windows API specifies the exit status as unsigned, cmd.exe and PowerShell treat the exit status as signed.

[1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html

[2] https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess

6.19.1. PROCESS.pid

`pid` returns the current process id in an int num.

Example:

:PROCESS.require_from('kink/')

stdout.print_line(PROCESS.pid.repr) # => 123

6.19.2. PROCESS.env(Env_name)

`env` returns the str of the environment variable specified by `Env_name`.

Preconditions:

• `Env_name` must be a str

• The process must have the specified environment variable

Case sensitivity of `Env_name` depends on the host system. Typically, it is case sensitive on Unix systems, and case insensitive on Windows systems.

Example:

:PROCESS.require_from('kink/')

stdout.print_line(PROCESS.env('PATH').repr)
# => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

6.19.3. PROCESS.have_env?(Env_name)

`have_env?` returns whether the process has the environment variable specified by `Env_name`.

Precondition:

• `Env_name` must be a str

Example:

:PROCESS.require_from('kink/')

stdout.print_line(PROCESS.have_env?('PATH').repr) # => true
stdout.print_line(PROCESS.have_env?('NO_SUCH_ENV').repr)  # => false

Case sensitivity of `Env_name` depends on the host system. Typically, it is case sensitive on Unix systems, and case insensitive on Windows systems.

6.19.4. PROCESS.exit(Exit_status)

`exit` terminates the process running the runtime system with the `Exit_status`.

Precondition

• `Exit_status` must be an int num in the range [0, 255].

6.19.5. PROCESS.start(Command_and_args ...[$config={}])

`start` launches a subprocess by the command specified by `Command_and_args`.

If `start` succeeds to launch a subprocess, it tail-calls $success with the `process` val which represents the launched subprocess. $success is provided by C.on_success, or VAL.identity by default.

If `start` fails to launch a subprocess, it tail-calls $error with an `exception`. $error is provided by C.on_error, or {(:Exc) Exc.raise } by default.

Preconditions

• `Command_and_args` must be a vec of strs

• `Command_and_args` must contain at least one element

• $config, if given, must be a fun which takes a val of `start_config` type

Example

:PROCESS.require_from('kink/')

:Ls <- PROCESS.start(['ls' '-1' '/']) # command: ls -1 /
stdout.print_line(Ls.wait) # => 0

The source of the standard input and the destination of the standard output and standard error of the subprocess can be configured.

:PROCESS.require_from('kink/')
:CONTROL.require_from('kink/')
:INPUT_SCANNER.require_from('kink/io/')
:CHARSET.require_from('kink/')

:Lines <- CONTROL.with_finally{(:finally)
  :Ls = PROCESS.start(['ls' '-1' '/']){(:C)
    C.stdout_to_pipe
  }
  finally{ Ls.wait }
  :Stdout = Ls.stdout
  finally{ Stdout.close }
  :Scanner = INPUT_SCANNER.new(Stdout CHARSET.utf8)
  :loop <- {(:Lines)
    Scanner.scan_line{(:C)
      C.on_success{(:L) loop(Lines + [L]) }
      C.on_eof{ Lines }
    }
  }
  loop([])
}
stdout.print_line(Lines.repr) # => ["bin\n" "boot\n" "dev\n" "etc\n" "home\n" ,,,]

See `start_config` for details.

6.19.6. type start_config

Config val type of PROCESS.start.

Invocation of stdin_xxx methods overwrites configuration of precedent invocation of stdin_xxx methods. In the next example, the subprocess reads stdin from /etc/passwd.

:PROCESS.require_from('kink/')

:Process <- PROCESS.start(['grep' 'nologin']){(:C)
  C.stdin_from_pipe # pipe is not used
  C.stdin_from_file('/etc/passwd')
}
Process.wait
# Output:
#   daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
#   bin:x:2:2:bin:/bin:/usr/sbin/nologin
#   ...

The same is true for stdout_xxx and stderr_xxx methods.

6.19.6.1. C.stdin_inherit

`stdin_inherit` specifies that the subprocess inherits standard input from the current process.

This is the default option for the standard input.

6.19.6.2. C.stdin_from_pipe

`stdin_from_pipe` specifies that bytes of the standard input of the subprocess comes from the pipe output of the current process.

If you specify `stdin_from_pipe`, you can call P.stdin to get the pipe linked to the subprocess.

6.19.6.3. C.stdin_from_file(File_path)

`stdin_from_file` specifies that bytes of the standard input of the subprocess comes from the file on `File_path`.

Precondition:

• `File_path` must be a str.

If the file cannot be opened, PROCESS.start fails.

6.19.6.4. C.stdout_inherit

`stdout_inherit` specifies that the subprocess inherits the standard output of the current process.

This is the default option for the standard output.

6.19.6.5. C.stdout_to_pipe

`stdout_to_pipe` specifies that the standard output of the subprocess goes to the pipe input of the current process.

If you specify `stdout_to_pipe`, you can call P.stdout to get the pipe input linked to the subprocess.

6.19.6.6. C.stdout_to_overwrite(File_path)

`stdout_to_overwrite` specifies that the standard output of the subprocess goes to a file specified by `File_path` by OVERWRITE mode.

Precondition:

• `File_path` must be a str

If the file cannot be opened, PROCESS.start fails.

See kink/io/FILE for OVERWRITE mode.

6.19.6.7. C.stdout_to_append(File_path)

`stdout_to_append` specifies that the standard output of the subprocess goes to a file specified by `File_path` by APPEND mode.

Precondition:

• `File_path` must be a str

If the file cannot be opened, PROCESS.start fails.

See kink/io/FILE for APPEND mode.

6.19.6.8. C.stderr_inherit

`stderr_inherit` specifies that the subprocess inherits the standard error of the current process.

This is the default option for the standard error.

6.19.6.9. C.stderr_to_pipe

`stderr_to_pipe` specifies that the standard error of the subprocess goes to the pipe input of the current process.

If you specify `stderr_to_pipe`, you can call P.stderr to get the pipe input liked to the subprocess.

6.19.6.10. C.stderr_to_overwrite(File_path)

`stderr_to_overwrite` specifies that the standard error of the subprocess goes to a file specified by `File_path` by OVERWRITE mode.

Precondition:

• `File_path` must be a str

If the file cannot be opened, PROCESS.start fails.

See kink/io/FILE for OVERWRITE mode.

6.19.6.11. C.stderr_to_append(File_path)

`stderr_to_append` specifies that the standard error of the subprocess goes to a file specified by `File_path` by APPEND mode.

Precondition:

• `File_path` must be a str

If the file cannot be opened, PROCESS.start fails.

See kink/io/FILE for APPEND mode.

6.19.6.12. C.stderr_to_stdout

`stderr_to_stdout` specifies that the standard error of the subprocess goes to its standard output.

It is similar to specifying `2>&1` in Unix sh.

6.19.6.13. C.dir(Dir_path)

`dir` specifies `Dir_path` as the working directory of the subprocess.

Precondition:

• Dir_path must be a str

If the subprocess cannot change directory to `Dir_path`, PROCESS.start fails.

6.19.6.14. C.set_env(Env_name Env_val)

`set_env` specifies that the subprocess has the environment variable with the name `Env_name` and the value `Env_val`.

Preconditions:

• `Env_name` must be a str

• `Env_val` must be a str

Case sensitivity of `Env_name` depends on the host system. Typically, it is case sensitive on Unix systems, and case insensitive on Windows systems.

6.19.6.15. C.unset_env(Env_name)

`unset_env` specifies that the subprocess does not have the environment variable with the name `Env_name`.

Precondition:

• `Env_name` must be a str

Case sensitivity of `Env_name` depends on the host system. Typically, it is case sensitive on Unix systems, and case insensitive on Windows systems.

6.19.6.16. C.on_success($success)

`on_success` sets $success.

Precondition:

• $success must be a fun which takes a `process`.

6.19.6.17. C.on_error($error)

`on_error` sets $error.

Precondition:

• $error must be a fun which takes an `exception`.

6.19.7. type process

`process` is a type of subprocesses launched by PROCESS.start.

6.19.7.1. P.wait(...[$config={}])

`wait` waits until the exit status of the subprocess is available, or it reaches the timeout.

Config methods:

• C.timeout(Timeout_seconds)

• C.on_success($success_cont): default = VAL.identity

• C.on_timeout($timeout_cont): default = a fun which raises an exception

`Timeout_seconds` is a non-negative num of arbitrary scale. It is used as the seconds until the timeout. If the timeout is reached before the exit status becomes available, `wait` tail-calls $timeout_cont with no arg.

`Timeout_seconds` migh be adjusted to an appropriate value by `wait`. If C.timeout is not called, `wait` never reaches the timeout.

If the exit status becomes available within the timeout. `wait` tail-calls $success_cont with the exit status as an int num in the range [0, 4294967295].

Preconditions

• `Timeout_seconds` must be a non-negative num

• $success_cont must be a fun which takes an int num in the range [0, 4294967295]

• $timeout_cont must be a fun which takes no arg

6.19.7.2. P.stdin

`stdin` returns the pipe `output` linked to the standard input of the subprocess.

Precondition:

• C.stdin_from_pipe must be called for the `start_config` val.

6.19.7.3. P.stdout

`stdout` returns the pipe `input` linked to the standard output of the subprocess.

Precondition:

• C.stdout_to_pipe must be called for the `start_config` val.

6.19.7.4. P.stderr

`stderr` returns the pipe `input` linked to the standard error of the subprocess.

Precondition:

• C.stderr_to_pipe must be called for the `start_config` val.