From 8c0ed3462fc012e2b99cbf73118b5690199fb782 Mon Sep 17 00:00:00 2001 From: lohhiiccc <96543753+lohhiiccc@users.noreply.github.com> Date: Sun, 11 Jan 2026 23:31:39 +0100 Subject: [PATCH] feat: c-md transpiler v0.0.1 --- Makefile | 2 +- includes/.gitkeep | 0 includes/cli.h | 21 ++++ includes/internal/map_internal.h | 19 ++++ includes/internal/transpile_internal.h | 37 +++++++ includes/io.h | 19 ++++ includes/map.h | 35 ++++++ includes/transpile.h | 11 ++ includes/utils.h | 22 ++++ includes/validator.h | 10 ++ sources.mk | 23 +++- srcs/cli/cli.c | 111 ++++++++++++++++++++ srcs/cli/help.c | 21 ++++ srcs/io/streams.c | 32 ++++++ srcs/main.c | 65 +++++++++++- srcs/map/core.c | 55 ++++++++++ srcs/map/io.c | 55 ++++++++++ srcs/transpile/code.c | 12 +++ srcs/transpile/core.c | 38 +++++++ srcs/transpile/fence.c | 50 +++++++++ srcs/transpile/state.c | 16 +++ srcs/utils/io/read_line.c | 24 +++++ srcs/utils/string/extract_fence_ext.c | 32 ++++++ srcs/utils/string/extract_file_ext.c | 14 +++ srcs/utils/string/infer_ext_from_filename.c | 37 +++++++ srcs/utils/string/starts_with.c | 13 +++ srcs/validator/validator.c | 22 ++++ tests/test_main.c | 5 - 28 files changed, 791 insertions(+), 10 deletions(-) delete mode 100644 includes/.gitkeep create mode 100644 includes/cli.h create mode 100644 includes/internal/map_internal.h create mode 100644 includes/internal/transpile_internal.h create mode 100644 includes/io.h create mode 100644 includes/map.h create mode 100644 includes/transpile.h create mode 100644 includes/utils.h create mode 100644 includes/validator.h create mode 100644 srcs/cli/cli.c create mode 100644 srcs/cli/help.c create mode 100644 srcs/io/streams.c create mode 100644 srcs/map/core.c create mode 100644 srcs/map/io.c create mode 100644 srcs/transpile/code.c create mode 100644 srcs/transpile/core.c create mode 100644 srcs/transpile/fence.c create mode 100644 srcs/transpile/state.c create mode 100644 srcs/utils/io/read_line.c create mode 100644 srcs/utils/string/extract_fence_ext.c create mode 100644 srcs/utils/string/extract_file_ext.c create mode 100644 srcs/utils/string/infer_ext_from_filename.c create mode 100644 srcs/utils/string/starts_with.c create mode 100644 srcs/validator/validator.c delete mode 100644 tests/test_main.c diff --git a/Makefile b/Makefile index 89dde71..9f0c987 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c test: $(TEST_BIN) ./$(TEST_BIN) -$(TEST_BIN): $(TESTS) $(filter %.o,$(OBJS)) +$(TEST_BIN): $(TESTS) $(filter-out $(OBJ_DIR)/main.o,$(OBJS)) @mkdir -p $(dir $@) $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $@ diff --git a/includes/.gitkeep b/includes/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/includes/cli.h b/includes/cli.h new file mode 100644 index 0000000..e2d6d44 --- /dev/null +++ b/includes/cli.h @@ -0,0 +1,21 @@ +#ifndef CLI_H +# define CLI_H + +# include + +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 diff --git a/includes/internal/map_internal.h b/includes/internal/map_internal.h new file mode 100644 index 0000000..3d5729b --- /dev/null +++ b/includes/internal/map_internal.h @@ -0,0 +1,19 @@ +#ifndef MAP_INTERNAL_H +# define MAP_INTERNAL_H + +# include +# include +# 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 diff --git a/includes/internal/transpile_internal.h b/includes/internal/transpile_internal.h new file mode 100644 index 0000000..5c95eee --- /dev/null +++ b/includes/internal/transpile_internal.h @@ -0,0 +1,37 @@ +#ifndef TRANSPILE_INTERNAL_H +# define TRANSPILE_INTERNAL_H + +# include +# include +# 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 diff --git a/includes/io.h b/includes/io.h new file mode 100644 index 0000000..fc26a88 --- /dev/null +++ b/includes/io.h @@ -0,0 +1,19 @@ +#ifndef IO_H +# define IO_H + +# include +# include + +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 diff --git a/includes/map.h b/includes/map.h new file mode 100644 index 0000000..a21a0af --- /dev/null +++ b/includes/map.h @@ -0,0 +1,35 @@ +#ifndef MAP_H +# define MAP_H + +# include +# include + +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 diff --git a/includes/transpile.h b/includes/transpile.h new file mode 100644 index 0000000..0147f8f --- /dev/null +++ b/includes/transpile.h @@ -0,0 +1,11 @@ +#ifndef TRANSPILE_H +# define TRANSPILE_H + +# include +# include +# include "map.h" + +int8_t +transpile(FILE *in, FILE *out, const char *ext, t_map *map); + +#endif diff --git a/includes/utils.h b/includes/utils.h new file mode 100644 index 0000000..1cf3141 --- /dev/null +++ b/includes/utils.h @@ -0,0 +1,22 @@ +#ifndef UTILS_H +# define UTILS_H + +# include +# include + +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 diff --git a/includes/validator.h b/includes/validator.h new file mode 100644 index 0000000..03178a6 --- /dev/null +++ b/includes/validator.h @@ -0,0 +1,10 @@ +#ifndef VALIDATOR_H +# define VALIDATOR_H + +# include +# include "cli.h" + +int8_t +validator_validate_args(t_args *args); + +#endif diff --git a/sources.mk b/sources.mk index 47b8ad4..7d66eb4 100644 --- a/sources.mk +++ b/sources.mk @@ -1,6 +1,25 @@ 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= $(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 diff --git a/srcs/cli/cli.c b/srcs/cli/cli.c new file mode 100644 index 0000000..eb8f2e8 --- /dev/null +++ b/srcs/cli/cli.c @@ -0,0 +1,111 @@ +#include +#include +#include + +#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; +} diff --git a/srcs/cli/help.c b/srcs/cli/help.c new file mode 100644 index 0000000..3eb251d --- /dev/null +++ b/srcs/cli/help.c @@ -0,0 +1,21 @@ +#include + +#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); +} diff --git a/srcs/io/streams.c b/srcs/io/streams.c new file mode 100644 index 0000000..9dec915 --- /dev/null +++ b/srcs/io/streams.c @@ -0,0 +1,32 @@ +#include + +#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); +} diff --git a/srcs/main.c b/srcs/main.c index d659c45..4bf24d2 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -1,6 +1,67 @@ +#include + +#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 -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); } diff --git a/srcs/map/core.c b/srcs/map/core.c new file mode 100644 index 0000000..d6b5206 --- /dev/null +++ b/srcs/map/core.c @@ -0,0 +1,55 @@ +#include + +#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); +} diff --git a/srcs/map/io.c b/srcs/map/io.c new file mode 100644 index 0000000..1732722 --- /dev/null +++ b/srcs/map/io.c @@ -0,0 +1,55 @@ +#include + +#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); +} diff --git a/srcs/transpile/code.c b/srcs/transpile/code.c new file mode 100644 index 0000000..c0d711b --- /dev/null +++ b/srcs/transpile/code.c @@ -0,0 +1,12 @@ +#include + +#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); +} diff --git a/srcs/transpile/core.c b/srcs/transpile/core.c new file mode 100644 index 0000000..6dd3e54 --- /dev/null +++ b/srcs/transpile/core.c @@ -0,0 +1,38 @@ +#include + +#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); +} diff --git a/srcs/transpile/fence.c b/srcs/transpile/fence.c new file mode 100644 index 0000000..b02722c --- /dev/null +++ b/srcs/transpile/fence.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#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); +} diff --git a/srcs/transpile/state.c b/srcs/transpile/state.c new file mode 100644 index 0000000..ee45382 --- /dev/null +++ b/srcs/transpile/state.c @@ -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; +} diff --git a/srcs/utils/io/read_line.c b/srcs/utils/io/read_line.c new file mode 100644 index 0000000..f91af4d --- /dev/null +++ b/srcs/utils/io/read_line.c @@ -0,0 +1,24 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include + +#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); +} diff --git a/srcs/utils/string/extract_fence_ext.c b/srcs/utils/string/extract_fence_ext.c new file mode 100644 index 0000000..0694dfa --- /dev/null +++ b/srcs/utils/string/extract_fence_ext.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#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); +} diff --git a/srcs/utils/string/extract_file_ext.c b/srcs/utils/string/extract_file_ext.c new file mode 100644 index 0000000..5192737 --- /dev/null +++ b/srcs/utils/string/extract_file_ext.c @@ -0,0 +1,14 @@ +#include + +#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); +} diff --git a/srcs/utils/string/infer_ext_from_filename.c b/srcs/utils/string/infer_ext_from_filename.c new file mode 100644 index 0000000..d23434a --- /dev/null +++ b/srcs/utils/string/infer_ext_from_filename.c @@ -0,0 +1,37 @@ +#include + +#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); +} diff --git a/srcs/utils/string/starts_with.c b/srcs/utils/string/starts_with.c new file mode 100644 index 0000000..ec2ede9 --- /dev/null +++ b/srcs/utils/string/starts_with.c @@ -0,0 +1,13 @@ +#include +#include + +#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)); +} diff --git a/srcs/validator/validator.c b/srcs/validator/validator.c new file mode 100644 index 0000000..cf9734e --- /dev/null +++ b/srcs/validator/validator.c @@ -0,0 +1,22 @@ +#include + +#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); +} diff --git a/tests/test_main.c b/tests/test_main.c deleted file mode 100644 index 1e3099d..0000000 --- a/tests/test_main.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -Test(dummy, always_pass) { - cr_assert(0, "Hello, world!"); -}