contra/source/cli.cpp
2023-11-19 22:13:04 +01:00

205 lines
4.5 KiB
C++

#include "cli.hpp"
#include <getopt.h>
#include <stdio.h>
#include <string.h>
#include <stack>
#include "exit_values.hpp"
#include "scanner.hpp"
#define DECLARE_LEXER(x) \
extern FILE * x ## _in; \
extern FILE * x ## _out; \
extern int x ## _lex(void); \
DECLARE_LEXER(csml);
DECLARE_LEXER(xml);
extern std::stack<std::string> csml_tag_stack;
extern unsigned xml_tag_stack;
const char * const csml_extension = ".csml";
static
const char * const version =
# include "version.inc"
;
static
const char * const help_message =
"contra [options] <file>+\n"
" -c : the input is to be force interpeted as CSML\n"
" -x : the input is to be force interpeted as XML/HTML\n"
" -s <string> : colon separeted list of option sets\n"
" -S <string> : colon separeted list of special asymetric tags starters\n"
" -i <string> : colon separeted list of tags which contents should be ignored\n"
" -o <file> : specify output file name for the NEXT file\n"
" -q <char> : use <char> for quoting (default: \"'\")\n"
" -v : print version and quit\n"
" -h : print help and quit\n"
;
const char * output = NULL;
const char * input = NULL;
enum class input_type_t {
CSML,
XML,
AUTO_DETECT,
} input_type = input_type_t::AUTO_DETECT;
// ### Local functions ###
static
inline
void try_fopen(FILE * &file, const char * const path, const char * const mode) {
file = fopen(path, mode);
if (!file) {
fprintf(stderr, "Error opening file '%s'.\n", path);
fflush(stderr);
exit(IO_ERROR);
}
}
static
void yylex(FILE * &yyin, FILE * &yyout, int (*yylex_)(void)) {
if (output) {
try_fopen(yyout, output, "w");
} else {
yyout = stdout;
}
try_fopen(yyin, input, "r");
yylex_();
if (yyin != stdin) {
fclose(yyin);
}
if (yyout != stdout) {
fclose(yyout);
}
}
// ### global functions ###
extern "C"
signed parse_round1_arguments(int argc, char * * argv){
const char * const optstring = "-" "hv" "cxs:S:i:o:q:";
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
char opt;
while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
case 'h': {
fputs(help_message, stdout);
} return EXIT_EARLY_SUCCESS;
case 'v': {
fputs(version, stdout);
} return EXIT_EARLY_SUCCESS;
case '?': {
} return UNKNOWN_OPTION;
default: {
} break;
}
}
return 0;
}
extern "C"
signed parse_round2_arguments(int argc, char * * argv) {
for (int n = 0; n < argc; n++) {
if (!strcmp(argv[n], "-c")) {
input_type = input_type_t::CSML;
} else if (!strcmp(argv[n], "-x")) {
input_type = input_type_t::XML;
} else if (!strcmp(argv[n], "-q")) {
++n;
quote = argv[n][0];
} else if (!strcmp(argv[n], "-i")) {
++n;
parse_colon_list(argv[n], ignore_list);
} else if (!strcmp(argv[n], "-s")) {
++n;
const int err = parse_sets(argv[n]);
if (err) {
exit(err);
}
} else if (!strcmp(argv[n], "-S")) {
++n;
parse_colon_list(argv[n], asymmetric_special_list);
} else if (!strcmp(argv[n], "-o")) {
++n;
output = argv[n];
} else {
input = argv[n];
if (input_type == input_type_t::AUTO_DETECT) {
if (!strcmp(input + strlen(input) - (sizeof(csml_extension)-1), csml_extension)) {
input_type = input_type_t::CSML;
} else {
input_type = input_type_t::XML;
}
}
switch (input_type) {
case input_type_t::CSML: {
yylex(csml_in, csml_out, csml_lex);
if (not csml_tag_stack.empty()) {
exit(POPULATED_STACK);
}
} break;
case input_type_t::XML: {
yylex(xml_in, xml_out, xml_lex);
if(xml_tag_stack) {
exit(POPULATED_STACK);
}
} break;
default: {
};
}
output = NULL;
}
}
return 0;
}
extern "C"
signed parse_colon_list(char * const list, std::vector<std::string> destination) {
const char * delimiter = ":";
char * data = strtok(list, delimiter);
int i = 0;
do {
destination.emplace_back(data);
++i;
} while((data = strtok(NULL, delimiter), data));
return 0;
}
extern "C"
signed parse_sets(char * const list) {
const char * delimiter = ":";
char * data = strtok(list, delimiter);
int i = 0;
do {
if (!strcmp(data, "html")) {
ignore_list.emplace_back("style");
ignore_list.emplace_back("script");
asymmetric_special_list.emplace_back("?");
} else {
return UNKNOWN_SET;
}
++i;
} while((data = strtok(NULL, delimiter), data));
return 0;
}