205 lines
4.5 KiB
C++
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;
|
|
}
|