summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--components/exception_dev7
-rw-r--r--configure.ac4
-rw-r--r--include/sitecing/sitecing_util.h87
-rw-r--r--lib/component_factory.cc31
-rw-r--r--lib/configuration.cc9
-rw-r--r--lib/sitecing_parser.ll13
-rw-r--r--lib/sitecing_util.cc117
-rw-r--r--lib/sitespace.cc3
-rw-r--r--src/sitecing-build.cc5
-rw-r--r--src/sitecing-fastcgi.cc4
-rw-r--r--src/sitecing-plaincgi.cc4
11 files changed, 48 insertions, 236 deletions
diff --git a/components/exception_dev b/components/exception_dev
index d8c84e1..d62f462 100644
--- a/components/exception_dev
+++ b/components/exception_dev
@@ -1,346 +1,347 @@
%%decl using namespace std;
<%impl>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cassert>
#include <cstdarg>
#include <stdexcept>
#include <cxxabi.h>
#include <sitecing/sitecing_util.h>
#include <sitecing/util.h>
#include <sitecing/magic.h>
+ #include <konforka/util.h>
#include <konforka/exception.h>
</%impl>
%%var string message;
%%var string root_source;
%%var string root_intermediate;
%%var string root_so;
%%var string component;
%%var int line_number = -1;
%%var const exception* exception_caught;
<%code>
__SCIF->headers.clear();
__SCIF->out->seekp(0);
int magic = _magic;
va_list va = _args;
switch(magic) {
case sitecing::__magic_compile_error:
message = va_arg(va,const char*);
root_source = va_arg(va,const char*);
root_intermediate = va_arg(va,const char*);
root_so = va_arg(va,const char*);
component = va_arg(va,const char*);
break;
case sitecing::__magic_preprocess_error:
message = va_arg(va,const char*);
root_source = va_arg(va,const char*);
root_intermediate = va_arg(va,const char*);
root_so = va_arg(va,const char*);
component = va_arg(va,const char*);
line_number = va_arg(va,int);
break;
case sitecing::__magic_generic_exception:
message = va_arg(va,const char*);
root_source = va_arg(va,const char*);
root_intermediate = va_arg(va,const char *);
root_so = va_arg(va,const char *);
component = va_arg(va,const char*);
exception_caught = va_arg(va,const exception*);
break;
default:
break;
}
</%code>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title><% message %></title>
<style type="text/css">
<!--
body {
font-family: sans-serif;
font-size: 11pt;
}
h1 {
font-family: serif;
font-size: 130%;
font-weight: bold;
text-align: center;
}
p {
text-indent: 2em;
text-align: justify;
}
dl.exception-props {
margin: 1ex 1em;
padding: 0.5ex;
border: solid 1px gray;
background-color: #e0e0e0;
}
dl.exception-props dt {
font-weight: bold;
color: blue;
}
dl.exception-props dd {
color: gray;
}
div.exception-codepoint-report {
border: solid 1px black;
margin: 0.5ex 1em 0.ex 3em;
}
div.exception-codepoint-report h3 {
display: block;
color: blue;
border-bottom: 3px double black;
padding: 0.3ex; margin: 0px;
background: #e0e0e0;
}
div.exception-codepoint-report ul {
padding: 0px;
margin: 0px;
background: #87fdff;
font-size: 70%;
}
div.exception-codepoint-report li {
font-family: monospace;
list-style-type: none;
white-space: nowrap;
overflow: hidden;
}
div.exception-codepoint-report li.focused {
color: red;
border-top: solid 1px red; border-bottom: solid 1px red;
}
div.exception-codepoint-report li .lineno {
padding-right: 0.5ex;
border-right: dotted black 1px;
}
div.exception-codepoint-report div.what {
border-top: double 3px black;
padding: 0.5ex 2em;
font-weight: bold; color: #4040c0;
overflow: auto;
}
div.backtrace div.exception-codepoint-report div.what {
color: gray;
}
div.exception-compile div.what {
font-weight: normal;
color: red;
}
div.powered {
margin: 2em 0px 0px 50%;
padding: 1ex 2ex;
text-align: right;
font-family: serif;
font-size: 140%;
font-weight: bold;
border-top: solid 2px black;
border-left: solid 1px gray; border-right: solid 1px gray; border-bottom: solid 1px gray;
background: #c0c0f0;
}
-->
</style>
% __SCIF->headers["Content-Type"]="text/html; charset=utf-8";
% __SCIF->headers["Pragma"]="no-cache";
</head>
<body>
<%code>
switch(magic) {
case sitecing::__magic_compile_error:
handle_compile_error();
break;
case sitecing::__magic_preprocess_error:
handle_preprocess_error();
break;
case sitecing::__magic_generic_exception:
handle_generic_exception();
break;
default:
handle_unknown_error();
break;
}
</%code>
<div class="powered">Powered by <a href="http://kin.klever.net/sitecing/" title="site-C-ing">site-C-ing</a>.</div>
</body>
</html>
<%method void handle_generic_exception() %>
<div class="exception-generic">
<h1>exception caught while running component '<code><% component %></code>'</h1>
<dl class="exception-props">
<dt><code>typeid(<em>e</em>).name()</code></dt>
% int destat;
% char *demangled = abi::__cxa_demangle(typeid(*exception_caught).name(),NULL,NULL,&destat);
<dd><code><% destat?typeid(*exception_caught).name():demangled %></code></dd>
% if(!destat) free(demangled);
<dt><code><em>e</em>.what()</code></dt>
<dd><% message %></dd>
% if(typeid(*exception_caught)==typeid(konforka::exception&)) {
% konforka::exception* ke = (konforka::exception*)exception_caught;
<dt><code><em>e</em>.where()</code></dt>
<dd><code>
% if(ke->_where.line<0) {
<% ke->where() %>
% }else{
<% strip_roots(ke->_where.file) %>:<% ke->_where.line %> [<% ke->_where.function %>]
% }
</code></dd>
% }
</dl>
% if(typeid(*exception_caught)==typeid(konforka::exception&)) {
% konforka::exception* ke = (konforka::exception*)exception_caught;
% if(ke->_where.line>=0) {
% report_error(ke->_where.file,ke->_where.line,ke->what());
% }
% if(!ke->_seen.empty()) {
<h2>seen at:</h2>
<div class="backtrace">
% for(list<konforka::code_point>::const_iterator i=ke->_seen.begin();i!=ke->_seen.end();++i) {
% if(i->line>=0) {
% report_error(i->file,i->line,i->function);
% }
% }
</div>
% }
% }
</div>
</%method>
<%method void handle_preprocess_error() %>
<div class="exception-preprocess">
<h1>error preprocessing component '<code><% component %></code>'</h1>
% report_error(root_source+component,line_number,message);
</div>
</%method>
<%method void handle_compile_error() %>
<div class="exception-compile">
<h1>error compiling component '<code><% component %></code>'</h1>
<%code>
ifstream err((root_intermediate+component+".stderr").c_str(),ios::in);
if(err.bad()) {
<%output>
Failed to access compiler output
</%output>
}else{
string cumulative;
string error_file;
long error_line = -1;
while(!err.eof()) {
string oef = error_file;
long oel = error_line;
string line;
getline(err,line);
if(line[0]!=' ') {
string::size_type c = line.find(':');
if(c!=string::npos) {
string fn = line.substr(0,c);
string::size_type c1 = line.find(':',c+1);
if(c1!=string::npos) {
string ln = line.substr(c+1,c1-c-1);
string::size_type nd = ln.find_first_not_of("0123456789");
if(nd==string::npos) {
try {
error_file = sitecing::strip_prefix(fn,"In file included from ");
}catch(sitecing::utility_no_prefix& unp) {
error_file = fn;
}
error_line = strtol(ln.c_str(),0,10);
}
}
}
if((oel>0 && !oef.empty()) && (oel!=error_line || oef!=error_file)) {
- string ef = "/"+sitecing::combine_path(root_source+component,oef);
+ string ef = "/"+konforka::combine_path(root_source+component,oef);
report_error(ef,oel,remove_roots(cumulative));
cumulative.clear();
}
}
if(!cumulative.empty())
cumulative += '\n';
cumulative += line;
}
if(!(cumulative.empty() || error_file.empty() || error_line<0)) {
- error_file = "/"+sitecing::combine_path(root_source+component,error_file);
+ error_file = "/"+konforka::combine_path(root_source+component,error_file);
report_error(error_file,error_line,remove_roots(cumulative));
}
}
</%code>
</div>
</%method>
<%method void handle_unknown_error() %>
<div class="exception-unknown">
<h1>unknown error</h1>
</div>
</%method>
<%method void report_error(const string& file,long line,const string& message) %>
<div class="exception-codepoint-report">
<h3><% sitecing::html_escape(strip_roots(file)) %></h3>
<%code>
if(line>=0) {
int firstline = line-5, lastline = line+5;
if(firstline<1)
firstline = 1;
ifstream ifs(file.c_str(),ios::in);
if(ifs.bad()) {
// TODO:
}else{
for(int l=1;l<firstline && !ifs.eof();l++) {
ifs.ignore(65536,'\n');
}
if(ifs.eof()) {
// TODO: no such line in file
}else{
<%output><ul></%output>
for(int l=firstline;l<=lastline && !ifs.eof();l++) {
string str;
getline(ifs,str);
for(string::size_type t=str.find('\t');t!=string::npos;t=str.find('\t')) {
str.replace(t,1,8-(t%8),' ');
}
char tln[16];
snprintf(tln,sizeof(tln),"%5d",l);
<%output>
<li class="<% l==line?"focused":"unfocused" %>"><span class="lineno"><% sitecing::html_escape(tln,sitecing::html_escape_nbsp) %></span>&nbsp;<span class="line"><% sitecing::html_escape(str,sitecing::html_escape_nbsp) %></span></li>
</%output>
}
<%output></ul></%output>
}
}
}
</%code>
<div class="what">
<% sitecing::html_escape(message,sitecing::html_escape_br) %>
</div>
</div>
</%method>
<%codemethod string strip_roots(const string& filename) %>
- string np = sitecing::normalize_path(filename);
+ string np = konforka::normalize_path(filename);
try{
return sitecing::strip_prefix(np,root_source);
}catch(sitecing::utility_no_prefix& e){ }
try{
return sitecing::strip_prefix(np,root_intermediate);
}catch(sitecing::utility_no_prefix& e){ }
</%codemethod>
<%codemethod string remove_roots(const string& str) %>
string rv = str;
string::size_type rp;
string::size_type rl = root_source.length();
while((rp=rv.find(root_source))!=string::npos) {
rv.erase(rp,rl);
}
rl = root_intermediate.length();
while((rp=rv.find(root_intermediate))!=string::npos) {
rv.erase(rp,rl);
}
rl = root_so.length();
while((rp=rv.find(root_so))!=string::npos) {
rv.erase(rp,rl);
}
return rv;
</%codemethod>
% /* vim:set ft=sitecing: */
diff --git a/configure.ac b/configure.ac
index a8aa142..fde326b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,89 +1,93 @@
AC_INIT([sitecing], [0.0.1], [sitecing-bugs@klever.net])
AC_CONFIG_SRCDIR([include/sitecing/sitecing_parser.h])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_PROG_INSTALL
AC_PROG_AWK
AC_PROG_CXX
AC_PROG_CC
AM_PROG_LEX
AC_PROG_LIBTOOL
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h unistd.h])
AC_C_CONST
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_WITH_PKGCONFIG
+PKG_CHECK_MODULES([KONFORKA],[konforka >= 0.0.1],,[
+ AC_MSG_ERROR([no proper version of konforka library found, get it at http://kin.klever.net/konforka/])
+])
+
PKG_CHECK_MODULES([KINGATE],[kingate >= 0.0.1],,[
AC_MSG_ERROR([no kingate library found, get it at http://kin.klever.net/kingate/])
])
HAVE_FCGI=false
HAVE_PLAINCGI=false
PKG_CHECK_MODULES([KINGATE_FCGI],[kingate-fcgi >= 0.0.1],[
HAVE_FCGI=true
],[
AC_MSG_NOTICE([no fastcgi support in kingate library])
])
PKG_CHECK_MODULES([KINGATE_PLAINCGI],[kingate-plaincgi >= 0.0.1],[
HAVE_PLAINCGI=true
],[
AC_MSG_NOTICE([no plaincgi support in kingate library])
])
if ! (${HAVE_FCGI} || ${HAVE_PLAINCGI}) ; then
AC_MSG_ERROR([not a single CGI interface supported in kingate])
fi
AM_CONDITIONAL([HAVE_FCGI],[${HAVE_FCGI}])
AM_CONDITIONAL([HAVE_PLAINCGI],[${HAVE_PLAINCGI}])
PKG_CHECK_MODULES([DOTCONF],[dotconf],,[
AC_MSG_ERROR([no dotconf library found])
])
AC_WITH_PCRE([
AC_WITH_PCREPP(,[
AC_MSG_ERROR([no pcre++ library found])
])
],[
AC_MSG_ERROR([no pcre library found])
])
AC_CHECK_FUNC([dlopen],,[
AC_CHECK_LIB([dl],[dlopen],,[
AC_MSG_ERROR([no dlopen library found])
])
])
AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
WANT_DOXYGEN="yes"
AC_ARG_ENABLE([doxygen],
AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
[
test "${enableval}" = "no" && WANT_DOXYGEN="no"
]
)
if test "${WANT_DOXYGEN}" = "yes" ; then
AC_WITH_DOXYGEN
AC_WITH_DOT
else
AM_CONDITIONAL([HAVE_DOXYGEN],[false])
AM_CONDITIONAL([HAVE_DOT],[false])
fi
AC_CONFIG_FILES([
Makefile
Doxyfile
sitecing.pc
include/Makefile
lib/Makefile
share/Makefile
src/Makefile
components/Makefile
])
AC_OUTPUT
diff --git a/include/sitecing/sitecing_util.h b/include/sitecing/sitecing_util.h
index d1a6c4a..f642c74 100644
--- a/include/sitecing/sitecing_util.h
+++ b/include/sitecing/sitecing_util.h
@@ -1,341 +1,260 @@
#ifndef __SITECING_SITECING_UTIL_H
#define __SITECING_SITECING_UTIL_H
#include <sys/types.h>
#include <string>
#include <konforka/exception.h>
+#include <konforka/util.h>
/**
* @file
* @brief utility classes and functions.
*/
namespace sitecing {
using namespace std;
/**
* Base class for utility exceptions.
*/
class utility_error : public konforka::exception {
public:
utility_error(const string& fi,const string& fu,int l,const string& w)
: konforka::exception(fi,fu,l,w) { }
};
- /**
- * Restricted sequence encountered.
- */
- class utility_restricted_sequence : public utility_error {
- public:
- utility_restricted_sequence(const string& fi,const string& fu,int l,const string& w)
- : utility_error(fi,fu,l,w) { }
- };
+
/**
* No prefix or suffix found to strip out.
*/
class utility_no_affix : public utility_error {
public:
utility_no_affix(const string& fi,const string& fu,int l,const string& w)
: utility_error(fi,fu,l,w) { }
};
/**
* No prefix to strip found.
*/
class utility_no_prefix : public utility_no_affix {
public:
utility_no_prefix(const string& fi,const string& fu,int l,const string& w)
: utility_no_affix(fi,fu,l,w) { }
};
/**
* No suffix to strip found.
*/
class utility_no_suffix : public utility_no_affix {
public:
utility_no_suffix(const string& fi,const string& fu,int l,const string& w)
: utility_no_affix(fi,fu,l,w) { }
};
/**
- * Went up beyond root.
- * @todo TODO: wish I could remember the details -- document me.
- */
- class utility_beyond_root : public utility_error {
- public:
- utility_beyond_root(const string& fi,const string& fu,int l,const string& w)
- : utility_error(fi,fu,l,w) { }
- };
-
- /**
* The file lock object. Released at the object destruction.
*/
class file_lock {
public:
/**
* The file descriptor.
*/
int fd;
file_lock()
: fd(-1) { }
/**
* @param f file name.
*/
file_lock(const string& f)
: fd(-1) { lock(f); }
~file_lock() { unlock(); }
/**
* Do lock.
* @param f file name.
*/
void lock(const string& f);
/**
* @todo TODO: wish I could remember the details -- document me.
*/
void lock();
/**
* Release the lock obtained.
*/
void unlock();
};
/**
* The pid file. Removed at object destruction.
*/
class pid_file {
public:
/**
* The file name.
*/
string file_name;
/**
* Do we unlink the file after we're done?
*/
bool unlink_pid;
pid_file()
: unlink_pid(false) { }
~pid_file() { unlink(); }
/**
* @param f file name.
* @param u whether we want to unlink the file.
*/
void set(const string& f,bool u=true);
/**
* Unlink the file if we wanted to in the first place.
*/
void unlink();
};
/**
* The semaphore object.
*/
class semaphore {
public:
/**
* The semaphore id.
*/
int semid;
semaphore()
: semid(-1) { }
/**
* @param sid semaphore id.
*/
semaphore(int sid)
: semid(sid) { }
~semaphore() {
deinit();
}
/**
* Init semaphore.
*/
void init();
/**
* Undo the init.
*/
void deinit();
/**
* Semaphore on.
*/
void on();
/**
* Semaphore off.
*/
void off();
};
/**
* The semaphor lock object, released at object destruction.
*/
class semaphore_lock {
public:
/**
* Pointer to the semaphore we're operating on.
*/
semaphore* sem;
/**
* Whether it is locked.
*/
bool locked;
semaphore_lock()
: sem(NULL), locked(false) {}
/**
* @param s pointer to the semaphore.
* @param l lock at creation?
*/
semaphore_lock(semaphore* s,bool l=true)
: sem(s), locked(false) {
if(l) lock();
}
/**
* @param s reference to the semaphore.
* @param l lock at creation?
*/
semaphore_lock(semaphore& s,bool l=true)
: sem(&s), locked(false) {
if(l) lock();
}
~semaphore_lock() {
unlock();
}
/**
* Lock it.
*/
void lock();
/**
* Unlock it.
*/
void unlock();
};
/**
- * normalize_path options enumeration.
- * @see normalize_path()
- */
- enum normalize_path_options {
- /**
- * Restrict the /../ sequence.
- */
- restrict_dotdot = 1,
- /**
- * Strip out the leading slash.
- */
- strip_leading_slash = 2,
- /**
- * Strip out the trailing slash.
- */
- strip_trailing_slash = 4
- };
- /**
- * combine_path options enumeration.
- * @see combine_path()
- */
- enum combine_path_options {
- /**
- * The origin is file. Otherwise it is directory.
- */
- origin_is_file = 1,
- /**
- * Fail if we've gone up beyond root.
- */
- fail_beyond_root = 2
- };
-
- /**
- * Normalize pathname by stripping duplicate slashes, etc.
- * @param path the path name.
- * @param opts options.
- * @return the normalized path.
- * @see normalize_path_options
- * @todo TODO: document exceptions.
- */
- string normalize_path(const string& path,int opts=(restrict_dotdot|strip_trailing_slash));
- /**
* Strip prefix from the string.
* @param str the string.
* @param prefix prefix to strip.
* @return the string without prefix.
* @todo TODO: document exceptions.
*/
string strip_prefix(const string& str,const string& prefix);
/**
* Strip suffix from the string.
* @param str the string.
* @param suffix suffix to strip.
* @return the string without suffix.
* @todo TODO: document exceptions.
*/
string strip_suffix(const string& str,const string& suffix);
- /**
- * Get the directory part of the filename.
- * @param filename the full file name.
- * @return the directory part.
- */
- string dir_name(const string& filename);
- /**
- * Combine path with the relative path.
- * @param origin the origin.
- * @param relative relative path to combine origin with.
- * @param opts options.
- * @return the pathc combined.
- * @see combine_path_options
- * @todo TODO: document exceptions.
- */
- string combine_path(const string& origin,const string& relative,int opts=origin_is_file);
-
- /**
- * Create directory and parent directories if needed.
- * @param path the pathname.
- * @param mode the mode for newly created directories.
- */
- void make_path(const string& path,mode_t mode);
-
+
/**
* Change to the directory and pop back at object's destruction (e.g. when
* the object goes out of scope).
*/
class auto_chdir {
public:
/**
* Saved working directory.
*/
string saved_pwd;
/**
* Whether we want to change back automatically.
*/
bool autopop;
auto_chdir()
: autopop(false) { }
/**
* @param td destination path.
* @param ap automatically come back?
*/
auto_chdir(const string& td,bool ap=true)
: autopop(false) { pushdir(td,ap); }
~auto_chdir() {
if(autopop)
popdir();
}
/**
* Change into directory.
* @param td the directory.
* @param ap automaticall pop back?
*/
void pushdir(const string& td,bool ap=true);
/**
* Change to the saved directory.
*/
void popdir();
};
}
#endif /* __SITECING_SITECING_UTIL_H */
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);
}
}
}
}
diff --git a/src/sitecing-build.cc b/src/sitecing-build.cc
index 4cad0a3..887ef83 100644
--- a/src/sitecing-build.cc
+++ b/src/sitecing-build.cc
@@ -1,231 +1,232 @@
#include <sys/types.h>
#include <dirent.h>
#include <getopt.h>
#include <iostream>
#include <memory>
#include <fstream>
#include <cassert>
#include <set>
using namespace std;
+#include <konforka/util.h>
#include "sitecing/sitecing_util.h"
#include "sitecing/util.h"
#include "sitecing/sitespace.h"
#include "sitecing/sitecing_interface_cgi.h"
#include "sitecing/cgi_component.h"
#include "sitecing/configuration.h"
#include "sitecing/magic.h"
#include "sitecing/sitecing_exception.h"
#include "sitecing/exception.h"
using namespace sitecing;
#include "config.h"
#define PHEADER PACKAGE "-build Version " VERSION
#define PCOPY "Copyright (c) 2004 Klever Group"
static sitespace* site_space = NULL;
typedef pair<dev_t,ino_t> the_inode_t;
set<the_inode_t> built_inodes;
void build_component(const string& component) {
assert(site_space);
cerr << "Building " << component << endl;
try {
site_space->factory.make(site_space->config.root_so+component+".so");
}catch(compile_error& ce) {
ce.see(CODEPOINT);
ifstream err((site_space->config.root_intermediate+ce.component_path+".stderr").c_str(),ios::in);
if(err) {
cerr << err.rdbuf();
}
throw;
}catch(preprocessor_error& pe) {
pe.see(CODEPOINT);
cerr << site_space->config.root_source << pe.component_name << ":" << pe.line_number << ":" << pe.what() << endl;
throw;
}
}
void build_imports(const string& component);
void build_with_imports(const string& component) {
assert(site_space);
struct stat st;
string cp = site_space->config.root_source+component;
if(!lstat(cp.c_str(),&st)) {
if(built_inodes.find(the_inode_t(st.st_dev,st.st_ino))!=built_inodes.end())
return;
built_inodes.insert(the_inode_t(st.st_dev,st.st_ino));
}
build_component(component);
build_imports(component);
}
void build_imports(const string& component) {
assert(site_space);
ifstream ifs((site_space->config.root_intermediate+component+".imports").c_str(),ios::in);
cerr << "Building components imported by " << component << endl;
if(ifs) {
string import;
while(!ifs.eof()) {
ifs >> import;
if(!import.empty())
build_with_imports(import);
}
}
}
void build_http_status_handlers(const string& target) {
assert(site_space);
set<string> stop_list;
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 = site_space->config.lookup_loaded_options(t);
if( lo && (lo->flags&config_options::flag_http_status_handlers) ) {
for(config_options::http_status_handlers_t::const_iterator i=lo->http_status_handlers.begin();i!=lo->http_status_handlers.end();++i) {
if(stop_list.find(i->first)==stop_list.end()) {
build_with_imports(i->second);
stop_list.insert(i->first);
}
}
}
}
configuration::specs_t::iterator i=site_space->config.specs.find(t);
if( i!=site_space->config.specs.end() && (i->second.flags&config_options::flag_http_status_handlers) ) {
for(config_options::http_status_handlers_t::const_iterator ii=i->second.http_status_handlers.begin();ii!=i->second.http_status_handlers.end();++i) {
if(stop_list.find(ii->first)==stop_list.end()) {
build_with_imports(ii->second);
stop_list.insert(ii->first);
}
}
}
if(t.empty())
return;
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 build_target(const string& target) {
assert(site_space);
string action = target;
config_options::action_handler_t *ah = site_space->config.lookup_action_handler(target);
if(ah)
action = ah->action;
build_with_imports(action);
}
void build(const string& target) {
assert(site_space);
build_http_status_handlers(target);
config_options *co_exception_handler = site_space->config.lookup_config(target,config_options::flag_exception_handler);
if(co_exception_handler) {
string handler = co_exception_handler->exception_handler;
build_with_imports(handler);
}
string target_source = site_space->config.root_source+target;
struct stat st;
if(stat(target_source.c_str(),&st))
throw konforka::exception(CODEPOINT,"failed to stat() target");
if(S_ISREG(st.st_mode)) {
build_target(target);
}else if(S_ISDIR(st.st_mode)) {
build_http_status_handlers(target);
DIR *d=opendir(target_source.c_str());
if(!d)
throw konforka::exception(CODEPOINT,"failed to opendir()");
for(struct dirent *de=readdir(d);de;de=readdir(d)) {
if(!strcmp(de->d_name,"."))
continue;
if(!strcmp(de->d_name,".."))
continue;
- string subtarget = normalize_path(target+"/"+de->d_name);
+ string subtarget = konforka::normalize_path(target+"/"+de->d_name);
struct stat sts;
if(stat((site_space->config.root_source+subtarget).c_str(),&sts))
throw konforka::exception(CODEPOINT,"failed to stat() subtarget");
if(S_ISDIR(sts.st_mode)) {
build(subtarget);
}else{
if(site_space->config.match_autobuild_files(target,de->d_name)){
build_target(subtarget);
}
}
}
closedir(d);
}
}
int main(int argc,char **argv) {
try {
string config_file = "sitecing.conf";
while(true) {
static struct option opts[] = {
{ "help", no_argument, 0, 'h' },
{ "usage", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "license", no_argument, 0, 'L' },
{ "config", required_argument, 0, 'f' },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc,argv,"f:hVL",opts,NULL);
if(c==-1)
break;
switch(c) {
case 'h':
cerr << PHEADER << endl
<< PCOPY << endl << endl
<< " -h, --help" << endl
<< " --usage display this text" << endl
<< " -V, --version display version number" << endl
<< " -L, --license show license" << endl
<< " -f filename, --config=filename" << endl
<< " specify configuration file to use" << endl;
exit(0);
break;
case 'V':
cerr << VERSION << endl;
exit(0);
break;
case 'L':
extern const char *COPYING;
cerr << COPYING << endl;
exit(0);
break;
case 'f':
config_file = optarg;
break;
default:
cerr << "Huh??" << endl;
break;
}
}
configuration config(config_file,true);
if(!(config.flags&configuration::flag_root_source))
throw konforka::exception(CODEPOINT,"Unspecified root for sources");
if(!(config.flags&configuration::flag_root_intermediate))
throw konforka::exception(CODEPOINT,"Unspecified root for intermediate files");
if(!(config.flags&configuration::flag_root_so))
throw konforka::exception(CODEPOINT,"Unspecified root for shared objects");
sitespace ss(config);
site_space = &ss;
if(optind<argc) {
for(int narg=optind;narg<argc;narg++) {
const char *arg = argv[narg];
build(arg);
}
}else
build("/");
return 0;
}catch(exception& e) {
cerr << "Oops: " << e.what() << endl;
return 1;
}
}
diff --git a/src/sitecing-fastcgi.cc b/src/sitecing-fastcgi.cc
index 756dcee..03587aa 100644
--- a/src/sitecing-fastcgi.cc
+++ b/src/sitecing-fastcgi.cc
@@ -1,328 +1,328 @@
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <syslog.h>
#include <iostream>
#include <memory>
#include <typeinfo>
using namespace std;
#include "kingate/fastcgi.h"
#include "kingate/cgi_gateway.h"
using namespace kingate;
#include "sitecing/sitecing_util.h"
#include "sitecing/util.h"
#include "sitecing/sitespace.h"
#include "sitecing/sitecing_interface_cgi.h"
#include "sitecing/cgi_component.h"
#include "sitecing/configuration.h"
#include "sitecing/magic.h"
#include "sitecing/sitecing_exception.h"
#include "sitecing/exception.h"
#include "sitecing/process_manager.h"
using namespace sitecing;
#include "config.h"
#define PHEADER PACKAGE " Version " VERSION
#define PCOPY "Copyright (c) 2004 Klever Group"
class cdummyClass : public acomponent {
public:
void main(int _magic,va_list _args) {}
void *__the_most_derived_this() { return NULL; }
} cdummyInstance;
class adummyClass : public cgi_component {
public:
void main(int _magic,va_list _args) {}
void *__the_most_derived_this() { return NULL; }
} adummyInstance;
class sitecing_fastcgi_pm : public process_manager {
public:
configuration config;
fcgi_socket *fss;
semaphore sem;
bool multi;
uid_t uid;
gid_t gid;
pid_file pidfile;
sitecing_fastcgi_pm(const string& config_file);
~sitecing_fastcgi_pm();
void process(int slot);
void run();
void give_up_privs();
};
sitecing_fastcgi_pm::sitecing_fastcgi_pm(const string& config_file)
: config(config_file), multi(false) {
if(( (config.flags&configuration::flag_user) || (config.flags&configuration::flag_group) || (config.flags&configuration::flag_chroot) ) && geteuid() )
throw konforka::exception(CODEPOINT,"can't use User, Group or Chroot when started without root privileges");
if(config.flags&configuration::flag_user) {
struct passwd *ptmp = getpwnam(config.user.c_str());
if(ptmp) {
uid = ptmp->pw_uid;
}else{
errno=0;
uid = strtol(config.user.c_str(),NULL,0);
if(errno)
throw konforka::exception(CODEPOINT,"failed to resolve User value to uid");
}
}
if(config.flags&configuration::flag_group) {
struct group *gtmp = getgrnam(config.group.c_str());
if(gtmp) {
gid = gtmp->gr_gid;
}else{
errno=0;
gid = strtol(config.group.c_str(),NULL,0);
if(errno)
throw konforka::exception(CODEPOINT,"failed to resolve Group value to gid");
}
}
if(!(config.flags&configuration::flag_root_source))
throw konforka::exception(CODEPOINT,"unspecified root for sources");
if(!(config.flags&configuration::flag_root_intermediate))
throw konforka::exception(CODEPOINT,"unspecified root for intermediate files");
if(!(config.flags&configuration::flag_root_so))
throw konforka::exception(CODEPOINT,"unspecified root for shared objects");
if(config.flags&configuration::flag_min_children)
min_children = config.min_children;
if(config.flags&configuration::flag_max_children)
max_children = config.max_children;
if(config.flags&configuration::flag_min_spare_children)
min_spare_children = config.min_spare_children;
if(config.flags&configuration::flag_max_spare_children)
max_spare_children = config.max_spare_children;
if(max_children<min_spare_children)
throw konforka::exception(CODEPOINT,"inconsistent numbers of MaxChildren and MinSpareChildren");
if(min_children>max_spare_children && max_spare_children>=0)
throw konforka::exception(CODEPOINT,"inconsistent numbers of MinChildren and MaxSpareChildren");
if(config.flags&configuration::flag_multi_process) {
multi = config.multi_process;
}else{
if(config.flags&configuration::flag_listen_socket)
multi = true;
else
multi = false;
}
fss = (config.flags&configuration::flag_listen_socket)?new fcgi_socket(config.listen_socket.c_str(),5):new fcgi_socket(0);
if(!fss)
throw konforka::exception(CODEPOINT,"failed to establish listening socket");
if(config.flags&configuration::flag_daemonize && config.daemonize) {
pid_t pf = fork();
if(pf<0)
throw konforka::exception(CODEPOINT,"failed to fork()");
if(pf) {
die_humbly=true;
_exit(0);
}
}
if(config.flags&configuration::flag_pid_file) {
pidfile.set(config.pid_file);
}
if(multi)
sem.init();
}
sitecing_fastcgi_pm::~sitecing_fastcgi_pm() {
if(fss)
delete fss;
}
void sitecing_fastcgi_pm::process(int slot) {
signal(SIGINT,SIG_DFL);
signal(SIGABRT,SIG_DFL);
signal(SIGTERM,SIG_DFL);
give_up_privs();
scoreboard_slot *sslot = sboard.get_slot(slot);
try {
sitespace ss(config);
fcgi_socket& fs = *fss;
sitecing_interface_cgi scif(&ss);
string component_path;
string action;
config_options::action_handler_t *action_handler;
int rpc = 0;
if(config.flags&configuration::flag_requests_per_child)
rpc = config.requests_per_child;
for(int req=0;(rpc<=0) || (req<rpc);rpc++) {
semaphore_lock sl;
if(multi) {
sslot->state = scoreboard_slot::state_idle;
sl.sem = &sem;
sl.lock();
}
sslot->state = scoreboard_slot::state_accept;
fcgi_interface fi(fs);
sslot->state = scoreboard_slot::state_processing;
if(multi)
sl.unlock();
cgi_gateway gw(fi);
scif.prepare(&gw);
try {
- component_path = normalize_path(gw.path_info(),strip_leading_slash|strip_trailing_slash);
+ component_path = konforka::normalize_path(gw.path_info(),konforka::strip_leading_slash|konforka::strip_trailing_slash);
string full_component_path;
string sitecing_path_info;
while(true) {
full_component_path = config.root_source+'/'+component_path;
if(!access(full_component_path.c_str(),F_OK))
break;
string::size_type sl = component_path.rfind('/');
if(sl==string::npos)
throw konforka::exception(CODEPOINT,"can't find the target component");
sitecing_path_info.insert(0,component_path,sl,string::npos);
component_path.erase(sl);
}
fi.metavars["SITECING_PATH_INFO"]=sitecing_path_info;
action = component_path;
action_handler = config.lookup_action_handler(component_path);
if(action_handler) {
action = action_handler->action;
}
- string pwd = dir_name(full_component_path);
+ string pwd = konforka::dir_name(full_component_path);
if(chdir(pwd.c_str()))
throw konforka::exception(CODEPOINT,"failed to chdir() into document's directory");
so_component soc = ss.fetch(action,&scif);
if(action_handler) {
soc.ac->run(__magic_action,
config.root_source.c_str(), config.root_intermediate.c_str(), config.root_so.c_str(),
&(action_handler->args)
);
}else{
soc.ac->main(0,NULL);
}
}catch(http_status& hs) {
scif.headers["Status"] = hs.status+" "+hs.message;
string hshp = config.lookup_http_status_handler(component_path,hs.status);
if(!hshp.empty()) {
so_component hsh = ss.fetch(hshp,&scif); // TODO: handle error trying to handle status
hsh.ac->run(__magic_http_status,config.root_source.c_str(),config.root_intermediate.c_str(),
config.root_so.c_str(),action.c_str(),&hs);
}
}catch(compile_error& ce) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_compile_error,ce.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),ce.component_path.c_str());
}else{
ce.see(CODEPOINT);
throw;
}
}catch(preprocessor_error& pe) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_preprocess_error,pe.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),pe.component_name.c_str(),pe.line_number);
}else{
pe.see(CODEPOINT);
throw;
}
}catch(exception& e) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_generic_exception,e.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),component_path.c_str(),&e);
}
}
scif.flush();
}
}catch(exception& e) {
cerr << "->Oops: " << e.what() << endl;
}
}
void sitecing_fastcgi_pm::run() {
if(multi)
manage();
else
process(0);
}
void sitecing_fastcgi_pm::give_up_privs() {
if(config.flags&configuration::flag_chroot) {
if(chroot(config.chroot.c_str()))
throw konforka::exception(CODEPOINT,"failed to chroot()");
}
if(config.flags&configuration::flag_group) {
if((getgid()!=gid) && setgid(gid))
throw konforka::exception(CODEPOINT,"failed to setgid()");
}
if(config.flags&configuration::flag_user) {
if((getuid()!=uid) && setuid(uid))
throw konforka::exception(CODEPOINT,"failed to setuid()");
}
}
static sitecing_fastcgi_pm* _process_manager = NULL;
static void lethal_signal_handler(int signum) {
_process_manager->finishing=true;
}
int main(int argc,char **argv) {
const char* id = *argv;
const char* t;
while(t = index(id,'/')) {
id=t; id++;
}
openlog(id,LOG_PERROR|LOG_PID,LOG_USER);
try {
string config_file = "sitecing.conf";
while(true) {
static struct option opts[] = {
{ "help", no_argument, 0, 'h' },
{ "usage", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "license", no_argument, 0, 'L' },
{ "config", required_argument, 0, 'f' },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc,argv,"f:hVL",opts,NULL);
if(c==-1)
break;
switch(c) {
case 'h':
cerr << PHEADER << endl
<< PCOPY << endl << endl
<< " -h, --help" << endl
<< " --usage display this text" << endl
<< " -V, --version display version number" << endl
<< " -L, --license show license" << endl
<< " -f filename, --config=filename" << endl
<< " specify configuration file to use" << endl;
exit(0);
break;
case 'V':
cerr << VERSION << endl;
exit(0);
break;
case 'L':
extern const char *COPYING;
cerr << COPYING << endl;
exit(0);
break;
case 'f':
config_file = optarg;
break;
default:
cerr << "Huh??" << endl;
break;
}
}
sitecing_fastcgi_pm sfpm(config_file);
_process_manager = &sfpm;
signal(SIGINT,lethal_signal_handler);
signal(SIGABRT,lethal_signal_handler);
signal(SIGTERM,lethal_signal_handler);
sfpm.run();
}catch(exception& e) {
/* cerr << "Oops: " << e.what() << endl; */
syslog(LOG_ERR,"uncaught exception: %s",e.what());
}
closelog();
}
diff --git a/src/sitecing-plaincgi.cc b/src/sitecing-plaincgi.cc
index 3bd291a..2f93cc5 100644
--- a/src/sitecing-plaincgi.cc
+++ b/src/sitecing-plaincgi.cc
@@ -1,181 +1,181 @@
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <syslog.h>
#include <iostream>
#include <memory>
#include <typeinfo>
using namespace std;
#include "kingate/plaincgi.h"
#include "kingate/cgi_gateway.h"
using namespace kingate;
#include "sitecing/sitecing_util.h"
#include "sitecing/util.h"
#include "sitecing/sitespace.h"
#include "sitecing/sitecing_interface_cgi.h"
#include "sitecing/cgi_component.h"
#include "sitecing/configuration.h"
#include "sitecing/magic.h"
#include "sitecing/sitecing_exception.h"
#include "sitecing/exception.h"
using namespace sitecing;
#include "config.h"
#define PHEADER PACKAGE " Version " VERSION
#define PCOPY "Copyright (c) 2005 Klever Group"
class cdummyClass : public acomponent {
public:
void main(int _magic,va_list _args) {}
void *__the_most_derived_this() { return NULL; }
} cdummyInstance;
class adummyClass : public cgi_component {
public:
void main(int _magic,va_list _args) {}
void *__the_most_derived_this() { return NULL; }
} adummyInstance;
void process_request(configuration& config) {
try {
sitespace ss(config);
sitecing_interface_cgi scif(&ss);
string component_path;
string action;
config_options::action_handler_t *action_handler;
plaincgi_interface ci;
cgi_gateway gw(ci);
scif.prepare(&gw);
try {
- component_path = normalize_path(gw.path_info(),strip_leading_slash|strip_trailing_slash);
+ component_path = konforka::normalize_path(gw.path_info(),konforka::strip_leading_slash|konforka::strip_trailing_slash);
string full_component_path;
string sitecing_path_info;
while(true) {
full_component_path = config.root_source+'/'+component_path;
if(!access(full_component_path.c_str(),F_OK))
break;
string::size_type sl = component_path.rfind('/');
if(sl==string::npos)
throw konforka::exception(CODEPOINT,"can't find the target component");
sitecing_path_info.insert(0,component_path,sl,string::npos);
component_path.erase(sl);
}
ci.metavars["SITECING_PATH_INFO"]=sitecing_path_info;
action = component_path;
action_handler = config.lookup_action_handler(component_path);
if(action_handler) {
action = action_handler->action;
}
- string pwd = dir_name(full_component_path);
+ string pwd = konforka::dir_name(full_component_path);
if(chdir(pwd.c_str()))
throw konforka::exception(CODEPOINT,"failed to chdir() into document's directory");
so_component soc = ss.fetch(action,&scif);
if(action_handler) {
soc.ac->run(__magic_action,
config.root_source.c_str(), config.root_intermediate.c_str(), config.root_so.c_str(),
&(action_handler->args)
);
}else{
soc.ac->main(0,NULL);
}
}catch(http_status& hs) {
scif.headers["Status"] = hs.status+" "+hs.message;
string hshp = config.lookup_http_status_handler(component_path,hs.status);
if(!hshp.empty()) {
so_component hsh = ss.fetch(hshp,&scif); // TODO: handle error trying to handle status
hsh.ac->run(__magic_http_status,config.root_source.c_str(),config.root_intermediate.c_str(),
config.root_so.c_str(),action.c_str(),&hs);
}
}catch(compile_error& ce) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_compile_error,ce.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),ce.component_path.c_str());
}else{
ce.see(CODEPOINT);
throw;
}
}catch(preprocessor_error& pe) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_preprocess_error,pe.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),pe.component_name.c_str(),pe.line_number);
}else{
pe.see(CODEPOINT);
throw;
}
}catch(exception& e) {
config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
if(co_exception_handler) {
so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
eh.ac->run(__magic_generic_exception,e.what(),config.root_source.c_str(),config.root_intermediate.c_str(),config.root_so.c_str(),component_path.c_str(),&e);
}
}
scif.flush();
}catch(exception& e) {
cerr << "->Oops: " << e.what() << endl;
}
}
int main(int argc,char **argv) {
const char* id = *argv;
const char* t;
while(t = index(id,'/')) {
id=t; id++;
}
openlog(id,LOG_PERROR|LOG_PID,LOG_USER);
try {
const char *esccf = getenv("SITECING_CONF");
string config_file = esccf ? esccf : "sitecing.conf";
while(true) {
static struct option opts[] = {
{ "help", no_argument, 0, 'h' },
{ "usage", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "license", no_argument, 0, 'L' },
{ "config", required_argument, 0, 'f' },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc,argv,"f:hVL",opts,NULL);
if(c==-1)
break;
switch(c) {
case 'h':
cerr << PHEADER << endl
<< PCOPY << endl << endl
<< " -h, --help" << endl
<< " --usage display this text" << endl
<< " -V, --version display version number" << endl
<< " -L, --license show license" << endl
<< " -f filename, --config=filename" << endl
<< " specify configuration file to use" << endl;
exit(0);
break;
case 'V':
cerr << VERSION << endl;
exit(0);
break;
case 'L':
extern const char *COPYING;
cerr << COPYING << endl;
exit(0);
break;
case 'f':
config_file = optarg;
break;
default:
cerr << "Huh??" << endl;
break;
}
}
configuration config(config_file);
process_request(config);
}catch(exception& e) {
/* cerr << "Oops: " << e.what() << endl; */
syslog(LOG_ERR,"uncaught exception: %s",e.what());
}
closelog();
}