diff options
Diffstat (limited to 'Build/source/utils/asymptote/parser.cc')
-rw-r--r-- | Build/source/utils/asymptote/parser.cc | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/parser.cc b/Build/source/utils/asymptote/parser.cc new file mode 100644 index 00000000000..cdc8d81c680 --- /dev/null +++ b/Build/source/utils/asymptote/parser.cc @@ -0,0 +1,231 @@ +/***** + * parser.cc + * Tom Prince 2004/01/10 + * + *****/ + +#include <fstream> +#include <sstream> +#include <cstring> +#include <fcntl.h> +#include <algorithm> + +#include "common.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_LIBCURL +#include <curl/curl.h> +#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 bool 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; +} + +#ifdef CURLOPT_XFERINFODATA +#define CURL_OFF_T curl_off_t +#else +#define CURL_OFF_T double +#define CURLOPT_XFERINFOFUNCTION CURLOPT_PROGRESSFUNCTION +#endif + +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<string>("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 |