feat: c-md transpiler v0.0.1
This commit is contained in:
parent
f4e51df5e8
commit
8c0ed3462f
28 changed files with 791 additions and 10 deletions
2
Makefile
2
Makefile
|
|
@ -33,7 +33,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||||
test: $(TEST_BIN)
|
test: $(TEST_BIN)
|
||||||
./$(TEST_BIN)
|
./$(TEST_BIN)
|
||||||
|
|
||||||
$(TEST_BIN): $(TESTS) $(filter %.o,$(OBJS))
|
$(TEST_BIN): $(TESTS) $(filter-out $(OBJ_DIR)/main.o,$(OBJS))
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
|
|
||||||
21
includes/cli.h
Normal file
21
includes/cli.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef CLI_H
|
||||||
|
# define CLI_H
|
||||||
|
|
||||||
|
# include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct s_args
|
||||||
|
{
|
||||||
|
const char *ext;
|
||||||
|
const char *input;
|
||||||
|
const char *output;
|
||||||
|
const char *map_path;
|
||||||
|
uint8_t show_help;
|
||||||
|
} t_args;
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
cli_parse(t_args *args, int32_t argc, char **argv);
|
||||||
|
|
||||||
|
void
|
||||||
|
cli_print_help(const char *progname);
|
||||||
|
|
||||||
|
#endif
|
||||||
19
includes/internal/map_internal.h
Normal file
19
includes/internal/map_internal.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef MAP_INTERNAL_H
|
||||||
|
# define MAP_INTERNAL_H
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdint.h>
|
||||||
|
# include "map.h"
|
||||||
|
|
||||||
|
# define MAP_INIT_CAP 16
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
map_grow(t_map *map);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
write_header(FILE *f, const char *source, const char *target);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
write_ranges(FILE *f, t_map *map);
|
||||||
|
|
||||||
|
#endif
|
||||||
37
includes/internal/transpile_internal.h
Normal file
37
includes/internal/transpile_internal.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef TRANSPILE_INTERNAL_H
|
||||||
|
# define TRANSPILE_INTERNAL_H
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdint.h>
|
||||||
|
# include "map.h"
|
||||||
|
|
||||||
|
typedef struct s_state
|
||||||
|
{
|
||||||
|
FILE *in;
|
||||||
|
FILE *out;
|
||||||
|
const char *ext;
|
||||||
|
t_map *map;
|
||||||
|
uint32_t src_line;
|
||||||
|
uint32_t dst_line;
|
||||||
|
uint32_t block_src_start;
|
||||||
|
uint32_t block_dst_start;
|
||||||
|
uint8_t in_block;
|
||||||
|
uint8_t first_block;
|
||||||
|
} t_state;
|
||||||
|
|
||||||
|
void
|
||||||
|
state_init(t_state *s, FILE *in, FILE *out, const char *ext, t_map *map);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
process_line(t_state *s, char *line);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_fence_open(t_state *s, char *line);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_fence_close(t_state *s);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_code_line(t_state *s, char *line);
|
||||||
|
|
||||||
|
#endif
|
||||||
19
includes/io.h
Normal file
19
includes/io.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef IO_H
|
||||||
|
# define IO_H
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct s_io
|
||||||
|
{
|
||||||
|
FILE *in;
|
||||||
|
FILE *out;
|
||||||
|
} t_io;
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
io_open(t_io *io, const char *input_path, const char *output_path);
|
||||||
|
|
||||||
|
void
|
||||||
|
io_close(t_io *io);
|
||||||
|
|
||||||
|
#endif
|
||||||
35
includes/map.h
Normal file
35
includes/map.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef MAP_H
|
||||||
|
# define MAP_H
|
||||||
|
|
||||||
|
# include <stddef.h>
|
||||||
|
# include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct s_range
|
||||||
|
{
|
||||||
|
uint32_t src_start;
|
||||||
|
uint32_t src_end;
|
||||||
|
uint32_t dst_start;
|
||||||
|
uint32_t dst_end;
|
||||||
|
} t_range;
|
||||||
|
|
||||||
|
typedef struct s_map
|
||||||
|
{
|
||||||
|
t_range *ranges;
|
||||||
|
size_t count;
|
||||||
|
size_t capacity;
|
||||||
|
} t_map;
|
||||||
|
|
||||||
|
void
|
||||||
|
map_init(t_map *map);
|
||||||
|
|
||||||
|
void
|
||||||
|
map_add(t_map *map, uint32_t src_start, uint32_t src_end,
|
||||||
|
uint32_t dst_start, uint32_t dst_end);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
map_write(t_map *map, const char *path, const char *source, const char *target);
|
||||||
|
|
||||||
|
void
|
||||||
|
map_free(t_map *map);
|
||||||
|
|
||||||
|
#endif
|
||||||
11
includes/transpile.h
Normal file
11
includes/transpile.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef TRANSPILE_H
|
||||||
|
# define TRANSPILE_H
|
||||||
|
|
||||||
|
# include <stdint.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
# include "map.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
transpile(FILE *in, FILE *out, const char *ext, t_map *map);
|
||||||
|
|
||||||
|
#endif
|
||||||
22
includes/utils.h
Normal file
22
includes/utils.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef UTILS_H
|
||||||
|
# define UTILS_H
|
||||||
|
|
||||||
|
# include <stdint.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
|
||||||
|
char *
|
||||||
|
read_line(FILE *f);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
starts_with(const char *str, const char *prefix);
|
||||||
|
|
||||||
|
char *
|
||||||
|
extract_fence_ext(const char *fence);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
extract_file_ext(const char *path);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
infer_ext_from_filename(const char *path);
|
||||||
|
|
||||||
|
#endif
|
||||||
10
includes/validator.h
Normal file
10
includes/validator.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef VALIDATOR_H
|
||||||
|
# define VALIDATOR_H
|
||||||
|
|
||||||
|
# include <stdint.h>
|
||||||
|
# include "cli.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
validator_validate_args(t_args *args);
|
||||||
|
|
||||||
|
#endif
|
||||||
23
sources.mk
23
sources.mk
|
|
@ -1,6 +1,25 @@
|
||||||
|
|
||||||
SRC_DIR = srcs
|
SRC_DIR = srcs
|
||||||
SRCS = $(SRC_DIR)/main.c
|
SRCS = $(SRC_DIR)/main.c \
|
||||||
|
$(SRC_DIR)/io/streams.c \
|
||||||
|
$(SRC_DIR)/utils/io/read_line.c \
|
||||||
|
$(SRC_DIR)/utils/string/starts_with.c \
|
||||||
|
$(SRC_DIR)/utils/string/extract_fence_ext.c \
|
||||||
|
$(SRC_DIR)/utils/string/extract_file_ext.c \
|
||||||
|
$(SRC_DIR)/utils/string/infer_ext_from_filename.c \
|
||||||
|
$(SRC_DIR)/transpile/state.c \
|
||||||
|
$(SRC_DIR)/transpile/fence.c \
|
||||||
|
$(SRC_DIR)/transpile/code.c \
|
||||||
|
$(SRC_DIR)/transpile/core.c \
|
||||||
|
$(SRC_DIR)/map/core.c \
|
||||||
|
$(SRC_DIR)/map/io.c \
|
||||||
|
$(SRC_DIR)/cli/cli.c \
|
||||||
|
$(SRC_DIR)/cli/help.c \
|
||||||
|
$(SRC_DIR)/validator/validator.c
|
||||||
|
|
||||||
TESTS_DIR = tests
|
TESTS_DIR = tests
|
||||||
TESTS= $(TESTS_DIR)/test_main.c
|
TESTS = $(TESTS_DIR)/test_utils.c \
|
||||||
|
$(TESTS_DIR)/test_map.c \
|
||||||
|
$(TESTS_DIR)/test_transpile.c \
|
||||||
|
$(TESTS_DIR)/test_cli.c \
|
||||||
|
$(TESTS_DIR)/test_integration.c
|
||||||
|
|
|
||||||
111
srcs/cli/cli.c
Normal file
111
srcs/cli/cli.c
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cli.h"
|
||||||
|
|
||||||
|
typedef void (*t_handler)(t_args *, const char *);
|
||||||
|
|
||||||
|
typedef struct s_opt
|
||||||
|
{
|
||||||
|
int8_t short_opt;
|
||||||
|
t_handler handler;
|
||||||
|
} t_opt;
|
||||||
|
|
||||||
|
static void handle_help(t_args *args, const char *value);
|
||||||
|
static void handle_ext(t_args *args, const char *value);
|
||||||
|
static void handle_input(t_args *args, const char *value);
|
||||||
|
static void handle_output(t_args *args, const char *value);
|
||||||
|
static void handle_map(t_args *args, const char *value);
|
||||||
|
static t_handler find_handler(int8_t opt);
|
||||||
|
static void init_args(t_args *args);
|
||||||
|
|
||||||
|
static const t_opt g_opts[] = {
|
||||||
|
{'h', handle_help},
|
||||||
|
{'e', handle_ext},
|
||||||
|
{'i', handle_input},
|
||||||
|
{'o', handle_output},
|
||||||
|
{'m', handle_map},
|
||||||
|
{0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct option g_long_opts[] = {
|
||||||
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"ext", required_argument, NULL, 'e'},
|
||||||
|
{"input", required_argument, NULL, 'i'},
|
||||||
|
{"map", required_argument, NULL, 'm'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
cli_parse(t_args *args, int32_t argc, char **argv)
|
||||||
|
{
|
||||||
|
int32_t opt;
|
||||||
|
t_handler handler;
|
||||||
|
|
||||||
|
init_args(args);
|
||||||
|
while (-1 != (opt = getopt_long(argc, argv, "he:i:o:m:", g_long_opts, NULL)))
|
||||||
|
{
|
||||||
|
handler = find_handler((int8_t)opt);
|
||||||
|
if (NULL == handler)
|
||||||
|
return (-1);
|
||||||
|
handler(args, optarg);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_args(t_args *args)
|
||||||
|
{
|
||||||
|
args->ext = NULL;
|
||||||
|
args->input = NULL;
|
||||||
|
args->output = NULL;
|
||||||
|
args->map_path = NULL;
|
||||||
|
args->show_help = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_handler
|
||||||
|
find_handler(int8_t opt)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (0 != g_opts[i].short_opt)
|
||||||
|
{
|
||||||
|
if (opt == g_opts[i].short_opt)
|
||||||
|
return (g_opts[i].handler);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_help(t_args *args, const char *value)
|
||||||
|
{
|
||||||
|
(void)value;
|
||||||
|
args->show_help = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_ext(t_args *args, const char *value)
|
||||||
|
{
|
||||||
|
args->ext = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_input(t_args *args, const char *value)
|
||||||
|
{
|
||||||
|
args->input = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_output(t_args *args, const char *value)
|
||||||
|
{
|
||||||
|
args->output = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_map(t_args *args, const char *value)
|
||||||
|
{
|
||||||
|
args->map_path = value;
|
||||||
|
}
|
||||||
21
srcs/cli/help.c
Normal file
21
srcs/cli/help.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cli.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
cli_print_help(const char *progname)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [OPTIONS]\n\n", progname);
|
||||||
|
fprintf(stderr, "Extract code blocks from literate markdown files.\n\n");
|
||||||
|
fprintf(stderr, "Options:\n");
|
||||||
|
fprintf(stderr, " -h, --help Show this help\n");
|
||||||
|
fprintf(stderr, " -e, --ext EXT Extension to extract (c, h, py, etc.)\n");
|
||||||
|
fprintf(stderr, " Required for stdin, optional for files\n");
|
||||||
|
fprintf(stderr, " -i, --input FILE Input file (default: stdin)\n");
|
||||||
|
fprintf(stderr, " -o, --output FILE Output file (default: stdout)\n");
|
||||||
|
fprintf(stderr, " -m, --map FILE Generate line mapping file\n\n");
|
||||||
|
fprintf(stderr, "Examples:\n");
|
||||||
|
fprintf(stderr, " %s -e c < input.md > output.c\n", progname);
|
||||||
|
fprintf(stderr, " %s -i main.c.md -o main.c\n", progname);
|
||||||
|
fprintf(stderr, " %s -e h -i file.md -o file.h -m file.map\n", progname);
|
||||||
|
}
|
||||||
32
srcs/io/streams.c
Normal file
32
srcs/io/streams.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
io_open(t_io *io, const char *input_path, const char *output_path)
|
||||||
|
{
|
||||||
|
io->in = (NULL != input_path) ? fopen(input_path, "r") : stdin;
|
||||||
|
if (NULL == io->in)
|
||||||
|
{
|
||||||
|
perror(input_path);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
io->out = (NULL != output_path) ? fopen(output_path, "w") : stdout;
|
||||||
|
if (NULL == io->out)
|
||||||
|
{
|
||||||
|
perror(output_path);
|
||||||
|
if (io->in != stdin)
|
||||||
|
fclose(io->in);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
io_close(t_io *io)
|
||||||
|
{
|
||||||
|
if (NULL != io->in && io->in != stdin)
|
||||||
|
fclose(io->in);
|
||||||
|
if (NULL != io->out && io->out != stdout)
|
||||||
|
fclose(io->out);
|
||||||
|
}
|
||||||
65
srcs/main.c
65
srcs/main.c
|
|
@ -1,6 +1,67 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cli.h"
|
||||||
|
#include "validator.h"
|
||||||
|
#include "transpile.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
static int8_t run(t_args *args);
|
||||||
|
static void print_error(int8_t code, const char *progname);
|
||||||
|
|
||||||
int
|
int
|
||||||
main()
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
return 0;
|
t_args args;
|
||||||
|
int8_t validation_code;
|
||||||
|
|
||||||
|
if (0 != cli_parse(&args, (int32_t)argc, argv))
|
||||||
|
{
|
||||||
|
cli_print_help(argv[0]);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (args.show_help)
|
||||||
|
{
|
||||||
|
cli_print_help(argv[0]);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
validation_code = validator_validate_args(&args);
|
||||||
|
if (0 != validation_code)
|
||||||
|
{
|
||||||
|
print_error(validation_code, argv[0]);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (run(&args));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_error(int8_t code, const char *progname)
|
||||||
|
{
|
||||||
|
if (1 == code)
|
||||||
|
fprintf(stderr, "Error: -e required when reading from stdin\n");
|
||||||
|
else if (2 == code)
|
||||||
|
fprintf(stderr, "Error: -e required (cannot infer from filename)\n");
|
||||||
|
cli_print_help(progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t
|
||||||
|
run(t_args *args)
|
||||||
|
{
|
||||||
|
t_io io;
|
||||||
|
t_map map;
|
||||||
|
int8_t ret;
|
||||||
|
|
||||||
|
if (0 != io_open(&io, args->input, args->output))
|
||||||
|
return (1);
|
||||||
|
map_init(&map);
|
||||||
|
ret = transpile(io.in, io.out, args->ext, &map);
|
||||||
|
if (0 == ret && NULL != args->map_path)
|
||||||
|
{
|
||||||
|
ret = map_write(&map, args->map_path,
|
||||||
|
(NULL != args->input) ? args->input : "stdin",
|
||||||
|
(NULL != args->output) ? args->output : "stdout");
|
||||||
|
}
|
||||||
|
map_free(&map);
|
||||||
|
io_close(&io);
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
srcs/map/core.c
Normal file
55
srcs/map/core.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
#include "internal/map_internal.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
map_init(t_map *map)
|
||||||
|
{
|
||||||
|
map->ranges = NULL;
|
||||||
|
map->count = 0;
|
||||||
|
map->capacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
map_add(t_map *map, uint32_t src_start, uint32_t src_end,
|
||||||
|
uint32_t dst_start, uint32_t dst_end)
|
||||||
|
{
|
||||||
|
t_range *range;
|
||||||
|
|
||||||
|
if (map->count >= map->capacity)
|
||||||
|
{
|
||||||
|
if (0 != map_grow(map))
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
range = &map->ranges[map->count];
|
||||||
|
range->src_start = src_start;
|
||||||
|
range->src_end = src_end;
|
||||||
|
range->dst_start = dst_start;
|
||||||
|
range->dst_end = dst_end;
|
||||||
|
map->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
map_free(t_map *map)
|
||||||
|
{
|
||||||
|
free(map->ranges);
|
||||||
|
map->ranges = NULL;
|
||||||
|
map->count = 0;
|
||||||
|
map->capacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
map_grow(t_map *map)
|
||||||
|
{
|
||||||
|
size_t new_cap;
|
||||||
|
t_range *new_ranges;
|
||||||
|
|
||||||
|
new_cap = (0 == map->capacity) ? MAP_INIT_CAP : map->capacity * 2;
|
||||||
|
new_ranges = realloc(map->ranges, new_cap * sizeof(t_range));
|
||||||
|
if (NULL == new_ranges)
|
||||||
|
return (1);
|
||||||
|
map->ranges = new_ranges;
|
||||||
|
map->capacity = new_cap;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
55
srcs/map/io.c
Normal file
55
srcs/map/io.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
#include "internal/map_internal.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
write_header(FILE *f, const char *source, const char *target)
|
||||||
|
{
|
||||||
|
if (0 > fprintf(f, "C-MD MAP v1\n"))
|
||||||
|
return (1);
|
||||||
|
if (0 > fprintf(f, "source: %s\n", source))
|
||||||
|
return (1);
|
||||||
|
if (0 > fprintf(f, "target: %s\n", target))
|
||||||
|
return (1);
|
||||||
|
if (0 > fprintf(f, "---\n"))
|
||||||
|
return (1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
write_ranges(FILE *f, t_map *map)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
t_range *r;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < map->count)
|
||||||
|
{
|
||||||
|
r = &map->ranges[i];
|
||||||
|
if (0 > fprintf(f, "%u-%u:%u-%u\n",
|
||||||
|
r->src_start, r->src_end, r->dst_start, r->dst_end))
|
||||||
|
return (1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
map_write(t_map *map, const char *path, const char *source, const char *target)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int8_t ret;
|
||||||
|
|
||||||
|
f = fopen(path, "w");
|
||||||
|
if (NULL == f)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
ret = write_header(f, source, target);
|
||||||
|
if (0 == ret)
|
||||||
|
ret = write_ranges(f, map);
|
||||||
|
fclose(f);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
12
srcs/transpile/code.c
Normal file
12
srcs/transpile/code.c
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "internal/transpile_internal.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_code_line(t_state *s, char *line)
|
||||||
|
{
|
||||||
|
if (0 > fputs(line, s->out))
|
||||||
|
return (1);
|
||||||
|
s->dst_line++;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
38
srcs/transpile/core.c
Normal file
38
srcs/transpile/core.c
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "transpile.h"
|
||||||
|
#include "internal/transpile_internal.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
process_line(t_state *s, char *line)
|
||||||
|
{
|
||||||
|
s->src_line++;
|
||||||
|
if (0 == s->in_block && starts_with(line, "```"))
|
||||||
|
return (handle_fence_open(s, line));
|
||||||
|
if (1 == s->in_block && starts_with(line, "```"))
|
||||||
|
return (handle_fence_close(s));
|
||||||
|
if (1 == s->in_block)
|
||||||
|
return (handle_code_line(s, line));
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
transpile(FILE *in, FILE *out, const char *ext, t_map *map)
|
||||||
|
{
|
||||||
|
t_state s;
|
||||||
|
char *line;
|
||||||
|
int8_t ret;
|
||||||
|
|
||||||
|
state_init(&s, in, out, ext, map);
|
||||||
|
ret = 0;
|
||||||
|
line = read_line(in);
|
||||||
|
while (NULL != line && 0 == ret)
|
||||||
|
{
|
||||||
|
ret = process_line(&s, line);
|
||||||
|
free(line);
|
||||||
|
line = read_line(in);
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
50
srcs/transpile/fence.c
Normal file
50
srcs/transpile/fence.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "internal/transpile_internal.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_fence_open(t_state *s, char *line)
|
||||||
|
{
|
||||||
|
char *block_ext;
|
||||||
|
|
||||||
|
block_ext = extract_fence_ext(line);
|
||||||
|
if (NULL == block_ext)
|
||||||
|
return (0);
|
||||||
|
if (0 != strcmp(block_ext, s->ext))
|
||||||
|
{
|
||||||
|
free(block_ext);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
free(block_ext);
|
||||||
|
if (0 == s->first_block)
|
||||||
|
{
|
||||||
|
if (0 > fprintf(s->out, "\n"))
|
||||||
|
return (1);
|
||||||
|
s->dst_line++;
|
||||||
|
}
|
||||||
|
s->first_block = 0;
|
||||||
|
s->in_block = 1;
|
||||||
|
s->block_src_start = s->src_line + 1;
|
||||||
|
s->block_dst_start = s->dst_line + 1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
handle_fence_close(t_state *s)
|
||||||
|
{
|
||||||
|
uint32_t src_end;
|
||||||
|
uint32_t dst_end;
|
||||||
|
|
||||||
|
s->in_block = 0;
|
||||||
|
src_end = s->src_line - 1;
|
||||||
|
dst_end = s->dst_line;
|
||||||
|
if (s->block_src_start <= src_end)
|
||||||
|
{
|
||||||
|
map_add(s->map, s->block_src_start, src_end,
|
||||||
|
s->block_dst_start, dst_end);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
16
srcs/transpile/state.c
Normal file
16
srcs/transpile/state.c
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "internal/transpile_internal.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
state_init(t_state *s, FILE *in, FILE *out, const char *ext, t_map *map)
|
||||||
|
{
|
||||||
|
s->in = in;
|
||||||
|
s->out = out;
|
||||||
|
s->ext = ext;
|
||||||
|
s->map = map;
|
||||||
|
s->src_line = 0;
|
||||||
|
s->dst_line = 0;
|
||||||
|
s->block_src_start = 0;
|
||||||
|
s->block_dst_start = 0;
|
||||||
|
s->in_block = 0;
|
||||||
|
s->first_block = 1;
|
||||||
|
}
|
||||||
24
srcs/utils/io/read_line.c
Normal file
24
srcs/utils/io/read_line.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
char *
|
||||||
|
read_line(FILE *f)
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
size_t len;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
line = NULL;
|
||||||
|
len = 0;
|
||||||
|
read = getline(&line, &len, f);
|
||||||
|
if (-1 == read)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
return (line);
|
||||||
|
}
|
||||||
32
srcs/utils/string/extract_fence_ext.c
Normal file
32
srcs/utils/string/extract_fence_ext.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
char *
|
||||||
|
extract_fence_ext(const char *fence)
|
||||||
|
{
|
||||||
|
const char *start;
|
||||||
|
const char *end;
|
||||||
|
size_t len;
|
||||||
|
char *ext;
|
||||||
|
|
||||||
|
if (0 != strncmp(fence, "```", 3))
|
||||||
|
return (NULL);
|
||||||
|
start = fence + 3;
|
||||||
|
while (' ' == *start || '\t' == *start)
|
||||||
|
start++;
|
||||||
|
if ('\n' == *start || '\0' == *start)
|
||||||
|
return (NULL);
|
||||||
|
end = start;
|
||||||
|
while ('\n' != *end && '\0' != *end && ' ' != *end && '\t' != *end)
|
||||||
|
end++;
|
||||||
|
len = (size_t)(end - start);
|
||||||
|
ext = malloc(len + 1);
|
||||||
|
if (NULL == ext)
|
||||||
|
return (NULL);
|
||||||
|
memcpy(ext, start, len);
|
||||||
|
ext[len] = '\0';
|
||||||
|
return (ext);
|
||||||
|
}
|
||||||
14
srcs/utils/string/extract_file_ext.c
Normal file
14
srcs/utils/string/extract_file_ext.c
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
const char *
|
||||||
|
extract_file_ext(const char *path)
|
||||||
|
{
|
||||||
|
const char *dot;
|
||||||
|
|
||||||
|
dot = strrchr(path, '.');
|
||||||
|
if (NULL == dot || dot == path)
|
||||||
|
return (NULL);
|
||||||
|
return (dot + 1);
|
||||||
|
}
|
||||||
37
srcs/utils/string/infer_ext_from_filename.c
Normal file
37
srcs/utils/string/infer_ext_from_filename.c
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
const char *
|
||||||
|
infer_ext_from_filename(const char *path)
|
||||||
|
{
|
||||||
|
static char ext_buffer[32];
|
||||||
|
const char *md_ext;
|
||||||
|
const char *before_md;
|
||||||
|
const char *dot;
|
||||||
|
size_t len;
|
||||||
|
size_t ext_len;
|
||||||
|
|
||||||
|
if (NULL == path)
|
||||||
|
return (NULL);
|
||||||
|
len = strlen(path);
|
||||||
|
if (len < 6)
|
||||||
|
return (NULL);
|
||||||
|
md_ext = path + len - 3;
|
||||||
|
if (0 != strcmp(md_ext, ".md"))
|
||||||
|
return (NULL);
|
||||||
|
before_md = md_ext - 1;
|
||||||
|
while (before_md > path && '.' != *before_md)
|
||||||
|
before_md--;
|
||||||
|
if (before_md == path || '.' != *before_md)
|
||||||
|
return (NULL);
|
||||||
|
dot = before_md;
|
||||||
|
if (dot + 1 >= md_ext)
|
||||||
|
return (NULL);
|
||||||
|
ext_len = md_ext - (dot + 1);
|
||||||
|
if (ext_len >= sizeof(ext_buffer))
|
||||||
|
return (NULL);
|
||||||
|
memcpy(ext_buffer, dot + 1, ext_len);
|
||||||
|
ext_buffer[ext_len] = '\0';
|
||||||
|
return (ext_buffer);
|
||||||
|
}
|
||||||
13
srcs/utils/string/starts_with.c
Normal file
13
srcs/utils/string/starts_with.c
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
starts_with(const char *str, const char *prefix)
|
||||||
|
{
|
||||||
|
size_t prefix_len;
|
||||||
|
|
||||||
|
prefix_len = strlen(prefix);
|
||||||
|
return (0 == strncmp(str, prefix, prefix_len));
|
||||||
|
}
|
||||||
22
srcs/validator/validator.c
Normal file
22
srcs/validator/validator.c
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "validator.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
validator_validate_args(t_args *args)
|
||||||
|
{
|
||||||
|
if (NULL == args->input)
|
||||||
|
{
|
||||||
|
if (NULL == args->ext)
|
||||||
|
return (1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (NULL == args->ext)
|
||||||
|
{
|
||||||
|
args->ext = infer_ext_from_filename(args->input);
|
||||||
|
if (NULL == args->ext)
|
||||||
|
return (2);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
#include <criterion/criterion.h>
|
|
||||||
|
|
||||||
Test(dummy, always_pass) {
|
|
||||||
cr_assert(0, "Hello, world!");
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue