2025-03-20 04:16:06 +01:00
|
|
|
// Written by retoor@molodetz.nl
|
|
|
|
|
|
|
|
// The code provides functionality to manage and merge files, particularly focusing on parsing and including scripts or C local includes. It
|
|
|
|
// implements functionality to read lines from files, extract local includes from script tags, and manage history to avoid duplicate merges.
|
|
|
|
|
|
|
|
// The code utilizes several external libraries: "rlexer.h" for lexical analysis, "rmalloc.h" for memory management, "rprint.h" for printing
|
|
|
|
// utilities, "rrex3.h" for regular expression handling, and "remo.h" for additional utilities. It also uses standard libraries like
|
|
|
|
// stdio.h, stdlib.h, string.h, and stdbool.h for fundamental operations.
|
|
|
|
|
|
|
|
// MIT License
|
|
|
|
|
2025-01-14 18:53:15 +01:00
|
|
|
#include "rlexer.h"
|
|
|
|
#include "rmalloc.h"
|
|
|
|
#include "rprint.h"
|
|
|
|
#include "rrex3.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "remo.h"
|
|
|
|
|
|
|
|
bool has_error = false;
|
|
|
|
|
|
|
|
char *extract_script_src_include(char *line, char *include_path) {
|
2025-03-20 04:16:06 +01:00
|
|
|
include_path[0] = '\0';
|
|
|
|
rrex3_t *rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>");
|
2025-01-14 18:53:15 +01:00
|
|
|
if (rrex) {
|
|
|
|
strcpy(include_path, rrex->matches[0]);
|
|
|
|
rrex3_free(rrex);
|
|
|
|
return include_path;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *extract_c_local_include(char *line, char *include_path) {
|
2025-03-20 04:16:06 +01:00
|
|
|
include_path[0] = '\0';
|
|
|
|
rrex3_t *rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\"");
|
2025-01-14 18:53:15 +01:00
|
|
|
if (rrex) {
|
|
|
|
strcpy(include_path, rrex->matches[0]);
|
|
|
|
rrex3_free(rrex);
|
|
|
|
return include_path;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *rmerge_readline(FILE *f) {
|
|
|
|
static char data[4096];
|
2025-03-20 04:16:06 +01:00
|
|
|
data[0] = '\0';
|
2025-01-14 18:53:15 +01:00
|
|
|
int index = 0;
|
|
|
|
char c;
|
|
|
|
while ((c = fgetc(f)) != EOF) {
|
|
|
|
if (c != '\0') {
|
2025-03-20 04:16:06 +01:00
|
|
|
data[index++] = c;
|
2025-01-14 18:53:15 +01:00
|
|
|
if (c == '\n')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2025-03-20 04:16:06 +01:00
|
|
|
data[index] = '\0';
|
|
|
|
if (data[0] == '\0')
|
2025-01-14 18:53:15 +01:00
|
|
|
return NULL;
|
|
|
|
return data;
|
|
|
|
}
|
2025-03-20 04:16:06 +01:00
|
|
|
|
2025-01-14 18:53:15 +01:00
|
|
|
void writestring(FILE *f, char *line) {
|
|
|
|
char c;
|
|
|
|
while ((c = *line) != '\0') {
|
|
|
|
fputc(c, f);
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
}
|
2025-03-20 04:16:06 +01:00
|
|
|
|
2025-01-14 18:53:15 +01:00
|
|
|
char files_history[8096];
|
|
|
|
char files_duplicate[8096];
|
|
|
|
bool is_merging = false;
|
|
|
|
|
|
|
|
void merge_file(char *source, FILE *d) {
|
2025-03-20 04:16:06 +01:00
|
|
|
if (!is_merging) {
|
2025-01-14 18:53:15 +01:00
|
|
|
is_merging = true;
|
2025-03-20 04:16:06 +01:00
|
|
|
files_history[0] = '\0';
|
|
|
|
files_duplicate[0] = '\0';
|
2025-01-14 18:53:15 +01:00
|
|
|
}
|
|
|
|
if (strstr(files_history, source)) {
|
|
|
|
if (strstr(files_duplicate, source)) {
|
|
|
|
rprintmf(stderr, "\\l Already included: %s. Already on duplicate list.\n", source);
|
|
|
|
} else {
|
|
|
|
rprintcf(stderr, "\\l Already included: %s. Adding to duplicate list.\n", source);
|
|
|
|
strcat(files_duplicate, source);
|
|
|
|
strcat(files_duplicate, "\n");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
rprintgf(stderr, "\\l Merging: %s.\n", source);
|
|
|
|
strcat(files_history, source);
|
|
|
|
strcat(files_history, "\n");
|
|
|
|
}
|
|
|
|
FILE *fd = fopen(source, "rb");
|
|
|
|
if (!fd) {
|
|
|
|
rprintrf(stderr, "\\l File does not exist: %s\n", source);
|
|
|
|
has_error = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *line;
|
|
|
|
char include_path[4096];
|
|
|
|
while ((line = rmerge_readline(fd))) {
|
2025-03-20 04:16:06 +01:00
|
|
|
include_path[0] = '\0';
|
2025-01-14 18:53:15 +01:00
|
|
|
if (!*line)
|
|
|
|
break;
|
|
|
|
char *inc = extract_c_local_include(line, include_path);
|
|
|
|
if (!inc)
|
|
|
|
inc = extract_script_src_include(line, include_path);
|
|
|
|
if (inc) {
|
|
|
|
merge_file(inc, d);
|
|
|
|
} else {
|
|
|
|
writestring(d, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
writestring(d, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int rmerge_main(int argc, char *argv[]) {
|
|
|
|
char *file_input = NULL;
|
|
|
|
if (argc != 2) {
|
|
|
|
printf("Usage: <input-file>\n");
|
|
|
|
} else {
|
|
|
|
file_input = argv[1];
|
|
|
|
}
|
|
|
|
FILE *f = tmpfile();
|
|
|
|
printf("// RETOOR - %s\n", __DATE__);
|
|
|
|
merge_file(file_input, f);
|
|
|
|
rewind(f);
|
|
|
|
char *data;
|
|
|
|
int line_number = 0;
|
|
|
|
while ((data = rmerge_readline(f))) {
|
|
|
|
if (line_number) {
|
|
|
|
printf("/*%.5d*/ ", line_number);
|
|
|
|
line_number++;
|
|
|
|
}
|
|
|
|
printf("%s", data);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
if (has_error) {
|
|
|
|
rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n");
|
|
|
|
} else {
|
2025-03-20 04:16:06 +01:00
|
|
|
rprintgf(stderr, "\\l Merge successful without error(s).%s\n", remo_get("fire"));
|
2025-01-14 18:53:15 +01:00
|
|
|
}
|
|
|
|
return 0;
|
2025-03-20 04:16:06 +01:00
|
|
|
}
|