Builtin Functions for Configuration Files

Builtins in category:type conversion

SignatureDescription
```bool(int) -> bool```

Converts an int to true/false. 0 is false, everything else is true.

```bool(float) -> bool```

Converts a float to true/false.

```bool(string) -> bool```

If the string is empty, returns false. Otherwise, returns true.

```bool(list[`x]) -> bool```

Returns false if the list is empty, true otherwise.

```bool(dict[`x, `y]) -> bool```

Returns false if the dict is empty, true otherwise

```float(int) -> float```

Converts the value into a float.

```int(float) -> int```

Converts a float to an int, with typical truncation semantics.

```int(char) -> int```

Casts a char to an int

```$(`t) -> string```

Converts any value into a string.

```Duration(string) -> Duration```

Parses a string into a Duration object. The config will error if the conversion fails.

Duration literals accept:

  • us usec usecs
  • ms msec msecs
  • s sec secs seconds
  • m min mins minutes
  • h hr hrs hours
  • d day days
  • w wk wks week weeks
  • y yr yrs year years

None of the above categories should be repeated. Multiple items can be space separated (though it is optional).

For instance, 1 week 2 days is valid, as is: 4yrs 2 days 4 hours 6min7sec2years

This is the exact same syntax as if you declare a Duration literal directly, except for the quoting mechanism. Specifically: myduration := <<1 hr 10 mins>> Is effectively the same as: myduration := Duration("1 hr 10 mins")

Except that syntax errors will be found before running the script in the first case.

```IPAddr(string) -> IPAddr```

Parses a string into an IP address. Both ipv4 and ipv6 addresses are allowed, but blocks of addresses are not; use the CIDR type for that.

Generally, using this function to convert from a string is not necessary; you can write IPAddr literals with 'special' literal quotes: x := << 2001:db8:1::ab9:C0A8:102 >> is functionally equal to: x := IPAddr("2001:db8:1::ab9:C0A8:102")

In the first case, con4m will catch syntax errors before the configuration starts executing. In the second, the checking won't be until runtime, at which point the config execution will abort with an error.

```CIDR(string) -> CIDR```

Parses a string that specifies a block of IP addresses into a CIDR type. CIDR stands for Classless Inter-Domain Routing; it's the standard way to express subnets.

Generally, using this function to convert from a string is not necessary; you can write CIDR literals with 'special' literal quotes: x := << 192.168.0.0/16 >> is functionally equal to: x := CIDR("192.168.0.0/16")

In the first case, con4m will catch syntax errors before the configuration starts executing. In the second, the checking won't be until runtime, at which point the config execution will abort with an error. IPv6 addresses are also supported. Either of the following work:

x := CIDR("2001:db8:1::ab9:C0A8:102/127")```
```Size(string) -> Size```

Converts a string representing a size in bytes into a con4m Size object. A size object can use any of the following units:

  • b, B, bytes, Bytes -- bytes
  • k, K, kb, Kb, KB -- kilobytes (1000 bytes)
  • ki, Ki, kib, KiB, KIB -- kibibytes (1024 bytes)
  • m, M, mb, Mb, MB -- megabytes (1,000,000 bytes)
  • mi, Mi, mib, MiB, MIB -- mebibytes (1,048,576 bytes)
  • g, G, gb, Gb, GB -- gigabytes (1,000,000,000 bytes)
  • gi, Gi, gib, GiB, GIB -- gibibytes (1,073,741,824 bytes)
  • t, T, tb, Tb, TB -- terabytes (10^12 bytes)
  • ti, Ti, tib, TiB, TIB -- tebibytes (2^40 bytes)

The following are functionally equal:

x := << 200ki >>

and:

x := Size("200ki")

The main difference is that the former is checked for syntax problems before execution, and the later is checked when the call is made.

```Date(string) -> Date```

Converts a string representing a date into a Con4m date object. We generally accept ISO dates.

However, we assume that it might make sense for people to only provide one of the three items, and possibly two. Year and day of month without the month probably doesn't make sense often, but whatever.

But even the old ISO spec doesn't accept all variations (you can't even do year by itself. When the year is omitted, we use the old ISO format, in hopes that it will be recognized by most software.

Specifically, depending on a second omission, the format will be:

--MM-DD
--MM
---DD

However, if the year is provided, we will instead turn omitted numbers into 0's, because for M and D that makes no semantic sense (whereas it does for Y), so should be unambiguous and could give the right reuslts depending on the checking native libraries do when parsing.

We also go the ISO route and only accept 4-digit dates. And, we don't worry about negative years. They might hate me in the year 10,000, but I don't think there are enough cases where someone needs to specify "200 AD" in a config file to deal w/ the challenges with not fixing the length of the year field.

There is a separate DateTime type.

The following are all valid con4m Date objects:

x := Date("Jan 7, 2007")
x := Date("Jan 18 2027")
x := Date("Jan 2027")
x := Date("Mar 0600")
x := Date("2 Mar 1401")
x := Date("2 Mar")
x := Date("2004-01-06")
x := Date("--03-02")
x := Date("--03")

The following give the same effective results as above, but syntax errors are surfaced at compile time instead of run time:

x := << Jan 7, 2007 >>
x := << Jan 18 2027 >>
x := << Jan 2027 >>
x := << Mar 0600 >>
x := << 2 Mar 1401 >>
x := << 2 Mar >>
x := << 2004-01-06 >>
x := << --03-02 >>
x := << --03 >>
```Time(string) -> Time```

Conversion of a string to a con4m Time specification, which follows ISO standards, including Z. The following are valid Time objects:

x := Time("12:23:01.13131423424214214-12:00")
x := Time("12:23:01.13131423424214214Z")
x := Time("12:23:01+23:00")
x := Time("2:03:01+23:00")
x := Time("02:03+23:00")
x := Time("2:03+23:00")
x := Time("2:03")

The following are identical, except that syntax errors are surfaced before execution begins:

x := << 12:23:01.13131423424214214-12:00 >>
x := << 12:23:01.13131423424214214Z >>
x := << 12:23:01+23:00 >>
x := << 2:03:01+23:00 >>
x := << 02:03+23:00 >>
x := << 2:03+23:00 >>
x := << 2:03 >>
```DateTime(string) -> DateTime```

Conversion of a string to a DateTime type, which follows ISO standards, including Z, though see notes on the separate Date type.

The following are valid DateType objects:

x := DateTime("2004-01-06T12:23:01+23:00")
x := DateTime("--03T2:03")
x := DateTime("2 Jan, 2004 T 12:23:01+23:00")

The following are identical, except that syntax errors are surfaced before execution begins:

x := << 2004-01-06T12:23:01+23:00 >>
x := << --03T2:03 >>
x := << 2 Jan, 2004 T 12:23:01+23:00 >>
```char(int) -> char```

Casts an int to a char, truncating on overflow

```to_usec(Duration) -> int```

Cast a duration object to an integer in seconds

```to_msec(Duration) -> int```

Convert a Duration object into an int representing msec

```to_sec(Duration) -> int```

Convert a Duration object into an int representing seconds, truncating any sub-second information.

```to_type(string) -> typespec```

Turns a string into a typespec object. Errors cause execution to terminate with an error. Generally, this shouldn't be necessary in user configuration files. Even if the user needs to name a type in a config file, the can directly write type literals.

For instance:

x := to_type("list[string]")

is equal to:

x := list[string]
```to_chars(string) -> list[char]```

Turns a string into an array of characters. These are unicode characters, not ASCII characters. Use to_bytes() to turn into bytes.

If the string isn't valid UTF-8, evaluation will stop with an error.

```to_bytes(string) -> list[char]```

Turns a string into an array of 8-bit bytes.

```to_string(list[char]) -> string```

Turn a list of characters into a string object. Will work for both arrays utf8 codepoints and for raw bytes.

Builtins in category:string

SignatureDescription
```contains(string, string) -> bool```

Returns true if the first argument contains the second argument.

```starts_with(string, string) -> bool```

Returns true if the first argument starts with the second argument.

```ends_with(string, string) -> bool```

Returns true if the first argument ends with the second argument.

```find(string, string) -> int```

If the first argument contains the first string anywhere in it, this returns the index of the first match. Otherwise, it returns -1 to indicate no match.

```len(string) -> int```

Returns the length of a string in bytes. This does NOT return the number of characters if there are multi-byte characters. utf8_len() does that.

```slice(string, int) -> string```

Returns a new string that's a substring of the first one, starting at the given index, continuing through to the end of the string. This has Python-like semantics, accepting negative numbers to index from the back.

```slice(string, int, int) -> string```

Returns a new string that's a substring of the first one, starting at the given index, continuing through to the second index (non-inclusive). This has Python-like semantics, accepting negative numbers to index from the back.

```slice(list[`x], int, int) -> list[`x]```

Returns a new list that's derived by copying from the first one, starting at the given index, continuing through to the second index (non-inclusive). This has python-like semantics, accepting negative numbers to index from the back.

```split(string, string) -> list[string]```

Turns a list into an array by splitting the first string based on the second string. The second string will not appear in the output.

```strip(string) -> string```

Returns a copy of the input, with any leading or trailing white space removed.

```pad(string, int) -> string```

Return a copy of the input string that is at least as wide as indicated by the integer parameter. If the input string is not long enough, spaces are added to the end.

```format(string) -> string```

Makes substitutions within a string, based on variables that are in scope. For the input string, anything inside braces {} will be treated as a specifier. You can access attributes that are out of scope by fully dotting from the top-level name. All tags are currently part of the dotted name. You can use both attributes and variables in a specifier. strings, bools, ints and floats are acceptable for specifiers, but lists and dictionaries are not.

There is currently no way to specify things like padding and alignment in a format specifier. If you want to insert an actual { or } character that shouldn't be part of a specifier, quote them by doubling them up (e.g., {{ to get a single left brace).

```base64(string) -> string```

Returns a base64-encoded version of the string, using the traditional Base64 character set.

```base64_web(string) -> string```

Returns a base64-encoded version of the string, using the web-safe Base64 character set.

```debase64(string) -> string```

Decodes a base64 encoded string, accepting either common character set.

```hex(string) -> string```

Hex-encodes a string.

```hex(int) -> string```

Turns an integer into a hex-encoded string.

```dehex(string) -> string```

Takes a hex-encoded string, and returns a string with the hex-decoded bytes.

```sha256(string) -> string```

Computes the SHA-256 hash of a string, returning the result as a hex-encoded string.

```sha512(string) -> string```

Computes the SHA-512 hash of a string, returning the result as a hex-encoded string.

```upper(string) -> string```

Converts any unicode characters to their upper-case representation, where possible, leaving them alone where not.

```lower(string) -> string```

Converts any unicode characters to their lower-case representation, where possible, leaving them alone where not.

```join(list[string], string) -> string```

Creates a single string from a list of string, by adding the second value between each item in the list.

Builtins in category:dict

SignatureDescription
```contains(list[`x], `x) -> bool```

Returns true if the first argument contains the second argument.

```contains(dict[`x, `y], `x) -> bool```

Returns true if the second argument is a set key in the dictionary, false otherwise.

```len(dict[`x, `y]) -> int```

Returns the number of items contained in a dict

```keys(dict[`x, `y]) -> list[`x]```

Returns a list of the keys in a dictionary.

```values(dict[`x, `y]) -> list[`y]```

Returns a list of the values in a dictionary.

```items(dict[`x, `y]) -> list[(`x, `y) -> void]```

Returns a list containing two-tuples representing the keys and values in a dictionary.

```set(dict[`k, `v], `k, `v) -> dict[`k, `v]```

Returns a new dictionary based on the old dictionary, except that the new key/value pair will be set. If the key was set in the old dictionary, the value will be replaced.

NO values in Con4m can be mutated. Everything copies.

```delete(dict[`k, `v], `k) -> dict[`k, `v]```

Returns a new dictionary that is a copy of the input dictionary, except the specified key will not be present, if it existed.

NO values in Con4m can be mutated. Everything copies.

Builtins in category:list

SignatureDescription
```len(list[`x]) -> int```

Returns the number of items in a list.

```set(list[`x], int, `x) -> list[`x]```

This creates a new list, that is a copy of the original list, except that the index specified by the second parameter is replaced with the value in the third parameter.

NO values in Con4m can be mutated. Everything copies.

```delete(list[`x], `x) -> list[`x]```

Returns a new list, based on the one passed in the first parameter, where any instances of the item (the second parameter) are removed. If the item does not appear, a copy of the original list will be returned.

NO values in Con4m can be mutated. Everything copies.

```remove(list[`x], int) -> list[`x]```

This returns a copy of the first parameter, except that the item at the given index in the input will not be in the output. This has Python indexing semantics.

NO values in Con4m can be mutated. Everything copies.

```array_add(list[`x], list[`x]) -> list[`x]```

This creates a new list by concatenating the items in two lists.

Con4m requires all items in a list have a comptable type.

Builtins in category:character

SignatureDescription
```replace(string, string, string) -> string```

Return a copy of the first argument, where any instances of the second argument are replaced with the third argument.

```utf8_len(char) -> int```

Return the number of UTF-8 encoded characters (aka codepoints) in a string.

```is_combining(char) -> bool```

Returns true if a character is a UTF-8 combining character, and false otherwise.

```is_lower(char) -> bool```

Returns true if the given character is a lower case character, false otherwise. This function is unicode aware.

```is_upper(char) -> bool```

Returns true if the given character is an upper case character, false otherwise. This function is unicode aware.

```is_space(char) -> bool```

Returns true if the given character is a valid space character, per the Unicode specification.

```is_alpha(char) -> bool```

Returns true if the given character is considered an alphabet character in the Unicode spec.

```is_num(char) -> bool```

Returns true if the given character is considered an number in the Unicode spec.

```is_alphanum(char) -> bool```

Returns true if the given character is considered an alpha-numeric character in the Unicode spec.

Builtins in category:filesystem

SignatureDescription
```list_dir() -> list[string]```

Returns a list of files in the current working directory.

```list_dir(string) -> list[string]```

Returns a list of files in the specified directory. If the directory is invalid, no error is given; the results will be the same as if the directory were empty.

```read_file(string) -> string```

Returns the contents of the file. On error, this will return the empty string.

```write_file(string, string) -> bool```

Writes, to the file name given in the first argument, the value of the string given in the second argument. Returns true if successful, false otherwise.

```copy_file(string, string) -> bool```

Copies the contents of the file specified by the first argument to the file specified by the second, creating the new file if necessary, overwriting it otherwise. Returns true if successful, false otherwise.

```move_file(string, string) -> bool```

Moves the file specified by the first argument to the location specified by the second, overwriting any file, if present. Returns true if successful, false otherwise.

```rm_file(string) -> bool```

Removes the specified file, if it exists, and the operation is allowed. Returns true if successful.

```join_path(string, string) -> string```

Combines two pieces of a path in a way where you don't have to worry about extra slashes.

```resolve_path(string) -> string```

Turns a possibly relative path into an absolute path. This also expands home directories.

```path_split(string) -> tuple[string, string]```

Separates out the final path component from the rest of the path, i.e., typically used to split out the file name from the remainder of the path.

```find_exe(string, list[string]) -> string```

Locate an executable with the given name in the PATH, adding any extra directories passed in the second argument.

```cwd() -> string```

Returns the current working directory of the process.

```chdir(string) -> bool```

Changes the current working directory of the process. Returns true if successful.

```mkdir(string) -> bool```

Creates a directory, and returns true on success.

```is_dir(string) -> bool```

Returns true if the given file name exists at the time of the call, and is a directory.

```is_file(string) -> bool```

Returns true if the given file name exists at the time of the call, and is a regular file.

```is_link(string) -> bool```

Returns true if the given file name exists at the time of the call, and is a link.

```chmod(string, int) -> bool```

Attempt to set the file permissions; returns true if successful.

```file_len(string) -> int```

Returns the number of bytes in the specified file, or -1 if there is an error (e.g., no file, or not readable).

```to_tmp_file(string, string) -> string```

Writes the string in the first argument to a new temporary file. The second argument specifies an extension; a random value is used in the tmp file name.

This call returns the location that the file was written to.

Builtins in category:system

SignatureDescription
```echo(*`a) -> void```

Output any parameters passed (after automatic conversion to string). A newline is added at the end, but no spaces are added between arguments.

This outputs to stderr, NOT stdout.

echo() is the only function in con4m that:

  • Accepts variable arguments
  • Automatically converts items to strings.
```abort(string) -> void```

Prints the given error message, then stops the entire program immediately (not just the config file execution).

The exit code of the process will be 1.

```env() -> dict[string, string]```

Returns all environment variables set for the process.

```env(string) -> string```

Returns the value of a specific environment variable. If the environment variable isn't set, you will get the empty string (""), same as if the value is explicitly set, but to no value.

To distinguish between the two cases, either call env_exists() or dump all environment variables to a dictionary via env() and then call contains().

```env_exists(string) -> bool```

Returns true if the parameter is a named environment variable in the current environment.

```set_env(string, string) -> bool```

Sets the value of the environment variable passed in the first parameter, to the value from the second parameter. It returns true if successful.

```getpid() -> int```

Return the process ID of the current process

```quote(string) -> string```

Quote a string, so that it can be safely passed as a parameter to any shell (e.g., via run())

```osname() -> string```

Return a string containing the runtime operating system used. Possible values: "macos", "linux", "windows", "netbsd", "freebsd", "openbsd".

```arch() -> string```

Return a string containing the underlying hardware architecture. Supported values: "amd64", "arm64"

The value "amd64" is returned for any x86-64 platform. Other values may be returned on other operating systems, such as i386 on 32-bit X86, but Con4m is not built or tested against other environments.

```program_args() -> list[string]```

Return the arguments passed to the program. This does not include the program name.

```program_path() -> string```

Returns the absolute path of the currently running program.

```program_name() -> string```

Returns the name of the executable program being run, without any path component.

```high() -> int```

Returns the highest possible value storable by an int. The int data type is always a signed 64-bit value, so this will always be: 9223372036854775807

```low() -> int```

Returns the lowest possible value storable by an int. The int data type is always a signed 64-bit value, so this will always be: -9223372036854775808

```rand() -> int```

Return a secure random, uniformly distributed 64-bit number.

```now() -> int```

Return the current Unix time in ms since Jan 1, 1970. Divide by 1000 for seconds.

```container_name() -> string```

Returns the name of the container we're running in, or the empty string if we don't seem to be running in one.

```in_container() -> bool```

Returns true if we can determine that we're running in a container, and false if not.

```copy_object(string, string) -> bool```

Deep-copys a con4m object specified by full path in the first parameter, creating the object named in the second parameter.

Note that the second parameter cannot be in dot notation; the new object will be created in the same scope of the object being copied.

For instance, copy_object("profile.foo", "bar") will create "profile.bar"

This function returns true on success. Reasons it would fail:

  1. The source path doesn't exist.
  2. The source path exists, but is a field, not an object.
  3. The destination already exists.

Note that this function does not enforce any c42 specification itself. So if you copy a singleton object that doesn't comply with the section, nothing will complain until (and if) a validation occurs.

Builtins in category:binary_ops

SignatureDescription
```bitor(int, int) -> int```

Returns the bitwise OR of its parameters.

```bitand(int, int) -> int```

Returns the bitwise AND of its parameters.

```xor(int, int) -> int```

Returns the bitwise XOR of its parameters.

```shl(int, int) -> int```

Shifts the bits of the first argument left by the number of bits indicated by the second argument.

```shr(int, int) -> int```

Shifts the bits of the first argument right by the number of bits indicated by the second argument. Note that this operation is a pure shift; it does NOT maintain the sign bit.

That is, it acts as if the two parameters are unsigned.

```bitnot(int) -> int```

Returns a new integer where every bit from the input is flipped.

Builtins in category:parsing

SignatureDescription
```mime_to_dict(string) -> dict[string, string]```

Takes a string consisting of mime headers, and converts them into a dictionary of key/value pairs.

For instance:

mime_to_dict("Content-Type: text/html\r\nCustom-Header: hi!\r\n")

will return:

{ "Content-Type" : "text/html",
  "Custom-Header" : "hi!"
}

Note that lines that aren't validly formatted are skipped.

Builtins in category:network

SignatureDescription
```url_get(string) -> string```

Retrieve the contents of the given URL, returning a string. If it's a HTTPS URL, the remote host's certificate chain must validate for data to be returned.

If there is an error, the first three digits will be an error code, followed by a space, followed by any returned message. If the error wasn't from a remote HTTP response code, it will be 000.

Requests that take more than 5 seconds will be canceled.

```url_get_pinned(string, string) -> string```

Same as url_get(), except takes a second parameter, which is a path to a pinned certificate.

The certificate will only be checked if it's an HTTPS connection, but the remote connection must be the party associated with the certificate passed, otherwise an error will be returned, instead of data.

```url_post(string, string, dict[string, string]) -> string```

Uses HTTP post to post to a given URL, returning the resulting as a string, if successful. If not, the error code works the same was as for url_get().

The parameters here are:

  1. The URL to which to post
  2. The body to send with the request
  3. The MIME headers to send, as a dictionary. Generally you should at least pass a Content-Type field (e.g., {"Content-Type" : "text/plain"}). Con4m will NOT assume one for you.

Requests that take more than 5 seconds will be canceled.

```external_ip() -> string```

Returns the external IP address for the current machine.

```url_post_pinned(string, string, dict[string, string], string) -> string```

Same as url_post(), but takes a certificate file location in the final parameter, with which HTTPS connections must authenticate against.

Builtins in category:posix

SignatureDescription
```run(string) -> string```

Execute the passed parameter via a shell, returning the output. This function blocks while the subprocess runs.

The exit code is not returned in this version.

Stdout and Stderr are combined in the output.

```system(string) -> tuple[string, int]```

Execute the passed parameter via a shell, returning a tuple containing the output and the return code of the subprocess. This function blocks while the subprocess runs.

Stdout and Stderr are combined in the output.

```getuid() -> int```

Returns the real UID of the underlying logged in user.

```geteuid() -> int```

Returns the effective UID of the underlying logged in user.

```uname() -> list[string]```

Returns a string with common system information, generally should be the same as running uname -a on the commadn line.

```using_tty() -> bool```

Returns true if the current process is attached to a TTY (unix terminal driver). Generally, logged-in users can be expected to have a TTY (though some automation tools can have a TTY with no user).

Still, it's common to act as if a user is present when there is a TTY. For instance, it's common to default to showing colors when attached to a TTY, but to default to no-color otherwise.

```tty_name() -> string```

Returns the name of the current tty, if any.

Builtins in category:chalk

SignatureDescription
```version() -> string```

The current version of the chalk program.

```subscribe(string, string) -> bool```

For the topic name given in the first parameter, subscribes the sink configuration named in the second parameter. The sink configuration object must already be defined at the time of the call to subscribe()

```unsubscribe(string, string) -> bool```

For the topic name given in the first parameter, unsubscribes the sink configuration named in the second parameter, if subscribed.

```error(string) -> void```

Immediately publishes a diagnostic message at log-level 'error'. Whether this gets delivered or not depends on the configuration. Generally, errors will go both to stderr, and be put in any published report.

```warn(string) -> void```

Immediately publishes a diagnostic message at log-level 'warn'. Whether this gets delivered or not depends on the configuration. Generally, warnings go to stderr, unless wrapping the docker command, but do not get published to reports.

```info(string) -> void```

Immediately publishes a diagnostic message at log-level 'info'. Whether this gets delivered or not depends on the configuration, but may be off by default.

```trace(string) -> void```

Immediately publishes a diagnostic message at log-level 'trace' (aka verbose). Generally, these can get very noisy, and are intended more for testing, debugging, etc.

```command_argv() -> list[string]```

Returns the arguments being passed to the command, such as the path parameters. This is not the same as the underlying process's argv; it represents the arguments getting passed to the underlying chalk command.

```command_name() -> string```

Returns the name of the chalk command being run (not the underlying executable name).