about summary refs log tree commit diff
path: root/boot/catboot.c
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-07-04 18:58:48 +0200
committerMel <mel@rnrd.eu>2025-07-04 18:58:48 +0200
commit7817842632f27a8b894de724ecc1df590142455f (patch)
tree6331b6752d93854c91fb0cc0b7b44e1615f5349b /boot/catboot.c
parent8f2e0f0202317cc27371d2833eb93b64230ac0e8 (diff)
downloadcatskill-7817842632f27a8b894de724ecc1df590142455f.tar.zst
catskill-7817842632f27a8b894de724ecc1df590142455f.zip
Argument parser for catboot tool, different command execution
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/catboot.c')
-rw-r--r--boot/catboot.c185
1 files changed, 168 insertions, 17 deletions
diff --git a/boot/catboot.c b/boot/catboot.c
index a62dc47..e2e5315 100644
--- a/boot/catboot.c
+++ b/boot/catboot.c
@@ -26,7 +26,9 @@
 
 #include "catboot.h"
 
-const ascii*
+#define VERSION "0.0.0"
+
+struct String
 read_file(const ascii* path)
 {
     struct stat stat_info;
@@ -42,33 +44,59 @@ read_file(const ascii* path)
     const unknown* file_data =
         mmap(nil, stat_info.st_size, mmap_prot, mmap_flags, file_descriptor, 0);
 
-    return file_data;
+    return string_from_static_c_string(file_data);
 }
 
-int32
-main(const int32 argc, const ascii* argv[])
+void
+usage(void)
 {
-    if (argc != 2) {
-        printf("usage: catboot <filename>\n");
-        return EXIT_FAILURE;
-    }
-    const ascii* file_path = argv[1];
+    fprintf(
+        stderr,
+        "usage:\n"
+        "    catboot <filename>\n"
+        "    catboot --test-lex <filename>\n"
+        "    catboot --test-parse <filename>\n"
+        "\n"
+        "options:\n"
+        "        --test-lex <file>\t output token stream for file\n"
+        "        --test-parse <file>\t output abstract syntax tree for file in s-expr format\n"
+        "    -?, --help\t\t\t print this help message\n"
+        "    -v, --version\t\t print current version\n");
+}
 
-    const ascii* source_buffer = read_file(file_path);
-    struct String source = string_from_static_c_string(source_buffer);
+void
+version(void)
+{
+    fprintf(
+        stderr,
+        "catboot (catskill), version " VERSION "\n"
+        "\n"
+        "This program's source code is subject to the terms of the Mozilla Public\n"
+        "License, v. 2.0. If a copy of the MPL was not distributed with this\n"
+        "file, You can obtain one at https://mozilla.org/MPL/2.0/.\n"
+        "\n"
+        "Copyright (c) 2025, Mel G. <mel@rnrd.eu>\n");
+}
 
+integer
+debug_lex_pass(struct String source)
+{
     struct Lexer lexer;
     lexer_new(&lexer, source);
 
     struct Token token;
-    printf("tokens: ");
     do {
         token = lexer_next(&lexer);
         printf("%s ", token_kind_to_string(token.kind));
     } while (token.kind != TOKEN_END_OF_FILE);
-    printf("\n");
 
-    // reset lexer
+    return 0;
+}
+
+integer
+debug_parse_pass(struct String source)
+{
+    struct Lexer lexer;
     lexer_new(&lexer, source);
 
     struct Parser parser;
@@ -77,11 +105,134 @@ main(const int32 argc, const ascii* argv[])
     struct Parser_Error parser_error = parser_error_none();
     struct Tree tree = parser_do_your_thing(&parser, &parser_error);
     if (!parser_error_is_none(&parser_error)) {
-        printf("parser error: %s\n", parser_error_to_string(&parser_error));
-        return EXIT_FAILURE;
+        fprintf(stderr, "parser error: %s\n", parser_error_to_string(&parser_error));
+        return 1;
     }
 
     tree_printer(&tree);
 
-    return EXIT_SUCCESS;
+    return 0;
+}
+
+enum Command_Result
+{
+    COMMAND_OK,
+    COMMAND_FAIL,
+};
+
+struct Command_Arguments
+{
+    const ascii* input;
+};
+
+enum Command_Result
+version_command(struct Command_Arguments* arguments)
+{
+    version();
+    return COMMAND_OK;
+}
+
+enum Command_Result
+help_command(struct Command_Arguments* arguments)
+{
+    usage();
+    return COMMAND_OK;
+}
+
+enum Command_Result
+test_lex_command(struct Command_Arguments* arguments)
+{
+    struct String source = read_file(arguments->input);
+
+    // TODO: lexer errors
+    debug_lex_pass(source);
+
+    return COMMAND_OK;
+}
+
+enum Command_Result
+test_parse_command(struct Command_Arguments* arguments)
+{
+    struct String source = read_file(arguments->input);
+
+    if (debug_parse_pass(source)) return COMMAND_FAIL;
+
+    return COMMAND_OK;
+}
+
+enum Command_Result
+default_command(struct Command_Arguments* arguments)
+{
+    struct String source = read_file(arguments->input);
+
+    debug_lex_pass(source);
+    printf("\n");
+    if (debug_parse_pass(source)) return COMMAND_FAIL;
+    printf("\n");
+
+    return COMMAND_OK;
+}
+
+typedef enum Command_Result (*Command_Function)(struct Command_Arguments*);
+
+struct Command_Definition
+{
+    bool is_default;
+    const ascii* name;
+    const ascii short_name;
+    Command_Function function;
+};
+
+struct Command_Definition command_definitions[] = {
+    { .name = "test-lex", .function = test_lex_command },
+    { .name = "test-parse", .function = test_parse_command },
+    { .name = "version", .short_name = 'v', .function = version_command },
+    { .name = "help", .short_name = '?', .function = help_command },
+
+    { .is_default = true, .function = default_command },
+};
+
+int32
+main(const int32 argc, ascii* argv[])
+{
+    if (argc < 2) {
+        usage();
+        return EXIT_FAILURE;
+    }
+
+    bool have_command = false;
+    ascii *command_name = nil, short_command_name = '\0', *input = nil;
+    for (uint a = 1; a < argc; ++a) {
+        ascii* arg = argv[a];
+
+        if (arg[0] == '-') {
+            check(!have_command, "multiple commands given");
+            if (arg[1] == '-') {
+                check(!command_name, "multiple full-name commands given");
+                command_name = &arg[2];
+            } else {
+                check(!short_command_name, "multiple short-name commands given");
+                short_command_name = arg[1];
+            }
+            have_command = true;
+        } else {
+            check(!input, "multiple inputs given");
+            input = arg;
+        }
+    }
+
+    struct Command_Arguments arguments = { .input = input };
+    for (uint d = 0; d < ARRAY_SIZE(command_definitions); ++d) {
+        struct Command_Definition* definition = &command_definitions[d];
+
+        if (definition->is_default || (command_name && strcmp(definition->name, command_name) == 0)
+            || (short_command_name && definition->short_name == short_command_name)) {
+            switch (definition->function(&arguments)) {
+            case COMMAND_OK:
+                return EXIT_SUCCESS;
+            case COMMAND_FAIL:
+                return EXIT_FAILURE;
+            }
+        }
+    }
 }