/*****
* parser.cc
* Tom Prince 2004/01/10
*
*****/
#include <fstream>
#include <sstream>
#include <cstring>
#include <fcntl.h>
#include <algorithm>
#include "common.h"
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
#include "exithandlers.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include "interact.h"
#include "locate.h"
#include "errormsg.h"
#include "asyparser.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();
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(true);
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<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