/* This file is part of Eclat.
Copyright (C) 2012, 2013 Sergey Poznyakoff.
Eclat is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Eclat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Eclat. If not, see . */
#include
#include
#include
#include
#include
#ifdef HAVE_GETOPT_H
# include
#endif
#include
#include
#include
#include
#include "forlan.h"
#include
void
usage()
{
printf("usage: %s [OPTIONS] FILE [INPUT]\n", program_name);
printf("OPTIONS are:\n");
printf(" -D dump parse tree\n");
printf(" -d LEVEL set debug level\n");
printf(" -f use file interface\n");
printf(" -s sort XML tree\n");
printf(" -h produce this help list\n");
}
struct grecs_node *
parse_xml(FILE *fp)
{
XML_Parser parser;
eclat_partial_tree_t part;
size_t size;
char buffer[256];
parser = XML_ParserCreate("UTF-8");
if (!parser)
die(EX_SOFTWARE, "cannot create XML parser");
XML_SetElementHandler(parser,
eclat_partial_tree_start_handler,
eclat_partial_tree_end_handler);
XML_SetCharacterDataHandler(parser,
eclat_partial_tree_data_handler);
part = eclat_partial_tree_create();
XML_SetUserData(parser, part);
while ((size = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
enum XML_Status status = XML_Parse(parser, buffer, size, 0);
if (status == XML_STATUS_ERROR) {
enum XML_Error error = XML_GetErrorCode(parser);
int line = XML_GetCurrentLineNumber(parser);
int column = XML_GetCurrentColumnNumber(parser);
die(EX_SOFTWARE, "XML parse error at %d:%d: %s",
line, column, XML_ErrorString(error));
}
}
XML_Parse(parser, "", 0, 1);
return eclat_partial_tree_finish(part);
}
static int
node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b)
{
return strcmp(a->ident, b->ident);
}
#define OPT_DUMP 0x01
#define OPT_SORT 0x02
#define OPT_FILE 0x04
int
main(int argc, char **argv)
{
FILE *fp;
char *buf;
size_t len;
struct stat st;
struct grecs_locus_point pt;
int rc;
int options = 0;
forlan_eval_env_t env;
set_program_name(argv[0]);
forlan_init();
while ((rc = getopt(argc, argv, "Dd:fhs")) != EOF)
switch (rc) {
case 'D':
options |= OPT_DUMP;
break;
case 'd':
if (parse_debug_level(optarg))
die(EX_USAGE, "bad debug category or level");
break;
case 'f':
options |= OPT_FILE;
break;
case 'h':
usage();
return 0;
case 's':
options |= OPT_SORT;
break;
default:
exit(EX_USAGE);
}
argc -= optind;
argv += optind;
if (argc == 0 || argc > 2)
die(EX_USAGE, "one or two arguments expected");
if (stat(argv[0], &st))
die(EX_UNAVAILABLE, "cannot stat input file \"%s\": %s",
argv[0], strerror(errno));
fp = fopen(argv[0], "r");
if (!fp)
die(EX_UNAVAILABLE, "cannot open input file \"%s\": %s",
argv[0], strerror(errno));
pt.file = argv[0];
pt.line = 1;
pt.col = 0;
if (options & OPT_FILE) {
env = forlan_parse_file(fp, &pt);
} else {
len = st.st_size;
buf = grecs_malloc(len);
if (fread(buf, len, 1, fp) != 1)
die(EX_UNAVAILABLE, "error reading from \"%s\": %s",
argv[0], strerror(errno));
env = forlan_parse_buffer(buf, len, &pt);
}
fclose(fp);
if (!env)
return EX_UNAVAILABLE;
if (options & OPT_DUMP)
forlan_dump_tree(stdout, env);
if (argv[1]) {
struct grecs_node *tree;
fp = fopen(argv[1], "r");
if (!fp)
die(EX_UNAVAILABLE,
"cannot open input file \"%s\": %s",
argv[1], strerror(errno));
tree = parse_xml(fp);
fclose(fp);
if (options & OPT_SORT)
grecs_tree_sort(tree, node_ident_cmp);
rc = forlan_run(env, tree);
grecs_tree_free(tree);
} else
rc = 0;
forlan_free_environment(env);
return rc;
}