diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-09-04 14:55:00 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-09-04 14:55:00 -0400 |
| commit | 05bc754679ca5b136b2f3a70b791db71e9260234 (patch) | |
| tree | 359ed3458c2f116e122e9b7b1f1a215d4f40e4a7 | |
| parent | 570c4c63caa6ea4341339b3925a0d823c4ff8d15 (diff) | |
Add ask() as a way to get user input
| -rw-r--r-- | builtins/functions.c | 42 | ||||
| -rw-r--r-- | builtins/functions.h | 1 | ||||
| -rw-r--r-- | environment.c | 13 |
3 files changed, 54 insertions, 2 deletions
diff --git a/builtins/functions.c b/builtins/functions.c index 27bb06f8..b69f81d9 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -246,6 +246,48 @@ public void say(Text_t text, bool newline) fputc('\n', stdout); } +public Text_t ask(Text_t prompt, bool bold, bool force_tty) +{ + Text_t ret = Text(""); + FILE *out = stdout; + FILE *in = stdin; + + if (force_tty && !isatty(STDOUT_FILENO)) { + out = fopen("/dev/tty", "w"); + if (!out) goto cleanup; + } + + if (bold) fputs("\x1b[1m", out); + Text$print(out, prompt); + if (bold) fputs("\x1b[m", out); + fflush(out); + + if (force_tty && !isatty(STDIN_FILENO)) { + in = fopen("/dev/tty", "r"); + if (!in) goto cleanup; + } + + char *line = NULL; + size_t bufsize = 0; + ssize_t length = getline(&line, &bufsize, in); + if (length == -1) goto cleanup; + + if (length > 0 && line[length-1] == '\n') { + line[length-1] = '\0'; + --length; + } + + char *gc_input = GC_MALLOC_ATOMIC(length + 1); + memcpy(gc_input, line, length + 1); + + ret = Text$from_strn(gc_input, length); + + cleanup: + if (out && out != stdout) fclose(out); + if (in && in != stdin) fclose(in); + return ret; +} + public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result) { if (argv[*i][0] != '-' || argv[*i][1] != '-') { diff --git a/builtins/functions.h b/builtins/functions.h index 263255f4..c9db6ea8 100644 --- a/builtins/functions.h +++ b/builtins/functions.h @@ -22,6 +22,7 @@ void end_test(const void *expr, const TypeInfo *type, const char *expected, cons start_test(__SOURCE_FILE__, start, end); \ end_test((__typeof__(expr)[1]){expr}, typeinfo, expected, __SOURCE_FILE__, start, end); } void say(Text_t text, bool newline); +Text_t ask(Text_t prompt, bool bold, bool force_tty); uint64_t generic_hash(const void *obj, const TypeInfo *type); int32_t generic_compare(const void *x, const void *y, const TypeInfo *type); diff --git a/environment.c b/environment.c index eb456030..32e3f7f6 100644 --- a/environment.c +++ b/environment.c @@ -30,8 +30,17 @@ env_t *new_compilation_unit(CORD *libname) const char *name; binding_t binding; } global_vars[] = { - {"say", {.code="say", .type=Type(FunctionType, .args=new(arg_t, .name="text", .type=TEXT_TYPE, - .next=new(arg_t, .name="newline", .type=Type(BoolType), .default_val=FakeAST(Bool, true))), .ret=Type(VoidType))}}, + {"say", {.code="say", .type=Type( + FunctionType, .args=new(arg_t, .name="text", .type=TEXT_TYPE, + .next=new(arg_t, .name="newline", .type=Type(BoolType), .default_val=FakeAST(Bool, true))), + .ret=Type(VoidType))}}, + {"ask", {.code="ask", .type=Type( + FunctionType, .args=new(arg_t, .name="prompt", .type=TEXT_TYPE, + .next=new(arg_t, .name="bold", .type=Type(BoolType), + .default_val=FakeAST(Bool, true), + .next=new(arg_t, .name="force_tty", .type=Type(BoolType), + .default_val=FakeAST(Bool, true)))), + .ret=TEXT_TYPE)}}, {"fail", {.code="fail", .type=Type(FunctionType, .args=new(arg_t, .name="message", .type=Type(CStringType)), .ret=Type(AbortType))}}, {"USE_COLOR", {.code="USE_COLOR", .type=Type(BoolType)}}, }; |
