From 05da5ef05778d0653685a20e9e5847b221a54f59 Mon Sep 17 00:00:00 2001 From: Mosder Date: Thu, 23 Jul 2026 13:59:15 +0200 Subject: refactor: generalized command parsing and moved it into a separate file --- Makefile | 28 +++++------- analyzer/commands.c | 99 ++++++++++++++++++++++++++++++++++++++++++ analyzer/commands.h | 30 +++++++++++++ csv_table_gen.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ csv_to_headers.c | 121 ---------------------------------------------------- main.c | 56 +++++------------------- 6 files changed, 271 insertions(+), 184 deletions(-) create mode 100644 analyzer/commands.c create mode 100644 analyzer/commands.h create mode 100644 csv_table_gen.c delete mode 100644 csv_to_headers.c diff --git a/Makefile b/Makefile index 31c1275..fa3a294 100644 --- a/Makefile +++ b/Makefile @@ -10,16 +10,22 @@ local: compile debug: CFLAGS=-iquote ./analyzer -Og -g debug: global -compile: csv structures utils parser capture analyzer render +compile: csv_table_gen main_files structures utils parser $(CC) $(CFLAGS) -lpcap *.o main.c -o branal rm *.o -csv: - $(CC) $(CFLAGS) csv_to_headers.c -o csv_to_headers - ./csv_to_headers - rm csv_to_headers +csv_table_gen: + $(CC) $(CFLAGS) csv_table_gen.c -o csv_table_gen + ./csv_table_gen + rm csv_table_gen $(CC) $(CFLAGS) -c analyzer/csv/*.c +main_files: + $(CC) $(CFLAGS) -c analyzer/commands.c + $(CC) $(CFLAGS) -c analyzer/capture.c + $(CC) $(CFLAGS) -c analyzer/analyzer.c + $(CC) $(CFLAGS) -c analyzer/render.c + structures: $(CC) $(CFLAGS) -c analyzer/structures/hashmap.c $(CC) $(CFLAGS) -c analyzer/structures/heap.c @@ -35,15 +41,3 @@ parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c $(CC) $(CFLAGS) -c analyzer/parser/structs.c $(CC) $(CFLAGS) -c analyzer/parser/fight_results/fight_results.c - -capture: - $(CC) $(CFLAGS) -c analyzer/capture.c - -analyzer: - $(CC) $(CFLAGS) -c analyzer/analyzer.c - -render: - $(CC) $(CFLAGS) -c analyzer/render.c - -.PHONY: analyzer -.PHONY: csv diff --git a/analyzer/commands.c b/analyzer/commands.c new file mode 100644 index 0000000..cb3cdea --- /dev/null +++ b/analyzer/commands.c @@ -0,0 +1,99 @@ +#include "commands.h" + +#include +#include + +#include "analyzer.h" +#include "capture.h" +#include "utils/memory.h" + +#define PROGRAM_NAME "branal" +#define INDENT " " +#define MAX_COMMAND_LENGTH 100 + +// calculate the longest command length to align explenations +int longest_command_length() { + int longest_len = 0; + for (size_t i = 0; i < commands_count; i++) { + Command cmd = commands[i]; + int len = strlen(PROGRAM_NAME); + len += strlen(" ( | ) "); + len += strlen(cmd.short_name) + strlen(cmd.name); + len += strlen(cmd.args_str) == 0 ? 0 : strlen(cmd.args_str) + 1; + if (len > longest_len) + longest_len = len; + } + return longest_len; +} + +// help command handler +int print_help(int argc, char *argv[]) { + int len = longest_command_length(); + + printf("A bare-bones analyzer for the game Broken Ranks\n"); + printf("\nUsage:\n"); + printf(INDENT "%-*s- same as below\n", len, PROGRAM_NAME); + + for (size_t i = 0; i < commands_count; i++) { + Command cmd = commands[i]; + + char buffer[MAX_COMMAND_LENGTH]; + sprintf(buffer, PROGRAM_NAME " (%s | %s) ", cmd.short_name, cmd.name); + if (strlen(cmd.args_str)) + strcat(buffer, cmd.args_str); + + printf(INDENT "%-*s- %s\n", len, buffer, cmd.explanation[0]); + for (size_t j = 1; j < cmd.explanation_lines; j++) { + printf(INDENT "%*s%s\n", len + 2, "", cmd.explanation[j]); + } + } + + return 0; +} + +// live analyzer command handler +int live_anal(int argc, char *argv[]) { + // TODO: implement + printf("Not implemented\n"); + return 1; +} + +// capturing mode command handler +int capture(int argc, char *argv[]) { + capturing_mode(argc >= 3 ? argv[2] : NULL); + return 0; +} + +// file analysis command handler +int file_anal(int argc, char *argv[]) { + if (argc < 3) { + printf("You need to provide a file (or files) to analyze"); + return 1; + } + + for (size_t i = 2; i < argc; i++) { + printf("FILE: %s\n", argv[i]); + analyze_file(argv[i]); + printf("\n"); + } + + return 0; +} + +const Command help_command = {"help", "h", "", {"display this help"}, 1, print_help}; +const Command commands[] = { + {"live", "l", "", {"start live analysis"}, 1, live_anal}, + {"capture", "c", "[file]", {"start capturing packers to file", "If file isn't provided - captures to: $HOME/.local/share/branal/captures"}, 2, capture}, + {"file", "f", "", {"analyze the specified file(s)"}, 1, file_anal}, + help_command +}; +const size_t commands_count = ARR_LEN(commands); + +int is_command(Command command, char *str) { + return !strcmp(command.short_name, str) || !strcmp(command.name, str); +} + +void command_not_recognized() { + printf("Command not recognized\n"); + printf("Use \"%s (%s | %s)\" for help\n", PROGRAM_NAME, help_command.short_name, help_command.name); +} diff --git a/analyzer/commands.h b/analyzer/commands.h new file mode 100644 index 0000000..f53a140 --- /dev/null +++ b/analyzer/commands.h @@ -0,0 +1,30 @@ +// commands.h +// commands to use in the program + +#include + +#define MAX_EXPLANATION_LINES 3 + +typedef struct { + char *name; + char *short_name; + char *args_str; + char *explanation[MAX_EXPLANATION_LINES]; + size_t explanation_lines; + int (*handler)(int argc, char *argv[]); +} Command; + +// all commands of the program +extern const Command commands[]; +extern const size_t commands_count; + +// check if the given command is represented by the given string +// params: +// - command - potentailly represented command +// - str - potentially representing string +// returns: +// 1 if command is represneted by string, 0 if not +extern int is_command(Command command, char *str); + +// print information about help when program didn't recognize command +extern void command_not_recognized(); diff --git a/csv_table_gen.c b/csv_table_gen.c new file mode 100644 index 0000000..9be57d0 --- /dev/null +++ b/csv_table_gen.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#define EXT ".csv" +#define EXT_LEN strlen(".csv") +#define CSV_PATH "csv" +#define OUT_PATH "analyzer/" CSV_PATH + +#define BUFFER_SIZE 256 +#define MAX_ARR_SIZE 4096 + +// read values from input csv and save them to buffers +// returns max_index of the array +int read_csv(char *path, char *from, char *to, char from_to_array[][BUFFER_SIZE]) { + FILE *fp = fopen(path, "r"); + + // read field names + fscanf(fp, "%[^,],%[^\n]", from, to); + + // read values + size_t max_index = 0; + size_t val1; + char val2[BUFFER_SIZE]; + while (fscanf(fp, "%zu,%[^\n]", &val1, val2) == 2) { + strcpy(from_to_array[val1], val2); + if (val1 > max_index) + max_index = val1; + } + + fclose(fp); + + return max_index; +} + +// create output .h file +void create_h(char *path, char *from, char *to) { + FILE *fp = fopen(path, "w"); + + // write comments and function prototype + fprintf(fp, "// %s\n", strstr(path, CSV_PATH)); + fprintf(fp, "// translate %s to %s - generated from csv\n\n", from, to); + fprintf(fp, "// get %s from %s\n", to, from); + fprintf(fp, "// params:\n"); + fprintf(fp, "// - %s - %s to translate from\n", from, from); + fprintf(fp, "// returns:\n"); + fprintf(fp, "// %s corresponding to %s\n", to, from); + fprintf(fp, "extern const char *get_%s_from_%s(int %s);", to, from, from); + + fclose(fp); +} + +// create output .c file +void create_c(char *path, char *h_path, char *from, char *to, char from_to_array[][BUFFER_SIZE], size_t max_index) { + FILE *fp = fopen(path, "w"); + + char arr_name[BUFFER_SIZE], arr_len_name[BUFFER_SIZE]; + sprintf(arr_name, "%s_to_%s", from, to); + sprintf(arr_len_name, "%s_to_%s_len", from, to); + + // write include and beginning of array + fprintf(fp, "#include \"%s\"\n\n", strstr(h_path, CSV_PATH)); + fprintf(fp, "static const char *%s[] = {\n", arr_name); + + // write values + for (size_t i = 0; i <= max_index; i++) { + if (strlen(from_to_array[i]) > 0) + fprintf(fp, " \"%s\",\n", from_to_array[i]); + else + fprintf(fp, " \"%zu\",\n", i); + } + + // write the end of array and len + fprintf(fp, "};\n"); + fprintf(fp, "int %s = %zu;\n\n", arr_len_name, max_index + 1); + + // write the getter + fprintf(fp, "const char *get_%s_from_%s(int %s) {\n", to, from, from); + fprintf(fp, " return %s >= 0 && %s < %s ? %s[%s] : \"null\";\n", from, from, arr_len_name, arr_name, from); + fprintf(fp, "}"); + + fclose(fp); +} + +void create_table(char *file_name) { + // read from input file + char input_path[BUFFER_SIZE]; + sprintf(input_path, "%s/%s", CSV_PATH, file_name); + char from[BUFFER_SIZE], to[BUFFER_SIZE]; + char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {0}; + size_t max_index = read_csv(input_path, from, to, from_to_array); + + // create output .h file + char h_path[BUFFER_SIZE]; + sprintf(h_path, "%s/%s_to_%s.h", OUT_PATH, from, to); + create_h(h_path, from, to); + + // create output .c file + char c_path[BUFFER_SIZE]; + sprintf(c_path, "%s/%s_to_%s.c", OUT_PATH, from, to); + create_c(c_path, h_path, from, to, from_to_array, max_index); +} + +int main() { + // make directory for output files + mkdir(OUT_PATH, 0755); + + DIR *csv_dir = opendir(CSV_PATH); + struct dirent *entry; + while ((entry = readdir(csv_dir))) { + char *file_name = entry->d_name; + size_t file_name_len = strlen(file_name); + // create lookup tables for each *.csv file + if (file_name_len > EXT_LEN && !strcmp(file_name + file_name_len - EXT_LEN, EXT)) + create_table(entry->d_name); + } + closedir(csv_dir); + + return 0; +} diff --git a/csv_to_headers.c b/csv_to_headers.c deleted file mode 100644 index 51a1c58..0000000 --- a/csv_to_headers.c +++ /dev/null @@ -1,121 +0,0 @@ -#include -#include -#include -#include - -#define EXT ".csv" -#define EXT_LEN strlen(".csv") -#define CSV_PATH "csv" -#define OUT_PATH "analyzer/" CSV_PATH - -#define BUFFER_SIZE 256 -#define MAX_ARR_SIZE 4096 - -// read values from input csv and save them to buffers -// returns max_index of the array -int read_csv(char *path, char *from, char *to, char from_to_array[][BUFFER_SIZE]) { - FILE *fp = fopen(path, "r"); - - // read field names - fscanf(fp, "%[^,],%[^\n]", from, to); - - // read values - size_t max_index = 0; - size_t val1; - char val2[BUFFER_SIZE]; - while (fscanf(fp, "%zu,%[^\n]", &val1, val2) == 2) { - strcpy(from_to_array[val1], val2); - if (val1 > max_index) - max_index = val1; - } - - fclose(fp); - - return max_index; -} - -// create output .h file -void create_h(char *path, char *from, char *to) { - FILE *fp = fopen(path, "w"); - - // write comments and function prototype - fprintf(fp, "// %s\n", strstr(path, CSV_PATH)); - fprintf(fp, "// translate %s to %s - generated from csv\n\n", from, to); - fprintf(fp, "// get %s from %s\n", to, from); - fprintf(fp, "// params:\n"); - fprintf(fp, "// - %s - %s to translate from\n", from, from); - fprintf(fp, "// returns:\n"); - fprintf(fp, "// %s corresponding to %s\n", to, from); - fprintf(fp, "extern const char *get_%s_from_%s(int %s);", to, from, from); - - fclose(fp); -} - -// create output .c file -void create_c(char *path, char *h_path, char *from, char *to, char from_to_array[][BUFFER_SIZE], size_t max_index) { - FILE *fp = fopen(path, "w"); - - char arr_name[BUFFER_SIZE], arr_len_name[BUFFER_SIZE]; - sprintf(arr_name, "%s_to_%s", from, to); - sprintf(arr_len_name, "%s_to_%s_len", from, to); - - // write include and beginning of array - fprintf(fp, "#include \"%s\"\n\n", strstr(h_path, CSV_PATH)); - fprintf(fp, "static const char *%s[] = {\n", arr_name); - - // write values - for (size_t i = 0; i <= max_index; i++) { - if (strlen(from_to_array[i]) > 0) - fprintf(fp, " \"%s\",\n", from_to_array[i]); - else - fprintf(fp, " \"%zu\",\n", i); - } - - // write the end of array and len - fprintf(fp, "};\n"); - fprintf(fp, "int %s = %zu;\n\n", arr_len_name, max_index + 1); - - // write the getter - fprintf(fp, "const char *get_%s_from_%s(int %s) {\n", to, from, from); - fprintf(fp, " return %s >= 0 && %s < %s ? %s[%s] : \"null\";\n", from, from, arr_len_name, arr_name, from); - fprintf(fp, "}"); - - fclose(fp); -} - -void create_table(char *file_name) { - // read from input file - char input_path[BUFFER_SIZE]; - sprintf(input_path, "%s/%s", CSV_PATH, file_name); - char from[BUFFER_SIZE], to[BUFFER_SIZE]; - char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {0}; - size_t max_index = read_csv(input_path, from, to, from_to_array); - - // create output .h file - char h_path[BUFFER_SIZE]; - sprintf(h_path, "%s/%s_to_%s.h", OUT_PATH, from, to); - create_h(h_path, from, to); - - // create output .c file - char c_path[BUFFER_SIZE]; - sprintf(c_path, "%s/%s_to_%s.c", OUT_PATH, from, to); - create_c(c_path, h_path, from, to, from_to_array, max_index); -} - -int main() { - // make directory for output files - mkdir(OUT_PATH, 0755); - - DIR *csv_dir = opendir(CSV_PATH); - struct dirent *entry; - while ((entry = readdir(csv_dir))) { - char *file_name = entry->d_name; - size_t file_name_len = strlen(file_name); - // create lookup tables for each *.csv file - if (file_name_len > EXT_LEN && strcmp(file_name + file_name_len - EXT_LEN, EXT) == 0) - create_table(entry->d_name); - } - closedir(csv_dir); - - return 0; -} diff --git a/main.c b/main.c index eadb516..38dfc36 100644 --- a/main.c +++ b/main.c @@ -1,54 +1,18 @@ -#include -#include - -#include "analyzer/analyzer.h" -#include "analyzer/capture.h" -#include "analyzer/utils/fs.h" - -// prints help -void print_help() { - printf("A bare-bones analyzer for the game Broken Ranks\n"); - printf("\nUsage:\n"); - printf(" branal - start live analysis\n"); - printf(" branal (l | live) - start live analysis (same as above)\n"); - printf(" branal (c | capture) [file] - start capturing packets to [file].\n"); - printf(" If [file] not given - captures to $HOME/.local/share/branal/captures\n"); - printf(" branal (f | file) - analyze the specified \n"); - printf(" branal (h | help) - display this help\n"); -} - -// starts live analyzer mode -void start_live_analyzer() { - // TODO: implement - printf("Not implemented\n"); -} +#include "commands.h" +#include "utils/fs.h" int main(int argc, char *argv[]) { create_necessary_directories(); - // start live analysis if no arguments provided - if (argc < 2) { - start_live_analyzer(); - return 0; - } + // start first command if no arguments provided + if (argc < 2) + return commands[0].handler(argc, argv); - if (strcmp("l", argv[1]) == 0 || strcmp("live", argv[1]) == 0) { - start_live_analyzer(); - } - else if (strcmp("c", argv[1]) == 0 || strcmp("capture", argv[1]) == 0) { - capturing_mode(argc >= 3 ? argv[2] : NULL); - } - else if (strcmp("h", argv[1]) == 0 || strcmp("help", argv[1]) == 0) { - print_help(); - } - else if (argc >= 3 && (strcmp("f", argv[1]) == 0 || strcmp("file", argv[1]) == 0)) { - analyze_file(argv[2]); - } - else { - printf("Command not recognized\n"); - printf("Use \"branal (h | help)\" for help\n"); - return 1; + for (size_t i = 0; i < commands_count; i++) { + if (is_command(commands[i], argv[1])) + return commands[i].handler(argc, argv); } - return 0; + command_not_recognized(); + return 1; } -- cgit v1.2.3