aboutsummaryrefslogtreecommitdiff
path: root/stdlib/shell.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-03-17 19:29:28 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-03-17 19:29:28 -0400
commit0bba31912665a82f848642e6b4247071a3ee177a (patch)
treeae5c3ac7501a0841c9a858d6559a0dfb7db69035 /stdlib/shell.c
parent94993c5f113b27083e586c7620eb896fe750c6d1 (diff)
Big overhaul:
- Clean up environment code using type strings instead of manually defining types - Add Commands module - Move Shell lang into an example module that uses Commands module - Fix some bugs with chained library dependencies
Diffstat (limited to 'stdlib/shell.c')
-rw-r--r--stdlib/shell.c157
1 files changed, 0 insertions, 157 deletions
diff --git a/stdlib/shell.c b/stdlib/shell.c
deleted file mode 100644
index 30dc7c6f..00000000
--- a/stdlib/shell.c
+++ /dev/null
@@ -1,157 +0,0 @@
-// A lang for Shell Command Language
-#include <errno.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <unistr.h>
-
-#include "arrays.h"
-#include "integers.h"
-#include "paths.h"
-#include "patterns.h"
-#include "shell.h"
-#include "text.h"
-#include "types.h"
-#include "util.h"
-
-public Shell_t Shell$escape_text(Text_t text)
-{
- return Texts(Text("'"), Text$replace(text, Text("'"), Text("'\"'\"'"), Text(""), false), Text("'"));
-}
-
-public Shell_t Shell$escape_path(Path_t path)
-{
- return Shell$escape_text(Path$as_text(&path, false, &Path$info));
-}
-
-public Shell_t Shell$escape_text_array(Array_t texts)
-{
- Array_t all_escaped = {};
- for (int64_t i = 0; i < texts.length; i++) {
- Text_t raw = *(Text_t*)(texts.data + i*texts.stride);
- Text_t escaped = Shell$escape_text(raw);
- Array$insert(&all_escaped, &escaped, I(0), sizeof(Text_t));
- }
- return Text$join(Text(" "), all_escaped);
-}
-
-public Shell_t Shell$escape_path_array(Array_t paths)
-{
- Array_t all_escaped = {};
- for (int64_t i = 0; i < paths.length; i++) {
- Path_t path = *(Path_t*)(paths.data + i*paths.stride);
- Text_t escaped = Shell$escape_path(path);
- Array$insert(&all_escaped, &escaped, I(0), sizeof(Text_t));
- }
- return Text$join(Text(" "), all_escaped);
-}
-
-public OptionalArray_t Shell$run_bytes(Shell_t command)
-{
- const char *cmd_str = Text$as_c_string(command);
- FILE *prog = popen(cmd_str, "r");
- if (!prog)
- return NONE_ARRAY;
-
- size_t capacity = 256, len = 0;
- char *content = GC_MALLOC_ATOMIC(capacity);
- char chunk[256];
- size_t just_read;
- do {
- just_read = fread(chunk, 1, sizeof(chunk), prog);
- if (just_read == 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- break;
- }
-
- if (len + (size_t)just_read >= capacity)
- content = GC_REALLOC(content, (capacity *= 2));
-
- memcpy(content + len, chunk, (size_t)just_read);
- len += (size_t)just_read;
- } while (just_read == sizeof(chunk));
-
- int status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- return NONE_ARRAY;
-
- return (Array_t){.data=content, .atomic=1, .stride=1, .length=len};
-}
-
-public OptionalText_t Shell$run(Shell_t command)
-{
- Array_t bytes = Shell$run_bytes(command);
- if (bytes.length < 0)
- return NONE_TEXT;
-
- if (bytes.length > 0 && *(char*)(bytes.data + (bytes.length-1)*bytes.stride) == '\n') {
- --bytes.length;
- if (bytes.length > 0 && *(char*)(bytes.data + (bytes.length-1)*bytes.stride) == '\r')
- --bytes.length;
- }
- return Text$from_bytes(bytes);
-}
-
-public OptionalInt32_t Shell$execute(Shell_t command)
-{
- const char *cmd_str = Text$as_c_string(command);
- int status = system(cmd_str);
- if (WIFEXITED(status))
- return (OptionalInt32_t){.i=WEXITSTATUS(status)};
- else
- return (OptionalInt32_t){.is_none=true};
-}
-
-static void _line_reader_cleanup(FILE **f)
-{
- if (f && *f) {
- pclose(*f);
- *f = NULL;
- }
-}
-
-static Text_t _next_line(FILE **f)
-{
- if (!f || !*f) return NONE_TEXT;
-
- char *line = NULL;
- size_t size = 0;
- ssize_t len = getline(&line, &size, *f);
- if (len <= 0) {
- _line_reader_cleanup(f);
- return NONE_TEXT;
- }
-
- while (len > 0 && (line[len-1] == '\r' || line[len-1] == '\n'))
- --len;
-
- if (u8_check((uint8_t*)line, (size_t)len) != NULL)
- fail("Invalid UTF8!");
-
- Text_t line_text = Text$format("%.*s", len, line);
- free(line);
- return line_text;
-}
-
-public OptionalClosure_t Shell$by_line(Shell_t command)
-{
- const char *cmd_str = Text$as_c_string(command);
- FILE *prog = popen(cmd_str, "r");
- if (!prog)
- return NONE_CLOSURE;
-
- FILE **wrapper = GC_MALLOC(sizeof(FILE*));
- *wrapper = prog;
- GC_register_finalizer(wrapper, (void*)_line_reader_cleanup, NULL, NULL, NULL);
- return (Closure_t){.fn=(void*)_next_line, .userdata=wrapper};
-}
-
-public const TypeInfo_t Shell$info = {
- .size=sizeof(Shell_t),
- .align=__alignof__(Shell_t),
- .tag=TextInfo,
- .TextInfo={.lang="Shell"},
- .metamethods=Text$metamethods,
-};
-
-// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0