summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2005-01-29 21:21:05 (UTC)
committer Michael Krelin <hacker@klever.net>2005-01-29 21:21:05 (UTC)
commitce1f37aae46ea95020d7b865f7a80e8abdfad0d8 (patch) (side-by-side diff)
tree4964383ab8cd7e6d8ea821f1a615d1bbcf98dad8
parent3c75c860fc1ad5b3f5185e23ec6f438dd2528958 (diff)
downloadsitecing-ce1f37aae46ea95020d7b865f7a80e8abdfad0d8.zip
sitecing-ce1f37aae46ea95020d7b865f7a80e8abdfad0d8.tar.gz
sitecing-ce1f37aae46ea95020d7b865f7a80e8abdfad0d8.tar.bz2
initial commit into repository0.0
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore23
-rw-r--r--AUTHORS3
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--Doxyfile.in247
-rw-r--r--Makefile.am27
-rw-r--r--NEWS.xml6
-rw-r--r--NEWS.xsl24
-rw-r--r--README0
-rw-r--r--acinclude.m4211
-rwxr-xr-xautogen.sh9
-rw-r--r--components/.gitignore2
-rw-r--r--components/Makefile.am5
-rw-r--r--components/exception_dev346
-rw-r--r--components/exception_prod52
-rw-r--r--configure.ac69
-rw-r--r--include/.gitignore2
-rw-r--r--include/Makefile.am18
-rw-r--r--include/sitecing/acomponent.h78
-rw-r--r--include/sitecing/cgi_component.h54
-rw-r--r--include/sitecing/component_factory.h84
-rw-r--r--include/sitecing/component_so.h159
-rw-r--r--include/sitecing/configuration.h459
-rw-r--r--include/sitecing/exception.h542
-rw-r--r--include/sitecing/file_factory.h64
-rw-r--r--include/sitecing/magic.h63
-rw-r--r--include/sitecing/process_manager.h89
-rw-r--r--include/sitecing/scoreboard.h102
-rw-r--r--include/sitecing/sitecing_enflesher.h65
-rw-r--r--include/sitecing/sitecing_exception.h103
-rw-r--r--include/sitecing/sitecing_interface.h40
-rw-r--r--include/sitecing/sitecing_interface_cgi.h62
-rw-r--r--include/sitecing/sitecing_parser.h326
-rw-r--r--include/sitecing/sitecing_util.h341
-rw-r--r--include/sitecing/sitespace.h76
-rw-r--r--include/sitecing/util.h148
-rw-r--r--lib/.gitignore9
-rw-r--r--lib/Makefile.am22
-rw-r--r--lib/acomponent.cc47
-rw-r--r--lib/cgi_component.cc30
-rw-r--r--lib/component_factory.cc279
-rw-r--r--lib/component_so.cc112
-rw-r--r--lib/configuration.cc474
-rw-r--r--lib/file_factory.cc55
-rw-r--r--lib/pch.h45
-rw-r--r--lib/process_manager.cc152
-rw-r--r--lib/scoreboard.cc71
-rw-r--r--lib/sitecing_enflesher.ll202
-rw-r--r--lib/sitecing_interface_cgi.cc25
-rw-r--r--lib/sitecing_parser.ll594
-rw-r--r--lib/sitecing_util.cc278
-rw-r--r--lib/sitespace.cc52
-rw-r--r--lib/util.cc83
-rw-r--r--share/.gitignore2
-rw-r--r--share/Makefile.am3
-rw-r--r--share/component.skel53
-rw-r--r--sitecing.pc.in11
-rw-r--r--src/.gitignore9
-rw-r--r--src/Makefile.am20
-rw-r--r--src/sitecing-build.cc231
-rw-r--r--src/sitecing-fastcgi.cc325
61 files changed, 7102 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e941fe5
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+configure
+Makefile.in
+Doxyfile
+config.log
+depcomp
+config.guess
+config.h
+ltmain.sh
+config.sub
+INSTALL
+sitecing.pc
+NEWS
+Makefile
+config.status
+stamp-h1
+doxydox
+config.h.in
+autom4te.cache
+libtool
+missing
+aclocal.m4
+ylwrap
+install-sh
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Klever dissected:
+ Michael 'hacker' Krelin <hacker@klever.net>
+ Leonid Ivanov <kamel@klever.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..96befc6
--- a/dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2005 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/ChangeLog
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644
index 0000000..b6e7ed2
--- a/dev/null
+++ b/Doxyfile.in
@@ -0,0 +1,247 @@
+# Doxyfile 1.3.9.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = @PACKAGE@
+PROJECT_NUMBER = @VERSION@
+OUTPUT_DIRECTORY = @builddir@/doxydox
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = include
+STRIP_FROM_INC_PATH = include
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = YES
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+INPUT = \
+ @srcdir@/include/sitecing/
+FILE_PATTERNS = *.h
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 2
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+GENERATE_XML = YES
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = @HAVE_DOT@
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = @DOT@
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+SEARCHENGINE = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..68f550d
--- a/dev/null
+++ b/Makefile.am
@@ -0,0 +1,27 @@
+SUBDIRS=include lib share src components
+EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
+
+DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig
+if HAVE_PKGCONFIG
+pkgconfigdir=@PKGCONFIG_DIR@
+pkgconfig_DATA=sitecing.pc
+endif
+
+LOCAL_TARGETS=
+if HAVE_DOXYGEN
+LOCAL_TARGETS+=doxygen
+endif
+
+all-local: NEWS $(addprefix all-lota-,${LOCAL_TARGETS})
+clean-local: $(addprefix clean-lota-,${LOCAL_TARGETS})
+
+NEWS: NEWS.xsl NEWS.xml
+ ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
+
+all-lota-doxygen: doxydox/built
+doxydox/built: $(wildcard ${top_srcdir}/include/sitecing/*.h)
+ ${DOXYGEN}
+ touch $@
+
+clean-lota-doxygen:
+ rm -rf doxydox
diff --git a/NEWS.xml b/NEWS.xml
new file mode 100644
index 0000000..d1d89f6
--- a/dev/null
+++ b/NEWS.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<news>
+ <version version="0.0" date="January 29th, 2005">
+ <ni>Initial release</ni>
+ </version>
+</news>
diff --git a/NEWS.xsl b/NEWS.xsl
new file mode 100644
index 0000000..7c71307
--- a/dev/null
+++ b/NEWS.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ >
+ <xsl:output
+ method="text"
+ encoding="us-ascii"
+ media-type="text/plain" />
+
+ <xsl:template match="news">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="version">
+ <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ni">
+ <xsl:text> - </xsl:text>
+ <xsl:apply-templates mode="text"/>
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:template>
+ <xsl:template match="*|text()"/>
+
+</xsl:stylesheet>
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/README
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..14b6de7
--- a/dev/null
+++ b/acinclude.m4
@@ -0,0 +1,211 @@
+dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR
+dnl AM_CONDTIONAL: HAVE_PKGCONFIG
+AC_DEFUN([AC_WITH_PKGCONFIG],[
+ PKGCONFIG_PKGCONFIG=""
+ PKGCONFIG_DIR=""
+ HAVE_PKGCONFIG="no"
+ EXPLICIT_PKGCONFIGDIR="no"
+ test -z "${WANT_PKGCONFIG}" && WANT_PKGCONFIG=""
+ AC_PATH_PROG([PKGCONFIG_PKGCONFIG],[pkg-config],[false])
+ if test "${PKGCONFIG_PKGCONFIG}" != "false" ; then
+ AC_ARG_WITH([pkgconfigdir],
+ AC_HELP_STRING([--with-pkgconfigdir=dir],[Specify pkgconfig directory]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PKGCONFIG="no"
+ else
+ PKGCONFIG_DIR="${withval}"
+ EXPLICIT_PKGCONFIGDIR="yes"
+ fi
+ ],[
+ AC_MSG_CHECKING([for pkgconfig directory])
+ PKGCONFIG_DIR="`${PKGCONFIG_PKGCONFIG} --debug 2>&1 | grep '^Scanning'| head -n 1 | cut -d\' -f2-|cut -d\' -f1`"
+ AC_MSG_RESULT([${PKGCONFIG_DIR}])
+ ]
+ )
+ if test -d "${PKGCONFIG_DIR}" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ AC_MSG_NOTICE([unexistent pkgconfig directory: ${PKGCONFIG_DIR}])
+ if test "${EXPLICIT_PKGCONFIGDIR}" = "yes" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ ifelse([$2], , :, [$2])
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PKGCONFIG],[test "${HAVE_PKGCONFIG}" = "yes"])
+])
+
+dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN
+dnl AM_CONDTIONAL: HAVE_DOXYGEN
+AC_DEFUN([AC_WITH_DOXYGEN],[
+ HAVE_DOXYGEN="no"
+ AC_PATH_PROG([DOXYGEN],[doxygen],[false])
+ if test "${DOXYGEN}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOXYGEN="yes"
+ AC_SUBST([DOXYGEN])
+ $1
+ fi
+ AC_SUBST([HAVE_DOXYGEN])
+ AM_CONDITIONAL([HAVE_DOXYGEN],[test "${HAVE_DOXYGEN}" = "yes"])
+])
+
+dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOT HAVE_DOT
+dnl AM_CONDITIONAL: HAVE_DOT
+AC_DEFUN([AC_WITH_DOT],[
+ HAVE_DOT="no"
+ AC_PATH_PROG([DOT],[dot],[false])
+ if test "${DOT}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOT="yes"
+ AC_SUBST([DOT])
+ $1
+ fi
+AC_SUBST([HAVE_DOT])
+ AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"])
+])
+
+dnl AC_WITH_PCRE([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PCRE_CONFIG PCRE_PREFIX PCRE_EXEC_PREFIX
+dnl PCRE_VERSION PCRE_CFLAGS PCRE_LIBS
+dnl PCRE_LIBS_POSIX PCRE_CFLAGS_POSIX
+dnl AM_CONDITIONAL: HAVE_PCRE
+dnl AC_DEFINE: HAVE_PCRE PCRE_VERSION
+AC_DEFUN([AC_WITH_PCRE],[
+ HAVE_PCRE="no"
+ PCRE_CONFIG=""
+ PCRE_PREFIX=""
+ PCRE_EXEC_PREFIX=""
+ PCRE_VERSION=""
+ PCRE_CFLAGS=""
+ PCRE_LIBS=""
+ PCRE_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
+ test -z "$WANT_PCRE" && WANT_PCRE=""
+ AC_ARG_WITH([pcre],
+ AC_HELP_STRING([--with-pcre=location],[Look for pcre in specified locations]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PCRE="no"
+ else
+ if test -x "${withval}" ; then
+ PCRE_CONFIG="${withval}"
+ elif test -x "${withval}/pcre-config" ; then
+ PCRE_CONFIG="${withval}/pcre-config"
+ elif test -x "${withval}/bin/pcre-config" ; then
+ PCRE_CONFIG="${withval}/bin/pcre-config"
+ fi
+ fi
+ ]
+ )
+ if test "${WANT_PCRE}" = "no" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test -z "${PCRE_CONFIG}" ; then
+ AC_PATH_PROG(PCRE_CONFIG,[pcre-config],false,[${PCRE_LOCATIONS}])
+ if test "${PCRE_CONFIG}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_PCRE="yes"
+ PCRE_PREFIX="`${PCRE_CONFIG} --prefix`"
+ PCRE_EXEC_PREFIX="`${PCRE_CONFIG} --exec-prefix`"
+ PCRE_VERSION="`${PCRE_CONFIG} --version`"
+ PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
+ PCRE_LIBS="`${PCRE_CONFIG} --libs`"
+ PCRE_CFLAGS_POSIX="`${PCRE_CONFIG} --cflags-posix`"
+ PCRE_LIBS_POSIX="`${PCRE_CONFIG} --libs-posix`"
+ AC_SUBST([PCRE_CONFIG])
+ AC_SUBST([PCRE_PREFIX])
+ AC_SUBST([PCRE_EXEC_PREFIX])
+ AC_SUBST([PCRE_VERSION])
+ AC_SUBST([PCRE_CFLAGS])
+ AC_SUBST([PCRE_LIBS])
+ AC_SUBST([PCRE_CFLAGS_POSIX])
+ AC_SUBST([PCRE_LIBS_POSIX])
+ AC_DEFINE([HAVE_PCRE],,[pcre support])
+ AC_DEFINE_UNQUOTED([PCRE_VERSION],["${PCRE_VERSION}"],[pcre version])
+ $1
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PCRE],[test "${HAVE_PCRE}" = "yes"])
+])
+
+dnl AC_WITH_PCREPP([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PCREPP_CONFIG PCREPP_PREFIX PCREPP_EXEC_PREFIX
+dnl PCREPP_VERSION PCREPP_CFLAGS PCREPP_LIBS
+dnl AM_CONDITIONAL: HAVE_PCREPP
+dnl AC_DEFINE: HAVE_PCREPP PCREPP_VERSION
+AC_DEFUN([AC_WITH_PCREPP],[
+ HAVE_PCREPP="no"
+ PCREPP_CONFIG=""
+ PCREPP_PREFIX=""
+ PCREPP_EXEC_PREFIX=""
+ PCREPP_VERSION=""
+ PCREPP_CFLAGS=""
+ PCREPP_LIBS=""
+ PCREPP_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
+ test -z "$WANT_PCREPP" && WANT_PCREPP=""
+ AC_ARG_WITH([pcre++],
+ AC_HELP_STRING([--with-pcre++=location],[Look for pcre++ in specified locations]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PCREPP="no"
+ else
+ if test -x "${withval}" ; then
+ PCREPP_CONFIG="${withval}"
+ elif test -x "${withval}/pcre++-config" ; then
+ PCREPP_CONFIG="${withval}/pcre++-config"
+ elif test -x "${withval}/bin/pcre++-config" ; then
+ PCREPP_CONFIG="${withval}/bin/pcre++-config"
+ fi
+ fi
+ ]
+ )
+ if test "${WANT_PCREPP}" = "no" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test "${HAVE_PCRE}" != "yes" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test -z "${PCREPP_CONFIG}" ; then
+ AC_PATH_PROG([PCREPP_CONFIG],[pcre++-config],false,[${PCREPP_LOCATIONS}])
+ if test "${PCREPP_CONFIG}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_PCREPP="yes"
+ PCREPP_PREFIX="`${PCREPP_CONFIG} --prefix`"
+ PCREPP_EXEC_PREFIX="`${PCREPP_CONFIG} --exec-prefix`"
+ PCREPP_VERSION="`${PCREPP_CONFIG} --version`"
+ PCREPP_CFLAGS="`${PCREPP_CONFIG} --cflags` ${PCRE_CFLAGS}"
+ PCREPP_LIBS="`${PCREPP_CONFIG} --libs` ${PCRE_LIBS}"
+ AC_SUBST([PCREPP_CONFIG])
+ AC_SUBST([PCREPP_PREFIX])
+ AC_SUBST([PCREPP_EXEC_PREFIX])
+ AC_SUBST([PCREPP_VERSION])
+ AC_SUBST([PCREPP_CFLAGS])
+ AC_SUBST([PCREPP_LIBS])
+ AC_DEFINE([HAVE_PCREPP],,[pcre++ support])
+ AC_DEFINE_UNQUOTED([PCREPP_VERSION],["${PCREPP_VERSION}"],[pcre++ version])
+ $1
+ fi
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PCREPP],[test "${HAVE_PCREPP}" = "yes"])
+])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ba27501
--- a/dev/null
+++ b/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+WANT_AUTOMAKE=1.8
+export WANT_AUTOMAKE
+libtoolize -f \
+&& aclocal \
+&& autoheader \
+&& automake -a \
+&& autoconf \
+&& ./configure "$@"
diff --git a/components/.gitignore b/components/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/components/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/components/Makefile.am b/components/Makefile.am
new file mode 100644
index 0000000..8a07ffc
--- a/dev/null
+++ b/components/Makefile.am
@@ -0,0 +1,5 @@
+componentsdir = ${pkgdatadir}/components
+
+components_DATA = exception_dev exception_prod
+
+EXTRA_DIST = exception_dev exception_prod
diff --git a/components/exception_dev b/components/exception_dev
new file mode 100644
index 0000000..d8c84e1
--- a/dev/null
+++ b/components/exception_dev
@@ -0,0 +1,346 @@
+%%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/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);
+ 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);
+ 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);
+ 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/components/exception_prod b/components/exception_prod
new file mode 100644
index 0000000..9768623
--- a/dev/null
+++ b/components/exception_prod
@@ -0,0 +1,52 @@
+<%code>
+ /* vim:set ft=sitecing: */
+ __SCIF->headers.clear(); /* reset all headers possibly set by the component throwing an exception. */
+ __SCIF->out->seekp(0); /* rollback the output that the exceptional component may have produced. */
+ /* set out headers */
+ __SCIF->headers["Content-Type"] = "text/html";
+ __SCIF->headers["Status"] = "500 server-side exception";
+ __SCIF->headers["Pragma"] = "no-cache";
+</%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>Server-side exception</title>
+ <style type="text/css">
+ <!--
+ body {
+ font-family: sans-serif;
+ font-size: 12pt;
+ }
+ h1 {
+ font-family: serif;
+ font-size: 130%;
+ font-weight: bold;
+ text-align: center;
+ }
+ p {
+ text-indent: 2em;
+ text-align: justify;
+ }
+
+ 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>
+ </head>
+ <body>
+ <h1>server-side exception</h1>
+ <p>Something has gone really wrong with the server. Feel free to report the
+ incident to <a href="mailto:<% __CGI->get_meta("SERVER_ADMIN") %>" title="e-mail
+ server administrator">webmaster</a>.</p>
+ <div class="powered">Powered by <a href="http://kin.klever.net/sitecing/" title="site-C-ing">site-C-ing</a>.</div>
+ </body>
+</html>
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..acd34b9
--- a/dev/null
+++ b/configure.ac
@@ -0,0 +1,69 @@
+AC_INIT([sitecing], [0.0], [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([KINGATE],[kingate-fcgi],,[
+ AC_MSG_ERROR([no kingate library found, get it at http://kin.klever.net/kingate/])
+])
+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_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/.gitignore b/include/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/include/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..88148d5
--- a/dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,18 @@
+# TODO: separate installable headers from internals
+# but to make it sensible one need to elimitate
+# abnoxious sitecing_interface_cgi.h inclusion of
+# sitespace.h
+nobase_include_HEADERS = \
+ sitecing/acomponent.h sitecing/cgi_component.h \
+ sitecing/component_so.h \
+ sitecing/file_factory.h sitecing/component_factory.h \
+ sitecing/sitecing_interface.h sitecing/sitecing_interface_cgi.h \
+ sitecing/sitecing_parser.h sitecing/sitecing_enflesher.h \
+ sitecing/sitespace.h \
+ sitecing/configuration.h \
+ sitecing/magic.h sitecing/util.h \
+ sitecing/exception.h sitecing/sitecing_exception.h \
+ sitecing/sitecing_util.h \
+ sitecing/process_manager.h \
+ sitecing/scoreboard.h
+
diff --git a/include/sitecing/acomponent.h b/include/sitecing/acomponent.h
new file mode 100644
index 0000000..160e854
--- a/dev/null
+++ b/include/sitecing/acomponent.h
@@ -0,0 +1,78 @@
+#ifndef __SITECING_ACOMPONENT_H
+#define __SITECING_ACOMPONENT_H
+
+#include "sitecing/sitecing_interface.h"
+
+/**
+ * @file
+ * @brief The acomponent class declaration.
+ */
+
+namespace sitecing {
+
+ /**
+ * An abstract base class for sitecing components.
+ */
+ class acomponent {
+ public:
+ /**
+ * Pointer to the interface object, used to communicate with the
+ * site-C-ing core.
+ */
+ sitecing_interface *__SCIF;
+
+ acomponent();
+ virtual ~acomponent();
+
+ /**
+ * Set the interface to core pointer.
+ * @param scif the pointer to the interface object.
+ */
+ virtual void __set_interface(sitecing_interface *scif=0);
+ /**
+ * Invoked if the interface to the core has changed.
+ * @param oscif pointer to the old interface object.
+ */
+ virtual void __on_change_interface(sitecing_interface *oscif);
+
+ /**
+ * do import components.
+ */
+ virtual void __do_imports();
+ /**
+ * invoked on components imports.
+ */
+ virtual void __on_imports();
+ /**
+ * fetch the pointer to the most derived component.
+ * @returns pointer to the most derived object.
+ */
+ virtual void *__the_most_derived_this() = 0;
+
+ /**
+ * Do the job.
+ * @param __magic the magic number used as a key to decipher the
+ * rest of parameters.
+ * @param __args the parameters.
+ */
+ virtual void main(int __magic,va_list __args) = 0;
+
+ /**
+ * Run the component. Convenience helper for calling main().
+ * @param __magic the magic number.
+ * @param ... the rest of parameters.
+ * @see main();
+ */
+ void run(int __magic,...);
+
+ /**
+ * Helper function (which doesn't necessarily belongs here!) for
+ * reading the file and passing it to the output stream.
+ * @param fn the file name.
+ */
+ void pass_file_through(const char *fn);
+ };
+
+}
+
+#endif /* __SITECING_ACOMPONENT_H */
diff --git a/include/sitecing/cgi_component.h b/include/sitecing/cgi_component.h
new file mode 100644
index 0000000..91df689
--- a/dev/null
+++ b/include/sitecing/cgi_component.h
@@ -0,0 +1,54 @@
+#ifndef __SITECING_CGI_COMPONENT_H
+#define __SITECING_CGI_COMPONENT_H
+
+#include <map>
+#include "kingate/cgi_gateway.h"
+#include "sitecing/acomponent.h"
+#include "sitecing/sitecing_interface_cgi.h"
+
+/**
+ * @file
+ * @brief The cgi_component class declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * The CGI-oriented component class.
+ */
+ class cgi_component : virtual public acomponent {
+ public:
+ /**
+ * The interface to site-C-ing core.
+ */
+ sitecing_interface_cgi* __SCIF;
+ /**
+ * The interface to the CGI gateway.
+ */
+ kingate::cgi_gateway* __CGI;
+
+ cgi_component();
+ virtual ~cgi_component();
+
+ /**
+ * @overload acomponent::__set_interface()
+ */
+ void __set_interface(sitecing_interface* scif);
+ /**
+ * @overload acomponent::__on_change_interface()
+ */
+ void __on_change_interface(sitecing_interface *o);
+ /**
+ * Invoked on the change of the interface to the CGI.
+ */
+ virtual void __on_change_CGI(kingate::cgi_gateway *o);
+ /**
+ * @overload acomponent::__on_imports()
+ */
+ virtual void __on_imports();
+ };
+
+}
+
+#endif /* __SITECING_CGI_COMPONENT_H */
diff --git a/include/sitecing/component_factory.h b/include/sitecing/component_factory.h
new file mode 100644
index 0000000..a208ed1
--- a/dev/null
+++ b/include/sitecing/component_factory.h
@@ -0,0 +1,84 @@
+#ifndef __SITECING_COMPONENT_FACTORY_H
+#define __SITECING_COMPONENT_FACTORY_H
+
+#include <string>
+#include <list>
+#include <stdexcept>
+#include "sitecing/file_factory.h"
+#include "sitecing/configuration.h"
+
+/**
+ * @file
+ * @brief The component_factory class declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * @brief The components builder.
+ */
+ class component_factory : public file_factory {
+ public:
+ /**
+ * Path to the source files root.
+ */
+ string root_source;
+ /**
+ * Path to the root of the intermediate files storage.
+ */
+ string root_intermediate;
+ /**
+ * Output path for .so components.
+ */
+ string root_so;
+ /**
+ * Reference to the configuration container.
+ */
+ configuration& config;
+
+ /**
+ * @param c reference to the configuration container.
+ */
+ component_factory(configuration& c);
+
+ /**
+ * @overload file_factory::get_dependencies()
+ */
+ virtual void get_dependencies(const string& dst,file_list_t& deps);
+ /**
+ * @overload file_factory::is_uptodate()
+ */
+ virtual bool is_uptodate(const string& dst,file_list_t *deps=NULL);
+ /**
+ * @overload file_factory::build()
+ */
+ virtual void build(const string& dst);
+
+ /**
+ * Helper function for executing external command.
+ * @param cmd the command to execute.
+ * @param args the command line arguments.
+ * @param stdo stdout for the child process.
+ * @param stde stderr for the child process.
+ * @return exit code.
+ */
+ int execute(const string& cmd,const list<string>& args,int stdo,int stde);
+ /**
+ * Fetch the class name of the component.
+ * @param component the component.
+ * @return the class name.
+ */
+ string get_classname(const string& component);
+ /**
+ * Get the components from which the target component has been
+ * derived.
+ * @param component the target component
+ * @param rv where to store the list of ancestors.
+ */
+ void get_ancestors(const string& component,file_list_t &rv);
+ };
+
+}
+
+#endif /* __SITECING_COMPONENT_FACTORY_H */
diff --git a/include/sitecing/component_so.h b/include/sitecing/component_so.h
new file mode 100644
index 0000000..3239d4a
--- a/dev/null
+++ b/include/sitecing/component_so.h
@@ -0,0 +1,159 @@
+#ifndef __SITECING_COMPONENT_SO_H
+#define __SITECING_COMPONENT_SO_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string>
+#include <map>
+#include <list>
+#include "sitecing/acomponent.h"
+
+/**
+ * @file
+ * @brief Classes related to the .so components handling.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * The 'class' component object.
+ */
+ class component_so {
+ public:
+ /**
+ * The type of the component instantiating function.
+ */
+ typedef acomponent *(*egg_t)();
+ /**
+ * Type for storing the list of instances and the reference counts.
+ */
+ typedef map<acomponent*,int> used_chickens_t;
+ /**
+ * The type for storing the list of unused instances.
+ */
+ typedef list<acomponent*> free_chickens_t;
+
+ /**
+ * The .so file name.
+ */
+ string sofile;
+ /**
+ * The stat structure for the .so loaded.
+ */
+ struct stat stso;
+ /**
+ * The dloaded .so handle.
+ */
+ void *dl;
+ /**
+ * Pointer to the instatiator function.
+ */
+ egg_t egg;
+ /**
+ * The list of instances in use.
+ */
+ used_chickens_t chickens_used;
+ /**
+ * The list of unused instances.
+ */
+ free_chickens_t chickens_free;
+
+ /**
+ * @param soname the .so file name
+ */
+ component_so(const string& soname);
+ ~component_so();
+ /**
+ * Check whether the loaded .so is in sync with the disk file.
+ */
+ bool is_uptodate() const;
+
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ acomponent* allocate_chicken();
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void allocate_chicken(acomponent *ac);
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void deallocate_chicken(acomponent *ac);
+ };
+
+ /**
+ * The component instance container.
+ */
+ class so_component {
+ public:
+ /**
+ * Pointer to the component 'class'.
+ */
+ component_so *hen;
+ /**
+ * The instance in question.
+ */
+ acomponent* ac;
+
+ so_component()
+ : hen(0), ac(0) { }
+ /**
+ * @param h the 'class' object.
+ * @param scif pointer to the interface to the site-C-ing core.
+ */
+ so_component(component_so *h,sitecing_interface *scif);
+ /**
+ * Copy constructor
+ * @param s source instance.
+ */
+ so_component(const so_component& s)
+ : hen(0), ac(0) { attach(s); }
+ ~so_component() { detach(); }
+
+ /**
+ * Assignment operator.
+ * @param s source instance.
+ */
+ so_component& operator=(const so_component& s) {
+ attach(s); return *this;
+ }
+
+ /**
+ * @todo TODO: wish I could remember the details -- document me.
+ * @param h the 'class' object.
+ * @param a the instance to be attached.
+ */
+ void attach(component_so *h,acomponent *a);
+ /**
+ * @todo TODO: wish I could remember the details -- document me.
+ * @param s the source instance.
+ */
+ void attach(const so_component& s) { attach(s.hen,s.ac); }
+ /**
+ * @todo TODO: wish I could remember the details -- document me.
+ */
+ void detach();
+ };
+
+ /**
+ * The typed component instance container template.
+ * @param CT the component class.
+ */
+ template<typename CT>
+ class so_component_t : public sitecing::so_component {
+ public:
+ /**
+ * @param s The untyped instance container.
+ */
+ so_component_t(const so_component& s)
+ : so_component(s) { }
+ CT* operator->() {
+ return static_cast<CT*>(ac->__the_most_derived_this());
+ }
+ };
+
+}
+
+#endif /* __SITECING_COMPONENT_SO_H */
diff --git a/include/sitecing/configuration.h b/include/sitecing/configuration.h
new file mode 100644
index 0000000..330a5a6
--- a/dev/null
+++ b/include/sitecing/configuration.h
@@ -0,0 +1,459 @@
+#ifndef __SITECING_CONFIGURATION_H
+#define __SITECING_CONFIGURATION_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string>
+#include <list>
+#include <map>
+#include <pcre++.h>
+
+/**
+ * @file
+ * @brief Classes related to configuration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ class configuration;
+
+ /**
+ * The config options container class.
+ */
+ class config_options {
+ public:
+ /**
+ * The flags enumeration.
+ */
+ enum _flags {
+ /**
+ * Skeleton has been specified in the context.
+ * @see skeleton
+ */
+ flag_skeleton = 0x0001,
+ /**
+ * CPPFLAGS have been specified in the context
+ * @see cpp_flags
+ */
+ flag_cpp_flags = 0x0002,
+ /**
+ * LDFLAGS have been specified in the context.
+ * @see ld_flags
+ */
+ flag_ld_flags = 0x0004,
+ /**
+ * Enforced intermediate dependencies have been specified in the
+ * context.
+ * @see internediate_deps
+ */
+ flag_intermediate_deps = 0x0008,
+ /**
+ * Enforced .so dependencies have been specified in the context.
+ * @see so_deps
+ */
+ flag_so_deps = 0x0010,
+ /**
+ * Whether components should be built specified in the context.
+ * @see build
+ */
+ flag_build = 0x0020,
+ /**
+ * Whether to track down cpp dependencies has been specified in
+ * the context.
+ * @see cpp_deps
+ */
+ flag_cpp_deps = 0x0040,
+ /**
+ * The exception handler has been specified in the context.
+ * @see exception_handler
+ */
+ flag_exception_handler = 0x0080,
+ /**
+ * Action handlers have been specified in the context.
+ * @see action_handlers
+ */
+ flag_action_handlers = 0x0100,
+ /**
+ * HTTP status handerls have been specified in the context.
+ * @see http_status_handlers
+ */
+ flag_http_status_handlers = 0x0200,
+ /**
+ * The files to be built are specified in the context.
+ * @see auto_build_files
+ */
+ flag_auto_build_files = 0x0400
+ };
+ /**
+ * The flags specifying what parts of configuration have been
+ * specified for the context.
+ */
+ int flags;
+
+ /**
+ * The skeleton for building components.
+ */
+ string skeleton;
+ /**
+ * The flags to pass to compiler.
+ */
+ list<string> cpp_flags;
+ /**
+ * The flags to pass to linker.
+ */
+ list<string> ld_flags;
+ /**
+ * Whether to build inexstent and outdated components.
+ */
+ bool build;
+ /**
+ * Whether to track cpp dependencies.
+ */
+ bool cpp_deps;
+ /**
+ * The component handling caught exceptions.
+ */
+ string exception_handler;
+ /**
+ * Enforced intermediate dependencies.
+ */
+ list<string> intermediate_deps;
+ /**
+ * Enforced depencies for .so objects.
+ */
+ list<string> so_deps;
+ /**
+ * The action handler type.
+ */
+ struct action_handler_t {
+ /**
+ * The regexp to check request against.
+ */
+ string s_regex;
+ /**
+ * Precompiled regex.
+ */
+ pcrepp::Pcre regex;
+ /**
+ * The action handler component.
+ */
+ string action;
+ /**
+ * Arguments for the action hander coponent.
+ */
+ list<string> args;
+
+ action_handler_t(const string& s,const string& a)
+ : s_regex(s), regex(s), action(a) { }
+ action_handler_t(const action_handler_t& s)
+ : s_regex(s.s_regex), regex(s.regex), action (s.action), args(s.args) { }
+ };
+ /**
+ * Type for the list of action handlers.
+ */
+ typedef list<action_handler_t> action_handlers_t;
+ /**
+ * The list of action handlers.
+ */
+ action_handlers_t action_handlers;
+ /**
+ * Type for the map of HTTP status handler components.
+ */
+ typedef map<string,string> http_status_handlers_t;
+ /**
+ * The map of HTTP status handler components.
+ */
+ http_status_handlers_t http_status_handlers;
+ /**
+ * Files to be built automatically.
+ */
+ list<string> auto_build_files;
+
+ config_options()
+ : flags(0) { }
+
+ /**
+ * Look up if there is an action handler for the target defined.
+ * @param target the target component.
+ * @return the pointer to handler or zero.
+ */
+ action_handler_t *lookup_action_handler(const string& target);
+ /**
+ * Look up if there is a handler defined for the HTTP status.
+ * @param status HTTP status
+ * @return the handler component.
+ */
+ string lookup_http_status_handler(const string& status);
+ /**
+ * Check whether the file should be build automatically.
+ * @param fn file name.
+ * @param rv reference to the boolean where the answer should go.
+ * @return true if we know the answer.
+ */
+ bool match_autobuild_files(const char *fn,bool &rv);
+ };
+
+ /**
+ * Configuration data container for the configuration loaded from disk file.
+ */
+ class loaded_options : public config_options {
+ public:
+ /**
+ * The file where configuration originates from.
+ */
+ string source_file;
+ /**
+ * The stat structure for the source file as it was when we have
+ * loaded it.
+ */
+ struct stat st;
+
+ /**
+ * See if the data is still valid.
+ * @return true if yes.
+ */
+ bool is_valid();
+
+ /**
+ * Load the configuration file.
+ * @param config the main configuration container.
+ * @param the configuration file.
+ */
+ void parse(configuration *config,const string& cfile);
+ };
+
+ /**
+ * The main configuration container.
+ */
+ class configuration {
+ public:
+ /**
+ * @todo TODO:: document me.
+ */
+ bool autobuild;
+ /**
+ * The flags enumeration.
+ */
+ enum _flags {
+ /**
+ * Was the source root specified?
+ * @see root_source
+ */
+ flag_root_source = 0x00000001,
+ /**
+ * Was the root for intermediate files specified?
+ * @see root_intermediate
+ */
+ flag_root_intermediate = 0x00000002,
+ /**
+ * Was the root for the resulting .so files specified?
+ * @see root_so
+ */
+ flag_root_so = 0x00000004,
+ /**
+ * Was the socket to listen to specified?
+ * @see listen_socket
+ */
+ flag_listen_socket = 0x00000008,
+ /**
+ * Was the per-dir config file name specified.
+ * @see rc_file_name
+ */
+ flag_rc_file_name = 0x00000010,
+ /**
+ * Was the minimum number of child processes specified?
+ * @see min_children
+ */
+ flag_min_children = 0x00000020,
+ /**
+ * Was the maximum number of child processes specified?
+ * @see max_children
+ */
+ flag_max_children = 0x00000040,
+ /**
+ * Was the minimum number of spare child processes specified?
+ * @see min_spare_children
+ */
+ flag_min_spare_children = 0x00000080,
+ /**
+ * Was he maximum number of spare child processes specified?
+ * @see max_spare_children
+ */
+ flag_max_spare_children = 0x00000100,
+ /**
+ * Was the number of requests to handle per child process
+ * specified?
+ * @see requests_per_child
+ */
+ flag_requests_per_child = 0x00000200,
+ /**
+ * Was the multiprocess node (or it's absences) specified?
+ * @see multi_process
+ */
+ flag_multi_process = 0x00000400,
+ /**
+ * Was the user specified?
+ * @see user
+ */
+ flag_user = 0x00000800,
+ /**
+ * @Was the group specified?
+ * @see group
+ */
+ flag_group = 0x00001000,
+ /**
+ * Was the root to change to specified?
+ * @see chroot
+ */
+ flag_chroot = 0x00002000,
+ /**
+ * Was the file for storing PID specified?
+ * @see pidfile
+ */
+ flag_pid_file = 0x00004000,
+ /**
+ * Was it specified wether we should daemonize the process?
+ * @see daemonize
+ */
+ flag_daemonize = 0x00008000
+ };
+ /**
+ * The flags specifying what parts of the configuration has been
+ * loaded into the object.
+ */
+ long flags;
+
+ /**
+ * The root for the components source code.
+ */
+ string root_source;
+ /**
+ * The root for intermediate files.
+ */
+ string root_intermediate;
+ /**
+ * The root for .so files.
+ */
+ string root_so;
+ /**
+ * Socket to bind to
+ */
+ string listen_socket;
+ /**
+ * per-dir config file name.
+ */
+ string rc_file_name;
+ /**
+ * The minimum number of child processes in multiprocess mode.
+ */
+ int min_children;
+ /**
+ * The maxium number of child processes in multiprocess mode.
+ */
+ int max_children;
+ /**
+ * The minimum number of spare chidren in multiprocess mode.
+ */
+ int min_spare_children;
+ /**
+ * The maximum number of spare children in multiprocess mode.
+ */
+ int max_spare_children;
+ /**
+ * The number of requests the child process should handle before
+ * exiting.
+ */
+ int requests_per_child;
+ /**
+ * Whether we should run in multiprocess mode or not.
+ */
+ bool multi_process;
+ /**
+ * User to change to.
+ */
+ string user;
+ /**
+ * Group to set to.
+ */
+ string group;
+ /**
+ * Directory to change root to.
+ */
+ string chroot;
+ /**
+ * The file to store PID into.
+ */
+ string pid_file;
+ /**
+ * Whether we should fork into background.
+ */
+ bool daemonize;
+
+ typedef map<string,config_options> specs_t;
+ /**
+ * The local config options map.
+ */
+ specs_t specs;
+ typedef map<string,loaded_options> loaded_specs_t;
+ /**
+ * The local config options as specified in per-dir config files
+ * map.
+ */
+ loaded_specs_t loaded_specs;
+
+ configuration();
+ /**
+ * @param cfile the configuration file.
+ * @param ab @todo TODO:: document me
+ */
+ configuration(const string& cfile,bool ab=false);
+
+ /**
+ * Parse the configuration file.
+ * @param cfile the configuration file.
+ */
+ void parse(const string& cfile);
+
+ /**
+ * Fetch the reference to options for the very root.
+ */
+ config_options& root_options() { return specs[""]; }
+ /**
+ * Lookup where the certain config option for the target lies in.
+ * @param target the target component.
+ * @param flag the flag specifying the option we're looking for.
+ * @return the destination options continer or zero.
+ */
+ config_options* lookup_config(const string& target,int flag);
+ /**
+ * Lookup the action handler for the target.
+ * @param target the target request.
+ * @return the action handler or zero.
+ */
+ config_options::action_handler_t *lookup_action_handler(const string& target);
+ /**
+ * Lookup the HTPP status handler for the target.
+ * @param target the target.
+ * @param status the HTTP status.
+ * @return the handler component.
+ */
+ string lookup_http_status_handler(const string& target,const string& status);
+ /**
+ * Lookup the options loaded from per-dir config for the target
+ * @param target the target.
+ * @return options container or zero.
+ */
+ loaded_options* lookup_loaded_options(const string& target);
+ /**
+ * Check whether the components for the target should be prebuilt.
+ * @param target the target.
+ * @param fn file name.
+ * @return true if yes.
+ */
+ bool match_autobuild_files(const string& target,const char *fn);
+ };
+
+}
+
+#endif /* __SITECING_CONFIGURATION_H */
diff --git a/include/sitecing/exception.h b/include/sitecing/exception.h
new file mode 100644
index 0000000..985fc6d
--- a/dev/null
+++ b/include/sitecing/exception.h
@@ -0,0 +1,542 @@
+#ifndef __SITECING_EXCEPTION_H
+#define __SITECING_EXCEPTION_H
+
+/**
+ * @file
+ * @brief The site-C-ing specific exceptions.
+ */
+
+/**
+ * @brief The main site-C-ing namespace.
+ */
+namespace sitecing {
+
+ // TODO: status specifics
+
+ /**
+ * The http status to return.
+ */
+ class http_status {
+ public:
+ /**
+ * The status string.
+ */
+ string status;
+ /**
+ * The message to follow the status string.
+ */
+ string message;
+
+ /**
+ * @param s HTTP status.
+ * @param m HTTP status message.
+ */
+ http_status(const string& s,const string& m)
+ : status(s), message(m) { }
+ virtual ~http_status() throw() { }
+ };
+
+ // per RFC 2616
+
+ /**
+ * Informational.
+ */
+ class http_status_1xx : public http_status {
+ public:
+ explicit http_status_1xx(const string &s,const string& m)
+ : http_status(s,m) { }
+ };
+ /**
+ * Continue.
+ */
+ class http_status_100 : public http_status_1xx {
+ public:
+ explicit http_status_100(const string& m)
+ : http_status_1xx("100",m) { }
+ explicit http_status_100()
+ : http_status_1xx("100","Continue") { }
+ };
+ /**
+ * Switching protocols.
+ */
+ class http_status_101 : public http_status_1xx {
+ public:
+ explicit http_status_101(const string& m)
+ : http_status_1xx("101",m) { }
+ explicit http_status_101()
+ : http_status_1xx("101","Switching protocols") { }
+ };
+
+ /**
+ * Successful.
+ */
+ class http_status_2xx : public http_status {
+ public:
+ explicit http_status_2xx(const string& s,const string& m)
+ : http_status(s,m) { }
+ };
+ /**
+ * OK.
+ */
+ class http_status_200 : public http_status_2xx {
+ public:
+ explicit http_status_200(const string& m)
+ : http_status_2xx("200",m) { }
+ explicit http_status_200()
+ : http_status_2xx("200","OK") { }
+ };
+ /**
+ * Created.
+ */
+ class http_status_201 : public http_status_2xx {
+ public:
+ explicit http_status_201(const string& m)
+ : http_status_2xx("201",m) { }
+ explicit http_status_201()
+ : http_status_2xx("201","Created") { }
+ };
+ /**
+ * Accepted.
+ */
+ class http_status_202 : public http_status_2xx {
+ public:
+ explicit http_status_202(const string& m)
+ : http_status_2xx("202",m) { }
+ explicit http_status_202()
+ : http_status_2xx("202","Accepted") { }
+ };
+ /**
+ * Non-authoritative infortmation.
+ */
+ class http_status_203 : public http_status_2xx {
+ public:
+ explicit http_status_203(const string& m)
+ : http_status_2xx("203",m) { }
+ explicit http_status_203()
+ : http_status_2xx("203","Non-authoritative information") { }
+ };
+ /**
+ * No content.
+ */
+ class http_status_204 : public http_status_2xx {
+ public:
+ explicit http_status_204(const string& m)
+ : http_status_2xx("204",m) { }
+ explicit http_status_204()
+ : http_status_2xx("204","No content") { }
+ };
+ /**
+ * Reset content.
+ */
+ class http_status_205 : public http_status_2xx {
+ public:
+ explicit http_status_205(const string& m)
+ : http_status_2xx("205",m) { }
+ explicit http_status_205()
+ : http_status_2xx("205","Reset content") { }
+ };
+ /**
+ * Partial content.
+ */
+ class http_status_206 : public http_status_2xx {
+ public:
+ explicit http_status_206(const string& m)
+ : http_status_2xx("206",m) { }
+ explicit http_status_206()
+ : http_status_2xx("206","Partial content") { }
+ };
+
+ /**
+ * Redirection.
+ */
+ class http_status_3xx : public http_status {
+ public:
+ explicit http_status_3xx(const string& s,const string& m)
+ : http_status(s,m) { }
+ };
+ /**
+ * Multiple choices.
+ */
+ class http_status_300 : public http_status_3xx {
+ public:
+ explicit http_status_300(const string& m)
+ : http_status_3xx("300",m) { }
+ explicit http_status_300()
+ : http_status_3xx("300","Multiple choices") { }
+ };
+ /**
+ * Moved permanently.
+ */
+ class http_status_301 : public http_status_3xx {
+ public:
+ explicit http_status_301(const string& m)
+ : http_status_3xx("301",m) { }
+ explicit http_status_301()
+ : http_status_3xx("301","Moved permanently") { }
+ };
+ /**
+ * Found.
+ */
+ class http_status_302 : public http_status_3xx {
+ public:
+ explicit http_status_302(const string& m)
+ : http_status_3xx("302",m) { }
+ explicit http_status_302()
+ : http_status_3xx("302","Found") { }
+ };
+ /**
+ * See other.
+ */
+ class http_status_303 : public http_status_3xx {
+ public:
+ explicit http_status_303(const string& m)
+ : http_status_3xx("303",m) { }
+ explicit http_status_303()
+ : http_status_3xx("303","See other") { }
+ };
+ /**
+ * Not modified.
+ */
+ class http_status_304 : public http_status_3xx {
+ public:
+ explicit http_status_304(const string& m)
+ : http_status_3xx("304",m) { }
+ explicit http_status_304()
+ : http_status_3xx("304","Not modified") { }
+ };
+ /**
+ * Use proxy.
+ */
+ class http_status_305 : public http_status_3xx {
+ public:
+ explicit http_status_305(const string& m)
+ : http_status_3xx("305",m) { }
+ explicit http_status_305()
+ : http_status_3xx("305","Use proxy") { }
+ };
+ // 306 is unused and reserved
+ /**
+ * Temporary redirect.
+ */
+ class http_status_307 : public http_status_3xx {
+ public:
+ explicit http_status_307(const string& m)
+ : http_status_3xx("307",m) { }
+ explicit http_status_307()
+ : http_status_3xx("307","Temporary redirect") { }
+ };
+
+ /**
+ * Error.
+ */
+ class http_status_4xx : public http_status {
+ public:
+ explicit http_status_4xx(const string& s,const string& m)
+ : http_status(s,m) { }
+ };
+ /**
+ * Bad request.
+ */
+ class http_status_400 : public http_status_4xx {
+ public:
+ explicit http_status_400(const string& m)
+ : http_status_4xx("400",m) { }
+ explicit http_status_400()
+ : http_status_4xx("400","Bad request") { }
+ };
+ /**
+ * Unauthorized.
+ */
+ class http_status_401 : public http_status_4xx {
+ public:
+ explicit http_status_401(const string& m)
+ : http_status_4xx("401",m) { }
+ explicit http_status_401()
+ : http_status_4xx("401","Unauthorized") { }
+ };
+ /**
+ * Payment required.
+ */
+ class http_status_402 : public http_status_4xx {
+ public:
+ explicit http_status_402(const string& m)
+ : http_status_4xx("402",m) { }
+ explicit http_status_402()
+ : http_status_4xx("402","Payment required") { }
+ };
+ /**
+ * Forbidden.
+ */
+ class http_status_403 : public http_status_4xx {
+ public:
+ explicit http_status_403(const string& m)
+ : http_status_4xx("403",m) { }
+ explicit http_status_403()
+ : http_status_4xx("403","Forbidden") { }
+ };
+ /**
+ * Not found.
+ */
+ class http_status_404 : public http_status_4xx {
+ public:
+ explicit http_status_404(const string& m)
+ : http_status_4xx("404",m) { }
+ explicit http_status_404()
+ : http_status_4xx("404","Not found") { }
+ };
+ /**
+ * Method not allowed.
+ */
+ class http_status_405 : public http_status_4xx {
+ public:
+ explicit http_status_405(const string& m)
+ : http_status_4xx("405",m) { }
+ explicit http_status_405()
+ : http_status_4xx("405","Method not allowed") { }
+ };
+ /**
+ * Not acceptable.
+ */
+ class http_status_406 : public http_status_4xx {
+ public:
+ explicit http_status_406(const string& m)
+ : http_status_4xx("406",m) { }
+ explicit http_status_406()
+ : http_status_4xx("406","Not acceptable") { }
+ };
+ /**
+ * Proxy authentication required.
+ */
+ class http_status_407 : public http_status_4xx {
+ public:
+ explicit http_status_407(const string& m)
+ : http_status_4xx("407",m) { }
+ explicit http_status_407()
+ : http_status_4xx("407","Proxy authentication required") { }
+ };
+ /**
+ * Request timeout.
+ */
+ class http_status_408 : public http_status_4xx {
+ public:
+ explicit http_status_408(const string& m)
+ : http_status_4xx("408",m) { }
+ explicit http_status_408()
+ : http_status_4xx("408","Request timeout") { }
+ };
+ /**
+ * Conflict.
+ */
+ class http_status_409 : public http_status_4xx {
+ public:
+ explicit http_status_409(const string& m)
+ : http_status_4xx("409",m) { }
+ explicit http_status_409()
+ : http_status_4xx("409","Conflict") { }
+ };
+ /**
+ * Gone.
+ */
+ class http_status_410 : public http_status_4xx {
+ public:
+ explicit http_status_410(const string& m)
+ : http_status_4xx("410",m) { }
+ explicit http_status_410()
+ : http_status_4xx("410","Gone") { }
+ };
+ /**
+ * Length required.
+ */
+ class http_status_411 : public http_status_4xx {
+ public:
+ explicit http_status_411(const string& m)
+ : http_status_4xx("411",m) { }
+ explicit http_status_411()
+ : http_status_4xx("411","Length required") { }
+ };
+ /**
+ * Precondition failed.
+ */
+ class http_status_412 : public http_status_4xx {
+ public:
+ explicit http_status_412(const string& m)
+ : http_status_4xx("412",m) { }
+ explicit http_status_412()
+ : http_status_4xx("412","Precondition failed") { }
+ };
+ /**
+ * Request entity too large.
+ */
+ class http_status_413 : public http_status_4xx {
+ public:
+ explicit http_status_413(const string& m)
+ : http_status_4xx("413",m) { }
+ explicit http_status_413()
+ : http_status_4xx("413","Request entity too large") { }
+ };
+ /**
+ * Request URI too long.
+ */
+ class http_status_414 : public http_status_4xx {
+ public:
+ explicit http_status_414(const string& m)
+ : http_status_4xx("414",m) { }
+ explicit http_status_414()
+ : http_status_4xx("414","Request URI too long") { }
+ };
+ /**
+ * Unsupported media type.
+ */
+ class http_status_415 : public http_status_4xx {
+ public:
+ explicit http_status_415(const string& m)
+ : http_status_4xx("415",m) { }
+ explicit http_status_415()
+ : http_status_4xx("415","Unsupported media type") { }
+ };
+ /**
+ * Requested range not satisfiable.
+ */
+ class http_status_416 : public http_status_4xx {
+ public:
+ explicit http_status_416(const string& m)
+ : http_status_4xx("416",m) { }
+ explicit http_status_416()
+ : http_status_4xx("416","Requested range not satisfiable") { }
+ };
+ /**
+ * Expectation failed.
+ */
+ class http_status_417 : public http_status_4xx {
+ public:
+ explicit http_status_417(const string& m)
+ : http_status_4xx("417",m) { }
+ explicit http_status_417()
+ : http_status_4xx("417","Expectation failed") { }
+ };
+
+ /**
+ * Server error.
+ */
+ class http_status_5xx : public http_status {
+ public:
+ explicit http_status_5xx(const string& s,const string& m)
+ : http_status(s,m) { }
+ };
+ /**
+ * Internal server error.
+ */
+ class http_status_500 : public http_status_5xx {
+ public:
+ explicit http_status_500(const string& m)
+ : http_status_5xx("500",m) { }
+ explicit http_status_500()
+ : http_status_5xx("500","Internal server error") { }
+ };
+ /**
+ * Not implemented.
+ */
+ class http_status_501 : public http_status_5xx {
+ public:
+ explicit http_status_501(const string& m)
+ : http_status_5xx("501",m) { }
+ explicit http_status_501()
+ : http_status_5xx("501","Not implemented") { }
+ };
+ /**
+ * Bad gateway.
+ */
+ class http_status_502 : public http_status_5xx {
+ public:
+ explicit http_status_502(const string& m)
+ : http_status_5xx("502",m) { }
+ explicit http_status_502()
+ : http_status_5xx("502","Bad gateway") { }
+ };
+ /**
+ * Service unavailable.
+ */
+ class http_status_503 : public http_status_5xx {
+ public:
+ explicit http_status_503(const string& m)
+ : http_status_5xx("503",m) { }
+ explicit http_status_503()
+ : http_status_5xx("503","Service unavailable") { }
+ };
+ /**
+ * Gateway timeout.
+ */
+ class http_status_504 : public http_status_5xx {
+ public:
+ explicit http_status_504(const string& m)
+ : http_status_5xx("504",m) { }
+ explicit http_status_504()
+ : http_status_5xx("504","Gateway timeout") { }
+ };
+ /**
+ * HTTP version not supported.
+ */
+ class http_status_505 : public http_status_5xx {
+ public:
+ explicit http_status_505(const string& m)
+ : http_status_5xx("505",m) { }
+ explicit http_status_505()
+ : http_status_5xx("505","HTTP version not supported") { }
+ };
+
+ // Aliases
+
+ typedef http_status_1xx http_status_informational;
+ typedef http_status_100 http_status_continue;
+ typedef http_status_101 http_status_switching_protocols;
+
+ typedef http_status_2xx http_status_sucessful;
+ typedef http_status_200 http_status_ok;
+ typedef http_status_201 http_status_created;
+ typedef http_status_202 http_status_accepted;
+ typedef http_status_203 http_status_non_authoritative_information;
+ typedef http_status_204 http_status_no_content;
+ typedef http_status_205 http_status_reset_content;
+ typedef http_status_206 http_status_partial_content;
+
+ typedef http_status_3xx http_status_redirection;
+ typedef http_status_300 http_status_multiple_choices;
+ typedef http_status_301 http_status_moved_permanently;
+ typedef http_status_302 http_status_found;
+ typedef http_status_303 http_status_see_other;
+ typedef http_status_304 http_status_not_modified;
+ typedef http_status_305 http_status_use_proxy;
+ // 306 is unused and reserved
+ typedef http_status_307 http_status_temporary_redirect;
+
+ typedef http_status_4xx http_status_client_error;
+ typedef http_status_400 http_status_bad_request;
+ typedef http_status_401 http_status_unauthorized;
+ typedef http_status_402 http_status_payment_required;
+ typedef http_status_403 http_status_forbidden;
+ typedef http_status_404 http_status_not_found;
+ typedef http_status_405 http_status_method_not_allowed;
+ typedef http_status_406 http_status_not_acceptable;
+ typedef http_status_407 http_status_proxy_authentication_required;
+ typedef http_status_408 http_status_request_timeout;
+ typedef http_status_409 http_status_conflict;
+ typedef http_status_410 http_status_gone;
+ typedef http_status_411 http_status_length_required;
+ typedef http_status_412 http_status_precondition_failed;
+ typedef http_status_413 http_status_request_entity_too_large;
+ typedef http_status_414 http_status_requrest_uri_too_long;
+ typedef http_status_415 http_status_unsupported_media_type;
+ typedef http_status_416 http_status_required_range_not_satisfiable;
+ typedef http_status_417 http_status_expectation_failed;
+
+ typedef http_status_5xx http_status_server_error;
+ typedef http_status_500 http_status_internal_server_error;
+ typedef http_status_501 http_status_not_implemented;
+ typedef http_status_502 http_status_bad_gateway;
+ typedef http_status_503 http_status_service_unavailable;
+ typedef http_status_504 http_status_gateway_timeout;
+ typedef http_status_505 http_status_http_version_not_supported;
+
+}
+
+#endif /* __SITECING_EXCEPTION_H */
diff --git a/include/sitecing/file_factory.h b/include/sitecing/file_factory.h
new file mode 100644
index 0000000..7ec82da
--- a/dev/null
+++ b/include/sitecing/file_factory.h
@@ -0,0 +1,64 @@
+#ifndef __SITECING_FILE_FACTORY_H
+#define __SITECING_FILE_FACTORY_H
+
+#include <string>
+#include <list>
+
+/**
+ * @file
+ * @brief the file_factory class declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * The factory class. Does the job similar to that which is done by make
+ * utility.
+ */
+ class file_factory {
+ public:
+ /**
+ * The recursion depth.
+ */
+ int depth;
+ /**
+ * The list of files type. The list of strings, in fact.
+ */
+ typedef list<string> file_list_t;
+
+ file_factory()
+ : depth(0) { }
+
+ /**
+ * Fetch depndencies for the given file.
+ * @param dst destination file.
+ * @param deps where to put dependencies to.
+ */
+ virtual void get_dependencies(const string& dst,file_list_t& deps) = 0;
+ /**
+ * Check if the destination is up to day.
+ * @param the destination file.
+ * @param deps if the deps pointer is non there, the dependencies
+ * retrieved will be stored there.
+ * @return true if yes.
+ * @see get_dependencies()
+ */
+ virtual bool is_uptodate(const string& dst,file_list_t* deps=0);
+ /**
+ * Build the file requested.
+ * @param dst the file requested.
+ */
+ virtual void build(const string& dst) = 0;
+ /**
+ * Make the file requested, which means: build it, unless it's
+ * uptodate.
+ * @see is_uptodate()
+ * @see build()
+ */
+ virtual void make(const string& dst);
+ };
+
+}
+
+#endif /* __SITECING_FILE_FACTORY_H */
diff --git a/include/sitecing/magic.h b/include/sitecing/magic.h
new file mode 100644
index 0000000..4802fcc
--- a/dev/null
+++ b/include/sitecing/magic.h
@@ -0,0 +1,63 @@
+#ifndef __SITECING_MAGIC_H
+#define __SITECING_MAGIC_H
+
+/**
+ * @file
+ * @brief The magic numbers globally defined.
+ */
+
+namespace sitecing {
+
+ /**
+ * The magic numbers enumeration.
+ */
+ enum {
+ /**
+ * There is no magic.
+ */
+ __magic_none = 0,
+ /**
+ * Here is where user-defined magic starts.
+ */
+ __user_magical_numbers_start = 1,
+ /**
+ * Here is where site-C-ing defined magic starts.
+ */
+ __sitecing_magical_numbers_start = 0x8000,
+ /**
+ * The compiler error occured. The parameters passed are:
+ *
+ * char *message, char *root_source, char *root_intermediate, char *root_so, char *component
+ */
+ __magic_compile_error,
+ /**
+ * The preprocessor error occured. The parameters passed are:
+ *
+ * char *message, char *root_source, char *root_intermediate, char *root_so, char *component,
+ * int line_number
+ */
+ __magic_preprocess_error,
+ /**
+ * Exception caught while executing the component. The parameters passed are:
+ *
+ * char *message, char *root_source, char *root_intermediate, char *root_so, char *component,
+ * const exception *exception_caught
+ */
+ __magic_generic_exception,
+ /**
+ * The component called as an action handler. The parameters passed are:
+ *
+ * char *root_source, char *root_intermediate, char *root_so, list<string>* args
+ */
+ __magic_action,
+ /**
+ * The component called as an HTTP status handler. The parameters passed are:
+ *
+ * char *root_source, char *root_intermediate, char *root_so, char *component,
+ * const http_status *http_status_caught
+ */
+ __magic_http_status
+ };
+}
+
+#endif /* __SITECING_MAGIC_H */
diff --git a/include/sitecing/process_manager.h b/include/sitecing/process_manager.h
new file mode 100644
index 0000000..73415d3
--- a/dev/null
+++ b/include/sitecing/process_manager.h
@@ -0,0 +1,89 @@
+#ifndef __SITECING_PROCESS_MANAGER_H
+#define __SITECING_PROCESS_MANAGER_H
+
+#include <sitecing/scoreboard.h>
+
+/**
+ * @file
+ * @brief the process manager.
+ */
+
+namespace sitecing {
+
+ /**
+ * The process manager.
+ */
+ class process_manager {
+ public:
+ /**
+ * Minimum number of child processes.
+ */
+ int min_children;
+ /**
+ * Maxinum number of child processes.
+ */
+ int max_children;
+ /**
+ * Minimum number of spare child processes.
+ */
+ int min_spare_children;
+ /**
+ * Maxiumum number of spare child processes.
+ */
+ int max_spare_children;
+ /**
+ * The scoreboard.
+ */
+ scoreboard sboard;
+ /**
+ * We're in the process of shutting down.
+ */
+ bool finishing;
+ /**
+ * @todo TODO: wish I could rememer -- document me.
+ */
+ bool die_humbly;
+
+ process_manager();
+ virtual ~process_manager();
+
+ /**
+ * The main loop.
+ */
+ void manage();
+
+ /**
+ * The worker function.
+ * @param the slot allocated for the process.
+ */
+ virtual void process(int slot) = 0;
+
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void manage_children();
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ bool spawn_children();
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ bool kill_children();
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void spawn_child();
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void wait_for_children(bool hang=false);
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void collect_dead_souls(bool actively=false);
+ };
+
+}
+
+#endif /* __SITECING_PROCESS_MANAGER_H */
diff --git a/include/sitecing/scoreboard.h b/include/sitecing/scoreboard.h
new file mode 100644
index 0000000..788f881
--- a/dev/null
+++ b/include/sitecing/scoreboard.h
@@ -0,0 +1,102 @@
+#ifndef __SITECING_SCOREBOARD_H
+#define __SITECING_SCOREBOARD_H
+
+#include <sys/types.h>
+
+/**
+ * @file
+ * @brief the scoreboard manager.
+ */
+
+/**
+ * @def MAX_SITECING_SCOREBOARD_SLOTS
+ * The maximum number of slots scoreboard can hold.
+ */
+#define MAX_SITECING_SCOREBOARD_SLOTS 512
+
+namespace sitecing {
+
+ /**
+ * The scoreboard slot.
+ */
+ struct scoreboard_slot {
+ /**
+ * The state enumeration.
+ */
+ enum _state {
+ /**
+ * The slot is free.
+ */
+ state_free = 0,
+ /**
+ * The slot is allocated.
+ */
+ state_allocated,
+ /**
+ * The process is idle.
+ */
+ state_idle,
+ /**
+ * The process is accepting connection.
+ */
+ state_accept,
+ /**
+ * The process is processing request.
+ */
+ state_processing
+ } state;
+ pid_t pid;
+ };
+
+ /**
+ * The scoreboard manager.
+ */
+ class scoreboard {
+ /**
+ * shared memory id.
+ */
+ int shmid;
+ public:
+ /**
+ * Pointer to the scoreboard slots.
+ */
+ scoreboard_slot *slots;
+
+ scoreboard();
+ ~scoreboard();
+
+ /**
+ * Allocate a scoreboard slot.
+ * @return the slot number.
+ */
+ int allocate_slot();
+ /**
+ * Free the slot allocated.
+ * @param slot the slot number.
+ */
+ void free_slot(int slot);
+
+ /**
+ * Get the pointer to the slot.
+ * @param slot the slot number.
+ * @return the pointer.
+ */
+ scoreboard_slot *get_slot(int slot);
+ /**
+ * Find the slot corresponding to the process ID.
+ * @param pid the process id.
+ * @return the slot number.
+ */
+ int get_slot_by_pid(pid_t pid);
+
+ /**
+ * Count the slots in the particular state.
+ * @param state the state.
+ * @return the number of slots found.
+ */
+ int count_slots(enum scoreboard_slot::_state state=scoreboard_slot::state_free);
+ };
+
+}
+
+#endif /* __SITECING_SCOREBOARD_H */
diff --git a/include/sitecing/sitecing_enflesher.h b/include/sitecing/sitecing_enflesher.h
new file mode 100644
index 0000000..ad57fb5
--- a/dev/null
+++ b/include/sitecing/sitecing_enflesher.h
@@ -0,0 +1,65 @@
+#ifndef __SITECING_SITECING_ENFLESHER_H
+#define __SITECING_SITECING_ENFLESHER_H
+
+#include <fstream>
+#include <string>
+using namespace std;
+
+/**
+ * @file
+ * @brief The preprocessed source builder.
+ */
+
+#ifndef sitecing_enflesher_flexlexer_once
+#define sitecing_enflesher_flexlexer_once
+#undef yyFlexLexer
+#define yyFlexLexer sitecing_enflesherFlexLexer
+#include <FlexLexer.h>
+#undef yyFlexLexerOnce
+#endif
+
+class sitecing_parser;
+/**
+ * The enfleshing of the skeleton file according to the in-memory parsed
+ * component source.
+ */
+class sitecing_enflesher : public sitecing_enflesherFlexLexer {
+ public:
+ /**
+ * It is time to anchor output with the #line directive.
+ */
+ bool anchor_time;
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ bool anchoraged;
+ /**
+ * The reference to the parser object containg the parsed source.
+ */
+ sitecing_parser& parser;
+ /**
+ * The output stream.
+ */
+ ofstream outs;
+
+ /**
+ * @param p The parser object containing preparsed data.
+ */
+ sitecing_enflesher(sitecing_parser& p)
+ : parser(p), anchor_time(true) { }
+
+ /**
+ * Do the job.
+ */
+ void enflesh();
+
+ virtual void LexerOutput(const char *buf,int size);
+ virtual int yylex();
+
+ /**
+ * Put a #line anchor into output.
+ */
+ void anchor();
+};
+
+#endif /* __SITECING_SITECING_ENFLESHER_H */
diff --git a/include/sitecing/sitecing_exception.h b/include/sitecing/sitecing_exception.h
new file mode 100644
index 0000000..bf475ac
--- a/dev/null
+++ b/include/sitecing/sitecing_exception.h
@@ -0,0 +1,103 @@
+#ifndef __SITECING_SITECING_EXCEPTION_H
+#define __SITECING_SITECING_EXCEPTION_H
+
+#include <konforka/exception.h>
+
+/**
+ * @file
+ * @brief The site-C-ing specific exception.
+ */
+
+namespace sitecing {
+
+ /**
+ * The component failed to compile.
+ */
+ class compile_error : public konforka::exception {
+ public:
+ /**
+ * The component path
+ */
+ string component_path;
+
+ /**
+ * @param w the message.
+ * @param cp component path.
+ */
+ compile_error(const string& w,const string& cp)
+ : konforka::exception(NOCODEPOINT,w), component_path(cp) { }
+ /**
+ * @param whe point in code.
+ * @param wha the message.
+ * @param cp component path.
+ */
+ compile_error(const string &whe,const string& wha,const string& cp)
+ : konforka::exception(whe,wha), component_path(cp) { }
+ /**
+ * @param fi the file name where the exception is thrown from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originates from.
+ * @param cp component path.
+ */
+ compile_error(const string &fi,const string& fu,int l,const string& w,const string& cp)
+ : konforka::exception(fi,fu,l,w), component_path(cp) { }
+ ~compile_error() throw() { }
+ };
+
+ /**
+ * Failed to preprocess component source.
+ */
+ class preprocessor_error : public konforka::exception {
+ public:
+ /**
+ * Component name.
+ */
+ string component_name;
+ /**
+ * The line number of the source code where the error occured.
+ */
+ int line_number;
+
+ /**
+ * @param fi file name where the exception originates from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originate from.
+ * @param w the error message.
+ * @param cn the component name.
+ * @param ln the line of the component source where the error occured.
+ */
+ preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn,int ln)
+ : konforka::exception(fi,fu,l,w), component_name(cn), line_number(ln) { }
+ /**
+ * @param fi file name where the exception originates from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originate from.
+ * @param w the error message.
+ * @param cn the component name.
+ */
+ preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn)
+ : konforka::exception(fi,fu,l,w), component_name(cn), line_number(-1) { }
+ /**
+ * @param fi file name where the exception originates from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originate from.
+ * @param w the error message.
+ * @param ln the line of the component source where the error occured.
+ */
+ preprocessor_error(const string& fi,const string& fu,int l,const string& w,int ln)
+ : konforka::exception(fi,fu,l,w), line_number(ln) { }
+ /**
+ * @param fi file name where the exception originates from.
+ * @param fu the function name where the exception originates from.
+ * @param l the line number where the exception originate from.
+ * @param w the error message.
+ */
+ preprocessor_error(const string& fi,const string& fu,int l,const string& w)
+ : konforka::exception(fi,fu,l,w), line_number(-1) { }
+
+ ~preprocessor_error() throw() {}
+ };
+
+}
+
+#endif /* __SITECING_SITECING_EXCEPTION_H */
diff --git a/include/sitecing/sitecing_interface.h b/include/sitecing/sitecing_interface.h
new file mode 100644
index 0000000..0cba2bb
--- a/dev/null
+++ b/include/sitecing/sitecing_interface.h
@@ -0,0 +1,40 @@
+#ifndef __SITECING_SITECING_INTERFACE_H
+#define __SITECING_SITECING_INTERFACE_H
+
+#include <ostream>
+
+/**
+ * @file
+ * @brief The sitecing_interface call declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * @brief the interface to site-C-ing.
+ *
+ * The basic class used to convey communications between the component and
+ * the sitecing core.
+ */
+ class sitecing_interface {
+ public:
+ /**
+ * Pointer to the output stream.
+ */
+ ostream *out;
+
+ /**
+ * The default constructor doesn't do much.
+ */
+ sitecing_interface() : out(0) {}
+ /**
+ * The constructor initializes the output stream pointer.
+ * @param o the value to initialize the output stream pointer with.
+ */
+ sitecing_interface(ostream* o) : out(o) {}
+ };
+
+}
+
+#endif /* __SITECING_SITECING_INTERFACE_H */
diff --git a/include/sitecing/sitecing_interface_cgi.h b/include/sitecing/sitecing_interface_cgi.h
new file mode 100644
index 0000000..cab947c
--- a/dev/null
+++ b/include/sitecing/sitecing_interface_cgi.h
@@ -0,0 +1,62 @@
+#ifndef __SITECING_SITECING_INTERFACE_CGI_H
+#define __SITECING_SITECING_INTERFACE_CGI_H
+
+#include <sstream>
+#include <string>
+#include <map>
+#include "kingate/cgi_gateway.h"
+#include "sitecing/sitecing_interface.h"
+#include "sitecing/sitespace.h"
+
+/**
+ * @file
+ * @brief The sitecing_interface_cgi class declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * The interface to site-C-ing core for the CGI component.
+ */
+ class sitecing_interface_cgi : public sitecing_interface {
+ public:
+ /**
+ * Pointer to the CGI gateway interface.
+ */
+ kingate::cgi_gateway* cgigw;
+ /**
+ * Type for the map of headers to spit out.
+ */
+ typedef map<string,string> headers_t;
+ /**
+ * The list of headers to spit out.
+ */
+ headers_t headers;
+ /**
+ * Here is where we prebuffer output.
+ */
+ ostringstream prebuffer;
+ /**
+ * Pointer to the sitespace object.
+ */
+ sitespace *ss; // XXX: or does it belong to the generic interface? or should this 'generic' interface exist at all?
+
+ /**
+ * @param s Pointer to the sitespace object.
+ */
+ sitecing_interface_cgi(sitespace *s);
+
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void prepare(kingate::cgi_gateway *cg);
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ void flush();
+
+ };
+}
+
+#endif /* __SITECING_SITECING_INTERFACE_CGI_H */
diff --git a/include/sitecing/sitecing_parser.h b/include/sitecing/sitecing_parser.h
new file mode 100644
index 0000000..22d716f
--- a/dev/null
+++ b/include/sitecing/sitecing_parser.h
@@ -0,0 +1,326 @@
+#ifndef __SITECING_SITECING_PARSER_H
+#define __SITECING_SITECING_PARSER_H
+
+#include <string>
+#include <list>
+#include <map>
+#include <stdexcept>
+using namespace std;
+
+#include "sitecing/component_factory.h"
+using namespace sitecing;
+
+/**
+ * @file
+ * @brief The component source parser.
+ */
+
+#ifndef sitecing_parser_flexlexer_once
+#define sitecing_parser_flexlexer_once
+#undef yyFlexLexer
+#define yyFlexLexer sitecing_parserFlexLexer
+#include <FlexLexer.h>
+#undef yyFlexLexerOnce
+#endif
+
+/**
+ * The component source parser.
+ */
+class sitecing_parser : public sitecing_parserFlexLexer {
+ public:
+ /**
+ * The ancestor class definition.
+ */
+ class ancestor_class {
+ public:
+ /**
+ * The class name.
+ */
+ string name;
+ /**
+ * The source component path.
+ */
+ string path;
+
+ /**
+ * @param n the class name.
+ * @param p the component path.
+ */
+ ancestor_class(const string& n,const string& p)
+ : name(n), path(p) { }
+ };
+ /**
+ * The list of ancestor classes.
+ */
+ typedef list<ancestor_class> ancestor_classes_t;
+ /**
+ * The ancestor classes.
+ */
+ ancestor_classes_t ancestor_classes;
+ /**
+ * The member variable definition.
+ */
+ class member_variable {
+ public:
+ /**
+ * The member variable type.
+ */
+ string type;
+ /**
+ * The member variable name.
+ */
+ string name;
+ /**
+ * The member variable is a component.
+ */
+ bool bComponent;
+ /**
+ * The variable initializer.
+ */
+ string initializer;
+ /**
+ * @todo TODO: wish I could remember -- document me.
+ */
+ bool bTypeOnly;
+
+ /**
+ * @param t type.
+ * @param n name.
+ * @param i initializer.
+ * @param bc whether it is a component.
+ * @param bto @todo TODO: @see bTypeOnly.
+ */
+ member_variable(const string& t,const string& n,const string& i,bool bc = false,bool bto = false)
+ : type(t), name(n), initializer(i), bComponent(bc), bTypeOnly(bto) { }
+ };
+ /**
+ * The list of member variables.
+ */
+ typedef list<member_variable> member_variables_t;
+ /**
+ * Member variables.
+ */
+ member_variables_t member_variables;
+ /**
+ * @todo TODO: wish I could remember the details -- document me.
+ */
+ bool have_initializers;
+ /**
+ * Whether the component has a constructor defined.
+ */
+ bool have_constructor;
+ /**
+ * Member function definition.
+ */
+ class member_function {
+ public:
+ /**
+ * Return type.
+ */
+ string type;
+ /**
+ * Function name.
+ */
+ string name;
+ /**
+ * Arguments declaration.
+ */
+ string args;
+ /**
+ * Function body.
+ */
+ string body;
+
+ /**
+ * @param t type.
+ * @param n name.
+ * @param a arguments.
+ * @param b body.
+ */
+ member_function(const string& t,const string& n,const string& a,const string& b)
+ : type(t), name(n), args(a), body(b) { }
+ };
+ /**
+ * The list of member functions.
+ */
+ typedef list<member_function> member_functions_t;
+ /**
+ * Member functions.
+ */
+ member_functions_t member_functions;
+ /**
+ * Current mode of operation.
+ */
+ class modus_operandi {
+ public:
+ /**
+ * The state enumeration.
+ */
+ enum modus_t {
+ /**
+ * Building the code.
+ */
+ modus_code = 0,
+ /**
+ * Ready to do the '<<' thing.
+ */
+ modus_preop,
+ /**
+ * Just made a '<<'.
+ */
+ modus_postop,
+ /**
+ * Outputting raw output data.
+ */
+ modus_text,
+ /**
+ * The number of modes.
+ */
+ modi
+ };
+ /**
+ * Processing flags enumeration.
+ */
+ enum {
+ /**
+ * Eat the comments.
+ */
+ flag_devour_comments = 0x0001,
+ /**
+ * Eat whitespace.
+ */
+ flag_devour_whitespace = 0x0002
+ };
+ /**
+ * The processing mode.
+ */
+ modus_t modus;
+ /**
+ * The processing flags.
+ */
+ int flags;
+ /**
+ * Output being built.
+ */
+ string output;
+ /**
+ * The type for compound modes.
+ */
+ string _type;
+ /**
+ * The last id encountered.
+ */
+ string _lastid;
+ /**
+ * The name for compound modes.
+ */
+ string _name;
+ /**
+ * The argument declaration. Obviously for member functions.
+ */
+ string _args;
+
+ /**
+ * @param flags.
+ * @see flags
+ */
+ modus_operandi(int f = 0)
+ : modus(modus_code), flags(f) { }
+
+ /**
+ * Change the processing mode.
+ */
+ void modify(modus_t m);
+
+ /**
+ * See if we're eating up whitespaces.
+ */
+ bool devour_whitespace() { return flags&flag_devour_whitespace; }
+ /**
+ * See if we're eating up the comments.
+ */
+ bool devour_comments() { return flags&flag_devour_comments; }
+ };
+ /**
+ * The modes stack type.
+ */
+ typedef list<modus_operandi> modi_operandi;
+ /**
+ * The modes stack.
+ */
+ modi_operandi modi;
+ /**
+ * Input file name.
+ */
+ string input_file;
+ /**
+ * Base class name.
+ */
+ string base_class;
+ /**
+ * Base class header.
+ */
+ string base_header;
+ /**
+ * Component's basename.
+ * @todo TODO: wish I could remember the details -- document me.
+ */
+ string component_basename;
+ /**
+ * The skeleton file name.
+ */
+ string skeleton;
+ /**
+ * The component class name.
+ */
+ string class_name;
+ /**
+ * Output basename.
+ * @todo TODO: wish I could remember the details -- document me.
+ */
+ string output_basename;
+ /**
+ * Verbatim declaration part.
+ */
+ string decl;
+ /**
+ * Verbatim implementation part.
+ */
+ string impl;
+ /**
+ * The reference to the component factory object.
+ */
+ component_factory& factory;
+
+ /**
+ * @param f the component factory.
+ */
+ sitecing_parser(component_factory& f);
+
+ /**
+ * Preprocess file.
+ * @param in input file name.
+ */
+ void preprocess(const string& in);
+
+ virtual void LexerOutput(const char *buf,int size);
+ virtual int yylex();
+
+ /**
+ * Retrieve reference to the to of the modes stack.
+ * @return the reference in question.
+ */
+ modus_operandi& M() {
+ return modi.front();
+ }
+ /**
+ * Anchor the output with the #line, if we're not in the text output mode.
+ */
+ void soft_anchor();
+ /**
+ * Anchor the output with the #line directive, changing to the appropriate output mode if needed.
+ */
+ void anchor();
+};
+
+#endif /* __SITECING_SITECING_PARSER_H */
diff --git a/include/sitecing/sitecing_util.h b/include/sitecing/sitecing_util.h
new file mode 100644
index 0000000..d1a6c4a
--- a/dev/null
+++ b/include/sitecing/sitecing_util.h
@@ -0,0 +1,341 @@
+#ifndef __SITECING_SITECING_UTIL_H
+#define __SITECING_SITECING_UTIL_H
+
+#include <sys/types.h>
+#include <string>
+#include <konforka/exception.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/include/sitecing/sitespace.h b/include/sitecing/sitespace.h
new file mode 100644
index 0000000..38fafe4
--- a/dev/null
+++ b/include/sitecing/sitespace.h
@@ -0,0 +1,76 @@
+#ifndef __SITECING_SITESPACE_H
+#define __SITECING_SITESPACE_H
+
+#include <string>
+#include <map>
+#include <list>
+#include "sitecing/component_factory.h"
+#include "sitecing/component_so.h"
+#include "sitecing/configuration.h"
+
+/**
+ * @file
+ * @brief The sitespace class declaration.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * The class responsible for handling the whole environment (as far as I can
+ * remember).
+ */
+ class sitespace {
+ public:
+ /**
+ * The type for the map of components from the component name/path
+ * to the loaded component objects.
+ */
+ typedef map<string,component_so*> components_t;
+ /**
+ * The type for listing the components.
+ */
+ typedef list<component_so*> sentenced_t;
+ /**
+ * The main configuration object.
+ */
+ configuration& config;
+ /**
+ * The components producing factory.
+ */
+ component_factory factory;
+ /**
+ * The components loaded.
+ */
+ components_t components;
+ /**
+ * The list of components sentenced to death.
+ */
+ sentenced_t sentenced;
+
+ /**
+ * Create an object in accordance with the configuration parsed.
+ * @param c the coniguration container.
+ */
+ sitespace(configuration& c);
+ ~sitespace();
+
+ /**
+ * Fetch the component, providing it with the interface object
+ * pointer.
+ * @param c the component name.
+ * @param scif the interface object.
+ * @return the component fetches.
+ */
+ so_component fetch(const string& c,sitecing_interface* scif);
+
+ private:
+ /**
+ * Execute the death sentence as much as we can.
+ */
+ void execute_sentenced();
+ };
+
+}
+
+#endif /* __SITECING_SITESPACE_H */
diff --git a/include/sitecing/util.h b/include/sitecing/util.h
new file mode 100644
index 0000000..5750ab6
--- a/dev/null
+++ b/include/sitecing/util.h
@@ -0,0 +1,148 @@
+#ifndef __SITECING_UTIL_H
+#define __SITECING_UTIL_H
+
+#include <ostream>
+#include <string>
+#include "sitecing/acomponent.h"
+
+/**
+ * @file
+ * @brief more or less non-internal utility classes and functions.
+ */
+
+namespace sitecing {
+ using namespace std;
+
+ /**
+ * the html_escape options enumeration.
+ */
+ enum html_escape_options {
+ /**
+ * Turn spaces into &nbsp;
+ */
+ html_escape_nbsp = 0x0001,
+ /**
+ * Turn newlines into <br/> or <br>.
+ */
+ html_escape_br = 0x0002,
+ /**
+ * Turn quotes to &quot;
+ */
+ html_escape_quot = 0x0004,
+ /**
+ * Do not put '/' into <br/> consruct.
+ */
+ html_escape_br_noslash = 0x0008
+ };
+ /**
+ * Escape string suitable for html output.
+ * @param str the string.
+ * @param flags options.
+ * @return the string escaped.
+ * @see html_escape_options
+ */
+ string html_escape(const string& str,int flags=html_escape_br);
+
+ /**
+ * The output string checkpoint object, letting one to rollback output.
+ */
+ class checkpoint {
+ public:
+ /**
+ * The object's death will enumeration.
+ */
+ enum will_t {
+ /**
+ * The stream is to be rolled back at object destruction.
+ */
+ will_rollback,
+ /**
+ * The stream is not to be rolled back at object destruction.
+ */
+ will_commit,
+ /**
+ * The object will die intestate. What's the point then?
+ */
+ will_intestate
+ };
+ /**
+ * The output stream in question.
+ */
+ ostream* stream;
+ /**
+ * The point at which objhect was created.
+ */
+ ostream::pos_type point;
+ /**
+ * The last will.
+ */
+ will_t last_will;
+
+ /**
+ * @param s reference to the stream.
+ * @param lw the last will.
+ */
+ checkpoint(ostream& s, will_t lw=will_rollback)
+ : stream(&s), last_will(lw) { set(); }
+ /**
+ * @param s pointer to the stream.
+ * @param lw the last will.
+ */
+ checkpoint(ostream* s, will_t lw=will_rollback)
+ : stream(s), last_will(lw) { set(); }
+ /**
+ * @param s reference to the sitecing interface where to get output
+ * stream from.
+ * @param lw the last will.
+ */
+ checkpoint(sitecing_interface& s, will_t lw=will_rollback)
+ : stream(s.out), last_will(lw) { set(); }
+ /**
+ * @param s pointer to the sitecing interface where to get output
+ * stream from.
+ * @param lw the last will.
+ */
+ checkpoint(sitecing_interface* s, will_t lw=will_rollback)
+ : stream(s->out), last_will(lw) { set(); }
+ /**
+ * @param c reference to the component from which the output stream
+ * is obtained.
+ * @param lw the last will.
+ */
+ checkpoint(acomponent& c, will_t lw=will_rollback)
+ : stream(c.__SCIF->out), last_will(lw) { set(); }
+ /**
+ * @param c pointer to the component from which the output stream is
+ * obtained.
+ * @param lw the last will.
+ */
+ checkpoint(acomponent* c, will_t lw=will_rollback)
+ : stream(c->__SCIF->out), last_will(lw) { set(); }
+ ~checkpoint() {
+ if(last_will==will_rollback)
+ rollback();
+ }
+
+ /**
+ * Set the possible rolback point to the current position in stream.
+ */
+ void set();
+ /**
+ * Make or change will.
+ */
+ void make_will(will_t lw);
+ /**
+ * Rollback the output made so far. In case of rollback will
+ * change to intestate.
+ */
+ void rollback();
+ /**
+ * Commit output so far. In case of rollback will, change to
+ * intestate.
+ */
+ void commit();
+ };
+
+}
+
+#endif /* __SITECING_UTIL_H */
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..8137060
--- a/dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,9 @@
+Makefile.in
+sitecing_enflesher.cc
+sitecing_parser.cc
+.libs
+.deps
+Makefile
+*.o
+*.lo
+*.la
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..53d8182
--- a/dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,22 @@
+lib_LTLIBRARIES = libsitecing.la
+noinst_HEADERS = pch.h
+
+INCLUDES = -I${top_srcdir}/include -I${top_builddir} ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \
+ ${PCREPP_CFLAGS}
+AM_CPPFLAGS = -D__SC_DEFAULT_SKELETON=\"${pkgdatadir}/component.skel\"
+AM_LFLAGS = -olex.yy.c
+
+libsitecing_la_SOURCES = \
+ sitecing_parser.ll sitecing_enflesher.ll \
+ sitecing_interface_cgi.cc \
+ acomponent.cc \
+ cgi_component.cc \
+ component_so.cc \
+ file_factory.cc component_factory.cc \
+ sitespace.cc \
+ configuration.cc \
+ util.cc sitecing_util.cc \
+ scoreboard.cc \
+ process_manager.cc
+libsitecing_la_LDFLAGS = \
+ -version-info 1:0:0
diff --git a/lib/acomponent.cc b/lib/acomponent.cc
new file mode 100644
index 0000000..8dfeee4
--- a/dev/null
+++ b/lib/acomponent.cc
@@ -0,0 +1,47 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <cstdarg>
+ #include <fstream>
+ #include <konforka/exception.h>
+ using namespace std;
+ #include "sitecing/acomponent.h"
+#endif
+
+namespace sitecing {
+
+ acomponent::acomponent()
+ : __SCIF(NULL) {
+ }
+ acomponent::~acomponent() {
+ }
+
+ void acomponent::__set_interface(sitecing_interface* scif) {
+ sitecing_interface *o = __SCIF;
+ __SCIF = scif;
+ if(o!=scif) {
+ __on_change_interface(o);
+ __do_imports();
+ __on_imports();
+ }
+ }
+
+ void acomponent::__on_change_interface(sitecing_interface *oscif) { }
+ void acomponent::__do_imports() { }
+ void acomponent::__on_imports() { }
+
+ void acomponent::run(int _magic,...) {
+ va_list va;
+ va_start(va,_magic);
+ main(_magic,va);
+ va_end(va);
+ }
+
+
+ void acomponent::pass_file_through(const char *fn) {
+ ifstream ifs(fn,ios::in|ios::binary);
+ if(!ifs)
+ throw konforka::exception(CODEPOINT,"failed to open file");
+ (*(__SCIF->out)) << ifs.rdbuf();
+ }
+}
diff --git a/lib/cgi_component.cc b/lib/cgi_component.cc
new file mode 100644
index 0000000..b5c4bee
--- a/dev/null
+++ b/lib/cgi_component.cc
@@ -0,0 +1,30 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include "sitecing/cgi_component.h"
+#endif
+
+namespace sitecing {
+
+ cgi_component::cgi_component()
+ : __CGI(NULL) {
+ }
+ cgi_component::~cgi_component() {
+ }
+
+ void cgi_component::__set_interface(sitecing_interface* scif) {
+ acomponent::__set_interface(scif);
+ kingate::cgi_gateway *oc = __CGI;
+ __CGI = __SCIF?__SCIF->cgigw:NULL;
+ if(__CGI!=oc)
+ __on_change_CGI(oc);
+ }
+ void cgi_component::__on_change_interface(sitecing_interface *o) {
+ acomponent::__on_change_interface(o); // But it's a no-op
+ // TODO: do something about runtime type check, maybe?
+ __SCIF = (sitecing_interface_cgi*)acomponent::__SCIF;
+ }
+ void cgi_component::__on_change_CGI(kingate::cgi_gateway *o) { }
+ void cgi_component::__on_imports() { }
+
+}
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
new file mode 100644
index 0000000..bcf19f2
--- a/dev/null
+++ b/lib/component_factory.cc
@@ -0,0 +1,279 @@
+#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 "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" };
+
+ 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)+'/') {
+ }
+
+ void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
+ deps.clear();
+ string dp = normalize_path(dst,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+".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+noro+".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+noro,str));
+ }
+ }
+ }
+ 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) {
+ }
+ // preprocessor targets
+ for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
+ try {
+ string nos = strip_suffix(dp,pp_targets[ppt]);
+ string noro = strip_prefix(nos,root_intermediate);
+ deps.push_back(root_source+noro);
+ ifstream imports((root_intermediate+noro+".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+noro+".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");
+ }
+ }
+ config_options *co_intermediate_deps = config.lookup_config(noro,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_affix& una) {
+ // do nothing. must be a cpp dependency.
+ }
+ }
+ }
+
+ bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
+ string dp = normalize_path(dst,strip_trailing_slash);
+ // XXX: or just compare it off, instead of throwing things around.
+ try {
+ strip_prefix(dp,root_intermediate);
+ return file_factory::is_uptodate(dst,deps);
+ }catch(utility_no_prefix& unp) {
+ }
+ 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);
+ // 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 cc = root_intermediate+noro+".cc";
+ if(access(cc.c_str(),R_OK))
+ throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")");
+ make_path(dir_name(root_so+noro),0755);
+ string pwd = dir_name(root_source+noro);
+ auto_chdir dir_changer(pwd);
+ file_lock lock_source(root_intermediate+noro+".lock");
+ file_lock lock_so(root_so+noro+".so.lock");
+ int stdO = open((root_intermediate+noro+".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+noro+".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(noro,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());
+ }
+ 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());
+ }
+ // 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+noro+".d");
+ args.push_back("-shared");
+ args.push_back("-o"); args.push_back(dp);
+ args.push_back(cc);
+ 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);
+ }
+ // TODO: "g++" configurable
+ int rv = execute("g++",args,stdO,stdE);
+ if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
+ throw compile_error(CODEPOINT,"failed to compile component",noro);
+ return;
+ }catch(utility_no_prefix& unp) {
+ throw konforka::exception(CODEPOINT,"component is outside of component root");
+ }catch(utility_no_suffix& uns) {
+ }
+ // preprocessor targets
+ for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
+ try {
+ string nos = strip_suffix(dp,pp_targets[ppt]);
+ string noro = strip_prefix(nos,root_intermediate);
+ string src = root_source+noro;
+ if(access(src.c_str(),R_OK))
+ throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
+ make_path(dir_name(root_intermediate+noro),0755);
+ file_lock lock(root_intermediate+noro+".lock");
+ sitecing_parser parser(*this);
+ config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton);
+ if(co_skeleton)
+ parser.skeleton = co_skeleton->skeleton;
+ static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ parser.class_name = normalize_path(noro,strip_leading_slash|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 = nos;
+ parser.component_basename = noro;
+ try {
+ parser.preprocess(src);
+ }catch(preprocessor_error& pe) {
+ pe.component_name = noro;
+ pe.see(CODEPOINT);
+ throw;
+ }
+ return;
+ }catch(utility_no_affix& una) {
+ // must be a crap from .d file
+ }
+ }
+ cerr << "ignoring build request for " << dp << endl;
+ }
+
+ 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";
+ 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";
+ make(cn);
+ ifstream ifs(cn.c_str());
+ if(!ifs.good())
+ throw konforka::exception(CODEPOINT,"filed to access component .ancestors");
+ rv.clear();
+ while(!ifs.eof()) {
+ string a;
+ ifs >> a;
+ if(!a.empty())
+ rv.push_back(a);
+ }
+ }
+
+}
diff --git a/lib/component_so.cc b/lib/component_so.cc
new file mode 100644
index 0000000..57cce01
--- a/dev/null
+++ b/lib/component_so.cc
@@ -0,0 +1,112 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <unistd.h>
+ #include <dlfcn.h>
+ #include <iostream>
+ #include <cassert>
+ #include <stdexcept>
+ using namespace std;
+ #include "sitecing/component_so.h"
+ #include "sitecing/sitecing_util.h"
+#endif
+
+namespace sitecing {
+
+ /*
+ * component_so
+ */
+
+ component_so::component_so(const string& soname)
+ : dl(NULL), sofile(soname) {
+ if(stat(sofile.c_str(),&stso))
+ throw konforka::exception(CODEPOINT,"failed to stat() shared object");
+ file_lock lock(sofile+".lock");
+ dl = dlopen(sofile.c_str(),RTLD_LAZY);
+ lock.unlock();
+ if(!dl)
+ throw konforka::exception(CODEPOINT,"failed to dlopen: "+string(dlerror()));
+ egg = (egg_t)dlsym(dl,"_egg");
+ if(!egg)
+ throw konforka::exception(CODEPOINT,"failed to dlsym: "+string(dlerror()));
+ }
+ component_so::~component_so() {
+ for(free_chickens_t::iterator i=chickens_free.begin();i!=chickens_free.end();i++)
+ delete *i;
+ chickens_free.clear();
+ if(!chickens_used.empty())
+ throw konforka::exception(CODEPOINT,"attempt to destroy the component in use");
+ dlclose(dl);
+ }
+
+ bool component_so::is_uptodate() const {
+ struct stat st;
+ if(stat(sofile.c_str(),&st))
+ throw konforka::exception(CODEPOINT,"failed to stat() shared object");
+ return stso.st_mtime==st.st_mtime;
+ }
+
+ acomponent* component_so::allocate_chicken() {
+ acomponent *rv;
+ if(!chickens_free.empty()) {
+ rv = chickens_free.front();
+ chickens_free.pop_front();
+ }else{
+ rv = (*egg)();
+ }
+ assert(chickens_used.find(rv)==chickens_used.end());
+ chickens_used[rv]=1;
+ return rv;
+ }
+
+ void component_so::allocate_chicken(acomponent* ac) {
+ used_chickens_t::iterator i = chickens_used.find(ac);
+ if(i!=chickens_used.end()) {
+ i->second++;
+ }else{
+ free_chickens_t::iterator i;
+ for(i=chickens_free.begin();*i!=ac && i!=chickens_free.end();i++);
+ if(i==chickens_free.end())
+ throw konforka::exception(CODEPOINT,"hens rarely adopt chickens");
+ chickens_free.erase(i);
+ chickens_used[ac]=1;
+ }
+ }
+
+ void component_so::deallocate_chicken(acomponent* ac) {
+ used_chickens_t::iterator i = chickens_used.find(ac);
+ if(i==chickens_used.end())
+ throw konforka::exception(CODEPOINT,"you can't deallocate what is not allocated");
+ i->second--;
+ if(i->second>0)
+ return;
+ chickens_used.erase(i);
+ chickens_free.push_front(ac);
+ }
+
+ /*
+ * so_component
+ */
+
+ so_component::so_component(component_so *h,sitecing_interface *scif)
+ : hen(h), ac(NULL) {
+ if(!hen)
+ throw konforka::exception(CODEPOINT,"can't get an egg from the null-hen");
+ ac = hen->allocate_chicken();
+ ac->__set_interface(scif);
+ }
+
+ void so_component::attach(component_so *h,acomponent *a) {
+ detach(); hen = h; ac = a;
+ if(!ac)
+ throw konforka::exception(CODEPOINT,"trying to clone null-chicken");
+ if(!hen)
+ throw konforka::exception(CODEPOINT,"trying to clone orphan chicken");
+ hen->allocate_chicken(ac);
+ }
+ void so_component::detach() {
+ if(hen && ac)
+ hen->deallocate_chicken(ac);
+ }
+
+}
diff --git a/lib/configuration.cc b/lib/configuration.cc
new file mode 100644
index 0000000..4ee1526
--- a/dev/null
+++ b/lib/configuration.cc
@@ -0,0 +1,474 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <unistd.h>
+ #include <fnmatch.h>
+ #include <cassert>
+ #include <stdexcept>
+ using namespace std;
+ #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);
+ 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);
+ 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);
+ // 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 += "/";
+ 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/file_factory.cc b/lib/file_factory.cc
new file mode 100644
index 0000000..c6b5748
--- a/dev/null
+++ b/lib/file_factory.cc
@@ -0,0 +1,55 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+ #include <konforka/exception.h>
+ using namespace std;
+ #include "sitecing/file_factory.h"
+#endif
+
+namespace sitecing {
+
+ bool file_factory::is_uptodate(const string& dst,file_list_t* deps) {
+ file_list_t deplist;
+ file_list_t *fl = deps?deps:&deplist;
+ get_dependencies(dst,*fl);
+ struct stat stdst;
+ if(stat(dst.c_str(),&stdst))
+ return false;
+ for(file_list_t::const_iterator i=fl->begin();i!=fl->end();i++) {
+ struct stat stdep;
+ if(stat(i->c_str(),&stdep))
+ return false;
+ if(stdst.st_mtime<stdep.st_mtime)
+ return false;
+ if(!is_uptodate(*i))
+ return false;
+ }
+ return true;
+ }
+
+ void file_factory::make(const string& dst) {
+ try {
+ depth++;
+ if(depth>25)
+ throw konforka::exception(CODEPOINT,"recursed too deeply.");
+ file_list_t deps;
+ if(!is_uptodate(dst,&deps)) {
+ for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++)
+ make(*i);
+ build(dst);
+ }
+ depth--;
+ }catch(konforka::exception& ke) {
+ depth--;
+ ke.see(CODEPOINT);
+ throw;
+ }catch(...) {
+ depth--;
+ throw;
+ }
+ }
+
+}
diff --git a/lib/pch.h b/lib/pch.h
new file mode 100644
index 0000000..67f9d6d
--- a/dev/null
+++ b/lib/pch.h
@@ -0,0 +1,45 @@
+#ifndef __PCH_H
+#define __PCH_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <fnmatch.h>
+
+#include <dotconf.h>
+
+#include <cstdarg>
+#include <cassert>
+#include <iostream>
+#include <fstream>
+
+#include <vector>
+using namespace std;
+
+#include <konforka/exception.h>
+
+#include "sitecing/acomponent.h"
+#include "sitecing/cgi_component.h"
+#include "sitecing/component_factory.h"
+#include "sitecing/sitecing_util.h"
+#include "sitecing/sitecing_exception.h"
+#include "sitecing/component_so.h"
+#include "sitecing/configuration.h"
+#include "sitecing/file_factory.h"
+#include "sitecing/sitecing_interface_cgi.h"
+#include "sitecing/sitespace.h"
+#include "sitecing/util.h"
+#include "sitecing/scoreboard.h"
+#include "sitecing/process_manager.h"
+
+#include "sitecing/sitecing_parser.h"
+#include "sitecing/sitecing_enflesher.h"
+
+#endif /* __PCH_H */
diff --git a/lib/process_manager.cc b/lib/process_manager.cc
new file mode 100644
index 0000000..48bcb03
--- a/dev/null
+++ b/lib/process_manager.cc
@@ -0,0 +1,152 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <sys/wait.h>
+ #include <signal.h>
+ #include <errno.h>
+ #include <cassert>
+ #include <string>
+ #include <konforka/exception.h>
+ using namespace std;
+ #include "sitecing/process_manager.h"
+#endif
+
+namespace sitecing {
+
+ process_manager::process_manager()
+ : min_children(1), max_children(MAX_SITECING_SCOREBOARD_SLOTS),
+ min_spare_children(0), max_spare_children(-1), finishing(false),
+ die_humbly(false) {
+ }
+ process_manager::~process_manager() {
+ if(die_humbly)
+ return;
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ scoreboard_slot *sslot = sboard.get_slot(tmp);
+ if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
+ kill(sslot->pid,SIGTERM);
+ }
+ collect_dead_souls(true);
+ }
+
+ void process_manager::manage() {
+ while(!finishing) {
+ manage_children();
+ // XXX: is it the way it should be?
+ sleep(10);
+ wait_for_children();
+ }
+ collect_dead_souls(true);
+ }
+
+ void process_manager::collect_dead_souls(bool actively) {
+ for(int tries=5;(tries>0) && (sboard.count_slots(scoreboard_slot::state_free)!=MAX_SITECING_SCOREBOARD_SLOTS);tries--) {
+ if(actively) {
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ scoreboard_slot *sslot = sboard.get_slot(tmp);
+ if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
+ kill(sslot->pid,SIGTERM);
+ }
+ }
+ wait_for_children(false);
+ // XXX: again.. is it the right way?
+ sleep(1);
+ }
+ }
+
+ void process_manager::wait_for_children(bool hang) {
+ int status;
+ int o = WUNTRACED;
+ if(!hang)
+ o|=WNOHANG;
+ while(sboard.count_slots(scoreboard_slot::state_free)<MAX_SITECING_SCOREBOARD_SLOTS) {
+ pid_t pid = waitpid(-1,&status,o);
+ if(!pid)
+ return;
+ if(pid<0) {
+ if(errno==EINTR)
+ return;
+ throw konforka::exception(CODEPOINT,"failed to waitpid()");
+ }
+ assert(pid);
+ int slot = sboard.get_slot_by_pid(pid);
+ sboard.free_slot(slot);
+ if(hang)
+ return;
+ }
+ }
+
+ void process_manager::manage_children() {
+ if(!spawn_children())
+ kill_children();
+ else
+ sleep(1); // just to get some rest.
+ }
+
+ bool process_manager::spawn_children() {
+ int total_children = 0;
+ int idle_children = 0;
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ switch(sboard.get_slot(tmp)->state) {
+ case scoreboard_slot::state_free:
+ break;
+ case scoreboard_slot::state_idle:
+ idle_children++;
+ default:
+ total_children++;
+ break;
+ }
+ }
+ int total_lack = 0;
+ if(total_children<min_children)
+ total_lack = min_children-total_children;
+ int idle_lack = 0;
+ if(idle_children<min_spare_children)
+ idle_lack = min_spare_children-idle_children;
+ bool rv = false;
+ for(;(idle_lack>0 || total_lack>0) && (total_children<max_children);idle_lack--,total_lack--,total_children++) {
+ spawn_child();
+ rv = true;
+ }
+ return rv;
+ }
+
+ bool process_manager::kill_children() {
+ int idle_children = 0;
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ if(sboard.get_slot(tmp)->state==scoreboard_slot::state_idle)
+ idle_children++;
+ }
+ int idle_excess = idle_children-max_spare_children;
+ bool rv = false;
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS && idle_excess>0;tmp++) {
+ scoreboard_slot *sslot = sboard.get_slot(tmp);
+ if((sslot->state==scoreboard_slot::state_idle) && (sslot->pid>0)) {
+ kill(sslot->pid,SIGTERM);
+ idle_excess--;
+ rv = true;
+ }
+ }
+ return rv;
+ }
+
+ void process_manager::spawn_child() {
+ int slot = sboard.allocate_slot();
+ pid_t pid = fork();
+ if(pid<0) {
+ sboard.free_slot(slot);
+ throw konforka::exception(CODEPOINT,"failed to fork()");
+ }
+ if(!pid) {
+ // child
+ sboard.get_slot(slot)->pid = getpid();
+ process(slot);
+ _exit(0);
+ }
+ // parent
+ sboard.get_slot(slot)->pid = pid;
+ }
+
+}
diff --git a/lib/scoreboard.cc b/lib/scoreboard.cc
new file mode 100644
index 0000000..370cd93
--- a/dev/null
+++ b/lib/scoreboard.cc
@@ -0,0 +1,71 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+ #include <cassert>
+ #include <string>
+ #include <konforka/exception.h>
+ using namespace std;
+ #include "sitecing/scoreboard.h"
+#endif
+
+namespace sitecing {
+
+ scoreboard::scoreboard()
+ : shmid(-1), slots(NULL) {
+ shmid = shmget(IPC_PRIVATE,MAX_SITECING_SCOREBOARD_SLOTS*sizeof(scoreboard_slot),IPC_CREAT|0600);
+ if(shmid<0)
+ throw konforka::exception(CODEPOINT,"failed to shmget()");
+ slots = (scoreboard_slot*)shmat(shmid,NULL,0);
+ if(shmctl(shmid,IPC_RMID,NULL))
+ throw konforka::exception(CODEPOINT,"failed to shmctl()");
+ if(!slots)
+ throw konforka::exception(CODEPOINT,"failed to shmat()");
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++)
+ slots[tmp].state=scoreboard_slot::state_free;
+ }
+ scoreboard::~scoreboard() {
+ shmdt(slots);
+ }
+
+ int scoreboard::allocate_slot() {
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ if(slots[tmp].state==scoreboard_slot::state_free) {
+ slots[tmp].state=scoreboard_slot::state_allocated;
+ slots[tmp].pid=0;
+ return tmp;
+ }
+ }
+ throw konforka::exception(CODEPOINT,"out of scoreboard slots");
+ }
+ void scoreboard::free_slot(int slot) {
+ assert(slot>=0 && slot<MAX_SITECING_SCOREBOARD_SLOTS);
+ if(slots[slot].state==scoreboard_slot::state_free)
+ throw konforka::exception(CODEPOINT,"freeing unallocated slot");
+ slots[slot].state=scoreboard_slot::state_free;
+ }
+
+ scoreboard_slot *scoreboard::get_slot(int slot) {
+ assert(slot>=0 && slot<MAX_SITECING_SCOREBOARD_SLOTS);
+ return &slots[slot];
+ }
+ int scoreboard::get_slot_by_pid(pid_t pid) {
+ for(int rv=0;rv<MAX_SITECING_SCOREBOARD_SLOTS;rv++)
+ if( (slots[rv].state!=scoreboard_slot::state_free) && (slots[rv].pid == pid) )
+ return rv;
+ throw konforka::exception(CODEPOINT,"no such process");
+ }
+
+ int scoreboard::count_slots(enum scoreboard_slot::_state state) {
+ int rv = 0;
+ for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
+ if(slots[tmp].state==state)
+ rv++;
+ }
+ return rv;
+ }
+
+}
diff --git a/lib/sitecing_enflesher.ll b/lib/sitecing_enflesher.ll
new file mode 100644
index 0000000..5f631d7
--- a/dev/null
+++ b/lib/sitecing_enflesher.ll
@@ -0,0 +1,202 @@
+%{
+#include <iostream>
+#include <fstream>
+#include <cassert>
+#include <stdexcept>
+using namespace std;
+#include "sitecing/sitecing_exception.h"
+using namespace sitecing;
+#define sitecing_enflesher_flexlexer_once
+#include "sitecing/sitecing_enflesher.h"
+#include "sitecing/sitecing_parser.h"
+#undef yyFlexLexer
+#define yyFlexLexer sitecing_enflesherFlexLexer
+%}
+%option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug
+
+ID [A-Za-z_][A-Za-z0-9_]*
+
+%%
+
+^\%\%\#[^\n]+\n {
+ string line = yytext;
+ line.erase(0,3);
+ line.erase(line.length()-1);
+ outs.flush();
+ outs.close();
+ outs.clear();
+ outs.open((parser.output_basename+line).c_str(),ios::trunc);
+ if(!outs.good())
+ throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ anchor();
+ anchoraged = true;
+}
+^\%\%[^\n]+\n {
+ string line = yytext;
+ line.erase(0,2);
+ line.erase(line.length()-1);
+ outs.flush();
+ outs.close();
+ outs.clear();
+ outs.open((parser.output_basename+line).c_str(),ios::trunc);
+ if(!outs.good())
+ throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ anchoraged = false;
+}
+
+\<\%component_basename\%\> outs << parser.component_basename; anchor_time = true;
+\<\%impl\%\> outs << parser.impl; anchor_time = true;
+\<\%member_functions:impl\%\> {
+ for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
+ outs << i->type << " " << parser.class_name << "::";
+ if(i->name.empty()) {
+ outs << parser.class_name << "()";
+ bool first = true;
+ for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
+ if(i->initializer.empty())
+ continue;
+ if(first) {
+ outs << ":";
+ first=false;
+ }else{
+ outs << ",";
+ }
+ if(i->bComponent) {
+ outs << i->name << "(NULL)";
+ }else {
+ outs << i->name << "(" << i->initializer << ")";
+ }
+ }
+ }else if(i->name == "~")
+ outs << "~" << parser.class_name << "()";
+ else
+ outs << i->name << i->args;
+ outs << "{\n" << i->body << "\n}\n";
+ }
+ anchor_time = true;
+}
+\<\%class_name\%\> outs << parser.class_name; anchor_time = true;
+\<\%baseclass_header\%\> outs << parser.base_header; anchor_time = true;
+\<\%decl\%\> outs << parser.decl; anchor_time = true;
+\<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true;
+\<\%member_variables:decl\%\> {
+ for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
+ if(i->bComponent) {
+ if(i->type.empty()) {
+ i->type = parser.factory.get_classname(i->initializer);
+ }
+ if(i->bTypeOnly) {
+ outs << "typedef " << i->type << " " << i->name << ";\n";
+ }else{
+ outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n";
+ }
+ }else{
+ outs << i->type << " " << i->name << ";\n";
+ }
+ }
+ anchor_time = true;
+}
+\<\%member_functions:decl\%\> {
+ for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
+ (i->name.empty()?outs:outs << "virtual ")
+ << i->type << " ";
+ if(i->name.empty()) {
+ outs << parser.class_name << "()";
+ }else if(i->name == "~")
+ outs << "~" << parser.class_name << "()";
+ else
+ outs << i->name << i->args;
+ outs << ";\n";
+ }
+ anchor_time = true;
+}
+\<\%imports:list\%\> {
+ for(sitecing_parser::member_variables_t::const_iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
+ if(i->bComponent)
+ outs << i->initializer << endl;
+ }
+ anchor_time = true;
+}
+\<\%imports:includes\%\> {
+ for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
+ if(i->bComponent)
+ outs << "\n#include \"" << i->initializer << ".h\"\n";
+ }
+ anchor_time = true;
+}
+\<\%imports:import\%\> {
+ for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
+ if(!i->bComponent)
+ continue;
+ if(i->bTypeOnly)
+ continue;
+ outs << "__soc_" << i->name << "=__SCIF->ss->fetch(\"" << i->initializer << "\",__SCIF); " << i->name << "=static_cast<__type_" << i->name << "*>(__soc_" << i->name << ".ac->__the_most_derived_this());\n";
+ }
+ anchor_time = true;
+}
+
+\<\%base_component\%\> {
+ // TODO:
+ anchor_time = true;
+}
+
+\<\%ancestors:includes\%\> {
+ for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
+ outs << "#include \"" << i->path << ".h\"\n";
+ }
+ anchor_time = true;
+}
+\<\%ancestors:component_list\%\> {
+ for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
+ outs << i->path << "\n";
+ }
+ anchor_time = true;
+}
+\<\%ancestors:base_clause_part\%\> {
+ for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
+ outs << ", virtual public " << parser.factory.get_classname(i->path);
+ }
+}
+\<\%ancestors:typedefs\%\> {
+ for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
+ outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n";
+ }
+ anchor_time = true;
+}
+\<\%ancestors:import\%\> {
+ for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
+ outs << i->name << "::__do_imports();\n";
+ }
+ anchor_time = true;
+}
+
+\n {
+ if(anchor_time)
+ anchor();
+ ECHO;
+}
+. ECHO;
+
+%%
+
+void sitecing_enflesher::LexerOutput(const char *buf,int size) {
+ outs.write(buf,size);
+}
+
+void sitecing_enflesher::enflesh() {
+ ifstream ifs(parser.skeleton.c_str());
+ if(!ifs.good())
+ throw preprocessor_error(CODEPOINT,"failed to open skeleton file");
+ switch_streams(&ifs,NULL);
+ yylex();
+}
+
+void sitecing_enflesher::anchor() {
+ if(!anchoraged)
+ return;
+ outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
+ anchor_time = false;
+}
+/*
+ * vim:set ft=lex:
+ */
diff --git a/lib/sitecing_interface_cgi.cc b/lib/sitecing_interface_cgi.cc
new file mode 100644
index 0000000..5c3d295
--- a/dev/null
+++ b/lib/sitecing_interface_cgi.cc
@@ -0,0 +1,25 @@
+#include <cassert>
+#include "sitecing/sitecing_interface_cgi.h"
+
+namespace sitecing {
+
+ sitecing_interface_cgi::sitecing_interface_cgi(sitespace *s)
+ : sitecing_interface(&prebuffer), ss(s), cgigw(NULL) {
+ }
+
+ void sitecing_interface_cgi::prepare(kingate::cgi_gateway *cg) {
+ cgigw = cg;
+ headers.clear();
+ headers["Content-Type"] = "text/html";
+ prebuffer.str("");
+ }
+
+ void sitecing_interface_cgi::flush() {
+ assert(cgigw);
+ for(headers_t::const_iterator i=headers.begin();i!=headers.end();i++)
+ cgigw->out() << i->first << ": " << i->second << "\n";
+ (cgigw->out() << "\n").write(prebuffer.str().c_str(),prebuffer.tellp());
+ cgigw->out().flush();
+ }
+
+}
diff --git a/lib/sitecing_parser.ll b/lib/sitecing_parser.ll
new file mode 100644
index 0000000..6cb78f3
--- a/dev/null
+++ b/lib/sitecing_parser.ll
@@ -0,0 +1,594 @@
+%{
+ /*
+ * 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 "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
+%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);
+ }
+ <<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);
+ }
+}
+
+<METHODLINE>{
+ {WHITESPACE}+ {
+ modus_operandi& m = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ m._args = m.output;
+ m.output.clear();
+ m.flags=0;
+ anchor();
+ BEGIN(CODEMETHODBLOCK);
+ }
+}
+
+<IMPORTLINE>{
+ {WHITESPACE}+ { }
+ {ID} {
+ if(!modi.front()._name.empty())
+ throw preprocessor_error(CODEPOINT,"syntax error",lineno());
+ modi.front()._name = yytext;
+ }
+ \= {
+ modi.front().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));
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+}
+
+<IMPORTTYPELINE>{
+ {WHITESPACE}+ { }
+ {ID} {
+ if(!modi.front()._name.empty())
+ throw preprocessor_error(CODEPOINT,"syntax error",lineno());
+ modi.front()._name = yytext;
+ }
+ \= {
+ modi.front().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));
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+}
+
+<DERIVELINE>{
+ {WHITESPACE}+ { }
+ {ID} {
+ if(!modi.front()._name.empty())
+ throw preprocessor_error(CODEPOINT,"syntax_error",lineno());
+ modi.front()._name = yytext;
+ }
+ \= {
+ modi.front().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)));
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+}
+
+<VARLINE>{
+ {WHITESPACE}+ {
+ modus_operandi& m = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 = modi.front();
+ 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 += modi.front().output;
+ modi.pop_front();
+ BEGIN(INITIAL);
+}
+<IMPLLINE>\n {
+ ECHO;
+ impl += modi.front().output;
+ modi.pop_front();
+ BEGIN(INITIAL);
+}
+<CLASSLINE>\n {
+ class_name = modi.front().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>{
+ "/*" {
+ 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 += modi.front().output;
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+ \<\/\%impl\> {
+ if(YY_START!=IMPLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
+ impl += modi.front().output;
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+ \<\/\%constructor\> {
+ if(YY_START!=CONSTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
+ member_functions.push_back(member_function("","","",modi.front().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("","~","",modi.front().output));
+ modi.pop_front();
+ BEGIN(INITIAL);
+ }
+ \<\/\%codemethod\> {
+ if(YY_START!=CODEMETHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
+ modus_operandi& m = modi.front();
+ 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 = modi.front();
+ 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");
+ member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output));
+ 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
new file mode 100644
index 0000000..9b6c54e
--- a/dev/null
+++ b/lib/sitecing_util.cc
@@ -0,0 +1,278 @@
+#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.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.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) {
+ char *tmp = get_current_dir_name();
+ 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
new file mode 100644
index 0000000..0406d11
--- a/dev/null
+++ b/lib/sitespace.cc
@@ -0,0 +1,52 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <cassert>
+ #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 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/lib/util.cc b/lib/util.cc
new file mode 100644
index 0000000..1a81c56
--- a/dev/null
+++ b/lib/util.cc
@@ -0,0 +1,83 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <cassert>
+ #include "sitecing/util.h"
+#endif
+
+namespace sitecing {
+
+ static const char *unsafeChars = "<>& \n\"";
+
+ string html_escape(const string& str,int flags) {
+ string rv = str;
+ string::size_type screwed = 0;
+ for(;;) {
+ screwed = rv.find_first_of(unsafeChars,screwed);
+ if(screwed == string::npos)
+ break;
+ while(screwed<rv.length() && strchr(unsafeChars,rv.at(screwed))) {
+ char danger = rv.at(screwed);
+ switch(danger) {
+ case '<':
+ rv.replace(screwed,1,"&lt;"); screwed+=4;
+ break;
+ case '>':
+ rv.replace(screwed,1,"&gt;"); screwed+=4;
+ break;
+ case '&':
+ rv.replace(screwed,1,"&amp;"); screwed+=5;
+ break;
+ case ' ':
+ if(flags&html_escape_nbsp) {
+ rv.replace(screwed,1,"&nbsp;"); screwed+=6;
+ }else
+ screwed++;
+ break;
+ case '\n':
+ if(flags&html_escape_br) {
+ if(flags&html_escape_br_noslash) {
+ rv.replace(screwed,1,"<br>\n"); screwed += 5;
+ }else{
+ rv.replace(screwed,1,"<br/>\n"); screwed += 6;
+ }
+ }else
+ screwed++;
+ break;
+ case '\"':
+ if(flags&html_escape_quot) {
+ rv.replace(screwed,1,"&quot;"); screwed+=6;
+ }else
+ screwed++;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+ return rv;
+ }
+
+ void checkpoint::set() {
+ point = stream->tellp();
+ if(last_will==will_intestate)
+ last_will = will_rollback;
+ }
+
+ void checkpoint::make_will(will_t lw) {
+ last_will = lw;
+ }
+
+ void checkpoint::rollback() {
+ stream->seekp(point);
+ if(last_will == will_rollback)
+ last_will = will_intestate;
+ }
+ void checkpoint::commit() {
+ point = stream->tellp();
+ if(last_will == will_rollback)
+ last_will = will_intestate;
+ }
+
+}
diff --git a/share/.gitignore b/share/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/share/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/share/Makefile.am b/share/Makefile.am
new file mode 100644
index 0000000..7947380
--- a/dev/null
+++ b/share/Makefile.am
@@ -0,0 +1,3 @@
+pkgdata_DATA = component.skel
+
+EXTRA_DIST = component.skel
diff --git a/share/component.skel b/share/component.skel
new file mode 100644
index 0000000..f96c5b3
--- a/dev/null
+++ b/share/component.skel
@@ -0,0 +1,53 @@
+%%#.cc
+#include "<%component_basename%>.h"
+#undef __THIS_CLASS
+#define __THIS_CLASS <%class_name%>
+<%impl%>
+
+<%member_functions:impl%>
+
+void *<%class_name%>::__the_most_derived_this() {
+ return this;
+}
+void <%class_name%>::__do_imports() {
+ __base_class::__do_imports();
+ <%ancestors:import%>
+ <%imports:import%>
+}
+
+extern "C" sitecing::acomponent* _egg () {
+ return dynamic_cast<sitecing::acomponent*>(new <%class_name%>());
+}
+%%#.h
+#ifndef __<%class_name%>_H
+#define __<%class_name%>_H
+#include "<%baseclass_header%>"
+<%ancestors:includes%>
+<%imports:includes%>
+#undef __THIS_CLASS
+#define __THIS_CLASS <%class_name%>
+<%decl%>
+
+class <%class_name%> : virtual public <%baseclass_name%><%ancestors:base_clause_part%> {
+ public:
+ typedef <%baseclass_name%> __base_class;
+ typedef <%class_name%> __this_class;
+ <%ancestors:typedefs%>
+ <%member_variables:decl%>
+
+ <%member_functions:decl%>
+
+ virtual void *__the_most_derived_this();
+ virtual void __do_imports();
+};
+
+#undef __THIS_CLASS
+#endif /* __<%class_name%>_H */
+%%.imports
+<%imports:list%>
+%%.classname
+<%class_name%>
+%%.basecomponent
+<%base_component%>
+%%.ancestors
+<%ancestors:component_list%>
diff --git a/sitecing.pc.in b/sitecing.pc.in
new file mode 100644
index 0000000..5801b51
--- a/dev/null
+++ b/sitecing.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: sitecing
+Description: site-C-ing web site development engine
+Version: @VERSION@
+Requires: kingate konforka
+Cflags: -I${includedir}
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..6c2c79e
--- a/dev/null
+++ b/src/.gitignore
@@ -0,0 +1,9 @@
+Makefile.in
+sitecing-build
+sitecing-fastcgi
+COPYING.o
+.libs
+.deps
+COPYING.cc
+Makefile
+*.o
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..cc33f3f
--- a/dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,20 @@
+bin_PROGRAMS = sitecing-fastcgi sitecing-build
+
+INCLUDES = -I${top_srcdir}/include ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \
+ ${PCREPP_CFLAGS}
+LIBS += ${top_builddir}/lib/libsitecing.la ${KINGATE_LIBS} ${DOTCONF_LIBS} \
+ ${PCREPP_LIBS}
+
+sitecing_fastcgi_SOURCES = sitecing-fastcgi.cc \
+ COPYING.cc
+sitecing_fastcgi_LDFLAGS = -rdynamic
+sitecing_fastcgi_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la
+
+sitecing_build_SOURCES = sitecing-build.cc \
+ COPYING.cc
+sitecing_build_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la
+
+COPYING.cc: ${top_srcdir}/COPYING
+ echo "const char * COPYING =" >$@ || (rm $@;exit 1)
+ sed 's/"/\\"/g' $< | sed 's/^/\"/' | sed 's/$$/\\n\"/' >>$@ || (rm $@;exit 1)
+ echo ";" >>$@ || (rm $@;exit 1)
diff --git a/src/sitecing-build.cc b/src/sitecing-build.cc
new file mode 100644
index 0000000..4cad0a3
--- a/dev/null
+++ b/src/sitecing-build.cc
@@ -0,0 +1,231 @@
+#include <sys/types.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <iostream>
+#include <memory>
+#include <fstream>
+#include <cassert>
+#include <set>
+using namespace std;
+#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);
+ 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);
+ 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
new file mode 100644
index 0000000..963c257
--- a/dev/null
+++ b/src/sitecing-fastcgi.cc
@@ -0,0 +1,325 @@
+#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.get_meta("PATH_INFO"),strip_leading_slash|strip_trailing_slash);
+ string full_component_path;
+ 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");
+ component_path.erase(sl);
+ }
+ 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);
+ 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();
+}