Add mkllfs tool
This commit is contained in:
187
mkllfs/main.c
Normal file
187
mkllfs/main.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @brief Converts files to a C file that can be used by llfs (linked list file system).
|
||||
* @version 0.1.0
|
||||
* @author Lorenz C.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "tinydir.h"
|
||||
|
||||
#define VERSION "0.1.0"
|
||||
#define LLFS_VERSION "0.1.0"
|
||||
#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, "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;\n", 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);
|
||||
}
|
||||
Reference in New Issue
Block a user