-rw-r--r-- | lib/component_factory.cc | 31 | ||||
-rw-r--r-- | lib/configuration.cc | 9 | ||||
-rw-r--r-- | lib/sitecing_parser.ll | 13 | ||||
-rw-r--r-- | lib/sitecing_util.cc | 117 | ||||
-rw-r--r-- | lib/sitespace.cc | 3 |
5 files changed, 30 insertions, 143 deletions
diff --git a/lib/component_factory.cc b/lib/component_factory.cc index d9692de..af3d911 100644 --- a/lib/component_factory.cc +++ b/lib/component_factory.cc @@ -1,344 +1,345 @@ #ifdef USE_PCH #include "pch.h" #else #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <sys/wait.h> #include <fcntl.h> #include <iostream> #include <fstream> #include <stdexcept> #include <vector> using namespace std; + #include <konforka/util.h> #include "sitecing/component_factory.h" #include "sitecing/sitecing_util.h" #include "sitecing/sitecing_parser.h" #include "sitecing/sitecing_exception.h" #endif namespace sitecing { static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" }; static const char *cc_targets[] = { ".o", ".d" }; component_factory::component_factory(configuration& c) : config(c), - root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'), - root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'), - root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') { + root_source(konforka::normalize_path(c.root_source,konforka::strip_trailing_slash)+'/'), + root_intermediate(konforka::normalize_path(c.root_intermediate,konforka::strip_trailing_slash)+'/'), + root_so(konforka::normalize_path(c.root_so,konforka::strip_trailing_slash)+'/') { } void component_factory::get_dependencies(const string& dst,file_list_t& deps) { deps.clear(); - string dp = normalize_path(dst,strip_trailing_slash); + string dp = konforka::normalize_path(dst,konforka::strip_trailing_slash); // source documents try { // XXX: or just compare it off? string noro = strip_prefix(dp,root_source); return; }catch(utility_no_affix& una) { } // .so binaries try { string noso = strip_suffix(dp,".so"); string noro = strip_prefix(noso,root_so); deps.push_back(root_intermediate+noro+".o"); config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps); if(co_so_deps) { for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i) deps.push_back(*i); } return; }catch(utility_no_prefix& unp) { throw konforka::exception(CODEPOINT,"component is outside of component root"); }catch(utility_no_suffix& uns) { } try { // preprocessor targets string noro = strip_prefix(dp,root_intermediate); for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { try { string nos = strip_suffix(noro,pp_targets[ppt]); deps.push_back(root_source+nos); // depends on the source ifstream imports((root_intermediate+nos+".imports").c_str(),ios::in); if(imports.good()) { string str; while(!imports.eof()) { imports >> str; if(!str.empty()) deps.push_back(root_intermediate+str+".classname"); } } ifstream ancestors((root_intermediate+nos+".ancestors").c_str(),ios::in); if(ancestors.good()) { string str; while(!ancestors.eof()) { ancestors >> str; if(!str.empty()) deps.push_back(root_intermediate+str+".classname"); } } // XXX: intermediate_deps should be broken down config_options *co_intermediate_deps = config.lookup_config(nos,config_options::flag_intermediate_deps); if(co_intermediate_deps) { for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i) deps.push_back(*i); } return; }catch(utility_no_suffix& uns) { } } // compiler targets for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { try { string nos = strip_suffix(noro,cc_targets[cct]); deps.push_back(root_intermediate+nos+".cc"); config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps); if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) { ifstream df((root_intermediate+nos+".d").c_str(),ios::in); if(df.good()) { string str; while(!df.eof()) { df >> str; if(str.find_first_of("\\:")==string::npos) - deps.push_back(combine_path(config.root_source+nos,str)); + deps.push_back(konforka::combine_path(config.root_source+nos,str)); } } } // XXX: intermediate_deps should be broken down config_options *co_intermediate_deps = config.lookup_config(nos,config_options::flag_intermediate_deps); if(co_intermediate_deps) { for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i) deps.push_back(*i); } }catch(utility_no_suffix& uns) { } } }catch(utility_no_prefix& unp) { } } bool component_factory::is_uptodate(const string& dst,file_list_t *deps) { - string dp = normalize_path(dst,strip_trailing_slash); + string dp = konforka::normalize_path(dst,konforka::strip_trailing_slash); try { string noro = strip_prefix(dp,root_intermediate); for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { try { string nos = strip_suffix(noro,pp_targets[ppt]); return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps); }catch(utility_no_suffix& uns) { } } bool rv = file_factory::is_uptodate(dst,deps); return rv; }catch(utility_no_prefix& unp) { } // XXX: or just compare it off, instead of throwing things around. try { strip_prefix(dp,root_so); return file_factory::is_uptodate(dst,deps); }catch(utility_no_prefix& unp) { } return true; } void component_factory::build(const string& dst) { - string dp = normalize_path(dst,strip_trailing_slash); + string dp = konforka::normalize_path(dst,konforka::strip_trailing_slash); // sources try { string noro = strip_prefix(dp,root_source); // building the sources is left up to developer return; }catch(utility_no_prefix& unp) { } // .so files try { string noso = strip_suffix(dp,".so"); string noro = strip_prefix(noso,root_so); string o = root_intermediate+noro+".o"; cerr << "Linking " << noro << endl; if(access(o.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")"); - make_path(dir_name(root_so+noro),0755); + konforka::make_path(konforka::dir_name(root_so+noro),0755); file_lock lock_cc(root_intermediate+noro+".o.lock"); file_lock lock_so(root_so+noro+".so.lock"); int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdO<0) throw konforka::exception(CODEPOINT,"failed to open/create linker stdout"); int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdE<0) { close(stdO); throw konforka::exception(CODEPOINT,"failed to open/create linker stderr"); } list<string> args; config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags); if(co_ld_flags) { args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end()); } args.push_back("-shared"); args.push_back(o); file_list_t ancestors; get_ancestors(noro,ancestors); for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) { string aso=root_so+*i+".so"; make(aso); args.push_back(aso); } args.push_back("-o"); args.push_back(dp); // TODO: "g++" configurable int rv = execute("g++",args,stdO,stdE); if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) throw link_error(CODEPOINT,"failed to link component",noro); return; }catch(utility_no_prefix& unp) { throw konforka::exception(CODEPOINT,"component is outside of component root"); }catch(utility_no_suffix& uns) { } try { string noro = strip_prefix(dp,root_intermediate); // compiler targets for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { try { string nos = strip_suffix(noro,cc_targets[cct]); string cc = root_intermediate+nos+".cc"; string o = root_intermediate+nos+".o"; cerr << "Compiling " << nos << endl; if(access(cc.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")"); - make_path(dir_name(cc),0755); - string pwd = dir_name(root_source+nos); + konforka::make_path(konforka::dir_name(cc),0755); + string pwd = konforka::dir_name(root_source+nos); auto_chdir dir_changer(pwd); file_lock lock_source(root_intermediate+nos+".lock"); file_lock lock_cc(root_intermediate+nos+".o.lock"); int stdO = open((root_intermediate+nos+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdO<0) throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout"); int stdE = open((root_intermediate+nos+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdE<0) { close(stdO); throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr"); } list<string> args; config_options *co_cpp_flags = config.lookup_config(nos,config_options::flag_cpp_flags); if(co_cpp_flags) { args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end()); } // TODO: maybe move it to separare config option like CoreCPPFLags? args.push_back("-I"+root_intermediate); args.push_back("-I"+root_source); args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+nos+".d"); args.push_back("-c"); args.push_back(cc); args.push_back("-o"); args.push_back(o); // TODO: "g++" configurable int rv = execute("g++",args,stdO,stdE); if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) throw compile_error(CODEPOINT,"failed to compile component",nos); return; }catch(utility_no_suffix& uns) { } } // preprocessor targets for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { try { string nos = strip_suffix(noro,pp_targets[ppt]); string src = root_source+nos; cerr << "Preprocessing " << nos << endl; if(access(src.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")"); - make_path(dir_name(root_intermediate+nos),0755); + konforka::make_path(konforka::dir_name(root_intermediate+nos),0755); file_lock lock(root_intermediate+nos+".lock"); sitecing_parser parser(*this); config_options *co_skeleton = config.lookup_config(nos,config_options::flag_skeleton); if(co_skeleton) parser.skeleton = co_skeleton->skeleton; static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - parser.class_name = normalize_path(nos,strip_leading_slash|strip_trailing_slash); + parser.class_name = konforka::normalize_path(nos,konforka::strip_leading_slash|konforka::strip_trailing_slash); for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) { string::size_type lc = parser.class_name.find_first_of(id_chars,illc); int n = ((lc==string::npos)?parser.class_name.length():lc)-illc; parser.class_name.replace(illc,n,n,'_'); } parser.class_name = "_SCC_"+parser.class_name; parser.output_basename = root_intermediate+nos; parser.component_basename = nos; try { parser.preprocess(src); string sf = root_intermediate+nos+".pp_stamp"; ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp }catch(preprocessor_error& pe) { pe.component_name = nos; pe.see(CODEPOINT); throw; } return; }catch(utility_no_suffix& uns) { } } }catch(utility_no_prefix& unp) { } cerr << "ignoring build request for " << dp << endl; } void component_factory::make(const string& dst) { - string dp = normalize_path(dst,strip_trailing_slash); + string dp = konforka::normalize_path(dst,konforka::strip_trailing_slash); try { string noso = strip_suffix(dp,".so"); string noro = strip_prefix(noso,root_so); file_list_t a; get_ancestors(noro,a); for(file_list_t::const_iterator i=a.begin();i!=a.end();++i) { make(root_so+*i+".so"); } }catch(utility_no_affix& una) { } file_factory::make(dst); } int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) { // XXX: is it right that we do stdio/stderr tricks outside of the function? // cerr << "executing: " << cmd; vector<const char*> argv(args.size()+2); argv[0]=cmd.c_str(); int an = 1; for(list<string>::const_iterator i=args.begin();i!=args.end();i++) { // cerr << " " << *i ; argv[an++] = i->c_str(); } // cerr << endl; argv[an++]=NULL; pid_t pid = vfork(); if(pid==-1) { close(stdo); close(stde); throw konforka::exception(CODEPOINT,"failed to vfork()"); } if(!pid) { // child if(dup2(stdo,1)!=1) _exit(-1); if(dup2(stde,2)!=2) _exit(-1); close(0); execvp(cmd.c_str(),(char**)&argv.front()); _exit(-1); } // parent close(stdo); close(stde); int rv; if(waitpid(pid,&rv,0)<0) throw konforka::exception(CODEPOINT,"failed to waitpid()"); return rv; } string component_factory::get_classname(const string& component) { - string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname"; + string cn = root_intermediate+konforka::normalize_path(component,konforka::strip_trailing_slash|konforka::strip_leading_slash)+".classname"; make(cn); ifstream ifs(cn.c_str()); if(!ifs.good()) throw konforka::exception(CODEPOINT,"failed to access component .classname"); ifs >> cn; return cn; } void component_factory::get_ancestors(const string& component,file_list_t& rv) { - string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors"; + string cn = root_intermediate+konforka::normalize_path(component,konforka::strip_trailing_slash|konforka::strip_leading_slash)+".ancestors"; make(cn); ifstream ifs(cn.c_str()); if(!ifs.good()) throw konforka::exception(CODEPOINT,string("failed to access component '")+component+"' .ancestors"); rv.clear(); while(!ifs.eof()) { string a; ifs >> a; if(!a.empty()) rv.push_back(a); } } } diff --git a/lib/configuration.cc b/lib/configuration.cc index 4ee1526..6b21690 100644 --- a/lib/configuration.cc +++ b/lib/configuration.cc @@ -1,474 +1,475 @@ #ifdef USE_PCH #include "pch.h" #else #include <unistd.h> #include <fnmatch.h> #include <cassert> #include <stdexcept> using namespace std; + #include <konforka/util.h> #include <dotconf.h> #include "sitecing/configuration.h" #include "sitecing/sitecing_util.h" #include "sitecing/scoreboard.h" #endif namespace sitecing { configuration::configuration() : flags(0), autobuild(false) { } configuration::configuration(const string& cfile,bool ab) : flags(0), autobuild(ab) { parse(cfile); } enum dc_ctx { DCC_ROOT = 1, DCC_PATH = 2, DCC_SCRC = 4 }; struct dc_context { dc_ctx ctx; configuration* cf; list<config_options*> co; }; static DOTCONF_CB(dco_root_source) { dc_context *dcc = (dc_context*)ctx; dcc->cf->root_source = cmd->data.str; dcc->cf->flags |= configuration::flag_root_source; return NULL; } static DOTCONF_CB(dco_root_intermediate) { dc_context *dcc = (dc_context*)ctx; dcc->cf->root_intermediate = cmd->data.str; dcc->cf->flags |= configuration::flag_root_intermediate; return NULL; } static DOTCONF_CB(dco_root_so) { dc_context *dcc = (dc_context*)ctx; dcc->cf->root_so = cmd->data.str; dcc->cf->flags |= configuration::flag_root_so; return NULL; } static DOTCONF_CB(dco_listen_socket) { dc_context *dcc = (dc_context*)ctx; dcc->cf->listen_socket = cmd->data.str; dcc->cf->flags |= configuration::flag_listen_socket; return NULL; } static DOTCONF_CB(dco_rc_file_name) { dc_context *dcc = (dc_context*)ctx; dcc->cf->rc_file_name = cmd->data.str; dcc->cf->flags |= configuration::flag_rc_file_name; return NULL; } static DOTCONF_CB(dco_min_children) { dc_context *dcc = (dc_context*)ctx; if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS) return "MinChildren is too big"; dcc->cf->min_children = cmd->data.value; dcc->cf->flags |= configuration::flag_min_children; return NULL; } static DOTCONF_CB(dco_max_children) { dc_context *dcc = (dc_context*)ctx; if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS) return "MaxChildren is too big"; dcc->cf->max_children = cmd->data.value; dcc->cf->flags |= configuration::flag_max_children; return NULL; } static DOTCONF_CB(dco_min_spare_children) { dc_context *dcc = (dc_context*)ctx; if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS) return "MinSpareChildren is too big"; dcc->cf->min_spare_children = cmd->data.value; dcc->cf->flags |= configuration::flag_min_spare_children; return NULL; } static DOTCONF_CB(dco_max_spare_children) { dc_context *dcc = (dc_context*)ctx; if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS) return "MaxSpareChildren is too big"; dcc->cf->max_spare_children = cmd->data.value; dcc->cf->flags |= configuration::flag_max_spare_children; return NULL; } static DOTCONF_CB(dco_requests_per_child) { dc_context *dcc = (dc_context*)ctx; dcc->cf->requests_per_child = cmd->data.value; dcc->cf->flags |= configuration::flag_requests_per_child; return NULL; } static DOTCONF_CB(dco_multi_process) { dc_context *dcc = (dc_context*)ctx; dcc->cf->multi_process = cmd->data.value; dcc->cf->flags |= configuration::flag_multi_process; return NULL; } static DOTCONF_CB(dco_user) { dc_context *dcc = (dc_context*)ctx; dcc->cf->user = cmd->data.str; dcc->cf->flags |= configuration::flag_user; return NULL; } static DOTCONF_CB(dco_group) { dc_context *dcc = (dc_context*)ctx; dcc->cf->group = cmd->data.str; dcc->cf->flags |= configuration::flag_group; return NULL; } static DOTCONF_CB(dco_chroot) { dc_context *dcc = (dc_context*)ctx; dcc->cf->chroot = cmd->data.str; dcc->cf->flags |= configuration::flag_chroot; return NULL; } static DOTCONF_CB(dco_pid_file) { dc_context *dcc = (dc_context*)ctx; dcc->cf->pid_file = cmd->data.str; dcc->cf->flags |= configuration::flag_pid_file; return NULL; } static DOTCONF_CB(dco_daemonize) { dc_context *dcc = (dc_context*) ctx; dcc->cf->daemonize = cmd->data.value; dcc->cf->flags |= configuration::flag_daemonize; return NULL; } static DOTCONF_CB(dco_path) { dc_context *dcc = (dc_context*)ctx; string path = cmd->data.str; if(path[path.length()-1]=='>') path.erase(path.length()-1); // TODO: normalize path dcc->co.push_front(&(dcc->cf->specs[path])); dcc->ctx = DCC_PATH; // TODO: stack it, instead return NULL; } static DOTCONF_CB(dco__path) { dc_context *dcc = (dc_context*)ctx; dcc->co.pop_front(); assert(dcc->co.size()); dcc->ctx = DCC_ROOT; // TODO: stack it, instead return NULL; } static DOTCONF_CB(dco_skeleton) { dc_context *dcc = (dc_context*)ctx; dcc->co.front()->skeleton = cmd->data.str; dcc->co.front()->flags |= config_options::flag_skeleton; return NULL; } static DOTCONF_CB(dco_cpp_flags) { dc_context *dcc = (dc_context*)ctx; for(char **arg=cmd->data.list;*arg;arg++) dcc->co.front()->cpp_flags.push_back(*arg); dcc->co.front()->flags |= config_options::flag_cpp_flags; return NULL; } static DOTCONF_CB(dco_ld_flags) { dc_context *dcc = (dc_context*)ctx; for(char **arg=cmd->data.list;*arg;arg++) dcc->co.front()->ld_flags.push_back(*arg); dcc->co.front()->flags |= config_options::flag_ld_flags; return NULL; } static DOTCONF_CB(dco_intermediate_deps) { dc_context *dcc = (dc_context*) ctx; for(char **arg=cmd->data.list;*arg;arg++) dcc->co.front()->intermediate_deps.push_back(*arg); dcc->co.front()->flags |= config_options::flag_intermediate_deps; return NULL; } static DOTCONF_CB(dco_so_deps) { dc_context *dcc = (dc_context*) ctx; for(char **arg=cmd->data.list;*arg;arg++) dcc->co.front()->so_deps.push_back(*arg); dcc->co.front()->flags |= config_options::flag_so_deps; return NULL; } static DOTCONF_CB(dco_build) { dc_context *dcc = (dc_context*)ctx; dcc->co.front()->build = cmd->data.value; dcc->co.front()->flags |= config_options::flag_build; return NULL; } static DOTCONF_CB(dco_cpp_deps) { dc_context *dcc = (dc_context*)ctx; dcc->co.front()->cpp_deps = cmd->data.value; dcc->co.front()->flags |= config_options::flag_cpp_deps; return NULL; } static DOTCONF_CB(dco_exception_handler) { dc_context *dcc = (dc_context*)ctx; dcc->co.front()->exception_handler = cmd->data.str; dcc->co.front()->flags |= config_options::flag_exception_handler; return NULL; } static DOTCONF_CB(dco_http_status_handler) { dc_context *dcc = (dc_context*)ctx; if(cmd->arg_count!=2) return "Invalid number of arguments"; dcc->co.front()->http_status_handlers[cmd->data.list[0]] = cmd->data.list[1]; dcc->co.front()->flags |= config_options::flag_http_status_handlers; return NULL; } static DOTCONF_CB(dco_action) { dc_context *dcc = (dc_context*)ctx; if(cmd->arg_count<2) return "Invalid number of arguments"; try { char **arg=cmd->data.list; dcc->co.front()->action_handlers.push_back(config_options::action_handler_t(arg[0],arg[1])); for(arg+=2;*arg;arg++) dcc->co.front()->action_handlers.back().args.push_back(*arg); dcc->co.front()->flags |= config_options::flag_action_handlers; }catch(exception& e) { return "Error processing Action directive"; // XXX: could be done better } return NULL; } static DOTCONF_CB(dco_auto_build_files) { dc_context *dcc = (dc_context*)ctx; if(!( dcc->cf && dcc->cf->autobuild)) return NULL; for(char **arg=cmd->data.list;*arg;arg++) dcc->co.front()->auto_build_files.push_back(*arg); dcc->co.front()->flags |= config_options::flag_auto_build_files; return NULL; } static const configoption_t dc_options[] = { { "RootSource", ARG_STR, dco_root_source, NULL, DCC_ROOT }, { "RootIntermediate", ARG_STR, dco_root_intermediate, NULL, DCC_ROOT }, { "RootSO", ARG_STR, dco_root_so, NULL, DCC_ROOT }, { "ListenSocket", ARG_STR, dco_listen_socket, NULL, DCC_ROOT }, { "RCFileName", ARG_STR, dco_rc_file_name, NULL, DCC_ROOT }, { "MinChildren", ARG_INT, dco_min_children, NULL, DCC_ROOT }, { "MaxChildren", ARG_INT, dco_max_children, NULL, DCC_ROOT }, { "MinSpareChildren", ARG_INT, dco_min_spare_children, NULL, DCC_ROOT }, { "MaxSpareChildren", ARG_INT, dco_max_spare_children, NULL, DCC_ROOT }, { "RequestsPerChild", ARG_INT, dco_requests_per_child, NULL, DCC_ROOT }, { "MultiProcess", ARG_TOGGLE, dco_multi_process, NULL, DCC_ROOT }, { "User", ARG_STR, dco_user, NULL, DCC_ROOT }, { "Group", ARG_STR, dco_group, NULL, DCC_ROOT }, { "Chroot", ARG_STR, dco_chroot, NULL, DCC_ROOT }, { "PidFile", ARG_STR, dco_pid_file, NULL, DCC_ROOT }, { "Daemonize", ARG_TOGGLE, dco_daemonize, NULL, DCC_ROOT }, { "<Path", ARG_STR, dco_path, NULL, DCC_ROOT }, { "Skeleton", ARG_STR, dco_skeleton, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "CPPFLAGS", ARG_LIST, dco_cpp_flags, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "LDFLAGS", ARG_LIST, dco_ld_flags, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "Build", ARG_TOGGLE, dco_build, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "CPPDeps", ARG_TOGGLE, dco_cpp_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "ExceptionHandler", ARG_STR, dco_exception_handler, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "HTTPStatusHandler", ARG_LIST, dco_http_status_handler, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "IntermediateDeps", ARG_LIST, dco_intermediate_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "SODeps", ARG_LIST, dco_so_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "Action", ARG_LIST, dco_action, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "AutoBuildFiles", ARG_LIST, dco_auto_build_files, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC }, { "</Path>", ARG_NONE, dco__path, NULL, DCC_PATH }, LAST_OPTION }; static const char *dc_context_checker(command_t *cmd,unsigned long mask) { dc_context *dcc = (dc_context*)cmd->context; if( (mask==CTX_ALL) || ((mask&dcc->ctx)==dcc->ctx) ) return NULL; return "misplaced option"; } static FUNC_ERRORHANDLER(dc_error_handler) { throw konforka::exception(CODEPOINT,string("error parsing config file: ")+msg); } bool loaded_options::is_valid() { struct stat nst; if(stat(source_file.c_str(),&nst)) return false; if(st.st_mtime!=nst.st_mtime) return false; return true; } loaded_options *configuration::lookup_loaded_options(const string& target) { // we assume 'target' is a directory with trailing slash appended string scrc = root_source+target; if(flags&flag_rc_file_name) scrc += rc_file_name; else scrc += ".scrc"; // TODO: normalize me, anyway. if(access(scrc.c_str(),R_OK)) return 0; // TODO FIXME: this approach leaves already loaded .scrcs around in case of removal loaded_specs_t::iterator i = loaded_specs.find(target); if(i==loaded_specs.end() || !i->second.is_valid()) { if(i!=loaded_specs.end()) loaded_specs.erase(i); pair<loaded_specs_t::iterator,bool> ii = loaded_specs.insert(loaded_specs_t::value_type(target,loaded_options())); assert(ii.first!=loaded_specs.end()); ii.first->second.parse(this,scrc); i = ii.first; } assert(i!=loaded_specs.end()); return &(i->second); } config_options::action_handler_t *config_options::lookup_action_handler(const string& target) { for(action_handlers_t::iterator i=action_handlers.begin();i!=action_handlers.end();++i) { if(i->regex.search(target)) return &*i; } return NULL; } string config_options::lookup_http_status_handler(const string& status) { http_status_handlers_t::const_iterator i = http_status_handlers.find(status); string rv; if(i!=http_status_handlers.end()) rv = i->second; return rv; } string configuration::lookup_http_status_handler(const string& target,const string& status) { string t = "/"; - t += normalize_path(target,strip_leading_slash); + t += konforka::normalize_path(target,konforka::strip_leading_slash); string rv; for(;;) { if(t[t.length()-1]=='/') { loaded_options* lo = lookup_loaded_options(t); if( lo && (lo->flags&config_options::flag_http_status_handlers) ) { rv = lo->lookup_http_status_handler(status); if(!rv.empty()) return rv; } } specs_t::iterator i = specs.find(t); if( i!=specs.end() && (i->second.flags&&config_options::flag_http_status_handlers) ) { rv = i->second.lookup_http_status_handler(status); if(!rv.empty()) return rv; } if(t.empty()) return rv; string::size_type sl=t.rfind('/'); if(sl==string::npos) { t.erase(); }else{ if(sl==(t.length()-1)) t.erase(sl); else t.erase(sl+1); } } } config_options::action_handler_t *configuration::lookup_action_handler(const string& target) { string t = "/"; - t += normalize_path(target,strip_leading_slash); + t += konforka::normalize_path(target,konforka::strip_leading_slash); for(;;) { if(t[t.length()-1]=='/') { loaded_options* lo = lookup_loaded_options(t); if( lo && (lo->flags&config_options::flag_action_handlers) ) { config_options::action_handler_t *rv = lo->lookup_action_handler(target); if(rv) return rv; } } specs_t::iterator i = specs.find(t); if( i!=specs.end() && (i->second.flags&&config_options::flag_action_handlers) ) { config_options::action_handler_t *rv = i->second.lookup_action_handler(target); if(rv) return rv; } if(t.empty()) return NULL; string::size_type sl=t.rfind('/'); if(sl==string::npos) { t.erase(); }else{ if(sl==(t.length()-1)) t.erase(sl); else t.erase(sl+1); } } } config_options* configuration::lookup_config(const string& target,int flag) { string t = "/"; // always assume leading slash - t += normalize_path(target,strip_leading_slash); + t += konforka::normalize_path(target,konforka::strip_leading_slash); // XXX: reconsider precedence for(;;) { if(t[t.length()-1]=='/') { loaded_options* lo = lookup_loaded_options(t); if( lo && (lo->flags&flag)==flag ) return lo; } specs_t::iterator i = specs.find(t); if( i!=specs.end() && (i->second.flags&flag)==flag ) return &(i->second); if(t.empty()) return NULL; string::size_type sl=t.rfind('/'); if(sl==string::npos) { t.erase(); }else{ if(sl==(t.length()-1)) t.erase(sl); else t.erase(sl+1); } } } bool config_options::match_autobuild_files(const char *fn,bool &rv) { for(list<string>::reverse_iterator i=auto_build_files.rbegin();i!=auto_build_files.rend();++i) { const char *pat = i->c_str(); bool plus = true; if((*pat)=='+') pat++; else if((*pat)=='-') { plus = false; pat++; } if(!fnmatch(pat,fn,FNM_NOESCAPE|FNM_PATHNAME|FNM_PERIOD)) { rv = plus; return true; } } return false; } bool configuration::match_autobuild_files(const string& target,const char *fn) { string t = "/"; - t += normalize_path(target,strip_leading_slash|strip_trailing_slash); + t += konforka::normalize_path(target,konforka::strip_leading_slash|konforka::strip_trailing_slash); t += "/"; bool rv = false; for(;;) { if(t[t.length()-1]=='/') { loaded_options* lo = lookup_loaded_options(t); if(lo && (lo->flags&config_options::flag_auto_build_files) && lo->match_autobuild_files(fn,rv) ) return rv; } specs_t::iterator i = specs.find(t); if( i!=specs.end() && (i->second.flags&config_options::flag_auto_build_files) && i->second.match_autobuild_files(fn,rv) ) return rv; if(t.empty()) return rv; string::size_type sl=t.rfind('/'); if(sl==string::npos) { t.erase(); }else{ if(sl==(t.length()-1)) t.erase(sl); else t.erase(sl+1); } } } void configuration::parse(const string& cfile) { struct dc_context dcc; dcc.cf = this; dcc.ctx = DCC_ROOT; dcc.co.push_front(&root_options()); configfile_t *cf = dotconf_create((char*)cfile.c_str(),dc_options,(context_t*)&dcc,CASE_INSENSITIVE); if(!cf) throw konforka::exception(CODEPOINT,"failed to dotconf_create()"); cf->errorhandler = (dotconf_errorhandler_t) dc_error_handler; cf->contextchecker = (dotconf_contextchecker_t) dc_context_checker; if(!dotconf_command_loop(cf)) throw konforka::exception(CODEPOINT,"failed to dotconf_command_loop()"); dotconf_cleanup(cf); } void loaded_options::parse(configuration *config,const string& cfile) { struct dc_context dcc; dcc.cf = config; dcc.ctx = DCC_SCRC; dcc.co.push_front(this); configfile_t *cf = dotconf_create((char*)cfile.c_str(),dc_options,(context_t*)&dcc,CASE_INSENSITIVE); if(!cf) throw konforka::exception(CODEPOINT,"failed to dotconf_create()"); cf->errorhandler = (dotconf_errorhandler_t) dc_error_handler; cf->contextchecker = (dotconf_contextchecker_t) dc_context_checker; if(!dotconf_command_loop(cf)) throw konforka::exception(CODEPOINT,"failed to dotconf_command_loop()"); dotconf_cleanup(cf); source_file = cfile; stat(cfile.c_str(),&st); // TODO: handle errors? } } diff --git a/lib/sitecing_parser.ll b/lib/sitecing_parser.ll index 4fd6709..8dd8d5f 100644 --- a/lib/sitecing_parser.ll +++ b/lib/sitecing_parser.ll @@ -1,642 +1,643 @@ %{ /* * XXX: I have a strong feeling that this parser should be completely rewritten. */ #include <iostream> #include <fstream> #include <cassert> #include <stdexcept> using namespace std; +#include <konforka/util.h> #include "sitecing/sitecing_util.h" #include "sitecing/sitecing_exception.h" using namespace sitecing; #define sitecing_parser_flexlexer_once #include "sitecing/sitecing_parser.h" #include "sitecing/sitecing_enflesher.h" #undef yyFlexLexer #define yyFlexLexer sitecing_parserFlexLexer %} %x SLASHSTAR_COMMENT SLASHSLASH_COMMENT STRING %x CODELINE CLASSLINE DECLLINE IMPLLINE DECLBLOCK IMPLBLOCK VARLINE VARINIT %x IMPORTLINE IMPORTCOMPONENT %x IMPORTTYPELINE IMPORTTYPECOMPONENT %x DERIVELINE DERIVECOMPONENT %x CONSTRUCTOR DESTRUCTOR CODEMETHODLINE CODEMETHODARGS %x CODEMETHODBLOCK INLINE METHODLINE METHODARGS METHODBLOCK CODEBLOCK OUTPUTBLOCK %x PRAGMALINE %option 8bit c++ verbose noyywrap yyclass="sitecing_parser" prefix="sitecing_parser" stack yylineno WHITESPACE [ \t] ID [A-Za-z_][A-Za-z0-9_]* NOIDCHAR [^A-Za-z0-9_] %% <INITIAL>{ ^\%\%class{WHITESPACE}+ { // TODO: signal error if we already have class name acquired from source. modi.push_front(modus_operandi(modus_operandi::flag_devour_comments|modus_operandi::flag_devour_whitespace)); BEGIN(CLASSLINE); } ^\%\%decl{WHITESPACE}+ { modi.push_front(modus_operandi(0)); anchor(); BEGIN(DECLLINE); } ^\%\%impl{WHITESPACE}+ { modi.push_front(modus_operandi(0)); anchor(); BEGIN(IMPLLINE); } \<\%decl\> { modi.push_front(modus_operandi(0)); anchor(); BEGIN(DECLBLOCK); } \<\%impl\> { modi.push_front(modus_operandi(0)); anchor(); BEGIN(IMPLBLOCK); } ^\%\%var{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(VARLINE); } ^\%\%import{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(IMPORTLINE); } ^\%\%import_type{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(IMPORTTYPELINE); } ^\%\%derive{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(DERIVELINE); } \<\%constructor\> { modi.push_front(modus_operandi()); anchor(); BEGIN(CONSTRUCTOR); } \<\%destructor\> { modi.push_front(modus_operandi()); anchor(); BEGIN(DESTRUCTOR); } \<\%codemethod{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(CODEMETHODLINE); } \<\%method{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(METHODLINE); } ^\%\%pragma{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(PRAGMALINE); } <<EOF>> { assert(modi.size()==1); M().modify(modus_operandi::modus_preop); LexerOutput(";",1); return 0; } } <<EOF>> throw preprocessor_error(CODEPOINT,"unexpected end of file",lineno()); <CODEBLOCK,CODEMETHODBLOCK>{ "<%output>" { anchor(); yy_push_state(OUTPUTBLOCK); } } <PRAGMALINE>{ {WHITESPACE}+ { modus_operandi& m = M(); if(!m.output.empty()) { string::size_type eq = m.output.find('='); if(eq==string::npos) { pragmas[m.output]=m.output; }else{ pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1); } m.output.erase(); } } \n { modus_operandi& m = M(); if(!m.output.empty()) { string::size_type eq = m.output.find('='); if(eq==string::npos) { pragmas[m.output]=m.output; }else{ pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1); } m.output.erase(); } modi.pop_front(); BEGIN(INITIAL); anchor(); } } <METHODLINE>{ {WHITESPACE}+ { modus_operandi& m = M(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = M(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \( { modus_operandi& m = M(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy... if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name = m.output; m.output.clear(); } ECHO; BEGIN(METHODARGS); } } <METHODARGS>{ \%\> { modus_operandi& m = M(); m._args = m.output; m.output.clear(); anchor(); BEGIN(METHODBLOCK); } } <INITIAL,METHODBLOCK,OUTPUTBLOCK>{ \<\%{WHITESPACE}+ { M().modify(modus_operandi::modus_postop); anchor(); LexerOutput("(",1); yy_push_state(INLINE); } ^\%{WHITESPACE} { M().modify(modus_operandi::modus_code); anchor(); yy_push_state(CODELINE); } \<\%code\> { M().modify(modus_operandi::modus_code); anchor(); yy_push_state(CODEBLOCK); } "</%output>" { if(YY_START!=OUTPUTBLOCK) throw preprocessor_error(CODEPOINT,"unexpected tag",lineno()); M().modify(modus_operandi::modus_code); anchor(); yy_pop_state(); } } <INLINE>\%\> LexerOutput(")",1); M().modus=modus_operandi::modus_preop; yy_pop_state(); <CODELINE>\n yy_pop_state(); <CODEMETHODLINE>{ {WHITESPACE}+ { modus_operandi& m = M(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = M(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \( { modus_operandi& m = M(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy... if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name = m.output; m.output.clear(); } ECHO; BEGIN(CODEMETHODARGS); } } <CODEMETHODARGS>{ \%\> { modus_operandi& m = M(); m._args = m.output; m.output.clear(); m.flags=0; anchor(); BEGIN(CODEMETHODBLOCK); } } <IMPORTLINE>{ {WHITESPACE}+ { } {ID} { modus_operandi& m = M(); if(!m._name.empty()) throw preprocessor_error(CODEPOINT,"syntax error",lineno()); m._name = yytext; } \= { M().output.clear(); BEGIN(IMPORTCOMPONENT); } } <IMPORTCOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } - string c = combine_path(component_basename,m.output); - member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true)); + string c = konforka::combine_path(component_basename,m.output); + member_variables.push_back(member_variable(m._type,m._name,konforka::normalize_path(c,konforka::strip_leading_slash),true)); modi.pop_front(); BEGIN(INITIAL); } } <IMPORTTYPELINE>{ {WHITESPACE}+ { } {ID} { modus_operandi& m = M(); if(!m._name.empty()) throw preprocessor_error(CODEPOINT,"syntax error",lineno()); m._name = yytext; } \= { M().output.clear(); BEGIN(IMPORTTYPECOMPONENT); } } <IMPORTTYPECOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } - string c = combine_path(component_basename,m.output); - member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true,true)); + string c = konforka::combine_path(component_basename,m.output); + member_variables.push_back(member_variable(m._type,m._name,konforka::normalize_path(c,konforka::strip_leading_slash),true,true)); modi.pop_front(); BEGIN(INITIAL); } } <DERIVELINE>{ {WHITESPACE}+ { } {ID} { modus_operandi& m = M(); if(!m._name.empty()) throw preprocessor_error(CODEPOINT,"syntax_error",lineno()); m._name = yytext; } \= { M().output.clear(); BEGIN(DERIVECOMPONENT); } } <DERIVECOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } - string c = combine_path(component_basename,m.output); - ancestor_classes.push_back(ancestor_class(m._name,normalize_path(c,strip_leading_slash))); + string c = konforka::combine_path(component_basename,m.output); + ancestor_classes.push_back(ancestor_class(m._name,konforka::normalize_path(c,konforka::strip_leading_slash))); modi.pop_front(); BEGIN(INITIAL); } } <VARLINE>{ {WHITESPACE}+ { modus_operandi& m = M(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = M(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \;|\n|\= { modus_operandi& m = M(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid should never be emtpy, I believe? if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name=m.output; m.output.clear(); } BEGIN(VARINIT); if(*yytext!='=') unput('\n'); } } <VARINIT>{ \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); member_variables.push_back(member_variable(m._type,m._name,m.output)); if(!m.output.empty()) have_initializers=true; modi.pop_front(); BEGIN(INITIAL); } } <DECLLINE>\n { ECHO; decl += M().output; modi.pop_front(); BEGIN(INITIAL); } <IMPLLINE>\n { ECHO; impl += M().output; modi.pop_front(); BEGIN(INITIAL); } <CLASSLINE>\n { class_name = M().output; modi.pop_front(); BEGIN(INITIAL); } <CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK,PRAGMALINE,DERIVELINE,DERIVECOMPONENT>{ "/*" { yy_push_state(SLASHSTAR_COMMENT); if(!M().devour_comments()) { ECHO; } } "//" { yy_push_state(SLASHSLASH_COMMENT); if(!M().devour_comments()) { ECHO; } } \" { yy_push_state(STRING); ECHO; } \'\\.\' { ECHO; } } <INITIAL,METHODBLOCK,OUTPUTBLOCK>{ \" soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\\"",2); \n soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\n",2); \r soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\r",2); \t soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\t",2); \b soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\b",2); \a soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\a",2); . soft_anchor(); M().modify(modus_operandi::modus_text); ECHO; {WHITESPACE}+ soft_anchor(); M().modify(modus_operandi::modus_text); ECHO; } <DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,METHODBLOCK,CODEBLOCK>{ \<\/\%decl\> { if(YY_START!=DECLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); decl += M().output; modi.pop_front(); BEGIN(INITIAL); } \<\/\%impl\> { if(YY_START!=IMPLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); impl += M().output; modi.pop_front(); BEGIN(INITIAL); } \<\/\%constructor\> { if(YY_START!=CONSTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); member_functions.push_back(member_function("","","",M().output)); have_constructor = true; modi.pop_front(); BEGIN(INITIAL); } \<\/\%destructor\> { if(YY_START!=DESTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); member_functions.push_back(member_function("","~","",M().output)); modi.pop_front(); BEGIN(INITIAL); } \<\/\%codemethod\> { if(YY_START!=CODEMETHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); modus_operandi& m = M(); member_functions.push_back(member_function(m._type,m._name,m._args,m.output)); modi.pop_front(); BEGIN(INITIAL); } \<\/%method\> { if(YY_START!=METHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); modus_operandi& m = M(); m.modify(modus_operandi::modus_code); member_functions.push_back(member_function(m._type,m._name,m._args,m.output)); modi.pop_front(); BEGIN(INITIAL); } \<\/%code\> { if(YY_START!=CODEBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); yy_pop_state(); } \n ECHO; } <SLASHSTAR_COMMENT>{ "*/" { if(!M().devour_comments()) { ECHO; } yy_pop_state(); unput(' '); } \n { if(!M().devour_comments()) { ECHO; } } } <SLASHSLASH_COMMENT>{ \n { if(!M().devour_comments()) { ECHO; } yy_pop_state(); if(YY_START!=CODEBLOCK && YY_START!=CODEMETHODBLOCK && YY_START!=IMPLBLOCK && YY_START!=DECLBLOCK) unput('\n'); } } <SLASHSTAR_COMMENT,SLASHSLASH_COMMENT>. { if(!M().devour_comments()) { ECHO; } } <STRING>{ \\. ECHO; \" ECHO; yy_pop_state(); . ECHO; } {WHITESPACE}+ { if(!(M().flags&modus_operandi::flag_devour_whitespace)) { ECHO; } } %% sitecing_parser::sitecing_parser(component_factory& f) : factory(f), have_initializers(false), have_constructor(false), base_class("sitecing::cgi_component"), base_header("sitecing/cgi_component.h"), skeleton(__SC_DEFAULT_SKELETON) { } void sitecing_parser::preprocess(const string& in) { ifstream ifs(in.c_str(),ios::in); if(!ifs.good()) throw preprocessor_error(CODEPOINT,"failed to open input file"); input_file = in; modi.push_front(modus_operandi(0)); switch_streams(&ifs,NULL); if(yylex()) throw preprocessor_error(CODEPOINT,"unknown error"); pragmas_t::const_iterator mp = pragmas.find("main"); if(mp==pragmas.end()) { member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output)); }else{ member_functions.push_back( member_function( "void","main","(int _magic,va_list _args)", mp->second+"::main(_magic,_args);" ) ); } if(have_initializers && !have_constructor) member_functions.push_back(member_function("","","","")); sitecing_enflesher enflesher(*this); enflesher.enflesh(); } void sitecing_parser::LexerOutput(const char* buf,int size) { assert(modi.size()); M().output.append(buf,size); } static const char *modus_transitions [sitecing_parser::modus_operandi::modi] [sitecing_parser::modus_operandi::modi] = { // To: // code preop postop text From: { "", "(*(__SCIF->out))", "(*(__SCIF->out))<<", "(*(__SCIF->out))<<\"" }, // code { ";", "", "<<", "<<\"" }, // preop { NULL, NULL, "", "\"" }, // postop { "\";", "\"", "\"<<", "" } // text }; void sitecing_parser::modus_operandi::modify(modus_t m) { const char * x = modus_transitions[modus][m]; assert(x); output += x; modus = m; } void sitecing_parser::soft_anchor() { if(M().modus!=modus_operandi::modus_text) anchor(); } void sitecing_parser::anchor() { if(M().modus==modus_operandi::modus_text) M().modify(modus_operandi::modus_preop); M().output += "\n#line "; char tmp[7]; snprintf(tmp,sizeof(tmp),"%d",lineno()); M().output += tmp; M().output += " \""; M().output += input_file; M().output += "\"\n"; } /* vim:set ft=lex: */ diff --git a/lib/sitecing_util.cc b/lib/sitecing_util.cc index f892a60..f1432df 100644 --- a/lib/sitecing_util.cc +++ b/lib/sitecing_util.cc @@ -1,279 +1,162 @@ #ifdef USE_PCH #include "pch.h" #else #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/sem.h> #include <errno.h> #include <iostream> #include <fstream> #include <cassert> #include "sitecing/sitecing_util.h" #endif namespace sitecing { /* * XXX: all of these utilities could be sheerly optimized. */ - string normalize_path(const string& path,int opts) { - const char *s = path.c_str(); - string rv; - string::size_type notslash = 0; - if( (*s)=='.' && s[1]=='/' ) - s+=2; - if(opts&strip_leading_slash) - for(;(*s) && (*s)=='/';s++); - for(;*s;s++) { - if( (*s)=='/' ) { - if(s[1]=='/') - continue; - if(s[1]=='.' && s[2]=='/') { - s+=2; - continue; - } - } - if(opts&restrict_dotdot) { - if( - ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' ) // "^../" - || ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)" - ) - throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered"); - } - rv += *s; - if( (*s) != '/' ) - notslash=rv.length(); - } - if(!(opts&strip_trailing_slash)) - notslash++; - if(notslash<rv.length()) - rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash - return rv; - } - string strip_prefix(const string& str,const string& prefix) { if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix)) throw utility_no_prefix(CODEPOINT,"no such prefix"); return str.substr(prefix.length()); } string strip_suffix(const string& str,const string& suffix) { if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix)) throw utility_no_suffix(CODEPOINT,"no such suffix"); return str.substr(0,str.length()-suffix.length()); } - string dir_name(const string& filename) { - string::size_type sl = filename.find_last_of('/'); - if(sl==string::npos) - return ""; // no slashes -- no dir. - string::size_type nosl = filename.find_last_not_of('/',sl); - if(nosl==string::npos) - return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir? - return filename.substr(0,nosl+1); - } - - void make_path(const string& path,mode_t mode) { - struct stat st; - for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) { - if(!sl) - continue; - string p = path.substr(0,sl); - if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) { - if(mkdir(p.c_str(),mode)) - throw konforka::exception(CODEPOINT,"failed to mkdir()"); - } - } - if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) { - if(mkdir(path.c_str(),mode)) - throw konforka::exception(CODEPOINT,"failed to mkdir()"); - } - } - void file_lock::lock(const string& f) { unlock(); fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR); if(fd<0) throw konforka::exception(CODEPOINT,"failed to open/create lockfile"); try { lock(); }catch(konforka::exception& ke) { ke.see(CODEPOINT); close(fd); fd=-1; throw; }catch(...) { close(fd); fd=-1; throw; } } void file_lock::lock() { assert(fd>=0); struct flock fl; fl.l_type = F_WRLCK; fl.l_whence=SEEK_SET; fl.l_start=fl.l_len=0; for(int tries=3;tries;tries--) { if(!fcntl(fd,F_SETLK,&fl)) return; sleep(8); } throw konforka::exception(CODEPOINT,"failed to obtain file lock"); } void file_lock::unlock() { if(fd<0) return; struct flock fl; fl.l_type = F_UNLCK; fl.l_whence=SEEK_SET; fl.l_start=fl.l_len=0; int rv = fcntl(fd,F_SETLK,&fl); close(fd); fd=-1; if(rv) throw konforka::exception(CODEPOINT,"failed to release file lock"); } void pid_file::set(const string& f,bool u) { ofstream of(f.c_str(),ios::trunc); if(!of) throw konforka::exception(CODEPOINT,"failed to open file for writing pid"); of << getpid() << endl; of.close(); file_name = f; unlink_pid = u; } void pid_file::unlink() { if(!unlink_pid) return; ::unlink(file_name.c_str()); } void semaphore::init() { deinit(); semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600); if(semid<0) throw konforka::exception(CODEPOINT,"failed to semget()"); if(semctl(semid,0,SETVAL,1)) throw konforka::exception(CODEPOINT,"failed to semctl()"); } void semaphore::deinit() { if(semid<0) return; semctl(semid,0,IPC_RMID,0); } void semaphore::on() { assert(semid>=0); struct sembuf sb; sb.sem_num=0; sb.sem_op=-1; sb.sem_flg = SEM_UNDO; while(semop(semid,&sb,1)<0) { if(errno!=EINTR) throw konforka::exception(CODEPOINT,"failed to semop()"); } } void semaphore::off() { assert(semid>=0); struct sembuf sb; sb.sem_num=0; sb.sem_op=1; sb.sem_flg = SEM_UNDO; while(semop(semid,&sb,1)<0) { if(errno!=EINTR) throw konforka::exception(CODEPOINT,"failed to semop()"); } } void semaphore_lock::lock() { assert(sem); if(locked) return; sem->on(); locked = true; } void semaphore_lock::unlock() { if(!sem) return; if(!locked) return; sem->off(); locked=false; } - string combine_path(const string& origin,const string& relative,int opts) { - string r = normalize_path(relative,0); - string rv; - // XXX: what to do if relative is empty is a question, really. - if(r.empty()) { - return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash); - }else{ - if(r[0]=='/') { - r.erase(0,1); - }else{ - rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash); - } - } - string::size_type lsl = rv.rfind('/'); - for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) { - assert(sl!=0); - if(sl==1 && r[0]=='.') { - // it's a "./" - r.erase(0,2); - }else if(sl==2 && r[0]=='.' && r[1]=='.') { - // we have a "../" - if(lsl==string::npos) { - if(rv.empty() && (opts&fail_beyond_root)) - throw utility_beyond_root(CODEPOINT,"went beyond root while combining path"); - rv.clear(); - }else{ - rv.erase(lsl); - lsl = rv.rfind('/'); - } - r.erase(0,3); - }else{ - // we have a "something/" - lsl = rv.length(); - rv += '/'; - rv += r.substr(0,sl); - r.erase(0,sl+1); - } - } - if(r.empty()) - return rv+'/'; - if(r.length()==2 && r[0]=='.' && r[0]=='.') { - if(lsl==string::npos) { - if(rv.empty() & (opts&fail_beyond_root)) - throw utility_beyond_root(CODEPOINT,"went beyond root while combining path"); - return "/"; - }else{ - rv.erase(lsl+1); - return rv; - } - } - rv += '/'; - rv += r; - return rv; - } - void auto_chdir::pushdir(const string& td,bool ap) { /* TODO: make use of fchdir(2) instead */ char *tmp = getcwd(0,0); assert(tmp); saved_pwd = tmp; free(tmp); autopop=ap; if(chdir(td.c_str())) throw konforka::exception(CODEPOINT,"failed to chdir()"); } void auto_chdir::popdir() { autopop=false; if(chdir(saved_pwd.c_str())) throw konforka::exception(CODEPOINT,"failed to chdir()"); // XXX: or should it be thrown? after all we call it from destructor... } } diff --git a/lib/sitespace.cc b/lib/sitespace.cc index 0406d11..d5592bf 100644 --- a/lib/sitespace.cc +++ b/lib/sitespace.cc @@ -1,52 +1,53 @@ #ifdef USE_PCH #include "pch.h" #else #include <cassert> + #include <konforka/util.h> #include "sitecing/sitespace.h" #include "sitecing/sitecing_util.h" #endif namespace sitecing { sitespace::sitespace(configuration& c) : config(c), factory(c) { } sitespace::~sitespace() { for(sentenced_t::iterator i = sentenced.begin();i!=sentenced.end();++i) { assert((*i)->chickens_used.empty()); delete *i; } } so_component sitespace::fetch(const string& c,sitecing_interface* scif) { execute_sentenced(); - string sobase = normalize_path(c); + string sobase = konforka::normalize_path(c); string sopath = factory.root_so+sobase+".so"; config_options *co_build = config.lookup_config(sobase,config_options::flag_build); if( (!co_build) || co_build->build ) factory.make(sopath); components_t::iterator i = components.find(sopath); if(i!=components.end()) { if(i->second->is_uptodate()) return so_component(i->second,scif); if(i->second->chickens_used.empty()) { delete i->second; }else{ sentenced.push_back(i->second); } components.erase(i); } pair<components_t::iterator,bool> ins = components.insert(components_t::value_type(sopath,new component_so(sopath))); return so_component(ins.first->second,scif); } void sitespace::execute_sentenced() { for(sentenced_t::iterator i = sentenced.begin();i!=sentenced.end();++i) { if((*i)->chickens_used.empty()) { delete *i; sentenced.erase(i); } } } } |