/***** * parser.cc * Tom Prince 2004/01/10 * *****/ #include #include #include #include #include #include "common.h" #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_LIBCURL #include #endif #include "interact.h" #include "locate.h" #include "errormsg.h" #include "parser.h" #include "util.h" // The lexical analysis and parsing functions used by parseFile. void setlexer(size_t (*input) (char* bif, size_t max_size), string filename); extern int yyparse(void); extern int yydebug; extern int yy_flex_debug; extern bool lexerEOF(); extern void reportEOF(); extern bool hangup; namespace parser { namespace yy { // Lexers std::streambuf *sbuf = NULL; size_t stream_input(char *buf, size_t max_size) { return sbuf ? sbuf->sgetn(buf,max_size) : 0; } } // namespace yy void debug(bool state) { // For debugging the machine-generated lexer and parser. yy_flex_debug = yydebug = state; } namespace { void error(const string& filename) { em.sync(); em << "error: could not load module '" << filename << "'\n"; em.sync(); throw handled_error(); } } absyntax::file *doParse(size_t (*input) (char* bif, size_t max_size), const string& filename, bool extendable=false) { setlexer(input,filename); absyntax::file *root = yyparse() == 0 ? absyntax::root : 0; absyntax::root = 0; yy::sbuf = 0; if (!root) { if (lexerEOF()) { if (extendable) { return 0; } else { // Have the lexer report the error. reportEOF(); } } em.error(nullPos); if(!interact::interactive) error(filename); else throw handled_error(); } return root; } absyntax::file *parseStdin() { debug(false); yy::sbuf = cin.rdbuf(); return doParse(yy::stream_input,"-"); } bool isURL(const string& filename) { #ifdef HAVE_LIBCURL return filename.find("://") != string::npos; #else return false; #endif } absyntax::file *parseFile(const string& filename, const char *nameOfAction) { #ifdef HAVE_LIBCURL if(isURL(filename)) return parseURL(filename,nameOfAction); #endif if(filename == "-") return parseStdin(); string file = settings::locateFile(filename); if(file.empty()) error(filename); if(nameOfAction && settings::verbose > 1) cerr << nameOfAction << " " << filename << " from " << file << endl; debug(false); std::filebuf filebuf; if(!filebuf.open(file.c_str(),std::ios::in)) error(filename); #ifdef HAVE_SYS_STAT_H // Check that the file is not a directory. static struct stat buf; if(stat(file.c_str(),&buf) == 0) { if(S_ISDIR(buf.st_mode)) error(filename); } #endif // Check that the file can actually be read. try { filebuf.sgetc(); } catch (...) { error(filename); } yy::sbuf = &filebuf; return doParse(yy::stream_input,file); } absyntax::file *parseString(const string& code, const string& filename, bool extendable) { debug(false); stringbuf buf(code); yy::sbuf = &buf; return doParse(yy::stream_input,filename,extendable); } #ifdef HAVE_LIBCURL size_t curlCallback(char *data, size_t size, size_t n, stringstream& buf) { size_t Size=size*n; buf.write(data,Size); return Size; } int curlProgress(void *, curl_off_t, curl_off_t, curl_off_t, curl_off_t) { return errorstream::interrupt ? -1 : 0; } bool readURL(stringstream& buf, const string& filename) { CURL *curl=curl_easy_init(); if(settings::verbose > 3) curl_easy_setopt(curl,CURLOPT_VERBOSE,true); #ifdef __MSDOS__ string cert=settings::getSetting("sysdir")+settings::dirsep+ "ca-bundle.crt"; curl_easy_setopt(curl,CURLOPT_CAINFO,cert.c_str()); #endif curl_easy_setopt(curl,CURLOPT_URL,filename.c_str()); curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curlCallback); curl_easy_setopt(curl,CURLOPT_WRITEDATA,&buf); curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0); curl_easy_setopt(curl,CURLOPT_XFERINFOFUNCTION,curlProgress); CURLcode res=curl_easy_perform(curl); curl_easy_cleanup(curl); if(res != CURLE_OK) { cerr << curl_easy_strerror(res) << endl; return false; } string s=buf.str(); return !s.empty() && s != "404: Not Found"; } absyntax::file *parseURL(const string& filename, const char *nameOfAction) { stringstream code; if(!readURL(code,filename)) error(filename); if(nameOfAction && settings::verbose > 1) cerr << nameOfAction << " " << filename << endl; debug(false); yy::sbuf=code.rdbuf(); return doParse(yy::stream_input,filename); } #endif } // namespace parser