Files
2023-Webservices_And_Applic…/mkllfs/main.c
2023-11-16 16:03:36 +01:00

189 lines
5.8 KiB
C

/**
* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <stddef.h>\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] <directory> <output file>\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);
}