From 8c97575c8fb93671e4ac51fa8232a1a2cfb7ad22 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 17 Apr 2025 14:57:09 -0400 Subject: Add getenv()/setenv() --- docs/README.md | 133 +------------------------------------ docs/builtins.md | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/environment.c | 2 + src/stdlib/stdlib.c | 11 ++++ src/stdlib/stdlib.h | 2 + 5 files changed, 200 insertions(+), 132 deletions(-) create mode 100644 docs/builtins.md diff --git a/docs/README.md b/docs/README.md index e8cd4a2f..017e344b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,6 +6,7 @@ This is an overview of the documentation on Tomo. A few topics that are documented: +- [Built-In Functions](builtins.md) - [Compilation Pipeline](compilation.md) - [Functions](functions.md) - [Libraries/Modules](libraries.md) @@ -31,135 +32,3 @@ Information about Tomo's built-in types can be found here: - [Tables](tables.md) - [Text](text.md) - [Text Pattern Matching](patterns.md) - -## Built-in Functions - -### `ask` -Gets a line of user input text with a prompt. - -```tomo -func ask(prompt:Text, bold:Bool = yes, force_tty:Bool = yes -> Text?) -``` - -- `prompt`: The text to print as a prompt before getting the input. -- `bold`: Whether or not to print make the prompt appear bold on a console - using the ANSI escape sequence `\x1b[1m`. -- `force_tty`: When a program is receiving input from a pipe or writing its - output to a pipe, this flag (which is enabled by default) forces the program - to write the prompt to `/dev/tty` and read the input from `/dev/tty`, which - circumvents the pipe. This means that `foo | ./tomo your-program | baz` will - still show a visible prompt and read user input, despite the pipes. Setting - this flag to `no` will mean that the prompt is written to `stdout` and input - is read from `stdin`, even if those are pipes. - -**Returns:** -A line of user input text without a trailing newline, or empty text if -something went wrong (e.g. the user hit `Ctrl-D`). - -**Example:** -```tomo ->> ask("What's your name? ") -= "Arthur Dent" -``` - ---- - -### `exit` -Exits the program with a given status and optionally prints a message. - -```tomo -func ask(message:Text? = !Text, status:Int32 = 1[32] -> Void) -``` - -- `message`: If nonempty, this message will be printed (with a newline) before - exiting. -- `status`: The status code that the program with exit with (default: 1, which - is a failure status). - -**Returns:** -This function never returns. - -**Example:** -```tomo -exit(status=1, "Goodbye forever!") -``` - ---- - -### `print` -Prints a message to the console (alias for [`say`](#say)). - -```tomo -func print(text:Text, newline:Bool = yes -> Void) -``` - -- `text`: The text to print. -- `newline`: Whether or not to print a newline after the text. - -**Returns:** -Nothing. - -**Example:** -```tomo -print("Hello ", newline=no) -print("world!") -``` - ---- - -### `say` -Prints a message to the console. - -```tomo -func say(text:Text, newline:Bool = yes -> Void) -``` - -- `text`: The text to print. -- `newline`: Whether or not to print a newline after the text. - -**Returns:** -Nothing. - -**Example:** -```tomo -say("Hello ", newline=no) -say("world!") -``` - ---- - -### `sleep` -Pause execution for a given number of seconds. - -```tomo -func sleep(seconds: Num -> Void) -``` - -- `seconds`: How many seconds to sleep for. - -**Returns:** -Nothing. - -**Example:** -```tomo -sleep(1.5) -``` - ---- - -### `fail` -Prints a message to the console, aborts the program, and prints a stack trace. - -```tomo -func fail(message:Text -> Abort) -``` - -- `message`: The error message to print. - -**Returns:** -Nothing, aborts the program. - -**Example:** -```tomo -fail("Oh no!") -``` diff --git a/docs/builtins.md b/docs/builtins.md new file mode 100644 index 00000000..f1d8069f --- /dev/null +++ b/docs/builtins.md @@ -0,0 +1,184 @@ +# Built-in Functions + +These are the top-level functions built into Tomo. + +- [`func ask(prompt:Text, bold:Bool = yes, force_tty:Bool = yes -> Text?)`](#ask) +- [`func ask(message:Text? = !Text, status:Int32 = 1[32] -> Void)`](#exit) +- [`func getenv(name:Text -> Text?)`](#getenv) +- [`func print(text:Text, newline:Bool = yes -> Void)`](#print) +- [`func say(text:Text, newline:Bool = yes -> Void)`](#say) +- [`func setenv(name:Text, value:Text)`](#setenv) +- [`func sleep(seconds: Num -> Void)`](#sleep) +- [`func fail(message:Text -> Abort)`](#fail) + +--- + +### `ask` +Gets a line of user input text with a prompt. + +```tomo +func ask(prompt:Text, bold:Bool = yes, force_tty:Bool = yes -> Text?) +``` + +- `prompt`: The text to print as a prompt before getting the input. +- `bold`: Whether or not to print make the prompt appear bold on a console + using the ANSI escape sequence `\x1b[1m`. +- `force_tty`: When a program is receiving input from a pipe or writing its + output to a pipe, this flag (which is enabled by default) forces the program + to write the prompt to `/dev/tty` and read the input from `/dev/tty`, which + circumvents the pipe. This means that `foo | ./tomo your-program | baz` will + still show a visible prompt and read user input, despite the pipes. Setting + this flag to `no` will mean that the prompt is written to `stdout` and input + is read from `stdin`, even if those are pipes. + +**Returns:** +A line of user input text without a trailing newline, or empty text if +something went wrong (e.g. the user hit `Ctrl-D`). + +**Example:** +```tomo +>> ask("What's your name? ") += "Arthur Dent" +``` + +--- + +### `exit` +Exits the program with a given status and optionally prints a message. + +```tomo +func exit(message:Text? = !Text, status:Int32 = 1[32] -> Void) +``` + +- `message`: If nonempty, this message will be printed (with a newline) before + exiting. +- `status`: The status code that the program with exit with (default: 1, which + is a failure status). + +**Returns:** +This function never returns. + +**Example:** +```tomo +exit(status=1, "Goodbye forever!") +``` + +--- + +### `getenv` +Gets an environment variable. + +```tomo +func getenv(name:Text -> Text?) +``` + +- `name`: The name of the environment variable to get. + +**Returns:** +If set, the environment variable's value, otherwise, `none`. + +**Example:** +```tomo +>> getenv("TERM") += "xterm-256color"? +``` + +--- + +### `print` +Prints a message to the console (alias for [`say`](#say)). + +```tomo +func print(text:Text, newline:Bool = yes -> Void) +``` + +- `text`: The text to print. +- `newline`: Whether or not to print a newline after the text. + +**Returns:** +Nothing. + +**Example:** +```tomo +print("Hello ", newline=no) +print("world!") +``` + +--- + +### `say` +Prints a message to the console. + +```tomo +func say(text:Text, newline:Bool = yes -> Void) +``` + +- `text`: The text to print. +- `newline`: Whether or not to print a newline after the text. + +**Returns:** +Nothing. + +**Example:** +```tomo +say("Hello ", newline=no) +say("world!") +``` + +--- + +### `setenv` +Sets an environment variable. + +```tomo +func getenv(name:Text, value:Text -> Void) +``` + +- `name`: The name of the environment variable to set. +- `value`: The new value of the environment variable. + +**Returns:** +Nothing. + +**Example:** +```tomo +setenv("FOOBAR", "xyz") +``` + +--- + +### `sleep` +Pause execution for a given number of seconds. + +```tomo +func sleep(seconds: Num -> Void) +``` + +- `seconds`: How many seconds to sleep for. + +**Returns:** +Nothing. + +**Example:** +```tomo +sleep(1.5) +``` + +--- + +### `fail` +Prints a message to the console, aborts the program, and prints a stack trace. + +```tomo +func fail(message:Text -> Abort) +``` + +- `message`: The error message to print. + +**Returns:** +Nothing, aborts the program. + +**Example:** +```tomo +fail("Oh no!") +``` diff --git a/src/environment.c b/src/environment.c index bf012286..35c76fe5 100644 --- a/src/environment.c +++ b/src/environment.c @@ -518,6 +518,8 @@ env_t *global_env(bool source_mapping) {"USE_COLOR", "USE_COLOR", "Bool"}, {"say", "say", "func(text:Text, newline=yes)"}, {"print", "say", "func(text:Text, newline=yes)"}, + {"getenv", "getenv_text", "func(name:Text -> Text?)"}, + {"setenv", "setenv_text", "func(name:Text, value:Text -> Text?)"}, {"ask", "ask", "func(prompt:Text, bold=yes, force_tty=yes -> Text?)"}, {"exit", "tomo_exit", "func(message:Text?=none, code=Int32(1) -> Abort)"}, {"fail", "fail_text", "func(message:Text -> Abort)"}, diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c index 88553f54..a7eeb745 100644 --- a/src/stdlib/stdlib.c +++ b/src/stdlib/stdlib.c @@ -634,4 +634,15 @@ public void sleep_num(double seconds) nanosleep(&ts, NULL); } +public OptionalText_t getenv_text(Text_t name) +{ + const char *val = getenv(Text$as_c_string(name)); + return val ? Text$from_str(val) : NONE_TEXT; +} + +public void setenv_text(Text_t name, Text_t value) +{ + setenv(Text$as_c_string(name), Text$as_c_string(value), 1); +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h index a452a04b..c4bf83e0 100644 --- a/src/stdlib/stdlib.h +++ b/src/stdlib/stdlib.h @@ -93,5 +93,7 @@ _Noreturn void tomo_exit(Text_t text, int32_t status); Closure_t spawn(Closure_t fn); bool pop_flag(char **argv, int *i, const char *flag, Text_t *result); void sleep_num(double seconds); +OptionalText_t getenv_text(Text_t name); +void setenv_text(Text_t name, Text_t value); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 -- cgit v1.2.3