diff --git a/code/logic/fossil/io/parser.h b/code/logic/fossil/io/parser.h index c10baf3..d67fb14 100644 --- a/code/logic/fossil/io/parser.h +++ b/code/logic/fossil/io/parser.h @@ -22,40 +22,86 @@ extern "C" { // Types of command argument typedef enum { - FOSSIL_IO_PARSER_BOOL, // Boolean (enable/disable) - FOSSIL_IO_PARSER_STRING, // String argument - FOSSIL_IO_PARSER_INT, // Integer argument - FOSSIL_IO_PARSER_FLOAT, // Floating-point argument - FOSSIL_IO_PARSER_DATE, // Date argument - FOSSIL_IO_PARSER_ARRAY, // Array of values - FOSSIL_IO_PARSER_FEATURE, // Feature flag - FOSSIL_IO_PARSER_INVALID // Invalid argument type + // Boolean / Flag Types + FOSSIL_IO_PARSER_BOOL, // Boolean (enable/disable) + FOSSIL_IO_PARSER_FLAG, // Simple flag (on/off, no value) + FOSSIL_IO_PARSER_TOGGLE, // Explicit enable/disable toggle + + // String Types + FOSSIL_IO_PARSER_STRING, // Generic string + FOSSIL_IO_PARSER_FILE, // File path + FOSSIL_IO_PARSER_DIR, // Directory path + FOSSIL_IO_PARSER_REGEX, // Regular expression + FOSSIL_IO_PARSER_ENUM, // Strict set of options + FOSSIL_IO_PARSER_JSON, // JSON string + FOSSIL_IO_PARSER_BASE64, // Base64-encoded string + FOSSIL_IO_PARSER_URL, // URL string + FOSSIL_IO_PARSER_IP, // IPv4/IPv6 + + // Numeric Types + FOSSIL_IO_PARSER_INT, // Signed integer + FOSSIL_IO_PARSER_UINT, // Unsigned integer + FOSSIL_IO_PARSER_HEX, // Hexadecimal integer (0x prefix) + FOSSIL_IO_PARSER_OCT, // Octal integer (0 prefix) + FOSSIL_IO_PARSER_BIN, // Binary integer (0b prefix) + FOSSIL_IO_PARSER_FLOAT, // Floating-point number + FOSSIL_IO_PARSER_DOUBLE, // Double precision floating-point + FOSSIL_IO_PARSER_SIZE, // Size values (e.g., 10K, 2M) + FOSSIL_IO_PARSER_PERCENT, // Percentage (0-100%) + + // Time / Date Types + FOSSIL_IO_PARSER_DATE, // Date (YYYY-MM-DD) + FOSSIL_IO_PARSER_TIMESTAMP, // Timestamp (YYYY-MM-DD HH:MM:SS) + FOSSIL_IO_PARSER_DURATION, // Duration (e.g., 1h30m, 45s) + + // Collection Types + FOSSIL_IO_PARSER_ARRAY, // Array of values + FOSSIL_IO_PARSER_LIST, // List of values + FOSSIL_IO_PARSER_MAP, // Key-value pairs + + // Feature / Option Types + FOSSIL_IO_PARSER_FEATURE, // Feature flag + FOSSIL_IO_PARSER_COMBO, // Select from predefined options + + // Invalid / Sentinel + FOSSIL_IO_PARSER_INVALID // Invalid argument type } fossil_io_parser_arg_type_t; -// Structure to represent each argument in the command +typedef union fossil_io_parser_value_u { + int i; + unsigned int u; + long l; + float f; + double d; + char *s; + char **arr; + void *ptr; // For MAP or JSON structures +} fossil_io_parser_value_t; + typedef struct fossil_io_parser_argument_s { - char *name; // Argument name - fossil_io_parser_arg_type_t type; // Argument type - char *value; // Parsed value - char **combo_options; // Valid options for COMBO type - int combo_count; // Number of valid options - struct fossil_io_parser_argument_s *next; // Next argument in the list + char *name; + char short_name; + fossil_io_parser_arg_type_t type; + fossil_io_parser_value_t value; + char **combo_options; + int combo_count; + struct fossil_io_parser_argument_s *next; } fossil_io_parser_argument_t; // Structure for a command typedef struct fossil_io_parser_command_s { - char *name; // Command name - char *description; // Command description - fossil_io_parser_argument_t *arguments; // List of arguments - struct fossil_io_parser_command_s *prev; // Previous command in the list - struct fossil_io_parser_command_s *next; // Next command in the list + char *name; // Command name + char *description; // Command description + fossil_io_parser_argument_t *arguments; // List of arguments + struct fossil_io_parser_command_s *prev; // Previous command in the list + struct fossil_io_parser_command_s *next; // Next command in the list } fossil_io_parser_command_t; // Structure for the command palette typedef struct fossil_io_parser_palette_s { - char *name; // Palette name - char *description; // Palette description - fossil_io_parser_command_t *commands; // List of commands + char *name; // Palette name + char *description; // Palette description + fossil_io_parser_command_t *commands; // List of commands } fossil_io_parser_palette_t; // ================================================================== diff --git a/code/logic/parser.c b/code/logic/parser.c index a1fdb26..033182f 100644 --- a/code/logic/parser.c +++ b/code/logic/parser.c @@ -128,9 +128,11 @@ void show_version(void) { } void show_help(const char *command_name, const fossil_io_parser_palette_t *palette) { + if (!palette) return; + fossil_io_parser_command_t *command = palette->commands; - // If no specific command is provided, show all commands + // Show all commands if no specific command is requested if (!command_name) { fossil_io_printf("{blue}Available commands:{reset}\n"); while (command) { @@ -146,70 +148,146 @@ void show_help(const char *command_name, const fossil_io_parser_palette_t *palet if (strcmp(command->name, command_name) == 0) { fossil_io_printf("{blue}Command: %s\nDescription: %s{reset}\n", command->name, command->description); fossil_io_printf("{blue}Arguments:{reset}\n"); + fossil_io_parser_argument_t *arg = command->arguments; while (arg) { - fossil_io_printf("{cyan} --%s (%s): ", - arg->name, - arg->type == FOSSIL_IO_PARSER_BOOL ? "bool" : - arg->type == FOSSIL_IO_PARSER_STRING ? "string" : - arg->type == FOSSIL_IO_PARSER_INT ? "int" : - arg->type == FOSSIL_IO_PARSER_FLOAT ? "float" : - arg->type == FOSSIL_IO_PARSER_DATE ? "date" : - arg->type == FOSSIL_IO_PARSER_ARRAY ? "array" : - arg->type == FOSSIL_IO_PARSER_FEATURE ? "feature" : - arg->type == FOSSIL_IO_PARSER_INVALID ? "invalid" : - "unknown"); - - if (arg->value) { - switch (arg->type) { - case FOSSIL_IO_PARSER_BOOL: - case FOSSIL_IO_PARSER_FEATURE: - fossil_io_printf("%s", (*(int *)arg->value) ? "true" : "false"); - break; - case FOSSIL_IO_PARSER_INT: - fossil_io_printf("%d", *(int *)arg->value); - break; - case FOSSIL_IO_PARSER_FLOAT: - fossil_io_printf("%f", *(float *)arg->value); - break; - case FOSSIL_IO_PARSER_STRING: - case FOSSIL_IO_PARSER_DATE: - fossil_io_printf("%s", (char *)arg->value); - break; - case FOSSIL_IO_PARSER_ARRAY: { - char **arr = (char **)arg->value; - int idx = 0; + // Print long and short names + if (arg->short_name != '\0') { + fossil_io_printf("{cyan} -%c, --%s (%s): ", arg->short_name, arg->name, + arg->type == FOSSIL_IO_PARSER_BOOL ? "bool" : + arg->type == FOSSIL_IO_PARSER_FLAG ? "flag" : + arg->type == FOSSIL_IO_PARSER_TOGGLE ? "toggle" : + arg->type == FOSSIL_IO_PARSER_INT ? "int" : + arg->type == FOSSIL_IO_PARSER_UINT ? "uint" : + arg->type == FOSSIL_IO_PARSER_HEX ? "hex" : + arg->type == FOSSIL_IO_PARSER_OCT ? "oct" : + arg->type == FOSSIL_IO_PARSER_BIN ? "bin" : + arg->type == FOSSIL_IO_PARSER_FLOAT ? "float" : + arg->type == FOSSIL_IO_PARSER_DOUBLE ? "double" : + arg->type == FOSSIL_IO_PARSER_STRING ? "string" : + arg->type == FOSSIL_IO_PARSER_FILE ? "file" : + arg->type == FOSSIL_IO_PARSER_DIR ? "dir" : + arg->type == FOSSIL_IO_PARSER_DATE ? "date" : + arg->type == FOSSIL_IO_PARSER_TIMESTAMP ? "timestamp" : + arg->type == FOSSIL_IO_PARSER_DURATION ? "duration" : + arg->type == FOSSIL_IO_PARSER_REGEX ? "regex" : + arg->type == FOSSIL_IO_PARSER_JSON ? "json" : + arg->type == FOSSIL_IO_PARSER_BASE64 ? "base64" : + arg->type == FOSSIL_IO_PARSER_URL ? "url" : + arg->type == FOSSIL_IO_PARSER_IP ? "ip" : + arg->type == FOSSIL_IO_PARSER_SIZE ? "size" : + arg->type == FOSSIL_IO_PARSER_PERCENT ? "percent" : + arg->type == FOSSIL_IO_PARSER_ARRAY ? "array" : + arg->type == FOSSIL_IO_PARSER_LIST ? "list" : + arg->type == FOSSIL_IO_PARSER_MAP ? "map" : + arg->type == FOSSIL_IO_PARSER_FEATURE ? "feature" : + arg->type == FOSSIL_IO_PARSER_COMBO ? "combo" : + "unknown"); + + } else { + fossil_io_printf("{cyan} --%s (%s): ", arg->name, + arg->type == FOSSIL_IO_PARSER_BOOL ? "bool" : + arg->type == FOSSIL_IO_PARSER_FLAG ? "flag" : + arg->type == FOSSIL_IO_PARSER_TOGGLE ? "toggle" : + arg->type == FOSSIL_IO_PARSER_INT ? "int" : + arg->type == FOSSIL_IO_PARSER_UINT ? "uint" : + arg->type == FOSSIL_IO_PARSER_HEX ? "hex" : + arg->type == FOSSIL_IO_PARSER_OCT ? "oct" : + arg->type == FOSSIL_IO_PARSER_BIN ? "bin" : + arg->type == FOSSIL_IO_PARSER_FLOAT ? "float" : + arg->type == FOSSIL_IO_PARSER_DOUBLE ? "double" : + arg->type == FOSSIL_IO_PARSER_STRING ? "string" : + arg->type == FOSSIL_IO_PARSER_FILE ? "file" : + arg->type == FOSSIL_IO_PARSER_DIR ? "dir" : + arg->type == FOSSIL_IO_PARSER_DATE ? "date" : + arg->type == FOSSIL_IO_PARSER_TIMESTAMP ? "timestamp" : + arg->type == FOSSIL_IO_PARSER_DURATION ? "duration" : + arg->type == FOSSIL_IO_PARSER_REGEX ? "regex" : + arg->type == FOSSIL_IO_PARSER_JSON ? "json" : + arg->type == FOSSIL_IO_PARSER_BASE64 ? "base64" : + arg->type == FOSSIL_IO_PARSER_URL ? "url" : + arg->type == FOSSIL_IO_PARSER_IP ? "ip" : + arg->type == FOSSIL_IO_PARSER_SIZE ? "size" : + arg->type == FOSSIL_IO_PARSER_PERCENT ? "percent" : + arg->type == FOSSIL_IO_PARSER_ARRAY ? "array" : + arg->type == FOSSIL_IO_PARSER_LIST ? "list" : + arg->type == FOSSIL_IO_PARSER_MAP ? "map" : + arg->type == FOSSIL_IO_PARSER_FEATURE ? "feature" : + arg->type == FOSSIL_IO_PARSER_COMBO ? "combo" : + "unknown"); + } + + // Print argument value if set + switch(arg->type) { + case FOSSIL_IO_PARSER_BOOL: + case FOSSIL_IO_PARSER_FLAG: + case FOSSIL_IO_PARSER_TOGGLE: + case FOSSIL_IO_PARSER_FEATURE: + fossil_io_printf("%s", arg->value.i ? "true" : "false"); + break; + case FOSSIL_IO_PARSER_INT: fossil_io_printf("%d", arg->value.i); break; + case FOSSIL_IO_PARSER_UINT: fossil_io_printf("%u", arg->value.u); break; + case FOSSIL_IO_PARSER_HEX: fossil_io_printf("0x%lX", arg->value.l); break; + case FOSSIL_IO_PARSER_OCT: fossil_io_printf("0%lo", arg->value.l); break; + case FOSSIL_IO_PARSER_BIN: { + long val = arg->value.l; + char buf[65] = {0}; + for(int i=63;i>=0;i--) buf[63-i] = (val & (1L<value.f); break; + case FOSSIL_IO_PARSER_DOUBLE: fossil_io_printf("%lf", arg->value.d); break; + case FOSSIL_IO_PARSER_SIZE: + case FOSSIL_IO_PARSER_PERCENT: + case FOSSIL_IO_PARSER_STRING: + case FOSSIL_IO_PARSER_FILE: + case FOSSIL_IO_PARSER_DIR: + case FOSSIL_IO_PARSER_DATE: + case FOSSIL_IO_PARSER_TIMESTAMP: + case FOSSIL_IO_PARSER_DURATION: + case FOSSIL_IO_PARSER_REGEX: + case FOSSIL_IO_PARSER_JSON: + case FOSSIL_IO_PARSER_BASE64: + case FOSSIL_IO_PARSER_URL: + case FOSSIL_IO_PARSER_IP: + case FOSSIL_IO_PARSER_COMBO: + fossil_io_printf("%s", arg->value.s ? arg->value.s : "No default"); + break; + case FOSSIL_IO_PARSER_ARRAY: + case FOSSIL_IO_PARSER_LIST: + if (arg->value.arr) { fossil_io_printf("["); - while (arr && arr[idx]) { - fossil_io_printf("%s%s", idx > 0 ? ", " : "", arr[idx]); - idx++; + for (int j=0; arg->value.arr[j]; j++) { + if (j>0) fossil_io_printf(", "); + fossil_io_printf("%s", arg->value.arr[j]); } fossil_io_printf("]"); - break; - } - default: - fossil_io_printf("Unknown"); - break; - } - } else { - fossil_io_printf("No default value"); + } else fossil_io_printf("No default"); + break; + case FOSSIL_IO_PARSER_MAP: + fossil_io_printf("{...}"); // placeholder + break; + default: + fossil_io_printf("Unknown"); + break; } + fossil_io_printf("{reset}\n"); arg = arg->next; } - // Handle specific flags + // Built-in flags fossil_io_printf("{blue}Built-in:{reset}\n"); - fossil_io_printf("{cyan} --help: Show help information for this command.{reset}\n"); - fossil_io_printf("{cyan} --version: Display the version of the application.{reset}\n"); - fossil_io_printf("{cyan} --dry-run: Simulate the operation without making changes.{reset}\n"); - fossil_io_printf("{cyan} --verbose: Provide detailed output during execution.{reset}\n"); + fossil_io_printf("{cyan} --help: Show help information{reset}\n"); + fossil_io_printf("{cyan} --version: Show version{reset}\n"); + fossil_io_printf("{cyan} --dry-run: Simulate operation{reset}\n"); + fossil_io_printf("{cyan} --verbose: Verbose output{reset}\n"); return; } command = command->next; } - // If the command is not found fossil_io_fprintf(FOSSIL_STDERR, "{red}Unknown command '%s'. Use '--help' to see available commands.{reset}\n", command_name); } @@ -224,7 +302,14 @@ void show_usage(const char *command_name, const fossil_io_parser_palette_t *pale fossil_io_parser_argument_t *arg = command->arguments; while (arg) { - fossil_io_printf("{cyan} --%s {reset}", arg->name); + // Print both long and short names if available + if (arg->short_name) { + fossil_io_printf("{cyan} [--%s | -%c]{reset}", arg->name, arg->short_name); + } else { + fossil_io_printf("{cyan} --%s{reset}", arg->name); + } + + // Show expected type/value switch (arg->type) { case FOSSIL_IO_PARSER_STRING: fossil_io_printf("{cyan}{reset}"); @@ -247,10 +332,18 @@ void show_usage(const char *command_name, const fossil_io_parser_palette_t *pale case FOSSIL_IO_PARSER_FEATURE: fossil_io_printf("{cyan}{reset}"); break; + case FOSSIL_IO_PARSER_COMBO: + fossil_io_printf("{cyan}<"); + for (int i = 0; i < arg->combo_count; i++) { + fossil_io_printf("%s%s", i > 0 ? "|" : "", arg->combo_options[i]); + } + fossil_io_printf(">{reset}"); + break; default: fossil_io_printf("{cyan}{reset}"); break; } + arg = arg->next; } @@ -263,7 +356,9 @@ void show_usage(const char *command_name, const fossil_io_parser_palette_t *pale } // If the command is not found - fossil_io_fprintf(FOSSIL_STDERR, "{red}Unknown command '%s'. Use '--help' to see available commands.{reset}\n", command_name); + fossil_io_fprintf(FOSSIL_STDERR, + "{red}Unknown command '%s'. Use '--help' to see available commands.{reset}\n", + command_name); } fossil_io_parser_palette_t *fossil_io_parser_create_palette(const char *name, const char *description) { @@ -355,7 +450,14 @@ fossil_io_parser_command_t *fossil_io_parser_add_command(fossil_io_parser_palett return command; } -fossil_io_parser_argument_t *fossil_io_parser_add_argument(fossil_io_parser_command_t *command, const char *arg_name, fossil_io_parser_arg_type_t arg_type, char **combo_options, int combo_count) { +fossil_io_parser_argument_t *fossil_io_parser_add_argument( + fossil_io_parser_command_t *command, + const char *arg_name, + char short_name, // NEW + fossil_io_parser_arg_type_t arg_type, + char **combo_options, + int combo_count +) { if (!command || !arg_name) { fossil_io_fprintf(FOSSIL_STDERR, "{red}Error: Command and argument name cannot be NULL.{reset}\n"); return NULL; @@ -368,18 +470,7 @@ fossil_io_parser_argument_t *fossil_io_parser_add_argument(fossil_io_parser_comm } argument->name = _custom_strdup(arg_name); - if (!argument->name) { - fossil_io_fprintf(FOSSIL_STDERR, "{red}Error: Memory allocation failed for argument name.{reset}\n"); - free(argument); - return NULL; - } - - if (arg_type < FOSSIL_IO_PARSER_BOOL || arg_type > FOSSIL_IO_PARSER_FEATURE) { - fossil_io_fprintf(FOSSIL_STDERR, "{red}Error: Invalid argument type for '%s'.{reset}\n", arg_name); - free(argument->name); - free(argument); - return NULL; - } + argument->short_name = short_name ? short_name : '\0'; argument->type = arg_type; argument->value = NULL; argument->combo_options = combo_options; @@ -627,6 +718,32 @@ void fossil_io_parser_parse(fossil_io_parser_palette_t *palette, int argc, char } else { fossil_io_fprintf(FOSSIL_STDERR, "{red}Missing value for feature argument: %s{reset}\n", arg_value); } + break; + case FOSSIL_IO_PARSER_COMBO: + if (i + 1 < argc) { + char *candidate = argv[++i]; + int valid = 0; + for (int j = 0; j < argument->combo_count; j++) { + if (strcmp(candidate, argument->combo_options[j]) == 0) { + valid = 1; + break; + } + } + if (valid) { + argument->value = _custom_strdup(candidate); + } else { + fossil_io_fprintf(FOSSIL_STDERR, + "{red}Invalid value '%s' for combo argument '%s'. Valid options: ", + candidate, argument->name); + for (int j = 0; j < argument->combo_count; j++) { + fossil_io_printf("%s%s", j > 0 ? ", " : "", argument->combo_options[j]); + } + fossil_io_printf("{reset}\n"); + } + } else { + fossil_io_fprintf(FOSSIL_STDERR, + "{red}Missing value for combo argument: %s{reset}\n", arg_value); + } break; default: fossil_io_fprintf(FOSSIL_STDERR, "{red}Unknown argument type for: %s{reset}\n", arg_value);