diff --git a/Makefile b/Makefile index 683a306..ec4156c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SOURCE.d := source OBJECT.d := object LIB.d := library/ -SOURCE := main.c +SOURCE := main.c cli.c OBJECT := $(addprefix ${OBJECT.d}/,${SOURCE}) OBJECT := ${OBJECT:.c=.o} diff --git a/source/cli.c b/source/cli.c new file mode 100644 index 0000000..365a808 --- /dev/null +++ b/source/cli.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +extern void yyerror(const char * const fmt, ...); + +char * output_file_name = NULL; +char * input_file_name = NULL; + +static +const char * help_message = "\ +tbsp [options] : convert tbsp source file to C/C++ source file\n\ + -h : show help\n\ + -o : specify output file\ +"; + +static +char * default_output_name(const char * const name) { + static const char default_extension[] = ".tb.c"; + char * r; + + const int len = strlen(name); + + int i = len; + for (; i != 0; i--) { + if (name[i] == '.') { + break; + } + } + + if (i == 0) { + i = len; + } + + r = (char *)malloc(i + sizeof(default_extension)); + memcpy(r, name, i); + memcpy(r + i, default_extension, sizeof(default_extension)); + + return r; +} + +int handle_arguments(const int argc, const char * const * const argv) { + if (argc < 2) { + puts(help_message); + return 1; + } + + int opt; + while ((opt = getopt(argc, (char * const *)argv, "ho:")) != -1) { + switch (opt) { + case 'h': { + puts(help_message); + } exit(0); + case 'o': { + output_file_name = optarg; + } break; + default: { + yyerror("unknown option '%s'", argv[optind]); + } return 1; + } + } + + input_file_name = strdup(argv[argc-1]); + + if (!output_file_name) { + output_file_name = default_output_name(input_file_name); + } + + return 0; +} diff --git a/source/cli.h b/source/cli.h new file mode 100644 index 0000000..5dd9c8f --- /dev/null +++ b/source/cli.h @@ -0,0 +1,7 @@ +#ifndef CLI_H +#define CLI_H +extern char * const output_file_name; +extern char * const input_file_name; + +int handle_arguments(const int argc, const char * const * const argv); +#endif diff --git a/source/main.c b/source/main.c index 24d6214..2002b1c 100644 --- a/source/main.c +++ b/source/main.c @@ -1,12 +1,23 @@ #define _GNU_SOURCE #include +#include #include "tbsp.yy.h" #include "tbsp.tab.h" +#include "cli.h" + // XXX i am so desperate for #embed, you would not believe #include "TBSP_strings.inc" +#define CHECKED_FOPEN(target, filename, mode) do {\ + target = fopen(filename, mode);\ + if (!target) {\ + yyerror("failed to open '%s'", filename);\ + return 1;\ + }\ +} while (0) + extern int tbsp_yy_init(void); extern int tbsp_yy_deinit(void); @@ -26,6 +37,7 @@ void yyerror(const char * const fmt, ...) { va_end(args); } +static void put_rule_table(const char * const name, rule_type_t type_mask) { char * sprint_buffer; int sprint_r; @@ -47,32 +59,8 @@ void put_rule_table(const char * const name, rule_type_t type_mask) { fputs("};\n\n", yyout); } -signed main(const int argc, const char * const * const argv) { - #ifdef DEBUG - yydebug = 1; - #endif - - if (argc < 2) { - printf("%s ", argv[0]); - } - - tbsp_yy_init(); - tbsp_tab_init(); - - yyin = fopen(argv[1], "r"); - if (!yyin) { - puts("Failed to open file"); - return 1; - } - - //yyout = fopen("tbsp.c", "w"); - yyout = stdout; - - int yyparse_r = yyparse(); - if (yyparse_r) { - return 1; - } - +static +void put_output(void) { char * sprint_buffer; int sprint_r; (void)sprint_r; @@ -108,6 +96,25 @@ signed main(const int argc, const char * const * const argv) { // Code section fputs(verbatim, yyout); +} + +signed main(const int argc, const char * const * const argv) { + #ifdef DEBUG + yydebug = 1; + #endif + + if (handle_arguments(argc, argv)) { return 1; } + + tbsp_yy_init(); + tbsp_tab_init(); + + CHECKED_FOPEN(yyin, input_file_name, "r"); + CHECKED_FOPEN(yyout, output_file_name, "w"); + + int yyparse_r = yyparse(); + if (yyparse_r) { return yyparse_r; } + + put_output(); // Deinit for (int i = 0; i < kv_size(rules); i++) { @@ -116,6 +123,8 @@ signed main(const int argc, const char * const * const argv) { } tbsp_yy_deinit(); + free(output_file_name); + free(input_file_name); free(verbatim); free(language); free(top);