Improve parsing errors
This commit is contained in:
parent
af1de6d8fb
commit
577a1aef94
7 changed files with 129 additions and 37 deletions
2
Makefile
2
Makefile
|
|
@ -9,7 +9,7 @@ BINDIR=.
|
||||||
NAME = $(shell readlink -f . | xargs basename)
|
NAME = $(shell readlink -f . | xargs basename)
|
||||||
|
|
||||||
# global links
|
# global links
|
||||||
LDFLAGS = -lpthread
|
LDFLAGS = -Wl,--no-as-needed -lpthread
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
CC=g++
|
CC=g++
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <ztd/filedat.hpp>
|
||||||
|
|
||||||
#define INDENT indent(ind)
|
#define INDENT indent(ind)
|
||||||
|
|
||||||
extern std::string indenting_string;
|
extern std::string indenting_string;
|
||||||
|
|
@ -36,4 +38,7 @@ void _exec(std::string const& bin, std::vector<std::string> const& args);
|
||||||
|
|
||||||
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);
|
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);
|
||||||
|
|
||||||
|
void printFormatError(ztd::format_error const& e, bool print_line=true);
|
||||||
|
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line=true);
|
||||||
|
|
||||||
#endif //UTIL_HPP
|
#endif //UTIL_HPP
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ std::string pipeline::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
if(cmds.size()<=0)
|
||||||
|
return "";
|
||||||
|
|
||||||
ret += cmds[0].generate(ind);
|
ret += cmds[0].generate(ind);
|
||||||
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -57,7 +60,10 @@ std::string pipeline::generate(int ind)
|
||||||
std::string condlist::generate(int ind)
|
std::string condlist::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(!opt_minimize) ret += INDENT;
|
if(pls.size() <= 0)
|
||||||
|
return "";
|
||||||
|
if(!opt_minimize)
|
||||||
|
ret += INDENT;
|
||||||
ret += pls[0].generate(ind);
|
ret += pls[0].generate(ind);
|
||||||
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -114,7 +120,8 @@ std::string generate_resolve(std::vector<std::string> args, int ind)
|
||||||
dir=pwd();
|
dir=pwd();
|
||||||
std::string cddir=ztd::exec("dirname", g_origin).first;
|
std::string cddir=ztd::exec("dirname", g_origin).first;
|
||||||
cddir.pop_back();
|
cddir.pop_back();
|
||||||
chdir(cddir.c_str());
|
if(chdir(cddir.c_str()) != 0)
|
||||||
|
throw std::runtime_error("Cannot cd to '"+cddir+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -150,7 +157,8 @@ std::string generate_resolve(std::vector<std::string> args, int ind)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!opts['C'] && !piped)
|
if(!opts['C'] && !piped)
|
||||||
chdir(dir.c_str());
|
if(chdir(dir.c_str()) != 0)
|
||||||
|
throw std::runtime_error("Cannot cd to '"+dir+"'");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -176,7 +184,8 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
||||||
dir=pwd();
|
dir=pwd();
|
||||||
std::string cddir=ztd::exec("dirname", curfile).first;
|
std::string cddir=ztd::exec("dirname", curfile).first;
|
||||||
cddir.pop_back();
|
cddir.pop_back();
|
||||||
chdir(cddir.c_str());
|
if(chdir(cddir.c_str()) != 0)
|
||||||
|
throw std::runtime_error("Cannot cd to '"+cddir+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// do shell resolution
|
// do shell resolution
|
||||||
|
|
@ -199,7 +208,7 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
||||||
add_include(it) ) // not already included
|
add_include(it) ) // not already included
|
||||||
{
|
{
|
||||||
file=import_file(it);
|
file=import_file(it);
|
||||||
if(opts['e'])
|
if(opts['d'])
|
||||||
file = stringReplace(file, "\"", "\\\"");
|
file = stringReplace(file, "\"", "\\\"");
|
||||||
if(opts['r'])
|
if(opts['r'])
|
||||||
ret += file;
|
ret += file;
|
||||||
|
|
@ -226,7 +235,8 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!opts['C'] && !piped)
|
if(!opts['C'] && !piped)
|
||||||
chdir(dir.c_str());
|
if(chdir(dir.c_str()) != 0)
|
||||||
|
throw std::runtime_error("Cannot cd to '"+dir+"'");
|
||||||
g_origin=curfile;
|
g_origin=curfile;
|
||||||
|
|
||||||
if(!opts['r'])
|
if(!opts['r'])
|
||||||
|
|
@ -321,7 +331,7 @@ std::string block::generate(int ind, bool print_shebang)
|
||||||
// commands
|
// commands
|
||||||
for(auto it: cls)
|
for(auto it: cls)
|
||||||
ret += it.generate(ind+1);
|
ret += it.generate(ind+1);
|
||||||
if(opt_minimize)
|
if(opt_minimize && ret.size()>1)
|
||||||
ret.pop_back(); // ) can be right after command
|
ret.pop_back(); // ) can be right after command
|
||||||
else
|
else
|
||||||
ret += INDENT;
|
ret += INDENT;
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ int main(int argc, char* argv[])
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
block sh(parse(import_file(file)));
|
block sh(parse(import_file(file)));
|
||||||
if(options['E'])
|
if(options['e'])
|
||||||
{
|
{
|
||||||
std::string data=sh.generate();
|
std::string data=sh.generate();
|
||||||
// generate path
|
// generate path
|
||||||
|
|
@ -94,11 +94,13 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
catch(ztd::format_error& e)
|
catch(ztd::format_error& e)
|
||||||
{
|
{
|
||||||
printFormatException(e);
|
printFormatError(e);
|
||||||
|
return 100;
|
||||||
}
|
}
|
||||||
catch(std::exception& e)
|
catch(std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,12 @@ ztd::option_set options = gen_options();
|
||||||
bool opt_minimize;
|
bool opt_minimize;
|
||||||
bool piped=false;
|
bool piped=false;
|
||||||
|
|
||||||
|
|
||||||
ztd::option_set gen_options()
|
ztd::option_set gen_options()
|
||||||
{
|
{
|
||||||
ztd::option_set ret;
|
ztd::option_set ret;
|
||||||
ret.add(ztd::option('h', "help", false, "Display this help message"));
|
ret.add(ztd::option('h', "help", false, "Display this help message"));
|
||||||
ret.add(ztd::option('m', "minimize", false, "Minimize code"));
|
ret.add(ztd::option('m', "minimize", false, "Minimize code"));
|
||||||
ret.add(ztd::option('E', "exec", false, "Directly exec instead of outputting"));
|
ret.add(ztd::option('e', "exec", false, "Directly exec instead of outputting"));
|
||||||
ret.add(ztd::option("help-commands", false, "Print help for linker commands"));
|
ret.add(ztd::option("help-commands", false, "Print help for linker commands"));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ std::string g_origin;
|
||||||
|
|
||||||
inline bool is_in(char c, const char* set)
|
inline bool is_in(char c, const char* set)
|
||||||
{
|
{
|
||||||
return index(set, c) != NULL;
|
return strchr(set, c) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_alphanum(char c)
|
inline bool is_alphanum(char c)
|
||||||
|
|
@ -38,6 +38,15 @@ bool word_eq(const char* word, const char* in, uint32_t size, uint32_t start, co
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_word(const char* in, uint32_t size, uint32_t start, const char* end_set)
|
||||||
|
{
|
||||||
|
uint32_t i=start;
|
||||||
|
while(i<size && !is_in(in[i], end_set))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
return std::string(in+start, i-start);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t skip_chars(const char* in, uint32_t size, uint32_t start, const char* set)
|
uint32_t skip_chars(const char* in, uint32_t size, uint32_t start, const char* set)
|
||||||
{
|
{
|
||||||
for(uint32_t i=start; i<size ; i++)
|
for(uint32_t i=start; i<size ; i++)
|
||||||
|
|
@ -77,7 +86,11 @@ std::pair<arg, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start
|
||||||
{
|
{
|
||||||
arg ret;
|
arg ret;
|
||||||
// j : start of subarg
|
// j : start of subarg
|
||||||
uint32_t i=start,j=start;
|
uint32_t i=start,j=start,q=start;
|
||||||
|
|
||||||
|
if(is_in(in[i], "&|;\n#()"))
|
||||||
|
throw ztd::format_error( strf("Unexpected token '%c'", in[i]) , g_origin, in, i);
|
||||||
|
|
||||||
while(i<size && !is_in(in[i], " \t|&;\n()"))
|
while(i<size && !is_in(in[i], " \t|&;\n()"))
|
||||||
{
|
{
|
||||||
if(i+1<size && is_in(in[i], "<>") && in[i+1]=='&') // special case for <& and >&
|
if(i+1<size && is_in(in[i], "<>") && in[i+1]=='&') // special case for <& and >&
|
||||||
|
|
@ -93,15 +106,13 @@ std::pair<arg, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start
|
||||||
}
|
}
|
||||||
else if(in[i] == '"') // start double quote
|
else if(in[i] == '"') // start double quote
|
||||||
{
|
{
|
||||||
|
q=i;
|
||||||
i++;
|
i++;
|
||||||
while(i<size && in[i] != '"') // while inside quoted string
|
while(in[i] != '"') // while inside quoted string
|
||||||
{
|
{
|
||||||
if(in[i] == '\\') // backslash: don't check next char
|
if(in[i] == '\\') // backslash: don't check next char
|
||||||
{
|
{
|
||||||
i++;
|
i+=2;
|
||||||
if(i>=size)
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
else if( word_eq("$(", in, size, i) ) // substitution
|
else if( word_eq("$(", in, size, i) ) // substitution
|
||||||
{
|
{
|
||||||
|
|
@ -115,18 +126,20 @@ std::pair<arg, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
if(i>=size)
|
if(i>=size)
|
||||||
break;
|
throw ztd::format_error("Unterminated double quote", g_origin, in, q);
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if(in[i] == '\'') // start single quote
|
else if(in[i] == '\'') // start single quote
|
||||||
{
|
{
|
||||||
|
q=i;
|
||||||
i++;
|
i++;
|
||||||
while(i<size && in[i]!='\'')
|
while(i<size && in[i]!='\'')
|
||||||
i++;
|
i++;
|
||||||
if(i>=size)
|
if(i>=size)
|
||||||
break;
|
throw ztd::format_error("Unterminated single quote", g_origin, in, q);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if( word_eq("$(", in, size, i) ) // substitution
|
else if( word_eq("$(", in, size, i) ) // substitution
|
||||||
|
|
@ -155,10 +168,17 @@ std::pair<arg, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start
|
||||||
// must start at a read char
|
// must start at a read char
|
||||||
// first char has to be read
|
// first char has to be read
|
||||||
// ends at either &|;\n#()
|
// ends at either &|;\n#()
|
||||||
std::pair<arglist, uint32_t> parse_arglist(const char* in, uint32_t size, uint32_t start)
|
std::pair<arglist, uint32_t> parse_arglist(const char* in, uint32_t size, uint32_t start, bool hard_error=false)
|
||||||
{
|
{
|
||||||
uint32_t i=start;
|
uint32_t i=start;
|
||||||
arglist ret;
|
arglist ret;
|
||||||
|
if(is_in(in[i], "&|;\n#(){}"))
|
||||||
|
{
|
||||||
|
if(hard_error)
|
||||||
|
throw ztd::format_error( strf("Unexpected token '%c'", in[i]) , g_origin, in, i);
|
||||||
|
else
|
||||||
|
return std::make_pair(ret, i);
|
||||||
|
}
|
||||||
while(i<size)
|
while(i<size)
|
||||||
{
|
{
|
||||||
auto pp=parse_arg(in, size, i);
|
auto pp=parse_arg(in, size, i);
|
||||||
|
|
@ -178,7 +198,7 @@ std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t s
|
||||||
// ends at either &;\n#)
|
// ends at either &;\n#)
|
||||||
std::pair<pipeline, uint32_t> parse_pipeline(const char* in, uint32_t size, uint32_t start)
|
std::pair<pipeline, uint32_t> parse_pipeline(const char* in, uint32_t size, uint32_t start)
|
||||||
{
|
{
|
||||||
uint32_t i = skip_unread(in, size, start);
|
uint32_t i=start;
|
||||||
pipeline ret;
|
pipeline ret;
|
||||||
while(i<size)
|
while(i<size)
|
||||||
{
|
{
|
||||||
|
|
@ -237,6 +257,9 @@ std::pair<condlist, uint32_t> parse_condlist(const char* in, uint32_t size, uint
|
||||||
throw ztd::format_error( strf("Unexpected token: '%c%c'", in[i], in[i+1]), g_origin, in, i);
|
throw ztd::format_error( strf("Unexpected token: '%c%c'", in[i], in[i+1]), g_origin, in, i);
|
||||||
else // unknown
|
else // unknown
|
||||||
throw ztd::format_error("Unknown error", g_origin, in, i);
|
throw ztd::format_error("Unknown error", g_origin, in, i);
|
||||||
|
i = skip_unread(in, size, i);
|
||||||
|
if(i>=size)
|
||||||
|
throw ztd::format_error( "Unexpected end of file", g_origin, in, i );
|
||||||
}
|
}
|
||||||
return std::make_pair(ret, i);
|
return std::make_pair(ret, i);
|
||||||
}
|
}
|
||||||
|
|
@ -248,14 +271,16 @@ std::pair<block, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_
|
||||||
{
|
{
|
||||||
uint32_t i = skip_unread(in, size, start);
|
uint32_t i = skip_unread(in, size, start);
|
||||||
block ret(block::subshell);
|
block ret(block::subshell);
|
||||||
while(i<size && in[i] != ')')
|
while(in[i] != ')')
|
||||||
{
|
{
|
||||||
auto pp=parse_condlist(in, size, i);
|
auto pp=parse_condlist(in, size, i);
|
||||||
ret.cls.push_back(pp.first);
|
ret.cls.push_back(pp.first);
|
||||||
i = skip_unread(in, size, pp.second);
|
i = skip_unread(in, size, pp.second);
|
||||||
}
|
|
||||||
if(i>=size)
|
if(i>=size)
|
||||||
throw ztd::format_error("Expecting )", g_origin, in, start-1);
|
throw ztd::format_error("Expecting )", g_origin, in, start-1);
|
||||||
|
}
|
||||||
|
if(ret.cls.size()<=0)
|
||||||
|
throw ztd::format_error("Subshell is empty", g_origin, in, start-1);
|
||||||
i++;
|
i++;
|
||||||
return std::make_pair(ret,i);
|
return std::make_pair(ret,i);
|
||||||
}
|
}
|
||||||
|
|
@ -267,17 +292,18 @@ std::pair<block, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t s
|
||||||
{
|
{
|
||||||
uint32_t i = skip_unread(in, size, start);
|
uint32_t i = skip_unread(in, size, start);
|
||||||
block ret(block::brace);
|
block ret(block::brace);
|
||||||
while(i<size && in[i] != '}')
|
while(in[i] != '}')
|
||||||
{
|
{
|
||||||
auto pp=parse_condlist(in, size, i);
|
auto pp=parse_condlist(in, size, i);
|
||||||
ret.cls.push_back(pp.first);
|
ret.cls.push_back(pp.first);
|
||||||
i = skip_unread(in, size, pp.second);
|
i = skip_unread(in, size, pp.second);
|
||||||
|
if(i>=size)
|
||||||
|
throw ztd::format_error("Expecting }", g_origin, in, start-1);
|
||||||
if(is_in(in[i], ")"))
|
if(is_in(in[i], ")"))
|
||||||
throw ztd::format_error( strf("Unexpected token: '%c'", in[i]) , g_origin, in, i );
|
throw ztd::format_error( strf("Unexpected token: '%c'", in[i]) , g_origin, in, i );
|
||||||
}
|
}
|
||||||
if(i>=size)
|
if(ret.cls.size()<=0)
|
||||||
throw ztd::format_error("Expecting }", g_origin, in, start-1);
|
throw ztd::format_error("Brace block is empty", g_origin, in, start-1);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
return std::make_pair(ret,i);
|
return std::make_pair(ret,i);
|
||||||
|
|
@ -321,7 +347,7 @@ std::pair<block, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t sta
|
||||||
}
|
}
|
||||||
else // is a command
|
else // is a command
|
||||||
{
|
{
|
||||||
auto pp=parse_arglist(in, size, start);
|
auto pp=parse_arglist(in, size, start, true);
|
||||||
ret.args = pp.first;
|
ret.args = pp.first;
|
||||||
i = pp.second;
|
i = pp.second;
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +361,7 @@ std::pair<block, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t sta
|
||||||
std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start)
|
std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start)
|
||||||
{
|
{
|
||||||
block ret(block::case_block);
|
block ret(block::case_block);
|
||||||
uint32_t i=skip_unread(in, size, start);;
|
uint32_t i=skip_chars(in, size, start, " \t");;
|
||||||
|
|
||||||
// get the treated argument
|
// get the treated argument
|
||||||
auto pa = parse_arg(in, size, i);
|
auto pa = parse_arg(in, size, i);
|
||||||
|
|
@ -343,10 +369,10 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
|
||||||
i=skip_unread(in, size, pa.second);
|
i=skip_unread(in, size, pa.second);
|
||||||
|
|
||||||
// must be an 'in'
|
// must be an 'in'
|
||||||
if(!word_eq("in", in, size, i))
|
if(!word_eq("in", in, size, i, " \t\n"))
|
||||||
{
|
{
|
||||||
auto pp=parse_arg(in, size, i);
|
std::string pp=get_word(in, size, i, " \t\n");
|
||||||
throw ztd::format_error("Unexpected word: '"+pp.first.raw+"', expecting 'in' after case", g_origin, in, i);
|
throw ztd::format_error("Unexpected word: '"+pp+"', expecting 'in' after case", g_origin, in, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
i=skip_unread(in, size, i+2);
|
i=skip_unread(in, size, i+2);
|
||||||
|
|
@ -357,6 +383,8 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
|
||||||
// toto)
|
// toto)
|
||||||
std::pair<arg, list_t> cc;
|
std::pair<arg, list_t> cc;
|
||||||
pa = parse_arg(in, size, i);
|
pa = parse_arg(in, size, i);
|
||||||
|
if(pa.first.raw == "")
|
||||||
|
throw ztd::format_error("Empty case value", g_origin, in, i);
|
||||||
cc.first = pa.first;
|
cc.first = pa.first;
|
||||||
i=skip_unread(in, size, pa.second);
|
i=skip_unread(in, size, pa.second);
|
||||||
|
|
||||||
|
|
@ -410,6 +438,8 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
|
||||||
std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t start)
|
std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t start)
|
||||||
{
|
{
|
||||||
uint32_t i = skip_chars(in, size, start, " \n\t");
|
uint32_t i = skip_chars(in, size, start, " \n\t");
|
||||||
|
if(i>=size)
|
||||||
|
throw ztd::format_error("Unexpected end of file", g_origin, in, i);
|
||||||
std::pair<block, uint32_t> ret;
|
std::pair<block, uint32_t> ret;
|
||||||
if(in[i] == '{') // brace block
|
if(in[i] == '{') // brace block
|
||||||
{
|
{
|
||||||
|
|
@ -431,7 +461,7 @@ std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t s
|
||||||
}
|
}
|
||||||
if(ret.first.args.args.size()<=0)
|
if(ret.first.args.args.size()<=0)
|
||||||
{
|
{
|
||||||
auto pp=parse_arglist(in, size, ret.second); // in case of redirects
|
auto pp=parse_arglist(in, size, ret.second, false); // in case of redirects
|
||||||
ret.second=pp.second;
|
ret.second=pp.second;
|
||||||
ret.first.args=pp.first;
|
ret.first.args=pp.first;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
src/util.cpp
46
src/util.cpp
|
|
@ -89,3 +89,49 @@ std::string stringReplace(std::string subject, const std::string& search, const
|
||||||
}
|
}
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printFormatError(ztd::format_error const& e, bool print_line)
|
||||||
|
{
|
||||||
|
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string repeatString(std::string const& str, uint32_t n)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for(uint32_t i=0; i<n; i++)
|
||||||
|
ret += str;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line)
|
||||||
|
{
|
||||||
|
int i=0, j=0; // j: last newline
|
||||||
|
int line=1; //n: line #
|
||||||
|
int in_size=strlen(in);
|
||||||
|
if(index >= 0)
|
||||||
|
{
|
||||||
|
while(i < in_size && i < index)
|
||||||
|
{
|
||||||
|
if(in[i] == '\n')
|
||||||
|
{
|
||||||
|
line++;
|
||||||
|
j=i+1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while(i < in_size && in[i]!='\n')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(origin != "")
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s:%u:%u: %s\n", origin.c_str(), line, index-j+1, message.c_str());
|
||||||
|
if(print_line)
|
||||||
|
{
|
||||||
|
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||||
|
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue