#define STRVIEW_IMPLEMENTATION
#include "strview.h"
#include "compiler.h"
#include "parser.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* read_file(const char* path) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
return NULL;
}
if (fseek(file, 0, SEEK_END) != 0) {
fclose(file);
return NULL;
}
long length = ftell(file);
if (length < 0 || fseek(file, 0, SEEK_SET) != 0) {
fclose(file);
return NULL;
}
char* text = malloc((size_t)length + 1);
if (text == NULL) {
fclose(file);
return NULL;
}
size_t read_count = fread(text, 1, (size_t)length, file);
bool ok = read_count == (size_t)length && !ferror(file);
fclose(file);
if (!ok) {
free(text);
return NULL;
}
text[length] = '\0';
return text;
}
static void print_error(const char* stage, const Error* error) {
if (error->line > 0) {
fprintf(stderr, "%s:%d: %s\n", stage, error->line, error->message);
} else {
fprintf(stderr, "%s: %s\n", stage, error->message);
}
}
static void usage(FILE* stream, const char* name) {
fprintf(stream, "usage: %s [-n] PROGRAM OUTPUT [SCRIPT_ARGUMENT ...]\n", name);
fprintf(stream, " -n compile and print without running ffmpeg\n");
}
int main(int argc, char** argv) {
bool dry_run = false;
int argument = 1;
if (argument < argc && sv_equal(sv_from_cstr(argv[argument]), svlit("-n"))) {
dry_run = true;
argument++;
}
if (argc - argument < 2) {
usage(stderr, argv[0]);
return 2;
}
const char* program_path = argv[argument];
const char* output_path = argv[argument + 1];
size_t script_argument_count = (size_t)(argc - argument - 2);
const char* const* script_arguments = (const char* const*)(argv + argument + 2);
char* text = read_file(program_path);
if (text == NULL) {
fprintf(stderr, "%s: cannot read %s: %s\n", argv[0], program_path, strerror(errno));
return 1;
}
Error error = {0};
Program program;
TypedProgram typed;
CompiledCommand command;
ProbeCache probes;
probe_cache_init(&probes, NULL, NULL);
if (!parse_program_with_args(text, script_argument_count, script_arguments, &program, &error)) {
print_error(program_path, &error);
free(text);
probe_cache_destroy(&probes);
return 1;
}
free(text);
if (!typecheck_program(&program, &typed, &error)) {
print_error(program_path, &error);
program_destroy(&program);
probe_cache_destroy(&probes);
return 1;
}
if (!compile_program(&program, &typed, &probes, output_path, &command, &error)) {
print_error(program_path, &error);
typed_program_destroy(&typed);
program_destroy(&program);
probe_cache_destroy(&probes);
return 1;
}
printf("%s\n", command.shell_command);
int exit_code = 0;
if (!dry_run && !execute_command(&command, &exit_code, &error)) {
print_error("ffmpeg", &error);
exit_code = 1;
}
compiled_command_destroy(&command);
typed_program_destroy(&typed);
program_destroy(&program);
probe_cache_destroy(&probes);
return exit_code;
}