From 71385a1fd5e19f44979dfd31fea4fd4e418dea13 Mon Sep 17 00:00:00 2001 From: Joshua Vega Date: Sat, 24 Jan 2026 11:19:58 -0500 Subject: [PATCH 1/2] flesh out yaml parser. --- CMakeLists.txt | 7 ++- LICENSE | 2 +- README.md | 32 ++++++++++- config.c | 30 +++++++++++ config.h | 27 ++++++++++ format.sh | 3 ++ main.c | 11 +++- yaml.h | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 config.c create mode 100644 config.h create mode 100755 format.sh create mode 100644 yaml.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a708946..d953bf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 4.0) PROJECT(nfgen LANGUAGES C) SET(SOURCE_FILES - main.c + config.c + main.c ) ADD_EXECUTABLE(nfgen ${SOURCE_FILES}) @@ -24,5 +25,7 @@ ADD_EXECUTABLE(nfgen ${SOURCE_FILES}) SET_PROPERTY(TARGET nfgen PROPERTY C_STANDARD 11) TARGET_COMPILE_OPTIONS(nfgen PRIVATE - $<$: -Wall> + $<$: -Wall -Wextra -Wpedantic -Wformat=2 -Wuseless-cast -Wshadow> ) + +TARGET_COMPILE_OPTIONS(nfgen PRIVATE $<$>: -g>) diff --git a/LICENSE b/LICENSE index 7d1803d..b7696c4 100644 --- a/LICENSE +++ b/LICENSE @@ -209,7 +209,7 @@ If you develop a new program, and you want it to be of the greatest possible use To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. nfgen - Copyright (C) 2026 jsvcycling + Copyright (C) 2026 Joshua Vega This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/README.md b/README.md index 2313c5c..b32f69f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,33 @@ # nfgen -Generate realistic NetFlow v5 and v9 packets. \ No newline at end of file +Generate realistic NetFlow (v5 and/or v9) traffic. + +## Building + +```shell +$ cmake -DCMAKE_BUILD_TYPE=Release . +$ make +``` + +To build the executable with debugging symbols, remove the `-DCMAKE_BUILD_TYPE` +argument or set it to `-DCMAKE_BUILD_TYPE=Debug`. + +## License + +``` +Copyright (C) 2026 Joshua Vega + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +``` + +Please see `LICENSE` for the complete license details. diff --git a/config.c b/config.c new file mode 100644 index 0000000..0097e98 --- /dev/null +++ b/config.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2026 Joshua Vega + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include "config.h" + +#define YAML_IMPLEMENTATION +#include "yaml.h" + +#include + +int loadConfigFromFile(const char *path, size_t pathLength, Config **config) { + yaml_value_t *configRoot = yaml_parse(path, pathLength); + if (configRoot == NULL) { + fprintf(stderr, "%s", yaml_error()); + return -1; + } + return 0; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..eb34656 --- /dev/null +++ b/config.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2026 Joshua Vega + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#ifndef CONFIG_H +#define CONFIG_H + +#include + +typedef struct Config { + /* TODO */ +} Config; + +int loadConfigFromFile(const char *path, size_t pathLength, Config **config); + +#endif /* CONFIG_H */ diff --git a/format.sh b/format.sh new file mode 100755 index 0000000..599768b --- /dev/null +++ b/format.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +find . -regex '.*\.\(c\|h\)' -exec clang-format -i --sort-includes {} \; diff --git a/main.c b/main.c index 0517951..2295c86 100644 --- a/main.c +++ b/main.c @@ -18,14 +18,15 @@ #include #include +#include "config.h" + #define ARG_L_CONFIG_PATH "--config" #define ARG_S_CONFIG_PATH "-c" #define ARG_LEN_L_CONFIG_PATH 8 #define ARG_LEN_S_CONFIG_PATH 2 -char configPath[1024]; -size_t configPathLength = 0; +Config *config = NULL; int parseArguments(int, char**); void printHelp(void); @@ -42,6 +43,8 @@ int main(int argc, char** argv) int parseArguments(int argc, char** argv) { + char configPath[1024]; + size_t configPathLength = 0; bool expectConfigPath = false; for (int argIndex = 1; argIndex < argc; argIndex++) { @@ -70,6 +73,10 @@ int parseArguments(int argc, char** argv) } } + if (loadConfigFromFile(configPath, configPathLength, &config) != 0) { + return -1; + } + return 0; } diff --git a/yaml.h b/yaml.h new file mode 100644 index 0000000..76a75fc --- /dev/null +++ b/yaml.h @@ -0,0 +1,144 @@ +#ifndef YAML_H +#define YAML_H + +#include + +typedef enum { + YAML_TYPE_STRING, /**< A value that represents a string. */ + YAML_TYPE_NUMBER, /**< A value that represents a number. */ + YAML_TYPE_OBJECT, /**< A value that represents an object. */ + YAML_TYPE_ARRAY, /**< A value that represents an array. */ + YAML_TYPE_TRUE, /**< A value that represents true. */ + YAML_TYPE_FALSE, /**< A value that represents false. */ + YAML_TYPE_NULL, /**< A value that represents null. */ +} yaml_type_t; + +typedef struct { + void *data; + yaml_type_t type; +} yaml_value_t; + +typedef struct { + const char *data; + size_t length; +} yaml_string_t; + +typedef struct { + const char *data; + size_t length; +} yaml_number_t; + +typedef struct yaml_object_field_s { + yaml_string_t *name; + yaml_value_t *value; + + struct yaml_object_field_s *next; +} yaml_object_field_t; + +typedef struct { + yaml_object_field_t *head; + size_t count; +} yaml_object_t; + +typedef struct yaml_array_element_s { + yaml_value_t *value; + + struct yaml_array_element_s *next; +} yaml_array_element_t; + +typedef struct { + yaml_array_element_t *head; + size_t count; +} yaml_array_t; + +/** + * Parse a UTF-8 encoded string into a value object. + * + * Returns `NULL` if parsing fails. + */ +yaml_value_t *yaml_parse(const void *, size_t); + +/** + * Traverse the tree to retrieve a specific sub-value from a root value. + * + * Returns `NULL` if the requested sub-value does not exist. + */ +yaml_value_t *yaml_get(const yaml_value_t *, const char *); + +/** + * Access a value object as a string. + * + * Returns `NULL` if the value is not a string. + */ +yaml_string_t *yaml_value_as_string(const yaml_value_t *); + +/** + * Access a value object as a number. + * + * Returns `NULL` if the value is not a number. + */ +yaml_number_t *yaml_value_as_number(const yaml_value_t *); + +/** + * Access a value object as an object. + * + * Returns `NULL` if the value is not an object. + */ +yaml_object_t *yaml_value_as_object(const yaml_value_t *); + +/** + * Access a value object as an array. + * + * Returns `NULL` if the value is not an array. + */ +yaml_array_t *yaml_value_as_array(const yaml_value_t *); + +/** + * Return a string describing the most recently encountered error. + * + * Returns `NULL` if no error has been encountered. + */ +const char *yaml_error(void); + +#endif /* YAML_H */ + +#ifdef YAML_IMPLEMENTATION + +char error_message[4096]; + +yaml_value_t *yaml_parse(const void *content, size_t length) { + /* TODO */ + return NULL; +} + +yaml_value_t *yaml_get(const yaml_value_t *root, const char *path) { + /* TODO */ + return NULL; +} + +yaml_string_t *yaml_value_as_string(const yaml_value_t *value) { + /* TODO */ + return NULL; +} + +yaml_number_t *yaml_value_as_number(const yaml_value_t *value) { + /* TODO */ + return NULL; +} + +yaml_object_t *yaml_object_as_object(const yaml_value_t *value) { + /* TODO */ + return NULL; +} + +yaml_array_t *yaml_object_as_array(const yaml_value_t *value) { + /* TODO */ + return NULL; +} + +const char *yaml_error(void) { + if (error_message[0] == '\0') return NULL; + return error_message; +} + +#endif /* YAML_IMPLEMENTATION */ From 80d2ed51804d282bbdd4544c1e0b7e392080e06e Mon Sep 17 00:00:00 2001 From: Joshua Vega Date: Sat, 24 Jan 2026 12:48:05 -0500 Subject: [PATCH 2/2] run clang-format --- .clang-format | 12 +++++++++++- format.sh | 2 +- main.c | 17 ++++++++--------- yaml.h | 16 ++++++++-------- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/.clang-format b/.clang-format index 534401f..44280df 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,12 @@ --- -BasedOnStyle: WebKit +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 88 + +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: WithoutElse + +BinPackParameters: OnePerLine + +AlignConsecutiveMacros: Consecutive +AlignEscapedNewlines: LeftWithLastLine diff --git a/format.sh b/format.sh index 599768b..809ab0e 100755 --- a/format.sh +++ b/format.sh @@ -1,3 +1,3 @@ #!/bin/bash -find . -regex '.*\.\(c\|h\)' -exec clang-format -i --sort-includes {} \; +find . -regex '.*\.\(c\|h\)' -not -path "./CMakeFiles/*" -exec clang-format -i --sort-includes {} \; diff --git a/main.c b/main.c index 2295c86..27ea232 100644 --- a/main.c +++ b/main.c @@ -28,11 +28,10 @@ Config *config = NULL; -int parseArguments(int, char**); +int parseArguments(int, char **); void printHelp(void); -int main(int argc, char** argv) -{ +int main(int argc, char **argv) { if (parseArguments(argc, argv) != 0) { printHelp(); return 0; @@ -41,14 +40,13 @@ int main(int argc, char** argv) return 0; } -int parseArguments(int argc, char** argv) -{ +int parseArguments(int argc, char **argv) { char configPath[1024]; size_t configPathLength = 0; bool expectConfigPath = false; for (int argIndex = 1; argIndex < argc; argIndex++) { - const char* arg = argv[argIndex]; + const char *arg = argv[argIndex]; if (expectConfigPath) { size_t length = strlen(arg); @@ -65,7 +63,9 @@ int parseArguments(int argc, char** argv) continue; } - if (!expectConfigPath && (strncmp(arg, ARG_L_CONFIG_PATH, ARG_LEN_L_CONFIG_PATH) || strncmp(arg, ARG_S_CONFIG_PATH, ARG_LEN_S_CONFIG_PATH))) { + if (!expectConfigPath && + (strncmp(arg, ARG_L_CONFIG_PATH, ARG_LEN_L_CONFIG_PATH) || + strncmp(arg, ARG_S_CONFIG_PATH, ARG_LEN_S_CONFIG_PATH))) { printf("Encountered config path argument.\n"); expectConfigPath = true; } else { @@ -80,7 +80,6 @@ int parseArguments(int argc, char** argv) return 0; } -void printHelp(void) -{ +void printHelp(void) { /* TODO */ } diff --git a/yaml.h b/yaml.h index 76a75fc..d50a8c3 100644 --- a/yaml.h +++ b/yaml.h @@ -4,13 +4,13 @@ #include typedef enum { - YAML_TYPE_STRING, /**< A value that represents a string. */ - YAML_TYPE_NUMBER, /**< A value that represents a number. */ - YAML_TYPE_OBJECT, /**< A value that represents an object. */ - YAML_TYPE_ARRAY, /**< A value that represents an array. */ - YAML_TYPE_TRUE, /**< A value that represents true. */ - YAML_TYPE_FALSE, /**< A value that represents false. */ - YAML_TYPE_NULL, /**< A value that represents null. */ + YAML_TYPE_STRING, /**< A value that represents a string. */ + YAML_TYPE_NUMBER, /**< A value that represents a number. */ + YAML_TYPE_OBJECT, /**< A value that represents an object. */ + YAML_TYPE_ARRAY, /**< A value that represents an array. */ + YAML_TYPE_TRUE, /**< A value that represents true. */ + YAML_TYPE_FALSE, /**< A value that represents false. */ + YAML_TYPE_NULL, /**< A value that represents null. */ } yaml_type_t; typedef struct { @@ -42,7 +42,7 @@ typedef struct { typedef struct yaml_array_element_s { yaml_value_t *value; - + struct yaml_array_element_s *next; } yaml_array_element_t;