aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtins/functions.c42
-rw-r--r--builtins/functions.h1
-rw-r--r--environment.c13
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)}},
};