| #include "interpreter.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <stdint.h> |
|
|
| |
| static int sync_requested = 0; |
|
|
| void interpreter_request_sync(void) { |
| sync_requested = 1; |
| } |
|
|
| |
| static Command commands[] = { |
| { "boot", boot_disk }, |
| { "diag", run_diagnostic }, |
| { "status", get_status }, |
| { "replan", cmd_replan }, |
| { NULL, NULL } |
| }; |
|
|
| |
| |
| |
| typedef struct { |
| char *str; |
| size_t len; |
| size_t cap; |
| } string_builder; |
|
|
| static void sb_init(string_builder *sb) { |
| sb->str = NULL; |
| sb->len = 0; |
| sb->cap = 0; |
| } |
|
|
| static int sb_append_char(string_builder *sb, char c) { |
| if (sb->len + 2 > sb->cap) { |
| size_t new_cap = sb->cap ? sb->cap * 2 : 32; |
| char *new_str = realloc(sb->str, new_cap); |
| if (!new_str) return -1; |
| sb->str = new_str; |
| sb->cap = new_cap; |
| } |
| sb->str[sb->len++] = c; |
| sb->str[sb->len] = '\0'; |
| return 0; |
| } |
|
|
| static int sb_append_str(string_builder *sb, const char *s) { |
| while (*s) { |
| if (sb_append_char(sb, *s++) < 0) return -1; |
| } |
| return 0; |
| } |
|
|
| static void sb_free(string_builder *sb) { |
| free(sb->str); |
| sb->str = NULL; |
| sb->len = sb->cap = 0; |
| } |
|
|
| |
| |
| |
| |
| |
| static char** split_quoted(const char* input, int* argc) { |
| char **argv = NULL; |
| int capacity = 0; |
| *argc = 0; |
| const char *p = input; |
|
|
| while (*p) { |
| while (isspace(*p)) p++; |
| if (!*p) break; |
|
|
| if (*argc >= capacity) { |
| capacity = capacity ? capacity * 2 : 8; |
| char **new_argv = realloc(argv, capacity * sizeof(char*)); |
| if (!new_argv) goto error; |
| argv = new_argv; |
| } |
|
|
| string_builder sb; |
| sb_init(&sb); |
| char quote = 0; |
|
|
| if (*p == '"' || *p == '\'') { |
| quote = *p++; |
| } |
|
|
| int escaped = 0; |
| while (*p) { |
| if (escaped) { |
| if (sb_append_char(&sb, *p++) < 0) goto error; |
| escaped = 0; |
| } else if (*p == '\\') { |
| escaped = 1; |
| p++; |
| } else if (quote && *p == quote) { |
| p++; |
| break; |
| } else if (!quote && isspace(*p)) { |
| break; |
| } else { |
| if (sb_append_char(&sb, *p++) < 0) goto error; |
| } |
| } |
|
|
| if (quote && !*p) { |
| sb_free(&sb); |
| goto error; |
| } |
|
|
| argv[(*argc)++] = sb.str; |
| } |
|
|
| return argv; |
|
|
| error: |
| for (int i = 0; i < *argc; i++) free(argv[i]); |
| free(argv); |
| return NULL; |
| } |
|
|
| |
| |
| |
| char* interpret_command(const char* input) { |
| if (!input || *input == '\0') |
| return strdup("No input provided."); |
|
|
| int argc = 0; |
| char **argv = split_quoted(input, &argc); |
| if (!argv) return strdup("Memory error or unterminated quote."); |
|
|
| if (argc == 0) { |
| free(argv); |
| return strdup(""); |
| } |
|
|
| char *result = NULL; |
| for (Command *c = commands; c->name; c++) { |
| if (strcmp(c->name, argv[0]) == 0) { |
| |
| string_builder sb; |
| sb_init(&sb); |
| for (int i = 1; i < argc; i++) { |
| if (i > 1) { |
| if (sb_append_char(&sb, ' ') < 0) { |
| sb_free(&sb); |
| for (int j = 0; j < argc; j++) free(argv[j]); |
| free(argv); |
| return strdup("Memory error"); |
| } |
| } |
| if (sb_append_str(&sb, argv[i]) < 0) { |
| sb_free(&sb); |
| for (int j = 0; j < argc; j++) free(argv[j]); |
| free(argv); |
| return strdup("Memory error"); |
| } |
| } |
| result = c->fn(sb.str ? sb.str : ""); |
| sb_free(&sb); |
| break; |
| } |
| } |
|
|
| for (int i = 0; i < argc; i++) free(argv[i]); |
| free(argv); |
|
|
| if (!result) result = strdup("Unknown command."); |
| return result; |
| } |
|
|
| |
| |
| |
| char* boot_disk(const char* args) { |
| size_t len = strlen("Booting disk with args: ") + strlen(args) + 1; |
| char *buf = malloc(len); |
| if (!buf) return strdup("Memory error"); |
| snprintf(buf, len, "Booting disk with args: %s", args); |
| return buf; |
| } |
|
|
| char* run_diagnostic(const char* args) { |
| (void)args; |
| return strdup("Running diagnostic..."); |
| } |
|
|
| char* get_status(const char* args) { |
| (void)args; |
| return strdup("Status: All systems nominal."); |
| } |
|
|
| |
| |
| |
| |
| char* cmd_replan(const char* args) { |
| (void)args; |
| |
| interpreter_request_sync(); |
| |
| char *marker = malloc(strlen(INTERPRETER_MARKER_REPLAN) + 1); |
| if (!marker) return strdup("Memory error"); |
| strcpy(marker, INTERPRETER_MARKER_REPLAN); |
| return marker; |
| } |
|
|