/** * @file main.c * @brief Converts files to a C file that can be used by llfs (linked list file system). * @version 0.2.1 * @author Lorenz C. */ #include #include #include #include "tinydir.h" #define VERSION "0.2.1" #define LLFS_VERSION "0.1.1" #define MAX_PATH_LEN 256 static void file_name_to_llfs_name(char* llfs_name, const char* file_name); static void print_help(void); static void print_version(void); int main(int argc, char** argv) { char src_path[MAX_PATH_LEN]; char llfs_name[MAX_PATH_LEN]; char prev_llfs_name[MAX_PATH_LEN] = "NULL"; FILE* out_file; FILE* src_file; tinydir_dir dir; int file_count = 0; // Check if the help or version flag is set for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { print_help(); return 0; } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { print_version(); return 0; } } // Check if at least 2 arguments are given (directory and output file) if (argc < 3) { fprintf(stderr, "Error: Not enough arguments.\r\n"); print_help(); goto fail_init; } // Open the output file out_file = fopen(argv[argc - 1], "w"); if (out_file == NULL) { fprintf(stderr, "Error: Could not open output file\r\n"); goto fail_init; } // Open the source directory strcpy(src_path, argv[argc - 2]); if (tinydir_open(&dir, src_path) == -1) { fprintf(stderr, "Error: Could not open directory\r\n"); goto fail_open_dir; } // Write the header of the output file fprintf(out_file, "/**\n" " * @file %s\n" " * @brief Linked list file system (llfs) data file.\n" " * This file was generated by mkllfs %s.\n" " * @date %s\n */\n\n", argv[argc - 1], VERSION, __DATE__); // Write the headers of the output file fprintf(out_file, "#include \n"); fprintf(out_file, "#include \"llfs.h\"\n"); fprintf(out_file, "\n"); // Iterate over all files in the directory while (dir.has_next) { tinydir_file file; size_t file_size = 0; // Get file info if (tinydir_readfile(&dir, &file) == -1) { fprintf(stderr, "Error: Could not read file\r\n"); continue; } if (file.is_dir) { tinydir_next(&dir); continue; } // Open the source file src_file = fopen(file.path, "rb"); if (src_file == NULL) { printf("Error: Could not open source file: %s\r\n", file.path); continue; } // Convert the file name to a valid llfs name file_name_to_llfs_name(llfs_name, file.name); // Write the file data to the output file fprintf(out_file, "// File: %s\n", file.name); fprintf(out_file, "__attribute__((section(\".ext_qspi_flash\")))\n"); fprintf(out_file, "const uint8_t %s_data[] = {\n", llfs_name); for (int i = 0, c; (c = fgetc(src_file)) != EOF; i++) { file_size++; fprintf(out_file, "0x%02X, ", c); if (i % 16 == 15) { fprintf(out_file, "\n"); } } fprintf(out_file, "\n};\n"); // Write the file info to the output file fprintf(out_file, "const struct llfs_data_file %s = {\n .data = %s_data,\n .name = \"%s\",\n .len = %zu,\n " ".next =%s%s\n};\n\n", llfs_name, llfs_name, file.name, file_size, strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &", prev_llfs_name); file_count++; tinydir_next(&dir); strcpy(prev_llfs_name, llfs_name); fclose(src_file); } // Make the last file the root file of the llfs fprintf(out_file, "\n"); fprintf(out_file, "const struct llfs_data_file *llfs_root =%s%s;\n", (strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &"), prev_llfs_name); // Print the number of files printf("Successfully converted %d files.\r\n", file_count); fail: tinydir_close(&dir); fail_open_dir: fclose(out_file); fail_init: return 0; } /** * @brief Converts a file name to a valid llfs name, so that it can be used as a variable name in the generated C file. * The length of the generated llfs name is the same as the length of the original file name. * * @param[out] llfs_name The output llfs name. Must be at least as long as the file name. * @param[in] file_name The input file name as a null terminated string. */ static void file_name_to_llfs_name(char* llfs_name, const char* file_name) { size_t len = strlen(file_name); // Replace all invalid characters with '_' for (int i = 0; i < len; i++) { if (file_name[i] == '.' || file_name[i] == '-' || file_name[i] == ' ') { llfs_name[i] = '_'; } else { llfs_name[i] = file_name[i]; } } // Replace the first character if it is a number if (llfs_name[0] >= '0' && llfs_name[0] <= '9') { llfs_name[0] = '_'; } llfs_name[len] = '\0'; } /** * @brief Prints the help message. */ static void print_help(void) { printf("Make Linked list file system (mkllfs)\r\n"); printf("Converts files into a linked list file system.\r\n"); printf("By Lorenz C.\r\n"); printf("\r\n"); printf("Usage: mkllfs [options] \r\n"); printf("Options:\r\n"); printf(" -h, --help: Print this help message\r\n"); printf(" -v, --version: Print the version\r\n"); } /** * @brief Prints the version. */ static void print_version(void) { printf("mkllfs version %s\r\n", VERSION); printf("llfs version %s\r\n", LLFS_VERSION); }