summaryrefslogtreecommitdiffabout
Unidiff
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 @@
1configure
2Makefile.in
3Doxyfile
4config.log
5depcomp
6config.guess
7config.h
8ltmain.sh
9config.sub
10INSTALL
11sitecing.pc
12NEWS
13Makefile
14config.status
15stamp-h1
16doxydox
17config.h.in
18autom4te.cache
19libtool
20missing
21aclocal.m4
22ylwrap
23install-sh
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
1Klever dissected:
2 Michael 'hacker' Krelin <hacker@klever.net>
3 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 @@
1Copyright (c) 2004-2005 Klever Group (http://www.klever.net/)
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
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 @@
1# Doxyfile 1.3.9.1
2
3#---------------------------------------------------------------------------
4# Project related configuration options
5#---------------------------------------------------------------------------
6PROJECT_NAME = @PACKAGE@
7PROJECT_NUMBER = @VERSION@
8OUTPUT_DIRECTORY = @builddir@/doxydox
9CREATE_SUBDIRS = NO
10OUTPUT_LANGUAGE = English
11USE_WINDOWS_ENCODING = NO
12BRIEF_MEMBER_DESC = YES
13REPEAT_BRIEF = YES
14ABBREVIATE_BRIEF =
15ALWAYS_DETAILED_SEC = NO
16INLINE_INHERITED_MEMB = NO
17FULL_PATH_NAMES = YES
18STRIP_FROM_PATH = include
19STRIP_FROM_INC_PATH = include
20SHORT_NAMES = NO
21JAVADOC_AUTOBRIEF = NO
22MULTILINE_CPP_IS_BRIEF = NO
23DETAILS_AT_TOP = NO
24INHERIT_DOCS = YES
25DISTRIBUTE_GROUP_DOC = NO
26TAB_SIZE = 8
27ALIASES =
28OPTIMIZE_OUTPUT_FOR_C = NO
29OPTIMIZE_OUTPUT_JAVA = NO
30SUBGROUPING = YES
31
32#---------------------------------------------------------------------------
33# Build related configuration options
34#---------------------------------------------------------------------------
35
36EXTRACT_ALL = NO
37EXTRACT_PRIVATE = NO
38EXTRACT_STATIC = NO
39EXTRACT_LOCAL_CLASSES = YES
40EXTRACT_LOCAL_METHODS = NO
41HIDE_UNDOC_MEMBERS = NO
42HIDE_UNDOC_CLASSES = NO
43HIDE_FRIEND_COMPOUNDS = NO
44HIDE_IN_BODY_DOCS = NO
45INTERNAL_DOCS = NO
46CASE_SENSE_NAMES = YES
47HIDE_SCOPE_NAMES = NO
48SHOW_INCLUDE_FILES = NO
49INLINE_INFO = YES
50SORT_MEMBER_DOCS = YES
51SORT_BRIEF_DOCS = NO
52SORT_BY_SCOPE_NAME = YES
53GENERATE_TODOLIST = YES
54GENERATE_TESTLIST = YES
55GENERATE_BUGLIST = YES
56GENERATE_DEPRECATEDLIST= YES
57ENABLED_SECTIONS =
58MAX_INITIALIZER_LINES = 30
59SHOW_USED_FILES = NO
60SHOW_DIRECTORIES = YES
61
62#---------------------------------------------------------------------------
63# configuration options related to warning and progress messages
64#---------------------------------------------------------------------------
65
66QUIET = NO
67WARNINGS = YES
68WARN_IF_UNDOCUMENTED = YES
69WARN_IF_DOC_ERROR = YES
70WARN_FORMAT = "$file:$line: $text"
71WARN_LOGFILE =
72
73#---------------------------------------------------------------------------
74# configuration options related to the input files
75#---------------------------------------------------------------------------
76
77INPUT = \
78 @srcdir@/include/sitecing/
79FILE_PATTERNS = *.h
80RECURSIVE = NO
81EXCLUDE =
82EXCLUDE_SYMLINKS = NO
83EXCLUDE_PATTERNS =
84EXAMPLE_PATH =
85EXAMPLE_PATTERNS =
86EXAMPLE_RECURSIVE = NO
87IMAGE_PATH =
88INPUT_FILTER =
89FILTER_PATTERNS =
90FILTER_SOURCE_FILES = NO
91
92#---------------------------------------------------------------------------
93# configuration options related to source browsing
94#---------------------------------------------------------------------------
95
96SOURCE_BROWSER = NO
97INLINE_SOURCES = NO
98STRIP_CODE_COMMENTS = YES
99REFERENCED_BY_RELATION = YES
100REFERENCES_RELATION = YES
101VERBATIM_HEADERS = YES
102
103#---------------------------------------------------------------------------
104# configuration options related to the alphabetical class index
105#---------------------------------------------------------------------------
106
107ALPHABETICAL_INDEX = YES
108COLS_IN_ALPHA_INDEX = 2
109IGNORE_PREFIX =
110
111#---------------------------------------------------------------------------
112# configuration options related to the HTML output
113#---------------------------------------------------------------------------
114
115GENERATE_HTML = YES
116HTML_OUTPUT = html
117HTML_FILE_EXTENSION = .html
118HTML_HEADER =
119HTML_FOOTER =
120HTML_STYLESHEET =
121HTML_ALIGN_MEMBERS = YES
122GENERATE_HTMLHELP = NO
123CHM_FILE =
124HHC_LOCATION =
125GENERATE_CHI = NO
126BINARY_TOC = NO
127TOC_EXPAND = NO
128DISABLE_INDEX = NO
129ENUM_VALUES_PER_LINE = 4
130GENERATE_TREEVIEW = NO
131TREEVIEW_WIDTH = 250
132
133#---------------------------------------------------------------------------
134# configuration options related to the LaTeX output
135#---------------------------------------------------------------------------
136
137GENERATE_LATEX = NO
138LATEX_OUTPUT = latex
139LATEX_CMD_NAME = latex
140MAKEINDEX_CMD_NAME = makeindex
141COMPACT_LATEX = NO
142PAPER_TYPE = a4wide
143EXTRA_PACKAGES =
144LATEX_HEADER =
145PDF_HYPERLINKS = NO
146USE_PDFLATEX = NO
147LATEX_BATCHMODE = NO
148LATEX_HIDE_INDICES = NO
149
150#---------------------------------------------------------------------------
151# configuration options related to the RTF output
152#---------------------------------------------------------------------------
153
154GENERATE_RTF = NO
155RTF_OUTPUT = rtf
156COMPACT_RTF = NO
157RTF_HYPERLINKS = NO
158RTF_STYLESHEET_FILE =
159RTF_EXTENSIONS_FILE =
160
161#---------------------------------------------------------------------------
162# configuration options related to the man page output
163#---------------------------------------------------------------------------
164
165GENERATE_MAN = NO
166MAN_OUTPUT = man
167MAN_EXTENSION = .3
168MAN_LINKS = YES
169
170#---------------------------------------------------------------------------
171# configuration options related to the XML output
172#---------------------------------------------------------------------------
173
174GENERATE_XML = YES
175XML_OUTPUT = xml
176XML_SCHEMA =
177XML_DTD =
178XML_PROGRAMLISTING = YES
179
180#---------------------------------------------------------------------------
181# configuration options for the AutoGen Definitions output
182#---------------------------------------------------------------------------
183
184GENERATE_AUTOGEN_DEF = NO
185
186#---------------------------------------------------------------------------
187# configuration options related to the Perl module output
188#---------------------------------------------------------------------------
189
190GENERATE_PERLMOD = NO
191PERLMOD_LATEX = NO
192PERLMOD_PRETTY = YES
193PERLMOD_MAKEVAR_PREFIX =
194
195#---------------------------------------------------------------------------
196# Configuration options related to the preprocessor
197#---------------------------------------------------------------------------
198
199ENABLE_PREPROCESSING = YES
200MACRO_EXPANSION = NO
201EXPAND_ONLY_PREDEF = NO
202SEARCH_INCLUDES = YES
203INCLUDE_PATH =
204INCLUDE_FILE_PATTERNS =
205PREDEFINED =
206EXPAND_AS_DEFINED =
207SKIP_FUNCTION_MACROS = YES
208
209#---------------------------------------------------------------------------
210# Configuration::additions related to external references
211#---------------------------------------------------------------------------
212
213TAGFILES =
214GENERATE_TAGFILE =
215ALLEXTERNALS = NO
216EXTERNAL_GROUPS = YES
217PERL_PATH = /usr/bin/perl
218
219#---------------------------------------------------------------------------
220# Configuration options related to the dot tool
221#---------------------------------------------------------------------------
222
223CLASS_DIAGRAMS = YES
224HIDE_UNDOC_RELATIONS = YES
225HAVE_DOT = @HAVE_DOT@
226CLASS_GRAPH = YES
227COLLABORATION_GRAPH = YES
228UML_LOOK = NO
229TEMPLATE_RELATIONS = YES
230INCLUDE_GRAPH = YES
231INCLUDED_BY_GRAPH = YES
232CALL_GRAPH = NO
233GRAPHICAL_HIERARCHY = YES
234DOT_IMAGE_FORMAT = png
235DOT_PATH = @DOT@
236DOTFILE_DIRS =
237MAX_DOT_GRAPH_WIDTH = 1024
238MAX_DOT_GRAPH_HEIGHT = 1024
239MAX_DOT_GRAPH_DEPTH = 0
240GENERATE_LEGEND = YES
241DOT_CLEANUP = YES
242
243#---------------------------------------------------------------------------
244# Configuration::additions related to the search engine
245#---------------------------------------------------------------------------
246
247SEARCHENGINE = 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 @@
1SUBDIRS=include lib share src components
2EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
3
4DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig
5if HAVE_PKGCONFIG
6pkgconfigdir=@PKGCONFIG_DIR@
7pkgconfig_DATA=sitecing.pc
8endif
9
10LOCAL_TARGETS=
11if HAVE_DOXYGEN
12LOCAL_TARGETS+=doxygen
13endif
14
15all-local: NEWS $(addprefix all-lota-,${LOCAL_TARGETS})
16clean-local: $(addprefix clean-lota-,${LOCAL_TARGETS})
17
18NEWS: NEWS.xsl NEWS.xml
19 ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
20
21all-lota-doxygen: doxydox/built
22doxydox/built: $(wildcard ${top_srcdir}/include/sitecing/*.h)
23 ${DOXYGEN}
24 touch $@
25
26clean-lota-doxygen:
27 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 @@
1<?xml version="1.0" encoding="us-ascii"?>
2<news>
3 <version version="0.0" date="January 29th, 2005">
4 <ni>Initial release</ni>
5 </version>
6</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 @@
1<?xml version="1.0" encoding="us-ascii"?>
2<xsl:stylesheet version="1.0"
3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4 >
5 <xsl:output
6 method="text"
7 encoding="us-ascii"
8 media-type="text/plain" />
9
10 <xsl:template match="news">
11 <xsl:apply-templates/>
12 </xsl:template>
13 <xsl:template match="version">
14 <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
15 <xsl:apply-templates/>
16 </xsl:template>
17 <xsl:template match="ni">
18 <xsl:text> - </xsl:text>
19 <xsl:apply-templates mode="text"/>
20 <xsl:text>&#xA;</xsl:text>
21 </xsl:template>
22 <xsl:template match="*|text()"/>
23
24</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 @@
1dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
2dnl Outputs:
3dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR
4dnl AM_CONDTIONAL: HAVE_PKGCONFIG
5AC_DEFUN([AC_WITH_PKGCONFIG],[
6 PKGCONFIG_PKGCONFIG=""
7 PKGCONFIG_DIR=""
8 HAVE_PKGCONFIG="no"
9 EXPLICIT_PKGCONFIGDIR="no"
10 test -z "${WANT_PKGCONFIG}" && WANT_PKGCONFIG=""
11 AC_PATH_PROG([PKGCONFIG_PKGCONFIG],[pkg-config],[false])
12 if test "${PKGCONFIG_PKGCONFIG}" != "false" ; then
13 AC_ARG_WITH([pkgconfigdir],
14 AC_HELP_STRING([--with-pkgconfigdir=dir],[Specify pkgconfig directory]),
15 [
16 if test "${withval}" = "no" ; then
17 WANT_PKGCONFIG="no"
18 else
19 PKGCONFIG_DIR="${withval}"
20 EXPLICIT_PKGCONFIGDIR="yes"
21 fi
22 ],[
23 AC_MSG_CHECKING([for pkgconfig directory])
24 PKGCONFIG_DIR="`${PKGCONFIG_PKGCONFIG} --debug 2>&1 | grep '^Scanning'| head -n 1 | cut -d\' -f2-|cut -d\' -f1`"
25 AC_MSG_RESULT([${PKGCONFIG_DIR}])
26 ]
27 )
28 if test -d "${PKGCONFIG_DIR}" ; then
29 HAVE_PKGCONFIG=yes
30 AC_SUBST([PKGCONFIG_PKGCONFIG])
31 AC_SUBST([PKGCONFIG_DIR])
32 else
33 AC_MSG_NOTICE([unexistent pkgconfig directory: ${PKGCONFIG_DIR}])
34 if test "${EXPLICIT_PKGCONFIGDIR}" = "yes" ; then
35 HAVE_PKGCONFIG=yes
36 AC_SUBST([PKGCONFIG_PKGCONFIG])
37 AC_SUBST([PKGCONFIG_DIR])
38 else
39 ifelse([$2], , :, [$2])
40 fi
41 fi
42 fi
43 AM_CONDITIONAL([HAVE_PKGCONFIG],[test "${HAVE_PKGCONFIG}" = "yes"])
44])
45
46dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
47dnl Outputs:
48dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN
49dnl AM_CONDTIONAL: HAVE_DOXYGEN
50AC_DEFUN([AC_WITH_DOXYGEN],[
51 HAVE_DOXYGEN="no"
52 AC_PATH_PROG([DOXYGEN],[doxygen],[false])
53 if test "${DOXYGEN}" = "false" ; then
54 ifelse([$2], , :, [$2])
55 else
56 HAVE_DOXYGEN="yes"
57 AC_SUBST([DOXYGEN])
58 $1
59 fi
60 AC_SUBST([HAVE_DOXYGEN])
61 AM_CONDITIONAL([HAVE_DOXYGEN],[test "${HAVE_DOXYGEN}" = "yes"])
62])
63
64dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
65dnl Outputs:
66dnl AC_SUBST: DOT HAVE_DOT
67dnl AM_CONDITIONAL: HAVE_DOT
68AC_DEFUN([AC_WITH_DOT],[
69 HAVE_DOT="no"
70 AC_PATH_PROG([DOT],[dot],[false])
71 if test "${DOT}" = "false" ; then
72 ifelse([$2], , :, [$2])
73 else
74 HAVE_DOT="yes"
75 AC_SUBST([DOT])
76 $1
77 fi
78AC_SUBST([HAVE_DOT])
79 AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"])
80])
81
82dnl AC_WITH_PCRE([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
83dnl Outputs:
84dnl AC_SUBST: PCRE_CONFIG PCRE_PREFIX PCRE_EXEC_PREFIX
85dnl PCRE_VERSION PCRE_CFLAGS PCRE_LIBS
86dnl PCRE_LIBS_POSIX PCRE_CFLAGS_POSIX
87dnl AM_CONDITIONAL: HAVE_PCRE
88dnl AC_DEFINE: HAVE_PCRE PCRE_VERSION
89AC_DEFUN([AC_WITH_PCRE],[
90 HAVE_PCRE="no"
91 PCRE_CONFIG=""
92 PCRE_PREFIX=""
93 PCRE_EXEC_PREFIX=""
94 PCRE_VERSION=""
95 PCRE_CFLAGS=""
96 PCRE_LIBS=""
97 PCRE_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
98 test -z "$WANT_PCRE" && WANT_PCRE=""
99 AC_ARG_WITH([pcre],
100 AC_HELP_STRING([--with-pcre=location],[Look for pcre in specified locations]),
101 [
102 if test "${withval}" = "no" ; then
103 WANT_PCRE="no"
104 else
105 if test -x "${withval}" ; then
106 PCRE_CONFIG="${withval}"
107 elif test -x "${withval}/pcre-config" ; then
108 PCRE_CONFIG="${withval}/pcre-config"
109 elif test -x "${withval}/bin/pcre-config" ; then
110 PCRE_CONFIG="${withval}/bin/pcre-config"
111 fi
112 fi
113 ]
114 )
115 if test "${WANT_PCRE}" = "no" ; then
116 ifelse([$2], , :, [$2])
117 else
118 if test -z "${PCRE_CONFIG}" ; then
119 AC_PATH_PROG(PCRE_CONFIG,[pcre-config],false,[${PCRE_LOCATIONS}])
120 if test "${PCRE_CONFIG}" = "false" ; then
121 ifelse([$2], , :, [$2])
122 else
123 HAVE_PCRE="yes"
124 PCRE_PREFIX="`${PCRE_CONFIG} --prefix`"
125 PCRE_EXEC_PREFIX="`${PCRE_CONFIG} --exec-prefix`"
126 PCRE_VERSION="`${PCRE_CONFIG} --version`"
127 PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
128 PCRE_LIBS="`${PCRE_CONFIG} --libs`"
129 PCRE_CFLAGS_POSIX="`${PCRE_CONFIG} --cflags-posix`"
130 PCRE_LIBS_POSIX="`${PCRE_CONFIG} --libs-posix`"
131 AC_SUBST([PCRE_CONFIG])
132 AC_SUBST([PCRE_PREFIX])
133 AC_SUBST([PCRE_EXEC_PREFIX])
134 AC_SUBST([PCRE_VERSION])
135 AC_SUBST([PCRE_CFLAGS])
136 AC_SUBST([PCRE_LIBS])
137 AC_SUBST([PCRE_CFLAGS_POSIX])
138 AC_SUBST([PCRE_LIBS_POSIX])
139 AC_DEFINE([HAVE_PCRE],,[pcre support])
140 AC_DEFINE_UNQUOTED([PCRE_VERSION],["${PCRE_VERSION}"],[pcre version])
141 $1
142 fi
143 fi
144 fi
145 AM_CONDITIONAL([HAVE_PCRE],[test "${HAVE_PCRE}" = "yes"])
146])
147
148dnl AC_WITH_PCREPP([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
149dnl Outputs:
150dnl AC_SUBST: PCREPP_CONFIG PCREPP_PREFIX PCREPP_EXEC_PREFIX
151dnl PCREPP_VERSION PCREPP_CFLAGS PCREPP_LIBS
152dnl AM_CONDITIONAL: HAVE_PCREPP
153dnl AC_DEFINE: HAVE_PCREPP PCREPP_VERSION
154AC_DEFUN([AC_WITH_PCREPP],[
155 HAVE_PCREPP="no"
156 PCREPP_CONFIG=""
157 PCREPP_PREFIX=""
158 PCREPP_EXEC_PREFIX=""
159 PCREPP_VERSION=""
160 PCREPP_CFLAGS=""
161 PCREPP_LIBS=""
162 PCREPP_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
163 test -z "$WANT_PCREPP" && WANT_PCREPP=""
164 AC_ARG_WITH([pcre++],
165 AC_HELP_STRING([--with-pcre++=location],[Look for pcre++ in specified locations]),
166 [
167 if test "${withval}" = "no" ; then
168 WANT_PCREPP="no"
169 else
170 if test -x "${withval}" ; then
171 PCREPP_CONFIG="${withval}"
172 elif test -x "${withval}/pcre++-config" ; then
173 PCREPP_CONFIG="${withval}/pcre++-config"
174 elif test -x "${withval}/bin/pcre++-config" ; then
175 PCREPP_CONFIG="${withval}/bin/pcre++-config"
176 fi
177 fi
178 ]
179 )
180 if test "${WANT_PCREPP}" = "no" ; then
181 ifelse([$2], , :, [$2])
182 else
183 if test "${HAVE_PCRE}" != "yes" ; then
184 ifelse([$2], , :, [$2])
185 else
186 if test -z "${PCREPP_CONFIG}" ; then
187 AC_PATH_PROG([PCREPP_CONFIG],[pcre++-config],false,[${PCREPP_LOCATIONS}])
188 if test "${PCREPP_CONFIG}" = "false" ; then
189 ifelse([$2], , :, [$2])
190 else
191 HAVE_PCREPP="yes"
192 PCREPP_PREFIX="`${PCREPP_CONFIG} --prefix`"
193 PCREPP_EXEC_PREFIX="`${PCREPP_CONFIG} --exec-prefix`"
194 PCREPP_VERSION="`${PCREPP_CONFIG} --version`"
195 PCREPP_CFLAGS="`${PCREPP_CONFIG} --cflags` ${PCRE_CFLAGS}"
196 PCREPP_LIBS="`${PCREPP_CONFIG} --libs` ${PCRE_LIBS}"
197 AC_SUBST([PCREPP_CONFIG])
198 AC_SUBST([PCREPP_PREFIX])
199 AC_SUBST([PCREPP_EXEC_PREFIX])
200 AC_SUBST([PCREPP_VERSION])
201 AC_SUBST([PCREPP_CFLAGS])
202 AC_SUBST([PCREPP_LIBS])
203 AC_DEFINE([HAVE_PCREPP],,[pcre++ support])
204 AC_DEFINE_UNQUOTED([PCREPP_VERSION],["${PCREPP_VERSION}"],[pcre++ version])
205 $1
206 fi
207 fi
208 fi
209 fi
210 AM_CONDITIONAL([HAVE_PCREPP],[test "${HAVE_PCREPP}" = "yes"])
211])
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 @@
1#!/bin/sh
2WANT_AUTOMAKE=1.8
3export WANT_AUTOMAKE
4libtoolize -f \
5&& aclocal \
6&& autoheader \
7&& automake -a \
8&& autoconf \
9&& ./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 @@
1Makefile.in
2Makefile
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 @@
1componentsdir = ${pkgdatadir}/components
2
3components_DATA = exception_dev exception_prod
4
5EXTRA_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 @@
1%%decl using namespace std;
2<%impl>
3 #include <iostream>
4 #include <fstream>
5 #include <sstream>
6 #include <cassert>
7 #include <cstdarg>
8 #include <stdexcept>
9 #include <cxxabi.h>
10 #include <sitecing/sitecing_util.h>
11 #include <sitecing/util.h>
12 #include <sitecing/magic.h>
13 #include <konforka/exception.h>
14</%impl>
15%%var string message;
16%%var string root_source;
17%%var string root_intermediate;
18%%var string root_so;
19%%var string component;
20%%var int line_number = -1;
21%%var const exception* exception_caught;
22<%code>
23 __SCIF->headers.clear();
24 __SCIF->out->seekp(0);
25 int magic = _magic;
26 va_list va = _args;
27 switch(magic) {
28 case sitecing::__magic_compile_error:
29 message = va_arg(va,const char*);
30 root_source = va_arg(va,const char*);
31 root_intermediate = va_arg(va,const char*);
32 root_so = va_arg(va,const char*);
33 component = va_arg(va,const char*);
34 break;
35 case sitecing::__magic_preprocess_error:
36 message = va_arg(va,const char*);
37 root_source = va_arg(va,const char*);
38 root_intermediate = va_arg(va,const char*);
39 root_so = va_arg(va,const char*);
40 component = va_arg(va,const char*);
41 line_number = va_arg(va,int);
42 break;
43 case sitecing::__magic_generic_exception:
44 message = va_arg(va,const char*);
45 root_source = va_arg(va,const char*);
46 root_intermediate = va_arg(va,const char *);
47 root_so = va_arg(va,const char *);
48 component = va_arg(va,const char*);
49 exception_caught = va_arg(va,const exception*);
50 break;
51 default:
52 break;
53 }
54</%code>
55<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
56<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
57 <head>
58 <title><% message %></title>
59 <style type="text/css">
60 <!--
61 body {
62 font-family: sans-serif;
63 font-size: 11pt;
64 }
65
66 h1 {
67 font-family: serif;
68 font-size: 130%;
69 font-weight: bold;
70 text-align: center;
71 }
72 p {
73 text-indent: 2em;
74 text-align: justify;
75 }
76
77 dl.exception-props {
78 margin: 1ex 1em;
79 padding: 0.5ex;
80 border: solid 1px gray;
81 background-color: #e0e0e0;
82 }
83 dl.exception-props dt {
84 font-weight: bold;
85 color: blue;
86 }
87 dl.exception-props dd {
88 color: gray;
89 }
90
91 div.exception-codepoint-report {
92 border: solid 1px black;
93 margin: 0.5ex 1em 0.ex 3em;
94 }
95 div.exception-codepoint-report h3 {
96 display: block;
97 color: blue;
98 border-bottom: 3px double black;
99 padding: 0.3ex; margin: 0px;
100 background: #e0e0e0;
101 }
102 div.exception-codepoint-report ul {
103 padding: 0px;
104 margin: 0px;
105 background: #87fdff;
106 font-size: 70%;
107 }
108 div.exception-codepoint-report li {
109 font-family: monospace;
110 list-style-type: none;
111 white-space: nowrap;
112 overflow: hidden;
113 }
114 div.exception-codepoint-report li.focused {
115 color: red;
116 border-top: solid 1px red; border-bottom: solid 1px red;
117 }
118 div.exception-codepoint-report li .lineno {
119 padding-right: 0.5ex;
120 border-right: dotted black 1px;
121 }
122 div.exception-codepoint-report div.what {
123 border-top: double 3px black;
124 padding: 0.5ex 2em;
125 font-weight: bold; color: #4040c0;
126 overflow: auto;
127 }
128 div.backtrace div.exception-codepoint-report div.what {
129 color: gray;
130 }
131
132 div.exception-compile div.what {
133 font-weight: normal;
134 color: red;
135 }
136
137 div.powered {
138 margin: 2em 0px 0px 50%;
139 padding: 1ex 2ex;
140 text-align: right;
141 font-family: serif;
142 font-size: 140%;
143 font-weight: bold;
144 border-top: solid 2px black;
145 border-left: solid 1px gray; border-right: solid 1px gray; border-bottom: solid 1px gray;
146 background: #c0c0f0;
147 }
148 -->
149 </style>
150% __SCIF->headers["Content-Type"]="text/html; charset=utf-8";
151% __SCIF->headers["Pragma"]="no-cache";
152 </head>
153 <body>
154 <%code>
155 switch(magic) {
156 case sitecing::__magic_compile_error:
157 handle_compile_error();
158 break;
159 case sitecing::__magic_preprocess_error:
160 handle_preprocess_error();
161 break;
162 case sitecing::__magic_generic_exception:
163 handle_generic_exception();
164 break;
165 default:
166 handle_unknown_error();
167 break;
168 }
169 </%code>
170 <div class="powered">Powered by <a href="http://kin.klever.net/sitecing/" title="site-C-ing">site-C-ing</a>.</div>
171 </body>
172</html>
173<%method void handle_generic_exception() %>
174 <div class="exception-generic">
175 <h1>exception caught while running component '<code><% component %></code>'</h1>
176 <dl class="exception-props">
177 <dt><code>typeid(<em>e</em>).name()</code></dt>
178% int destat;
179% char *demangled = abi::__cxa_demangle(typeid(*exception_caught).name(),NULL,NULL,&destat);
180 <dd><code><% destat?typeid(*exception_caught).name():demangled %></code></dd>
181% if(!destat) free(demangled);
182 <dt><code><em>e</em>.what()</code></dt>
183 <dd><% message %></dd>
184% if(typeid(*exception_caught)==typeid(konforka::exception&)) {
185% konforka::exception* ke = (konforka::exception*)exception_caught;
186 <dt><code><em>e</em>.where()</code></dt>
187 <dd><code>
188% if(ke->_where.line<0) {
189 <% ke->where() %>
190% }else{
191 <% strip_roots(ke->_where.file) %>:<% ke->_where.line %> [<% ke->_where.function %>]
192% }
193 </code></dd>
194% }
195 </dl>
196% if(typeid(*exception_caught)==typeid(konforka::exception&)) {
197% konforka::exception* ke = (konforka::exception*)exception_caught;
198% if(ke->_where.line>=0) {
199% report_error(ke->_where.file,ke->_where.line,ke->what());
200% }
201% if(!ke->_seen.empty()) {
202 <h2>seen at:</h2>
203 <div class="backtrace">
204% for(list<konforka::code_point>::const_iterator i=ke->_seen.begin();i!=ke->_seen.end();++i) {
205% if(i->line>=0) {
206% report_error(i->file,i->line,i->function);
207% }
208% }
209 </div>
210% }
211% }
212 </div>
213</%method>
214<%method void handle_preprocess_error() %>
215 <div class="exception-preprocess">
216 <h1>error preprocessing component '<code><% component %></code>'</h1>
217% report_error(root_source+component,line_number,message);
218 </div>
219</%method>
220<%method void handle_compile_error() %>
221 <div class="exception-compile">
222 <h1>error compiling component '<code><% component %></code>'</h1>
223 <%code>
224 ifstream err((root_intermediate+component+".stderr").c_str(),ios::in);
225 if(err.bad()) {
226 <%output>
227 Failed to access compiler output
228 </%output>
229 }else{
230 string cumulative;
231 string error_file;
232 long error_line = -1;
233 while(!err.eof()) {
234 string oef = error_file;
235 long oel = error_line;
236 string line;
237 getline(err,line);
238 if(line[0]!=' ') {
239 string::size_type c = line.find(':');
240 if(c!=string::npos) {
241 string fn = line.substr(0,c);
242 string::size_type c1 = line.find(':',c+1);
243 if(c1!=string::npos) {
244 string ln = line.substr(c+1,c1-c-1);
245 string::size_type nd = ln.find_first_not_of("0123456789");
246 if(nd==string::npos) {
247 try {
248 error_file = sitecing::strip_prefix(fn,"In file included from ");
249 }catch(sitecing::utility_no_prefix& unp) {
250 error_file = fn;
251 }
252 error_line = strtol(ln.c_str(),0,10);
253 }
254 }
255 }
256 if((oel>0 && !oef.empty()) && (oel!=error_line || oef!=error_file)) {
257 string ef = "/"+sitecing::combine_path(root_source+component,oef);
258 report_error(ef,oel,remove_roots(cumulative));
259 cumulative.clear();
260 }
261 }
262 if(!cumulative.empty())
263 cumulative += '\n';
264 cumulative += line;
265 }
266 if(!(cumulative.empty() || error_file.empty() || error_line<0)) {
267 error_file = "/"+sitecing::combine_path(root_source+component,error_file);
268 report_error(error_file,error_line,remove_roots(cumulative));
269 }
270 }
271 </%code>
272 </div>
273</%method>
274<%method void handle_unknown_error() %>
275 <div class="exception-unknown">
276 <h1>unknown error</h1>
277 </div>
278</%method>
279<%method void report_error(const string& file,long line,const string& message) %>
280 <div class="exception-codepoint-report">
281 <h3><% sitecing::html_escape(strip_roots(file)) %></h3>
282 <%code>
283 if(line>=0) {
284 int firstline = line-5, lastline = line+5;
285 if(firstline<1)
286 firstline = 1;
287 ifstream ifs(file.c_str(),ios::in);
288 if(ifs.bad()) {
289 // TODO:
290 }else{
291 for(int l=1;l<firstline && !ifs.eof();l++) {
292 ifs.ignore(65536,'\n');
293 }
294 if(ifs.eof()) {
295 // TODO: no such line in file
296 }else{
297 <%output><ul></%output>
298 for(int l=firstline;l<=lastline && !ifs.eof();l++) {
299 string str;
300 getline(ifs,str);
301 for(string::size_type t=str.find('\t');t!=string::npos;t=str.find('\t')) {
302 str.replace(t,1,8-(t%8),' ');
303 }
304 char tln[16];
305 snprintf(tln,sizeof(tln),"%5d",l);
306 <%output>
307 <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>
308 </%output>
309 }
310 <%output></ul></%output>
311 }
312 }
313 }
314 </%code>
315 <div class="what">
316 <% sitecing::html_escape(message,sitecing::html_escape_br) %>
317 </div>
318 </div>
319</%method>
320<%codemethod string strip_roots(const string& filename) %>
321 string np = sitecing::normalize_path(filename);
322 try{
323 return sitecing::strip_prefix(np,root_source);
324 }catch(sitecing::utility_no_prefix& e){ }
325 try{
326 return sitecing::strip_prefix(np,root_intermediate);
327 }catch(sitecing::utility_no_prefix& e){ }
328</%codemethod>
329<%codemethod string remove_roots(const string& str) %>
330 string rv = str;
331 string::size_type rp;
332 string::size_type rl = root_source.length();
333 while((rp=rv.find(root_source))!=string::npos) {
334 rv.erase(rp,rl);
335 }
336 rl = root_intermediate.length();
337 while((rp=rv.find(root_intermediate))!=string::npos) {
338 rv.erase(rp,rl);
339 }
340 rl = root_so.length();
341 while((rp=rv.find(root_so))!=string::npos) {
342 rv.erase(rp,rl);
343 }
344 return rv;
345</%codemethod>
346% /* 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 @@
1<%code>
2 /* vim:set ft=sitecing: */
3 __SCIF->headers.clear(); /* reset all headers possibly set by the component throwing an exception. */
4 __SCIF->out->seekp(0); /* rollback the output that the exceptional component may have produced. */
5 /* set out headers */
6 __SCIF->headers["Content-Type"] = "text/html";
7 __SCIF->headers["Status"] = "500 server-side exception";
8 __SCIF->headers["Pragma"] = "no-cache";
9</%code>
10<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
11<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
12 <head>
13 <title>Server-side exception</title>
14 <style type="text/css">
15 <!--
16 body {
17 font-family: sans-serif;
18 font-size: 12pt;
19 }
20 h1 {
21 font-family: serif;
22 font-size: 130%;
23 font-weight: bold;
24 text-align: center;
25 }
26 p {
27 text-indent: 2em;
28 text-align: justify;
29 }
30
31 div.powered {
32 margin: 2em 0px 0px 50%;
33 padding: 1ex 2ex;
34 text-align: right;
35 font-family: serif;
36 font-size: 140%;
37 font-weight: bold;
38 border-top: solid 2px black;
39 border-left: solid 1px gray; border-right: solid 1px gray; border-bottom: solid 1px gray;
40 background: #c0c0f0;
41 }
42 -->
43 </style>
44 </head>
45 <body>
46 <h1>server-side exception</h1>
47 <p>Something has gone really wrong with the server. Feel free to report the
48 incident to <a href="mailto:<% __CGI->get_meta("SERVER_ADMIN") %>" title="e-mail
49 server administrator">webmaster</a>.</p>
50 <div class="powered">Powered by <a href="http://kin.klever.net/sitecing/" title="site-C-ing">site-C-ing</a>.</div>
51 </body>
52</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 @@
1AC_INIT([sitecing], [0.0], [sitecing-bugs@klever.net])
2AC_CONFIG_SRCDIR([include/sitecing/sitecing_parser.h])
3AC_CONFIG_HEADER([config.h])
4AM_INIT_AUTOMAKE([dist-bzip2])
5
6AC_PROG_INSTALL
7AC_PROG_AWK
8AC_PROG_CXX
9AC_PROG_CC
10AM_PROG_LEX
11AC_PROG_LIBTOOL
12
13AC_HEADER_STDC
14AC_CHECK_HEADERS([stdlib.h unistd.h])
15
16AC_C_CONST
17
18AC_FUNC_MALLOC
19AC_FUNC_REALLOC
20
21AC_WITH_PKGCONFIG
22
23PKG_CHECK_MODULES([KINGATE],[kingate-fcgi],,[
24 AC_MSG_ERROR([no kingate library found, get it at http://kin.klever.net/kingate/])
25])
26PKG_CHECK_MODULES([DOTCONF],[dotconf],,[
27 AC_MSG_ERROR([no dotconf library found])
28])
29
30AC_WITH_PCRE([
31 AC_WITH_PCREPP(,[
32 AC_MSG_ERROR([no pcre++ library found])
33 ])
34],[
35 AC_MSG_ERROR([no pcre library found])
36])
37
38AC_CHECK_LIB([dl],[dlopen],,[
39 AC_MSG_ERROR([no dlopen library found])
40])
41
42AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
43
44WANT_DOXYGEN="yes"
45AC_ARG_ENABLE([doxygen],
46 AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
47 [
48 test "${enableval}" = "no" && WANT_DOXYGEN="no"
49 ]
50)
51if test "${WANT_DOXYGEN}" = "yes" ; then
52 AC_WITH_DOXYGEN
53 AC_WITH_DOT
54else
55 AM_CONDITIONAL([HAVE_DOXYGEN],[false])
56 AM_CONDITIONAL([HAVE_DOT],[false])
57fi
58
59AC_CONFIG_FILES([
60 Makefile
61 Doxyfile
62 sitecing.pc
63 include/Makefile
64 lib/Makefile
65 share/Makefile
66 src/Makefile
67 components/Makefile
68])
69AC_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 @@
1Makefile.in
2Makefile
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 @@
1 #TODO: separate installable headers from internals
2 # but to make it sensible one need to elimitate
3 # abnoxious sitecing_interface_cgi.h inclusion of
4 # sitespace.h
5nobase_include_HEADERS = \
6 sitecing/acomponent.h sitecing/cgi_component.h \
7 sitecing/component_so.h \
8 sitecing/file_factory.h sitecing/component_factory.h \
9 sitecing/sitecing_interface.h sitecing/sitecing_interface_cgi.h \
10 sitecing/sitecing_parser.h sitecing/sitecing_enflesher.h \
11 sitecing/sitespace.h \
12 sitecing/configuration.h \
13 sitecing/magic.h sitecing/util.h \
14 sitecing/exception.h sitecing/sitecing_exception.h \
15 sitecing/sitecing_util.h \
16 sitecing/process_manager.h \
17 sitecing/scoreboard.h
18
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 @@
1#ifndef __SITECING_ACOMPONENT_H
2#define __SITECING_ACOMPONENT_H
3
4#include "sitecing/sitecing_interface.h"
5
6/**
7 * @file
8 * @brief The acomponent class declaration.
9 */
10
11namespace sitecing {
12
13 /**
14 * An abstract base class for sitecing components.
15 */
16 class acomponent {
17 public:
18 /**
19 * Pointer to the interface object, used to communicate with the
20 * site-C-ing core.
21 */
22 sitecing_interface *__SCIF;
23
24 acomponent();
25 virtual ~acomponent();
26
27 /**
28 * Set the interface to core pointer.
29 * @param scif the pointer to the interface object.
30 */
31 virtual void __set_interface(sitecing_interface *scif=0);
32 /**
33 * Invoked if the interface to the core has changed.
34 * @param oscif pointer to the old interface object.
35 */
36 virtual void __on_change_interface(sitecing_interface *oscif);
37
38 /**
39 * do import components.
40 */
41 virtual void __do_imports();
42 /**
43 * invoked on components imports.
44 */
45 virtual void __on_imports();
46 /**
47 * fetch the pointer to the most derived component.
48 * @returns pointer to the most derived object.
49 */
50 virtual void *__the_most_derived_this() = 0;
51
52 /**
53 * Do the job.
54 * @param __magic the magic number used as a key to decipher the
55 * rest of parameters.
56 * @param __args the parameters.
57 */
58 virtual void main(int __magic,va_list __args) = 0;
59
60 /**
61 * Run the component. Convenience helper for calling main().
62 * @param __magic the magic number.
63 * @param ... the rest of parameters.
64 * @see main();
65 */
66 void run(int __magic,...);
67
68 /**
69 * Helper function (which doesn't necessarily belongs here!) for
70 * reading the file and passing it to the output stream.
71 * @param fn the file name.
72 */
73 void pass_file_through(const char *fn);
74 };
75
76}
77
78#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 @@
1#ifndef __SITECING_CGI_COMPONENT_H
2#define __SITECING_CGI_COMPONENT_H
3
4#include <map>
5#include "kingate/cgi_gateway.h"
6#include "sitecing/acomponent.h"
7#include "sitecing/sitecing_interface_cgi.h"
8
9/**
10 * @file
11 * @brief The cgi_component class declaration.
12 */
13
14namespace sitecing {
15 using namespace std;
16
17 /**
18 * The CGI-oriented component class.
19 */
20 class cgi_component : virtual public acomponent {
21 public:
22 /**
23 * The interface to site-C-ing core.
24 */
25 sitecing_interface_cgi* __SCIF;
26 /**
27 * The interface to the CGI gateway.
28 */
29 kingate::cgi_gateway* __CGI;
30
31 cgi_component();
32 virtual ~cgi_component();
33
34 /**
35 * @overload acomponent::__set_interface()
36 */
37 void __set_interface(sitecing_interface* scif);
38 /**
39 * @overload acomponent::__on_change_interface()
40 */
41 void __on_change_interface(sitecing_interface *o);
42 /**
43 * Invoked on the change of the interface to the CGI.
44 */
45 virtual void __on_change_CGI(kingate::cgi_gateway *o);
46 /**
47 * @overload acomponent::__on_imports()
48 */
49 virtual void __on_imports();
50 };
51
52}
53
54#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 @@
1#ifndef __SITECING_COMPONENT_FACTORY_H
2#define __SITECING_COMPONENT_FACTORY_H
3
4#include <string>
5#include <list>
6#include <stdexcept>
7#include "sitecing/file_factory.h"
8#include "sitecing/configuration.h"
9
10/**
11 * @file
12 * @brief The component_factory class declaration.
13 */
14
15namespace sitecing {
16 using namespace std;
17
18 /**
19 * @brief The components builder.
20 */
21 class component_factory : public file_factory {
22 public:
23 /**
24 * Path to the source files root.
25 */
26 string root_source;
27 /**
28 * Path to the root of the intermediate files storage.
29 */
30 string root_intermediate;
31 /**
32 * Output path for .so components.
33 */
34 string root_so;
35 /**
36 * Reference to the configuration container.
37 */
38 configuration& config;
39
40 /**
41 * @param c reference to the configuration container.
42 */
43 component_factory(configuration& c);
44
45 /**
46 * @overload file_factory::get_dependencies()
47 */
48 virtual void get_dependencies(const string& dst,file_list_t& deps);
49 /**
50 * @overload file_factory::is_uptodate()
51 */
52 virtual bool is_uptodate(const string& dst,file_list_t *deps=NULL);
53 /**
54 * @overload file_factory::build()
55 */
56 virtual void build(const string& dst);
57
58 /**
59 * Helper function for executing external command.
60 * @param cmd the command to execute.
61 * @param args the command line arguments.
62 * @param stdo stdout for the child process.
63 * @param stde stderr for the child process.
64 * @return exit code.
65 */
66 int execute(const string& cmd,const list<string>& args,int stdo,int stde);
67 /**
68 * Fetch the class name of the component.
69 * @param component the component.
70 * @return the class name.
71 */
72 string get_classname(const string& component);
73 /**
74 * Get the components from which the target component has been
75 * derived.
76 * @param component the target component
77 * @param rv where to store the list of ancestors.
78 */
79 void get_ancestors(const string& component,file_list_t &rv);
80 };
81
82}
83
84#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 @@
1#ifndef __SITECING_COMPONENT_SO_H
2#define __SITECING_COMPONENT_SO_H
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <string>
7#include <map>
8#include <list>
9#include "sitecing/acomponent.h"
10
11/**
12 * @file
13 * @brief Classes related to the .so components handling.
14 */
15
16namespace sitecing {
17 using namespace std;
18
19 /**
20 * The 'class' component object.
21 */
22 class component_so {
23 public:
24 /**
25 * The type of the component instantiating function.
26 */
27 typedef acomponent *(*egg_t)();
28 /**
29 * Type for storing the list of instances and the reference counts.
30 */
31 typedef map<acomponent*,int> used_chickens_t;
32 /**
33 * The type for storing the list of unused instances.
34 */
35 typedef list<acomponent*> free_chickens_t;
36
37 /**
38 * The .so file name.
39 */
40 string sofile;
41 /**
42 * The stat structure for the .so loaded.
43 */
44 struct stat stso;
45 /**
46 * The dloaded .so handle.
47 */
48 void *dl;
49 /**
50 * Pointer to the instatiator function.
51 */
52 egg_t egg;
53 /**
54 * The list of instances in use.
55 */
56 used_chickens_t chickens_used;
57 /**
58 * The list of unused instances.
59 */
60 free_chickens_t chickens_free;
61
62 /**
63 * @param soname the .so file name
64 */
65 component_so(const string& soname);
66 ~component_so();
67 /**
68 * Check whether the loaded .so is in sync with the disk file.
69 */
70 bool is_uptodate() const;
71
72 /**
73 * @todo TODO: wish I could remember -- document me.
74 */
75 acomponent* allocate_chicken();
76 /**
77 * @todo TODO: wish I could remember -- document me.
78 */
79 void allocate_chicken(acomponent *ac);
80 /**
81 * @todo TODO: wish I could remember -- document me.
82 */
83 void deallocate_chicken(acomponent *ac);
84 };
85
86 /**
87 * The component instance container.
88 */
89 class so_component {
90 public:
91 /**
92 * Pointer to the component 'class'.
93 */
94 component_so *hen;
95 /**
96 * The instance in question.
97 */
98 acomponent* ac;
99
100 so_component()
101 : hen(0), ac(0) { }
102 /**
103 * @param h the 'class' object.
104 * @param scif pointer to the interface to the site-C-ing core.
105 */
106 so_component(component_so *h,sitecing_interface *scif);
107 /**
108 * Copy constructor
109 * @param s source instance.
110 */
111 so_component(const so_component& s)
112 : hen(0), ac(0) { attach(s); }
113 ~so_component() { detach(); }
114
115 /**
116 * Assignment operator.
117 * @param s source instance.
118 */
119 so_component& operator=(const so_component& s) {
120 attach(s); return *this;
121 }
122
123 /**
124 * @todo TODO: wish I could remember the details -- document me.
125 * @param h the 'class' object.
126 * @param a the instance to be attached.
127 */
128 void attach(component_so *h,acomponent *a);
129 /**
130 * @todo TODO: wish I could remember the details -- document me.
131 * @param s the source instance.
132 */
133 void attach(const so_component& s) { attach(s.hen,s.ac); }
134 /**
135 * @todo TODO: wish I could remember the details -- document me.
136 */
137 void detach();
138 };
139
140 /**
141 * The typed component instance container template.
142 * @param CT the component class.
143 */
144 template<typename CT>
145 class so_component_t : public sitecing::so_component {
146 public:
147 /**
148 * @param s The untyped instance container.
149 */
150 so_component_t(const so_component& s)
151 : so_component(s) { }
152 CT* operator->() {
153 return static_cast<CT*>(ac->__the_most_derived_this());
154 }
155 };
156
157}
158
159#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 @@
1#ifndef __SITECING_CONFIGURATION_H
2#define __SITECING_CONFIGURATION_H
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <string>
7#include <list>
8#include <map>
9#include <pcre++.h>
10
11/**
12 * @file
13 * @brief Classes related to configuration.
14 */
15
16namespace sitecing {
17 using namespace std;
18
19 class configuration;
20
21 /**
22 * The config options container class.
23 */
24 class config_options {
25 public:
26 /**
27 * The flags enumeration.
28 */
29 enum _flags {
30 /**
31 * Skeleton has been specified in the context.
32 * @see skeleton
33 */
34 flag_skeleton = 0x0001,
35 /**
36 * CPPFLAGS have been specified in the context
37 * @see cpp_flags
38 */
39 flag_cpp_flags = 0x0002,
40 /**
41 * LDFLAGS have been specified in the context.
42 * @see ld_flags
43 */
44 flag_ld_flags = 0x0004,
45 /**
46 * Enforced intermediate dependencies have been specified in the
47 * context.
48 * @see internediate_deps
49 */
50 flag_intermediate_deps = 0x0008,
51 /**
52 * Enforced .so dependencies have been specified in the context.
53 * @see so_deps
54 */
55 flag_so_deps = 0x0010,
56 /**
57 * Whether components should be built specified in the context.
58 * @see build
59 */
60 flag_build = 0x0020,
61 /**
62 * Whether to track down cpp dependencies has been specified in
63 * the context.
64 * @see cpp_deps
65 */
66 flag_cpp_deps = 0x0040,
67 /**
68 * The exception handler has been specified in the context.
69 * @see exception_handler
70 */
71 flag_exception_handler = 0x0080,
72 /**
73 * Action handlers have been specified in the context.
74 * @see action_handlers
75 */
76 flag_action_handlers = 0x0100,
77 /**
78 * HTTP status handerls have been specified in the context.
79 * @see http_status_handlers
80 */
81 flag_http_status_handlers = 0x0200,
82 /**
83 * The files to be built are specified in the context.
84 * @see auto_build_files
85 */
86 flag_auto_build_files = 0x0400
87 };
88 /**
89 * The flags specifying what parts of configuration have been
90 * specified for the context.
91 */
92 int flags;
93
94 /**
95 * The skeleton for building components.
96 */
97 string skeleton;
98 /**
99 * The flags to pass to compiler.
100 */
101 list<string> cpp_flags;
102 /**
103 * The flags to pass to linker.
104 */
105 list<string> ld_flags;
106 /**
107 * Whether to build inexstent and outdated components.
108 */
109 bool build;
110 /**
111 * Whether to track cpp dependencies.
112 */
113 bool cpp_deps;
114 /**
115 * The component handling caught exceptions.
116 */
117 string exception_handler;
118 /**
119 * Enforced intermediate dependencies.
120 */
121 list<string> intermediate_deps;
122 /**
123 * Enforced depencies for .so objects.
124 */
125 list<string> so_deps;
126 /**
127 * The action handler type.
128 */
129 struct action_handler_t {
130 /**
131 * The regexp to check request against.
132 */
133 string s_regex;
134 /**
135 * Precompiled regex.
136 */
137 pcrepp::Pcre regex;
138 /**
139 * The action handler component.
140 */
141 string action;
142 /**
143 * Arguments for the action hander coponent.
144 */
145 list<string> args;
146
147 action_handler_t(const string& s,const string& a)
148 : s_regex(s), regex(s), action(a) { }
149 action_handler_t(const action_handler_t& s)
150 : s_regex(s.s_regex), regex(s.regex), action (s.action), args(s.args) { }
151 };
152 /**
153 * Type for the list of action handlers.
154 */
155 typedef list<action_handler_t> action_handlers_t;
156 /**
157 * The list of action handlers.
158 */
159 action_handlers_t action_handlers;
160 /**
161 * Type for the map of HTTP status handler components.
162 */
163 typedef map<string,string> http_status_handlers_t;
164 /**
165 * The map of HTTP status handler components.
166 */
167 http_status_handlers_t http_status_handlers;
168 /**
169 * Files to be built automatically.
170 */
171 list<string> auto_build_files;
172
173 config_options()
174 : flags(0) { }
175
176 /**
177 * Look up if there is an action handler for the target defined.
178 * @param target the target component.
179 * @return the pointer to handler or zero.
180 */
181 action_handler_t *lookup_action_handler(const string& target);
182 /**
183 * Look up if there is a handler defined for the HTTP status.
184 * @param status HTTP status
185 * @return the handler component.
186 */
187 string lookup_http_status_handler(const string& status);
188 /**
189 * Check whether the file should be build automatically.
190 * @param fn file name.
191 * @param rv reference to the boolean where the answer should go.
192 * @return true if we know the answer.
193 */
194 bool match_autobuild_files(const char *fn,bool &rv);
195 };
196
197 /**
198 * Configuration data container for the configuration loaded from disk file.
199 */
200 class loaded_options : public config_options {
201 public:
202 /**
203 * The file where configuration originates from.
204 */
205 string source_file;
206 /**
207 * The stat structure for the source file as it was when we have
208 * loaded it.
209 */
210 struct stat st;
211
212 /**
213 * See if the data is still valid.
214 * @return true if yes.
215 */
216 bool is_valid();
217
218 /**
219 * Load the configuration file.
220 * @param config the main configuration container.
221 * @param the configuration file.
222 */
223 void parse(configuration *config,const string& cfile);
224 };
225
226 /**
227 * The main configuration container.
228 */
229 class configuration {
230 public:
231 /**
232 * @todo TODO:: document me.
233 */
234 bool autobuild;
235 /**
236 * The flags enumeration.
237 */
238 enum _flags {
239 /**
240 * Was the source root specified?
241 * @see root_source
242 */
243 flag_root_source = 0x00000001,
244 /**
245 * Was the root for intermediate files specified?
246 * @see root_intermediate
247 */
248 flag_root_intermediate = 0x00000002,
249 /**
250 * Was the root for the resulting .so files specified?
251 * @see root_so
252 */
253 flag_root_so = 0x00000004,
254 /**
255 * Was the socket to listen to specified?
256 * @see listen_socket
257 */
258 flag_listen_socket = 0x00000008,
259 /**
260 * Was the per-dir config file name specified.
261 * @see rc_file_name
262 */
263 flag_rc_file_name = 0x00000010,
264 /**
265 * Was the minimum number of child processes specified?
266 * @see min_children
267 */
268 flag_min_children = 0x00000020,
269 /**
270 * Was the maximum number of child processes specified?
271 * @see max_children
272 */
273 flag_max_children = 0x00000040,
274 /**
275 * Was the minimum number of spare child processes specified?
276 * @see min_spare_children
277 */
278 flag_min_spare_children = 0x00000080,
279 /**
280 * Was he maximum number of spare child processes specified?
281 * @see max_spare_children
282 */
283 flag_max_spare_children = 0x00000100,
284 /**
285 * Was the number of requests to handle per child process
286 * specified?
287 * @see requests_per_child
288 */
289 flag_requests_per_child = 0x00000200,
290 /**
291 * Was the multiprocess node (or it's absences) specified?
292 * @see multi_process
293 */
294 flag_multi_process = 0x00000400,
295 /**
296 * Was the user specified?
297 * @see user
298 */
299 flag_user = 0x00000800,
300 /**
301 * @Was the group specified?
302 * @see group
303 */
304 flag_group = 0x00001000,
305 /**
306 * Was the root to change to specified?
307 * @see chroot
308 */
309 flag_chroot = 0x00002000,
310 /**
311 * Was the file for storing PID specified?
312 * @see pidfile
313 */
314 flag_pid_file = 0x00004000,
315 /**
316 * Was it specified wether we should daemonize the process?
317 * @see daemonize
318 */
319 flag_daemonize = 0x00008000
320 };
321 /**
322 * The flags specifying what parts of the configuration has been
323 * loaded into the object.
324 */
325 long flags;
326
327 /**
328 * The root for the components source code.
329 */
330 string root_source;
331 /**
332 * The root for intermediate files.
333 */
334 string root_intermediate;
335 /**
336 * The root for .so files.
337 */
338 string root_so;
339 /**
340 * Socket to bind to
341 */
342 string listen_socket;
343 /**
344 * per-dir config file name.
345 */
346 string rc_file_name;
347 /**
348 * The minimum number of child processes in multiprocess mode.
349 */
350 int min_children;
351 /**
352 * The maxium number of child processes in multiprocess mode.
353 */
354 int max_children;
355 /**
356 * The minimum number of spare chidren in multiprocess mode.
357 */
358 int min_spare_children;
359 /**
360 * The maximum number of spare children in multiprocess mode.
361 */
362 int max_spare_children;
363 /**
364 * The number of requests the child process should handle before
365 * exiting.
366 */
367 int requests_per_child;
368 /**
369 * Whether we should run in multiprocess mode or not.
370 */
371 bool multi_process;
372 /**
373 * User to change to.
374 */
375 string user;
376 /**
377 * Group to set to.
378 */
379 string group;
380 /**
381 * Directory to change root to.
382 */
383 string chroot;
384 /**
385 * The file to store PID into.
386 */
387 string pid_file;
388 /**
389 * Whether we should fork into background.
390 */
391 bool daemonize;
392
393 typedef map<string,config_options> specs_t;
394 /**
395 * The local config options map.
396 */
397 specs_t specs;
398 typedef map<string,loaded_options> loaded_specs_t;
399 /**
400 * The local config options as specified in per-dir config files
401 * map.
402 */
403 loaded_specs_t loaded_specs;
404
405 configuration();
406 /**
407 * @param cfile the configuration file.
408 * @param ab @todo TODO:: document me
409 */
410 configuration(const string& cfile,bool ab=false);
411
412 /**
413 * Parse the configuration file.
414 * @param cfile the configuration file.
415 */
416 void parse(const string& cfile);
417
418 /**
419 * Fetch the reference to options for the very root.
420 */
421 config_options& root_options() { return specs[""]; }
422 /**
423 * Lookup where the certain config option for the target lies in.
424 * @param target the target component.
425 * @param flag the flag specifying the option we're looking for.
426 * @return the destination options continer or zero.
427 */
428 config_options* lookup_config(const string& target,int flag);
429 /**
430 * Lookup the action handler for the target.
431 * @param target the target request.
432 * @return the action handler or zero.
433 */
434 config_options::action_handler_t *lookup_action_handler(const string& target);
435 /**
436 * Lookup the HTPP status handler for the target.
437 * @param target the target.
438 * @param status the HTTP status.
439 * @return the handler component.
440 */
441 string lookup_http_status_handler(const string& target,const string& status);
442 /**
443 * Lookup the options loaded from per-dir config for the target
444 * @param target the target.
445 * @return options container or zero.
446 */
447 loaded_options* lookup_loaded_options(const string& target);
448 /**
449 * Check whether the components for the target should be prebuilt.
450 * @param target the target.
451 * @param fn file name.
452 * @return true if yes.
453 */
454 bool match_autobuild_files(const string& target,const char *fn);
455 };
456
457}
458
459#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 @@
1#ifndef __SITECING_EXCEPTION_H
2#define __SITECING_EXCEPTION_H
3
4/**
5 * @file
6 * @brief The site-C-ing specific exceptions.
7 */
8
9/**
10 * @brief The main site-C-ing namespace.
11 */
12namespace sitecing {
13
14 // TODO: status specifics
15
16 /**
17 * The http status to return.
18 */
19 class http_status {
20 public:
21 /**
22 * The status string.
23 */
24 string status;
25 /**
26 * The message to follow the status string.
27 */
28 string message;
29
30 /**
31 * @param s HTTP status.
32 * @param m HTTP status message.
33 */
34 http_status(const string& s,const string& m)
35 : status(s), message(m) { }
36 virtual ~http_status() throw() { }
37 };
38
39 // per RFC 2616
40
41 /**
42 * Informational.
43 */
44 class http_status_1xx : public http_status {
45 public:
46 explicit http_status_1xx(const string &s,const string& m)
47 : http_status(s,m) { }
48 };
49 /**
50 * Continue.
51 */
52 class http_status_100 : public http_status_1xx {
53 public:
54 explicit http_status_100(const string& m)
55 : http_status_1xx("100",m) { }
56 explicit http_status_100()
57 : http_status_1xx("100","Continue") { }
58 };
59 /**
60 * Switching protocols.
61 */
62 class http_status_101 : public http_status_1xx {
63 public:
64 explicit http_status_101(const string& m)
65 : http_status_1xx("101",m) { }
66 explicit http_status_101()
67 : http_status_1xx("101","Switching protocols") { }
68 };
69
70 /**
71 * Successful.
72 */
73 class http_status_2xx : public http_status {
74 public:
75 explicit http_status_2xx(const string& s,const string& m)
76 : http_status(s,m) { }
77 };
78 /**
79 * OK.
80 */
81 class http_status_200 : public http_status_2xx {
82 public:
83 explicit http_status_200(const string& m)
84 : http_status_2xx("200",m) { }
85 explicit http_status_200()
86 : http_status_2xx("200","OK") { }
87 };
88 /**
89 * Created.
90 */
91 class http_status_201 : public http_status_2xx {
92 public:
93 explicit http_status_201(const string& m)
94 : http_status_2xx("201",m) { }
95 explicit http_status_201()
96 : http_status_2xx("201","Created") { }
97 };
98 /**
99 * Accepted.
100 */
101 class http_status_202 : public http_status_2xx {
102 public:
103 explicit http_status_202(const string& m)
104 : http_status_2xx("202",m) { }
105 explicit http_status_202()
106 : http_status_2xx("202","Accepted") { }
107 };
108 /**
109 * Non-authoritative infortmation.
110 */
111 class http_status_203 : public http_status_2xx {
112 public:
113 explicit http_status_203(const string& m)
114 : http_status_2xx("203",m) { }
115 explicit http_status_203()
116 : http_status_2xx("203","Non-authoritative information") { }
117 };
118 /**
119 * No content.
120 */
121 class http_status_204 : public http_status_2xx {
122 public:
123 explicit http_status_204(const string& m)
124 : http_status_2xx("204",m) { }
125 explicit http_status_204()
126 : http_status_2xx("204","No content") { }
127 };
128 /**
129 * Reset content.
130 */
131 class http_status_205 : public http_status_2xx {
132 public:
133 explicit http_status_205(const string& m)
134 : http_status_2xx("205",m) { }
135 explicit http_status_205()
136 : http_status_2xx("205","Reset content") { }
137 };
138 /**
139 * Partial content.
140 */
141 class http_status_206 : public http_status_2xx {
142 public:
143 explicit http_status_206(const string& m)
144 : http_status_2xx("206",m) { }
145 explicit http_status_206()
146 : http_status_2xx("206","Partial content") { }
147 };
148
149 /**
150 * Redirection.
151 */
152 class http_status_3xx : public http_status {
153 public:
154 explicit http_status_3xx(const string& s,const string& m)
155 : http_status(s,m) { }
156 };
157 /**
158 * Multiple choices.
159 */
160 class http_status_300 : public http_status_3xx {
161 public:
162 explicit http_status_300(const string& m)
163 : http_status_3xx("300",m) { }
164 explicit http_status_300()
165 : http_status_3xx("300","Multiple choices") { }
166 };
167 /**
168 * Moved permanently.
169 */
170 class http_status_301 : public http_status_3xx {
171 public:
172 explicit http_status_301(const string& m)
173 : http_status_3xx("301",m) { }
174 explicit http_status_301()
175 : http_status_3xx("301","Moved permanently") { }
176 };
177 /**
178 * Found.
179 */
180 class http_status_302 : public http_status_3xx {
181 public:
182 explicit http_status_302(const string& m)
183 : http_status_3xx("302",m) { }
184 explicit http_status_302()
185 : http_status_3xx("302","Found") { }
186 };
187 /**
188 * See other.
189 */
190 class http_status_303 : public http_status_3xx {
191 public:
192 explicit http_status_303(const string& m)
193 : http_status_3xx("303",m) { }
194 explicit http_status_303()
195 : http_status_3xx("303","See other") { }
196 };
197 /**
198 * Not modified.
199 */
200 class http_status_304 : public http_status_3xx {
201 public:
202 explicit http_status_304(const string& m)
203 : http_status_3xx("304",m) { }
204 explicit http_status_304()
205 : http_status_3xx("304","Not modified") { }
206 };
207 /**
208 * Use proxy.
209 */
210 class http_status_305 : public http_status_3xx {
211 public:
212 explicit http_status_305(const string& m)
213 : http_status_3xx("305",m) { }
214 explicit http_status_305()
215 : http_status_3xx("305","Use proxy") { }
216 };
217 // 306 is unused and reserved
218 /**
219 * Temporary redirect.
220 */
221 class http_status_307 : public http_status_3xx {
222 public:
223 explicit http_status_307(const string& m)
224 : http_status_3xx("307",m) { }
225 explicit http_status_307()
226 : http_status_3xx("307","Temporary redirect") { }
227 };
228
229 /**
230 * Error.
231 */
232 class http_status_4xx : public http_status {
233 public:
234 explicit http_status_4xx(const string& s,const string& m)
235 : http_status(s,m) { }
236 };
237 /**
238 * Bad request.
239 */
240 class http_status_400 : public http_status_4xx {
241 public:
242 explicit http_status_400(const string& m)
243 : http_status_4xx("400",m) { }
244 explicit http_status_400()
245 : http_status_4xx("400","Bad request") { }
246 };
247 /**
248 * Unauthorized.
249 */
250 class http_status_401 : public http_status_4xx {
251 public:
252 explicit http_status_401(const string& m)
253 : http_status_4xx("401",m) { }
254 explicit http_status_401()
255 : http_status_4xx("401","Unauthorized") { }
256 };
257 /**
258 * Payment required.
259 */
260 class http_status_402 : public http_status_4xx {
261 public:
262 explicit http_status_402(const string& m)
263 : http_status_4xx("402",m) { }
264 explicit http_status_402()
265 : http_status_4xx("402","Payment required") { }
266 };
267 /**
268 * Forbidden.
269 */
270 class http_status_403 : public http_status_4xx {
271 public:
272 explicit http_status_403(const string& m)
273 : http_status_4xx("403",m) { }
274 explicit http_status_403()
275 : http_status_4xx("403","Forbidden") { }
276 };
277 /**
278 * Not found.
279 */
280 class http_status_404 : public http_status_4xx {
281 public:
282 explicit http_status_404(const string& m)
283 : http_status_4xx("404",m) { }
284 explicit http_status_404()
285 : http_status_4xx("404","Not found") { }
286 };
287 /**
288 * Method not allowed.
289 */
290 class http_status_405 : public http_status_4xx {
291 public:
292 explicit http_status_405(const string& m)
293 : http_status_4xx("405",m) { }
294 explicit http_status_405()
295 : http_status_4xx("405","Method not allowed") { }
296 };
297 /**
298 * Not acceptable.
299 */
300 class http_status_406 : public http_status_4xx {
301 public:
302 explicit http_status_406(const string& m)
303 : http_status_4xx("406",m) { }
304 explicit http_status_406()
305 : http_status_4xx("406","Not acceptable") { }
306 };
307 /**
308 * Proxy authentication required.
309 */
310 class http_status_407 : public http_status_4xx {
311 public:
312 explicit http_status_407(const string& m)
313 : http_status_4xx("407",m) { }
314 explicit http_status_407()
315 : http_status_4xx("407","Proxy authentication required") { }
316 };
317 /**
318 * Request timeout.
319 */
320 class http_status_408 : public http_status_4xx {
321 public:
322 explicit http_status_408(const string& m)
323 : http_status_4xx("408",m) { }
324 explicit http_status_408()
325 : http_status_4xx("408","Request timeout") { }
326 };
327 /**
328 * Conflict.
329 */
330 class http_status_409 : public http_status_4xx {
331 public:
332 explicit http_status_409(const string& m)
333 : http_status_4xx("409",m) { }
334 explicit http_status_409()
335 : http_status_4xx("409","Conflict") { }
336 };
337 /**
338 * Gone.
339 */
340 class http_status_410 : public http_status_4xx {
341 public:
342 explicit http_status_410(const string& m)
343 : http_status_4xx("410",m) { }
344 explicit http_status_410()
345 : http_status_4xx("410","Gone") { }
346 };
347 /**
348 * Length required.
349 */
350 class http_status_411 : public http_status_4xx {
351 public:
352 explicit http_status_411(const string& m)
353 : http_status_4xx("411",m) { }
354 explicit http_status_411()
355 : http_status_4xx("411","Length required") { }
356 };
357 /**
358 * Precondition failed.
359 */
360 class http_status_412 : public http_status_4xx {
361 public:
362 explicit http_status_412(const string& m)
363 : http_status_4xx("412",m) { }
364 explicit http_status_412()
365 : http_status_4xx("412","Precondition failed") { }
366 };
367 /**
368 * Request entity too large.
369 */
370 class http_status_413 : public http_status_4xx {
371 public:
372 explicit http_status_413(const string& m)
373 : http_status_4xx("413",m) { }
374 explicit http_status_413()
375 : http_status_4xx("413","Request entity too large") { }
376 };
377 /**
378 * Request URI too long.
379 */
380 class http_status_414 : public http_status_4xx {
381 public:
382 explicit http_status_414(const string& m)
383 : http_status_4xx("414",m) { }
384 explicit http_status_414()
385 : http_status_4xx("414","Request URI too long") { }
386 };
387 /**
388 * Unsupported media type.
389 */
390 class http_status_415 : public http_status_4xx {
391 public:
392 explicit http_status_415(const string& m)
393 : http_status_4xx("415",m) { }
394 explicit http_status_415()
395 : http_status_4xx("415","Unsupported media type") { }
396 };
397 /**
398 * Requested range not satisfiable.
399 */
400 class http_status_416 : public http_status_4xx {
401 public:
402 explicit http_status_416(const string& m)
403 : http_status_4xx("416",m) { }
404 explicit http_status_416()
405 : http_status_4xx("416","Requested range not satisfiable") { }
406 };
407 /**
408 * Expectation failed.
409 */
410 class http_status_417 : public http_status_4xx {
411 public:
412 explicit http_status_417(const string& m)
413 : http_status_4xx("417",m) { }
414 explicit http_status_417()
415 : http_status_4xx("417","Expectation failed") { }
416 };
417
418 /**
419 * Server error.
420 */
421 class http_status_5xx : public http_status {
422 public:
423 explicit http_status_5xx(const string& s,const string& m)
424 : http_status(s,m) { }
425 };
426 /**
427 * Internal server error.
428 */
429 class http_status_500 : public http_status_5xx {
430 public:
431 explicit http_status_500(const string& m)
432 : http_status_5xx("500",m) { }
433 explicit http_status_500()
434 : http_status_5xx("500","Internal server error") { }
435 };
436 /**
437 * Not implemented.
438 */
439 class http_status_501 : public http_status_5xx {
440 public:
441 explicit http_status_501(const string& m)
442 : http_status_5xx("501",m) { }
443 explicit http_status_501()
444 : http_status_5xx("501","Not implemented") { }
445 };
446 /**
447 * Bad gateway.
448 */
449 class http_status_502 : public http_status_5xx {
450 public:
451 explicit http_status_502(const string& m)
452 : http_status_5xx("502",m) { }
453 explicit http_status_502()
454 : http_status_5xx("502","Bad gateway") { }
455 };
456 /**
457 * Service unavailable.
458 */
459 class http_status_503 : public http_status_5xx {
460 public:
461 explicit http_status_503(const string& m)
462 : http_status_5xx("503",m) { }
463 explicit http_status_503()
464 : http_status_5xx("503","Service unavailable") { }
465 };
466 /**
467 * Gateway timeout.
468 */
469 class http_status_504 : public http_status_5xx {
470 public:
471 explicit http_status_504(const string& m)
472 : http_status_5xx("504",m) { }
473 explicit http_status_504()
474 : http_status_5xx("504","Gateway timeout") { }
475 };
476 /**
477 * HTTP version not supported.
478 */
479 class http_status_505 : public http_status_5xx {
480 public:
481 explicit http_status_505(const string& m)
482 : http_status_5xx("505",m) { }
483 explicit http_status_505()
484 : http_status_5xx("505","HTTP version not supported") { }
485 };
486
487 // Aliases
488
489 typedef http_status_1xx http_status_informational;
490 typedef http_status_100 http_status_continue;
491 typedef http_status_101 http_status_switching_protocols;
492
493 typedef http_status_2xx http_status_sucessful;
494 typedef http_status_200 http_status_ok;
495 typedef http_status_201 http_status_created;
496 typedef http_status_202 http_status_accepted;
497 typedef http_status_203 http_status_non_authoritative_information;
498 typedef http_status_204 http_status_no_content;
499 typedef http_status_205 http_status_reset_content;
500 typedef http_status_206 http_status_partial_content;
501
502 typedef http_status_3xx http_status_redirection;
503 typedef http_status_300 http_status_multiple_choices;
504 typedef http_status_301 http_status_moved_permanently;
505 typedef http_status_302 http_status_found;
506 typedef http_status_303 http_status_see_other;
507 typedef http_status_304 http_status_not_modified;
508 typedef http_status_305 http_status_use_proxy;
509 // 306 is unused and reserved
510 typedef http_status_307 http_status_temporary_redirect;
511
512 typedef http_status_4xx http_status_client_error;
513 typedef http_status_400 http_status_bad_request;
514 typedef http_status_401 http_status_unauthorized;
515 typedef http_status_402 http_status_payment_required;
516 typedef http_status_403 http_status_forbidden;
517 typedef http_status_404 http_status_not_found;
518 typedef http_status_405 http_status_method_not_allowed;
519 typedef http_status_406 http_status_not_acceptable;
520 typedef http_status_407 http_status_proxy_authentication_required;
521 typedef http_status_408 http_status_request_timeout;
522 typedef http_status_409 http_status_conflict;
523 typedef http_status_410 http_status_gone;
524 typedef http_status_411 http_status_length_required;
525 typedef http_status_412 http_status_precondition_failed;
526 typedef http_status_413 http_status_request_entity_too_large;
527 typedef http_status_414 http_status_requrest_uri_too_long;
528 typedef http_status_415 http_status_unsupported_media_type;
529 typedef http_status_416 http_status_required_range_not_satisfiable;
530 typedef http_status_417 http_status_expectation_failed;
531
532 typedef http_status_5xx http_status_server_error;
533 typedef http_status_500 http_status_internal_server_error;
534 typedef http_status_501 http_status_not_implemented;
535 typedef http_status_502 http_status_bad_gateway;
536 typedef http_status_503 http_status_service_unavailable;
537 typedef http_status_504 http_status_gateway_timeout;
538 typedef http_status_505 http_status_http_version_not_supported;
539
540}
541
542#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 @@
1#ifndef __SITECING_FILE_FACTORY_H
2#define __SITECING_FILE_FACTORY_H
3
4#include <string>
5#include <list>
6
7/**
8 * @file
9 * @brief the file_factory class declaration.
10 */
11
12namespace sitecing {
13 using namespace std;
14
15 /**
16 * The factory class. Does the job similar to that which is done by make
17 * utility.
18 */
19 class file_factory {
20 public:
21 /**
22 * The recursion depth.
23 */
24 int depth;
25 /**
26 * The list of files type. The list of strings, in fact.
27 */
28 typedef list<string> file_list_t;
29
30 file_factory()
31 : depth(0) { }
32
33 /**
34 * Fetch depndencies for the given file.
35 * @param dst destination file.
36 * @param deps where to put dependencies to.
37 */
38 virtual void get_dependencies(const string& dst,file_list_t& deps) = 0;
39 /**
40 * Check if the destination is up to day.
41 * @param the destination file.
42 * @param deps if the deps pointer is non there, the dependencies
43 * retrieved will be stored there.
44 * @return true if yes.
45 * @see get_dependencies()
46 */
47 virtual bool is_uptodate(const string& dst,file_list_t* deps=0);
48 /**
49 * Build the file requested.
50 * @param dst the file requested.
51 */
52 virtual void build(const string& dst) = 0;
53 /**
54 * Make the file requested, which means: build it, unless it's
55 * uptodate.
56 * @see is_uptodate()
57 * @see build()
58 */
59 virtual void make(const string& dst);
60 };
61
62}
63
64#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 @@
1 #ifndef__SITECING_MAGIC_H
2#define __SITECING_MAGIC_H
3
4/**
5 * @file
6 * @brief The magic numbers globally defined.
7 */
8
9namespace sitecing {
10
11 /**
12 * The magic numbers enumeration.
13 */
14 enum {
15 /**
16 * There is no magic.
17 */
18 __magic_none = 0,
19 /**
20 * Here is where user-defined magic starts.
21 */
22 __user_magical_numbers_start = 1,
23 /**
24 * Here is where site-C-ing defined magic starts.
25 */
26 __sitecing_magical_numbers_start = 0x8000,
27 /**
28 * The compiler error occured. The parameters passed are:
29 *
30 * char *message, char *root_source, char *root_intermediate, char *root_so, char *component
31 */
32 __magic_compile_error,
33 /**
34 * The preprocessor error occured. The parameters passed are:
35 *
36 * char *message, char *root_source, char *root_intermediate, char *root_so, char *component,
37 * int line_number
38 */
39 __magic_preprocess_error,
40 /**
41 * Exception caught while executing the component. The parameters passed are:
42 *
43 * char *message, char *root_source, char *root_intermediate, char *root_so, char *component,
44 * const exception *exception_caught
45 */
46 __magic_generic_exception,
47 /**
48 * The component called as an action handler. The parameters passed are:
49 *
50 * char *root_source, char *root_intermediate, char *root_so, list<string>* args
51 */
52 __magic_action,
53 /**
54 * The component called as an HTTP status handler. The parameters passed are:
55 *
56 * char *root_source, char *root_intermediate, char *root_so, char *component,
57 * const http_status *http_status_caught
58 */
59 __magic_http_status
60 };
61}
62
63#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 @@
1#ifndef __SITECING_PROCESS_MANAGER_H
2#define __SITECING_PROCESS_MANAGER_H
3
4#include <sitecing/scoreboard.h>
5
6/**
7 * @file
8 * @brief the process manager.
9 */
10
11namespace sitecing {
12
13 /**
14 * The process manager.
15 */
16 class process_manager {
17 public:
18 /**
19 * Minimum number of child processes.
20 */
21 int min_children;
22 /**
23 * Maxinum number of child processes.
24 */
25 int max_children;
26 /**
27 * Minimum number of spare child processes.
28 */
29 int min_spare_children;
30 /**
31 * Maxiumum number of spare child processes.
32 */
33 int max_spare_children;
34 /**
35 * The scoreboard.
36 */
37 scoreboard sboard;
38 /**
39 * We're in the process of shutting down.
40 */
41 bool finishing;
42 /**
43 * @todo TODO: wish I could rememer -- document me.
44 */
45 bool die_humbly;
46
47 process_manager();
48 virtual ~process_manager();
49
50 /**
51 * The main loop.
52 */
53 void manage();
54
55 /**
56 * The worker function.
57 * @param the slot allocated for the process.
58 */
59 virtual void process(int slot) = 0;
60
61 /**
62 * @todo TODO: wish I could remember -- document me.
63 */
64 void manage_children();
65 /**
66 * @todo TODO: wish I could remember -- document me.
67 */
68 bool spawn_children();
69 /**
70 * @todo TODO: wish I could remember -- document me.
71 */
72 bool kill_children();
73 /**
74 * @todo TODO: wish I could remember -- document me.
75 */
76 void spawn_child();
77 /**
78 * @todo TODO: wish I could remember -- document me.
79 */
80 void wait_for_children(bool hang=false);
81 /**
82 * @todo TODO: wish I could remember -- document me.
83 */
84 void collect_dead_souls(bool actively=false);
85 };
86
87}
88
89#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 @@
1#ifndef __SITECING_SCOREBOARD_H
2#define __SITECING_SCOREBOARD_H
3
4#include <sys/types.h>
5
6/**
7 * @file
8 * @brief the scoreboard manager.
9 */
10
11/**
12 * @def MAX_SITECING_SCOREBOARD_SLOTS
13 * The maximum number of slots scoreboard can hold.
14 */
15 #define MAX_SITECING_SCOREBOARD_SLOTS512
16
17namespace sitecing {
18
19 /**
20 * The scoreboard slot.
21 */
22 struct scoreboard_slot {
23 /**
24 * The state enumeration.
25 */
26 enum _state {
27 /**
28 * The slot is free.
29 */
30 state_free = 0,
31 /**
32 * The slot is allocated.
33 */
34 state_allocated,
35 /**
36 * The process is idle.
37 */
38 state_idle,
39 /**
40 * The process is accepting connection.
41 */
42 state_accept,
43 /**
44 * The process is processing request.
45 */
46 state_processing
47 } state;
48 pid_t pid;
49 };
50
51 /**
52 * The scoreboard manager.
53 */
54 class scoreboard {
55 /**
56 * shared memory id.
57 */
58 int shmid;
59 public:
60 /**
61 * Pointer to the scoreboard slots.
62 */
63 scoreboard_slot *slots;
64
65 scoreboard();
66 ~scoreboard();
67
68 /**
69 * Allocate a scoreboard slot.
70 * @return the slot number.
71 */
72 int allocate_slot();
73 /**
74 * Free the slot allocated.
75 * @param slot the slot number.
76 */
77 void free_slot(int slot);
78
79 /**
80 * Get the pointer to the slot.
81 * @param slot the slot number.
82 * @return the pointer.
83 */
84 scoreboard_slot *get_slot(int slot);
85 /**
86 * Find the slot corresponding to the process ID.
87 * @param pid the process id.
88 * @return the slot number.
89 */
90 int get_slot_by_pid(pid_t pid);
91
92 /**
93 * Count the slots in the particular state.
94 * @param state the state.
95 * @return the number of slots found.
96 */
97 int count_slots(enum scoreboard_slot::_state state=scoreboard_slot::state_free);
98 };
99
100}
101
102#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 @@
1#ifndef __SITECING_SITECING_ENFLESHER_H
2#define __SITECING_SITECING_ENFLESHER_H
3
4#include <fstream>
5#include <string>
6using namespace std;
7
8/**
9 * @file
10 * @brief The preprocessed source builder.
11 */
12
13#ifndef sitecing_enflesher_flexlexer_once
14#define sitecing_enflesher_flexlexer_once
15#undef yyFlexLexer
16#define yyFlexLexer sitecing_enflesherFlexLexer
17#include <FlexLexer.h>
18#undef yyFlexLexerOnce
19#endif
20
21class sitecing_parser;
22/**
23 * The enfleshing of the skeleton file according to the in-memory parsed
24 * component source.
25 */
26class sitecing_enflesher : public sitecing_enflesherFlexLexer {
27 public:
28 /**
29 * It is time to anchor output with the #line directive.
30 */
31 bool anchor_time;
32 /**
33 * @todo TODO: wish I could remember -- document me.
34 */
35 bool anchoraged;
36 /**
37 * The reference to the parser object containg the parsed source.
38 */
39 sitecing_parser& parser;
40 /**
41 * The output stream.
42 */
43 ofstream outs;
44
45 /**
46 * @param p The parser object containing preparsed data.
47 */
48 sitecing_enflesher(sitecing_parser& p)
49 : parser(p), anchor_time(true) { }
50
51 /**
52 * Do the job.
53 */
54 void enflesh();
55
56 virtual void LexerOutput(const char *buf,int size);
57 virtual int yylex();
58
59 /**
60 * Put a #line anchor into output.
61 */
62 void anchor();
63};
64
65#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 @@
1#ifndef __SITECING_SITECING_EXCEPTION_H
2#define __SITECING_SITECING_EXCEPTION_H
3
4#include <konforka/exception.h>
5
6/**
7 * @file
8 * @brief The site-C-ing specific exception.
9 */
10
11namespace sitecing {
12
13 /**
14 * The component failed to compile.
15 */
16 class compile_error : public konforka::exception {
17 public:
18 /**
19 * The component path
20 */
21 string component_path;
22
23 /**
24 * @param w the message.
25 * @param cp component path.
26 */
27 compile_error(const string& w,const string& cp)
28 : konforka::exception(NOCODEPOINT,w), component_path(cp) { }
29 /**
30 * @param whe point in code.
31 * @param wha the message.
32 * @param cp component path.
33 */
34 compile_error(const string &whe,const string& wha,const string& cp)
35 : konforka::exception(whe,wha), component_path(cp) { }
36 /**
37 * @param fi the file name where the exception is thrown from.
38 * @param fu the function name where the exception originates from.
39 * @param l the line number where the exception originates from.
40 * @param cp component path.
41 */
42 compile_error(const string &fi,const string& fu,int l,const string& w,const string& cp)
43 : konforka::exception(fi,fu,l,w), component_path(cp) { }
44 ~compile_error() throw() { }
45 };
46
47 /**
48 * Failed to preprocess component source.
49 */
50 class preprocessor_error : public konforka::exception {
51 public:
52 /**
53 * Component name.
54 */
55 string component_name;
56 /**
57 * The line number of the source code where the error occured.
58 */
59 int line_number;
60
61 /**
62 * @param fi file name where the exception originates from.
63 * @param fu the function name where the exception originates from.
64 * @param l the line number where the exception originate from.
65 * @param w the error message.
66 * @param cn the component name.
67 * @param ln the line of the component source where the error occured.
68 */
69 preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn,int ln)
70 : konforka::exception(fi,fu,l,w), component_name(cn), line_number(ln) { }
71 /**
72 * @param fi file name where the exception originates from.
73 * @param fu the function name where the exception originates from.
74 * @param l the line number where the exception originate from.
75 * @param w the error message.
76 * @param cn the component name.
77 */
78 preprocessor_error(const string& fi,const string& fu,int l,const string& w,const string& cn)
79 : konforka::exception(fi,fu,l,w), component_name(cn), line_number(-1) { }
80 /**
81 * @param fi file name where the exception originates from.
82 * @param fu the function name where the exception originates from.
83 * @param l the line number where the exception originate from.
84 * @param w the error message.
85 * @param ln the line of the component source where the error occured.
86 */
87 preprocessor_error(const string& fi,const string& fu,int l,const string& w,int ln)
88 : konforka::exception(fi,fu,l,w), line_number(ln) { }
89 /**
90 * @param fi file name where the exception originates from.
91 * @param fu the function name where the exception originates from.
92 * @param l the line number where the exception originate from.
93 * @param w the error message.
94 */
95 preprocessor_error(const string& fi,const string& fu,int l,const string& w)
96 : konforka::exception(fi,fu,l,w), line_number(-1) { }
97
98 ~preprocessor_error() throw() {}
99 };
100
101}
102
103#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 @@
1#ifndef __SITECING_SITECING_INTERFACE_H
2#define __SITECING_SITECING_INTERFACE_H
3
4#include <ostream>
5
6/**
7 * @file
8 * @brief The sitecing_interface call declaration.
9 */
10
11namespace sitecing {
12 using namespace std;
13
14 /**
15 * @brief the interface to site-C-ing.
16 *
17 * The basic class used to convey communications between the component and
18 * the sitecing core.
19 */
20 class sitecing_interface {
21 public:
22 /**
23 * Pointer to the output stream.
24 */
25 ostream *out;
26
27 /**
28 * The default constructor doesn't do much.
29 */
30 sitecing_interface() : out(0) {}
31 /**
32 * The constructor initializes the output stream pointer.
33 * @param o the value to initialize the output stream pointer with.
34 */
35 sitecing_interface(ostream* o) : out(o) {}
36 };
37
38}
39
40#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 @@
1#ifndef __SITECING_SITECING_INTERFACE_CGI_H
2#define __SITECING_SITECING_INTERFACE_CGI_H
3
4#include <sstream>
5#include <string>
6#include <map>
7#include "kingate/cgi_gateway.h"
8#include "sitecing/sitecing_interface.h"
9#include "sitecing/sitespace.h"
10
11/**
12 * @file
13 * @brief The sitecing_interface_cgi class declaration.
14 */
15
16namespace sitecing {
17 using namespace std;
18
19 /**
20 * The interface to site-C-ing core for the CGI component.
21 */
22 class sitecing_interface_cgi : public sitecing_interface {
23 public:
24 /**
25 * Pointer to the CGI gateway interface.
26 */
27 kingate::cgi_gateway* cgigw;
28 /**
29 * Type for the map of headers to spit out.
30 */
31 typedef map<string,string> headers_t;
32 /**
33 * The list of headers to spit out.
34 */
35 headers_t headers;
36 /**
37 * Here is where we prebuffer output.
38 */
39 ostringstream prebuffer;
40 /**
41 * Pointer to the sitespace object.
42 */
43 sitespace *ss; // XXX: or does it belong to the generic interface? or should this 'generic' interface exist at all?
44
45 /**
46 * @param s Pointer to the sitespace object.
47 */
48 sitecing_interface_cgi(sitespace *s);
49
50 /**
51 * @todo TODO: wish I could remember -- document me.
52 */
53 void prepare(kingate::cgi_gateway *cg);
54 /**
55 * @todo TODO: wish I could remember -- document me.
56 */
57 void flush();
58
59 };
60}
61
62#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 @@
1#ifndef __SITECING_SITECING_PARSER_H
2#define __SITECING_SITECING_PARSER_H
3
4#include <string>
5#include <list>
6#include <map>
7#include <stdexcept>
8using namespace std;
9
10#include "sitecing/component_factory.h"
11using namespace sitecing;
12
13/**
14 * @file
15 * @brief The component source parser.
16 */
17
18#ifndef sitecing_parser_flexlexer_once
19#define sitecing_parser_flexlexer_once
20#undef yyFlexLexer
21#define yyFlexLexer sitecing_parserFlexLexer
22#include <FlexLexer.h>
23#undef yyFlexLexerOnce
24#endif
25
26/**
27 * The component source parser.
28 */
29class sitecing_parser : public sitecing_parserFlexLexer {
30 public:
31 /**
32 * The ancestor class definition.
33 */
34 class ancestor_class {
35 public:
36 /**
37 * The class name.
38 */
39 string name;
40 /**
41 * The source component path.
42 */
43 string path;
44
45 /**
46 * @param n the class name.
47 * @param p the component path.
48 */
49 ancestor_class(const string& n,const string& p)
50 : name(n), path(p) { }
51 };
52 /**
53 * The list of ancestor classes.
54 */
55 typedef list<ancestor_class> ancestor_classes_t;
56 /**
57 * The ancestor classes.
58 */
59 ancestor_classes_t ancestor_classes;
60 /**
61 * The member variable definition.
62 */
63 class member_variable {
64 public:
65 /**
66 * The member variable type.
67 */
68 string type;
69 /**
70 * The member variable name.
71 */
72 string name;
73 /**
74 * The member variable is a component.
75 */
76 bool bComponent;
77 /**
78 * The variable initializer.
79 */
80 string initializer;
81 /**
82 * @todo TODO: wish I could remember -- document me.
83 */
84 bool bTypeOnly;
85
86 /**
87 * @param t type.
88 * @param n name.
89 * @param i initializer.
90 * @param bc whether it is a component.
91 * @param bto @todo TODO: @see bTypeOnly.
92 */
93 member_variable(const string& t,const string& n,const string& i,bool bc = false,bool bto = false)
94 : type(t), name(n), initializer(i), bComponent(bc), bTypeOnly(bto) { }
95 };
96 /**
97 * The list of member variables.
98 */
99 typedef list<member_variable> member_variables_t;
100 /**
101 * Member variables.
102 */
103 member_variables_t member_variables;
104 /**
105 * @todo TODO: wish I could remember the details -- document me.
106 */
107 bool have_initializers;
108 /**
109 * Whether the component has a constructor defined.
110 */
111 bool have_constructor;
112 /**
113 * Member function definition.
114 */
115 class member_function {
116 public:
117 /**
118 * Return type.
119 */
120 string type;
121 /**
122 * Function name.
123 */
124 string name;
125 /**
126 * Arguments declaration.
127 */
128 string args;
129 /**
130 * Function body.
131 */
132 string body;
133
134 /**
135 * @param t type.
136 * @param n name.
137 * @param a arguments.
138 * @param b body.
139 */
140 member_function(const string& t,const string& n,const string& a,const string& b)
141 : type(t), name(n), args(a), body(b) { }
142 };
143 /**
144 * The list of member functions.
145 */
146 typedef list<member_function> member_functions_t;
147 /**
148 * Member functions.
149 */
150 member_functions_t member_functions;
151 /**
152 * Current mode of operation.
153 */
154 class modus_operandi {
155 public:
156 /**
157 * The state enumeration.
158 */
159 enum modus_t {
160 /**
161 * Building the code.
162 */
163 modus_code = 0,
164 /**
165 * Ready to do the '<<' thing.
166 */
167 modus_preop,
168 /**
169 * Just made a '<<'.
170 */
171 modus_postop,
172 /**
173 * Outputting raw output data.
174 */
175 modus_text,
176 /**
177 * The number of modes.
178 */
179 modi
180 };
181 /**
182 * Processing flags enumeration.
183 */
184 enum {
185 /**
186 * Eat the comments.
187 */
188 flag_devour_comments = 0x0001,
189 /**
190 * Eat whitespace.
191 */
192 flag_devour_whitespace = 0x0002
193 };
194 /**
195 * The processing mode.
196 */
197 modus_t modus;
198 /**
199 * The processing flags.
200 */
201 int flags;
202 /**
203 * Output being built.
204 */
205 string output;
206 /**
207 * The type for compound modes.
208 */
209 string _type;
210 /**
211 * The last id encountered.
212 */
213 string _lastid;
214 /**
215 * The name for compound modes.
216 */
217 string _name;
218 /**
219 * The argument declaration. Obviously for member functions.
220 */
221 string _args;
222
223 /**
224 * @param flags.
225 * @see flags
226 */
227 modus_operandi(int f = 0)
228 : modus(modus_code), flags(f) { }
229
230 /**
231 * Change the processing mode.
232 */
233 void modify(modus_t m);
234
235 /**
236 * See if we're eating up whitespaces.
237 */
238 bool devour_whitespace() { return flags&flag_devour_whitespace; }
239 /**
240 * See if we're eating up the comments.
241 */
242 bool devour_comments() { return flags&flag_devour_comments; }
243 };
244 /**
245 * The modes stack type.
246 */
247 typedef list<modus_operandi> modi_operandi;
248 /**
249 * The modes stack.
250 */
251 modi_operandi modi;
252 /**
253 * Input file name.
254 */
255 string input_file;
256 /**
257 * Base class name.
258 */
259 string base_class;
260 /**
261 * Base class header.
262 */
263 string base_header;
264 /**
265 * Component's basename.
266 * @todo TODO: wish I could remember the details -- document me.
267 */
268 string component_basename;
269 /**
270 * The skeleton file name.
271 */
272 string skeleton;
273 /**
274 * The component class name.
275 */
276 string class_name;
277 /**
278 * Output basename.
279 * @todo TODO: wish I could remember the details -- document me.
280 */
281 string output_basename;
282 /**
283 * Verbatim declaration part.
284 */
285 string decl;
286 /**
287 * Verbatim implementation part.
288 */
289 string impl;
290 /**
291 * The reference to the component factory object.
292 */
293 component_factory& factory;
294
295 /**
296 * @param f the component factory.
297 */
298 sitecing_parser(component_factory& f);
299
300 /**
301 * Preprocess file.
302 * @param in input file name.
303 */
304 void preprocess(const string& in);
305
306 virtual void LexerOutput(const char *buf,int size);
307 virtual int yylex();
308
309 /**
310 * Retrieve reference to the to of the modes stack.
311 * @return the reference in question.
312 */
313 modus_operandi& M() {
314 return modi.front();
315 }
316 /**
317 * Anchor the output with the #line, if we're not in the text output mode.
318 */
319 void soft_anchor();
320 /**
321 * Anchor the output with the #line directive, changing to the appropriate output mode if needed.
322 */
323 void anchor();
324};
325
326#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 @@
1#ifndef __SITECING_SITECING_UTIL_H
2#define __SITECING_SITECING_UTIL_H
3
4#include <sys/types.h>
5#include <string>
6#include <konforka/exception.h>
7
8/**
9 * @file
10 * @brief utility classes and functions.
11 */
12
13namespace sitecing {
14 using namespace std;
15
16 /**
17 * Base class for utility exceptions.
18 */
19 class utility_error : public konforka::exception {
20 public:
21 utility_error(const string& fi,const string& fu,int l,const string& w)
22 : konforka::exception(fi,fu,l,w) { }
23 };
24 /**
25 * Restricted sequence encountered.
26 */
27 class utility_restricted_sequence : public utility_error {
28 public:
29 utility_restricted_sequence(const string& fi,const string& fu,int l,const string& w)
30 : utility_error(fi,fu,l,w) { }
31 };
32 /**
33 * No prefix or suffix found to strip out.
34 */
35 class utility_no_affix : public utility_error {
36 public:
37 utility_no_affix(const string& fi,const string& fu,int l,const string& w)
38 : utility_error(fi,fu,l,w) { }
39 };
40 /**
41 * No prefix to strip found.
42 */
43 class utility_no_prefix : public utility_no_affix {
44 public:
45 utility_no_prefix(const string& fi,const string& fu,int l,const string& w)
46 : utility_no_affix(fi,fu,l,w) { }
47 };
48 /**
49 * No suffix to strip found.
50 */
51 class utility_no_suffix : public utility_no_affix {
52 public:
53 utility_no_suffix(const string& fi,const string& fu,int l,const string& w)
54 : utility_no_affix(fi,fu,l,w) { }
55 };
56
57 /**
58 * Went up beyond root.
59 * @todo TODO: wish I could remember the details -- document me.
60 */
61 class utility_beyond_root : public utility_error {
62 public:
63 utility_beyond_root(const string& fi,const string& fu,int l,const string& w)
64 : utility_error(fi,fu,l,w) { }
65 };
66
67 /**
68 * The file lock object. Released at the object destruction.
69 */
70 class file_lock {
71 public:
72 /**
73 * The file descriptor.
74 */
75 int fd;
76
77 file_lock()
78 : fd(-1) { }
79 /**
80 * @param f file name.
81 */
82 file_lock(const string& f)
83 : fd(-1) { lock(f); }
84 ~file_lock() { unlock(); }
85
86 /**
87 * Do lock.
88 * @param f file name.
89 */
90 void lock(const string& f);
91 /**
92 * @todo TODO: wish I could remember the details -- document me.
93 */
94 void lock();
95 /**
96 * Release the lock obtained.
97 */
98 void unlock();
99 };
100
101 /**
102 * The pid file. Removed at object destruction.
103 */
104 class pid_file {
105 public:
106 /**
107 * The file name.
108 */
109 string file_name;
110 /**
111 * Do we unlink the file after we're done?
112 */
113 bool unlink_pid;
114
115 pid_file()
116 : unlink_pid(false) { }
117 ~pid_file() { unlink(); }
118
119 /**
120 * @param f file name.
121 * @param u whether we want to unlink the file.
122 */
123 void set(const string& f,bool u=true);
124 /**
125 * Unlink the file if we wanted to in the first place.
126 */
127 void unlink();
128 };
129
130 /**
131 * The semaphore object.
132 */
133 class semaphore {
134 public:
135 /**
136 * The semaphore id.
137 */
138 int semid;
139
140 semaphore()
141 : semid(-1) { }
142 /**
143 * @param sid semaphore id.
144 */
145 semaphore(int sid)
146 : semid(sid) { }
147 ~semaphore() {
148 deinit();
149 }
150
151 /**
152 * Init semaphore.
153 */
154 void init();
155 /**
156 * Undo the init.
157 */
158 void deinit();
159
160 /**
161 * Semaphore on.
162 */
163 void on();
164 /**
165 * Semaphore off.
166 */
167 void off();
168 };
169
170 /**
171 * The semaphor lock object, released at object destruction.
172 */
173 class semaphore_lock {
174 public:
175 /**
176 * Pointer to the semaphore we're operating on.
177 */
178 semaphore* sem;
179 /**
180 * Whether it is locked.
181 */
182 bool locked;
183
184 semaphore_lock()
185 : sem(NULL), locked(false) {}
186 /**
187 * @param s pointer to the semaphore.
188 * @param l lock at creation?
189 */
190 semaphore_lock(semaphore* s,bool l=true)
191 : sem(s), locked(false) {
192 if(l) lock();
193 }
194 /**
195 * @param s reference to the semaphore.
196 * @param l lock at creation?
197 */
198 semaphore_lock(semaphore& s,bool l=true)
199 : sem(&s), locked(false) {
200 if(l) lock();
201 }
202
203 ~semaphore_lock() {
204 unlock();
205 }
206
207 /**
208 * Lock it.
209 */
210 void lock();
211 /**
212 * Unlock it.
213 */
214 void unlock();
215 };
216
217 /**
218 * normalize_path options enumeration.
219 * @see normalize_path()
220 */
221 enum normalize_path_options {
222 /**
223 * Restrict the /../ sequence.
224 */
225 restrict_dotdot = 1,
226 /**
227 * Strip out the leading slash.
228 */
229 strip_leading_slash = 2,
230 /**
231 * Strip out the trailing slash.
232 */
233 strip_trailing_slash = 4
234 };
235 /**
236 * combine_path options enumeration.
237 * @see combine_path()
238 */
239 enum combine_path_options {
240 /**
241 * The origin is file. Otherwise it is directory.
242 */
243 origin_is_file = 1,
244 /**
245 * Fail if we've gone up beyond root.
246 */
247 fail_beyond_root = 2
248 };
249
250 /**
251 * Normalize pathname by stripping duplicate slashes, etc.
252 * @param path the path name.
253 * @param opts options.
254 * @return the normalized path.
255 * @see normalize_path_options
256 * @todo TODO: document exceptions.
257 */
258 string normalize_path(const string& path,int opts=(restrict_dotdot|strip_trailing_slash));
259 /**
260 * Strip prefix from the string.
261 * @param str the string.
262 * @param prefix prefix to strip.
263 * @return the string without prefix.
264 * @todo TODO: document exceptions.
265 */
266 string strip_prefix(const string& str,const string& prefix);
267 /**
268 * Strip suffix from the string.
269 * @param str the string.
270 * @param suffix suffix to strip.
271 * @return the string without suffix.
272 * @todo TODO: document exceptions.
273 */
274 string strip_suffix(const string& str,const string& suffix);
275 /**
276 * Get the directory part of the filename.
277 * @param filename the full file name.
278 * @return the directory part.
279 */
280 string dir_name(const string& filename);
281 /**
282 * Combine path with the relative path.
283 * @param origin the origin.
284 * @param relative relative path to combine origin with.
285 * @param opts options.
286 * @return the pathc combined.
287 * @see combine_path_options
288 * @todo TODO: document exceptions.
289 */
290 string combine_path(const string& origin,const string& relative,int opts=origin_is_file);
291
292 /**
293 * Create directory and parent directories if needed.
294 * @param path the pathname.
295 * @param mode the mode for newly created directories.
296 */
297 void make_path(const string& path,mode_t mode);
298
299 /**
300 * Change to the directory and pop back at object's destruction (e.g. when
301 * the object goes out of scope).
302 */
303 class auto_chdir {
304 public:
305 /**
306 * Saved working directory.
307 */
308 string saved_pwd;
309 /**
310 * Whether we want to change back automatically.
311 */
312 bool autopop;
313
314 auto_chdir()
315 : autopop(false) { }
316 /**
317 * @param td destination path.
318 * @param ap automatically come back?
319 */
320 auto_chdir(const string& td,bool ap=true)
321 : autopop(false) { pushdir(td,ap); }
322 ~auto_chdir() {
323 if(autopop)
324 popdir();
325 }
326
327 /**
328 * Change into directory.
329 * @param td the directory.
330 * @param ap automaticall pop back?
331 */
332 void pushdir(const string& td,bool ap=true);
333 /**
334 * Change to the saved directory.
335 */
336 void popdir();
337 };
338
339}
340
341#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 @@
1#ifndef __SITECING_SITESPACE_H
2#define __SITECING_SITESPACE_H
3
4#include <string>
5#include <map>
6#include <list>
7#include "sitecing/component_factory.h"
8#include "sitecing/component_so.h"
9#include "sitecing/configuration.h"
10
11/**
12 * @file
13 * @brief The sitespace class declaration.
14 */
15
16namespace sitecing {
17 using namespace std;
18
19 /**
20 * The class responsible for handling the whole environment (as far as I can
21 * remember).
22 */
23 class sitespace {
24 public:
25 /**
26 * The type for the map of components from the component name/path
27 * to the loaded component objects.
28 */
29 typedef map<string,component_so*> components_t;
30 /**
31 * The type for listing the components.
32 */
33 typedef list<component_so*> sentenced_t;
34 /**
35 * The main configuration object.
36 */
37 configuration& config;
38 /**
39 * The components producing factory.
40 */
41 component_factory factory;
42 /**
43 * The components loaded.
44 */
45 components_t components;
46 /**
47 * The list of components sentenced to death.
48 */
49 sentenced_t sentenced;
50
51 /**
52 * Create an object in accordance with the configuration parsed.
53 * @param c the coniguration container.
54 */
55 sitespace(configuration& c);
56 ~sitespace();
57
58 /**
59 * Fetch the component, providing it with the interface object
60 * pointer.
61 * @param c the component name.
62 * @param scif the interface object.
63 * @return the component fetches.
64 */
65 so_component fetch(const string& c,sitecing_interface* scif);
66
67 private:
68 /**
69 * Execute the death sentence as much as we can.
70 */
71 void execute_sentenced();
72 };
73
74}
75
76#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 @@
1#ifndef __SITECING_UTIL_H
2#define __SITECING_UTIL_H
3
4#include <ostream>
5#include <string>
6#include "sitecing/acomponent.h"
7
8/**
9 * @file
10 * @brief more or less non-internal utility classes and functions.
11 */
12
13namespace sitecing {
14 using namespace std;
15
16 /**
17 * the html_escape options enumeration.
18 */
19 enum html_escape_options {
20 /**
21 * Turn spaces into &nbsp;
22 */
23 html_escape_nbsp = 0x0001,
24 /**
25 * Turn newlines into <br/> or <br>.
26 */
27 html_escape_br = 0x0002,
28 /**
29 * Turn quotes to &quot;
30 */
31 html_escape_quot = 0x0004,
32 /**
33 * Do not put '/' into <br/> consruct.
34 */
35 html_escape_br_noslash = 0x0008
36 };
37 /**
38 * Escape string suitable for html output.
39 * @param str the string.
40 * @param flags options.
41 * @return the string escaped.
42 * @see html_escape_options
43 */
44 string html_escape(const string& str,int flags=html_escape_br);
45
46 /**
47 * The output string checkpoint object, letting one to rollback output.
48 */
49 class checkpoint {
50 public:
51 /**
52 * The object's death will enumeration.
53 */
54 enum will_t {
55 /**
56 * The stream is to be rolled back at object destruction.
57 */
58 will_rollback,
59 /**
60 * The stream is not to be rolled back at object destruction.
61 */
62 will_commit,
63 /**
64 * The object will die intestate. What's the point then?
65 */
66 will_intestate
67 };
68 /**
69 * The output stream in question.
70 */
71 ostream* stream;
72 /**
73 * The point at which objhect was created.
74 */
75 ostream::pos_type point;
76 /**
77 * The last will.
78 */
79 will_t last_will;
80
81 /**
82 * @param s reference to the stream.
83 * @param lw the last will.
84 */
85 checkpoint(ostream& s, will_t lw=will_rollback)
86 : stream(&s), last_will(lw) { set(); }
87 /**
88 * @param s pointer to the stream.
89 * @param lw the last will.
90 */
91 checkpoint(ostream* s, will_t lw=will_rollback)
92 : stream(s), last_will(lw) { set(); }
93 /**
94 * @param s reference to the sitecing interface where to get output
95 * stream from.
96 * @param lw the last will.
97 */
98 checkpoint(sitecing_interface& s, will_t lw=will_rollback)
99 : stream(s.out), last_will(lw) { set(); }
100 /**
101 * @param s pointer to the sitecing interface where to get output
102 * stream from.
103 * @param lw the last will.
104 */
105 checkpoint(sitecing_interface* s, will_t lw=will_rollback)
106 : stream(s->out), last_will(lw) { set(); }
107 /**
108 * @param c reference to the component from which the output stream
109 * is obtained.
110 * @param lw the last will.
111 */
112 checkpoint(acomponent& c, will_t lw=will_rollback)
113 : stream(c.__SCIF->out), last_will(lw) { set(); }
114 /**
115 * @param c pointer to the component from which the output stream is
116 * obtained.
117 * @param lw the last will.
118 */
119 checkpoint(acomponent* c, will_t lw=will_rollback)
120 : stream(c->__SCIF->out), last_will(lw) { set(); }
121 ~checkpoint() {
122 if(last_will==will_rollback)
123 rollback();
124 }
125
126 /**
127 * Set the possible rolback point to the current position in stream.
128 */
129 void set();
130 /**
131 * Make or change will.
132 */
133 void make_will(will_t lw);
134 /**
135 * Rollback the output made so far. In case of rollback will
136 * change to intestate.
137 */
138 void rollback();
139 /**
140 * Commit output so far. In case of rollback will, change to
141 * intestate.
142 */
143 void commit();
144 };
145
146}
147
148#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 @@
1Makefile.in
2sitecing_enflesher.cc
3sitecing_parser.cc
4.libs
5.deps
6Makefile
7*.o
8*.lo
9*.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 @@
1lib_LTLIBRARIES = libsitecing.la
2noinst_HEADERS = pch.h
3
4INCLUDES = -I${top_srcdir}/include -I${top_builddir} ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \
5 ${PCREPP_CFLAGS}
6AM_CPPFLAGS = -D__SC_DEFAULT_SKELETON=\"${pkgdatadir}/component.skel\"
7AM_LFLAGS = -olex.yy.c
8
9libsitecing_la_SOURCES = \
10 sitecing_parser.ll sitecing_enflesher.ll \
11 sitecing_interface_cgi.cc \
12 acomponent.cc \
13 cgi_component.cc \
14 component_so.cc \
15 file_factory.cc component_factory.cc \
16 sitespace.cc \
17 configuration.cc \
18 util.cc sitecing_util.cc \
19 scoreboard.cc \
20 process_manager.cc
21libsitecing_la_LDFLAGS = \
22 -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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <cstdarg>
5 #include <fstream>
6 #include <konforka/exception.h>
7 using namespace std;
8 #include "sitecing/acomponent.h"
9#endif
10
11namespace sitecing {
12
13 acomponent::acomponent()
14 : __SCIF(NULL) {
15 }
16 acomponent::~acomponent() {
17 }
18
19 void acomponent::__set_interface(sitecing_interface* scif) {
20 sitecing_interface *o = __SCIF;
21 __SCIF = scif;
22 if(o!=scif) {
23 __on_change_interface(o);
24 __do_imports();
25 __on_imports();
26 }
27 }
28
29 void acomponent::__on_change_interface(sitecing_interface *oscif) { }
30 void acomponent::__do_imports() { }
31 void acomponent::__on_imports() { }
32
33 void acomponent::run(int _magic,...) {
34 va_list va;
35 va_start(va,_magic);
36 main(_magic,va);
37 va_end(va);
38 }
39
40
41 void acomponent::pass_file_through(const char *fn) {
42 ifstream ifs(fn,ios::in|ios::binary);
43 if(!ifs)
44 throw konforka::exception(CODEPOINT,"failed to open file");
45 (*(__SCIF->out)) << ifs.rdbuf();
46 }
47}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include "sitecing/cgi_component.h"
5#endif
6
7namespace sitecing {
8
9 cgi_component::cgi_component()
10 : __CGI(NULL) {
11 }
12 cgi_component::~cgi_component() {
13 }
14
15 void cgi_component::__set_interface(sitecing_interface* scif) {
16 acomponent::__set_interface(scif);
17 kingate::cgi_gateway *oc = __CGI;
18 __CGI = __SCIF?__SCIF->cgigw:NULL;
19 if(__CGI!=oc)
20 __on_change_CGI(oc);
21 }
22 void cgi_component::__on_change_interface(sitecing_interface *o) {
23 acomponent::__on_change_interface(o); // But it's a no-op
24 // TODO: do something about runtime type check, maybe?
25 __SCIF = (sitecing_interface_cgi*)acomponent::__SCIF;
26 }
27 void cgi_component::__on_change_CGI(kingate::cgi_gateway *o) { }
28 void cgi_component::__on_imports() { }
29
30}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <sys/wait.h>
8 #include <fcntl.h>
9 #include <iostream>
10 #include <fstream>
11 #include <stdexcept>
12 #include <vector>
13 using namespace std;
14 #include "sitecing/component_factory.h"
15 #include "sitecing/sitecing_util.h"
16 #include "sitecing/sitecing_parser.h"
17 #include "sitecing/sitecing_exception.h"
18#endif
19
20namespace sitecing {
21
22 static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors" };
23
24 component_factory::component_factory(configuration& c)
25 : config(c),
26 root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'),
27 root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'),
28 root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') {
29 }
30
31 void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
32 deps.clear();
33 string dp = normalize_path(dst,strip_trailing_slash);
34 // source documents
35 try { // XXX: or just compare it off?
36 string noro = strip_prefix(dp,root_source);
37 return;
38 }catch(utility_no_affix& una) {
39 }
40 // .so binaries
41 try {
42 string noso = strip_suffix(dp,".so");
43 string noro = strip_prefix(noso,root_so);
44 deps.push_back(root_intermediate+noro+".cc");
45 config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps);
46 if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) {
47 ifstream df((root_intermediate+noro+".d").c_str(),ios::in);
48 if(df.good()) {
49 string str;
50 while(!df.eof()) {
51 df >> str;
52 if(str.find_first_of("\\:")==string::npos)
53 deps.push_back(combine_path(config.root_source+noro,str));
54 }
55 }
56 }
57 config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps);
58 if(co_so_deps) {
59 for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i)
60 deps.push_back(*i);
61 }
62 return;
63 }catch(utility_no_prefix& unp) {
64 throw konforka::exception(CODEPOINT,"component is outside of component root");
65 }catch(utility_no_suffix& uns) {
66 }
67 // preprocessor targets
68 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
69 try {
70 string nos = strip_suffix(dp,pp_targets[ppt]);
71 string noro = strip_prefix(nos,root_intermediate);
72 deps.push_back(root_source+noro);
73 ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in);
74 if(imports.good()) {
75 string str;
76 while(!imports.eof()) {
77 imports >> str;
78 if(!str.empty())
79 deps.push_back(root_intermediate+str+".classname");
80 }
81 }
82 ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in);
83 if(ancestors.good()) {
84 string str;
85 while(!ancestors.eof()) {
86 ancestors >> str;
87 if(!str.empty())
88 deps.push_back(root_intermediate+str+".classname");
89 }
90 }
91 config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps);
92 if(co_intermediate_deps) {
93 for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i)
94 deps.push_back(*i);
95 }
96 return;
97 }catch(utility_no_affix& una) {
98 // do nothing. must be a cpp dependency.
99 }
100 }
101 }
102
103 bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
104 string dp = normalize_path(dst,strip_trailing_slash);
105 // XXX: or just compare it off, instead of throwing things around.
106 try {
107 strip_prefix(dp,root_intermediate);
108 return file_factory::is_uptodate(dst,deps);
109 }catch(utility_no_prefix& unp) {
110 }
111 try {
112 strip_prefix(dp,root_so);
113 return file_factory::is_uptodate(dst,deps);
114 }catch(utility_no_prefix& unp) {
115 }
116 return true;
117 }
118
119 void component_factory::build(const string& dst) {
120 string dp = normalize_path(dst,strip_trailing_slash);
121 // sources
122 try {
123 string noro = strip_prefix(dp,root_source);
124 // building the sources is left up to developer
125 return;
126 }catch(utility_no_prefix& unp) {
127 }
128 // .so files
129 try {
130 string noso = strip_suffix(dp,".so");
131 string noro = strip_prefix(noso,root_so);
132 string cc = root_intermediate+noro+".cc";
133 if(access(cc.c_str(),R_OK))
134 throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")");
135 make_path(dir_name(root_so+noro),0755);
136 string pwd = dir_name(root_source+noro);
137 auto_chdir dir_changer(pwd);
138 file_lock lock_source(root_intermediate+noro+".lock");
139 file_lock lock_so(root_so+noro+".so.lock");
140 int stdO = open((root_intermediate+noro+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
141 if(stdO<0)
142 throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout");
143 int stdE = open((root_intermediate+noro+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
144 if(stdE<0) {
145 close(stdO);
146 throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr");
147 }
148 list<string> args;
149 config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags);
150 if(co_cpp_flags) {
151 args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end());
152 }
153 config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags);
154 if(co_ld_flags) {
155 args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end());
156 }
157 // TODO: maybe move it to separare config option like CoreCPPFLags?
158 args.push_back("-I"+root_intermediate);
159 args.push_back("-I"+root_source);
160 args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d");
161 args.push_back("-shared");
162 args.push_back("-o"); args.push_back(dp);
163 args.push_back(cc);
164 file_list_t ancestors;
165 get_ancestors(noro,ancestors);
166 for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) {
167 string aso=root_so+*i+".so";
168 make(aso);
169 args.push_back(aso);
170 }
171 // TODO: "g++" configurable
172 int rv = execute("g++",args,stdO,stdE);
173 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
174 throw compile_error(CODEPOINT,"failed to compile component",noro);
175 return;
176 }catch(utility_no_prefix& unp) {
177 throw konforka::exception(CODEPOINT,"component is outside of component root");
178 }catch(utility_no_suffix& uns) {
179 }
180 // preprocessor targets
181 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
182 try {
183 string nos = strip_suffix(dp,pp_targets[ppt]);
184 string noro = strip_prefix(nos,root_intermediate);
185 string src = root_source+noro;
186 if(access(src.c_str(),R_OK))
187 throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
188 make_path(dir_name(root_intermediate+noro),0755);
189 file_lock lock(root_intermediate+noro+".lock");
190 sitecing_parser parser(*this);
191 config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton);
192 if(co_skeleton)
193 parser.skeleton = co_skeleton->skeleton;
194 static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
195 parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash);
196 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)) {
197 string::size_type lc = parser.class_name.find_first_of(id_chars,illc);
198 int n = ((lc==string::npos)?parser.class_name.length():lc)-illc;
199 parser.class_name.replace(illc,n,n,'_');
200 }
201 parser.class_name = "_SCC_"+parser.class_name;
202 parser.output_basename = nos;
203 parser.component_basename = noro;
204 try {
205 parser.preprocess(src);
206 }catch(preprocessor_error& pe) {
207 pe.component_name = noro;
208 pe.see(CODEPOINT);
209 throw;
210 }
211 return;
212 }catch(utility_no_affix& una) {
213 // must be a crap from .d file
214 }
215 }
216 cerr << "ignoring build request for " << dp << endl;
217 }
218
219 int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) {
220 // XXX: is it right that we do stdio/stderr tricks outside of the function?
221 cerr << "executing: " << cmd;
222 vector<const char*> argv(args.size()+2);
223 argv[0]=cmd.c_str();
224 int an = 1;
225 for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
226 cerr << " " << *i ;
227 argv[an++] = i->c_str();
228 }
229 cerr << endl;
230 argv[an++]=NULL;
231 pid_t pid = vfork();
232 if(pid==-1) {
233 close(stdo); close(stde);
234 throw konforka::exception(CODEPOINT,"failed to vfork()");
235 }
236 if(!pid) {
237 // child
238 if(dup2(stdo,1)!=1)
239 _exit(-1);
240 if(dup2(stde,2)!=2)
241 _exit(-1);
242 close(0);
243 execvp(cmd.c_str(),(char**)&argv.front());
244 _exit(-1);
245 }
246 // parent
247 close(stdo); close(stde);
248 int rv;
249 if(waitpid(pid,&rv,0)<0)
250 throw konforka::exception(CODEPOINT,"failed to waitpid()");
251 return rv;
252 }
253
254 string component_factory::get_classname(const string& component) {
255 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname";
256 make(cn);
257 ifstream ifs(cn.c_str());
258 if(!ifs.good())
259 throw konforka::exception(CODEPOINT,"failed to access component .classname");
260 ifs >> cn;
261 return cn;
262 }
263
264 void component_factory::get_ancestors(const string& component,file_list_t& rv) {
265 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors";
266 make(cn);
267 ifstream ifs(cn.c_str());
268 if(!ifs.good())
269 throw konforka::exception(CODEPOINT,"filed to access component .ancestors");
270 rv.clear();
271 while(!ifs.eof()) {
272 string a;
273 ifs >> a;
274 if(!a.empty())
275 rv.push_back(a);
276 }
277 }
278
279}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <unistd.h>
5 #include <dlfcn.h>
6 #include <iostream>
7 #include <cassert>
8 #include <stdexcept>
9 using namespace std;
10 #include "sitecing/component_so.h"
11 #include "sitecing/sitecing_util.h"
12#endif
13
14namespace sitecing {
15
16 /*
17 * component_so
18 */
19
20 component_so::component_so(const string& soname)
21 : dl(NULL), sofile(soname) {
22 if(stat(sofile.c_str(),&stso))
23 throw konforka::exception(CODEPOINT,"failed to stat() shared object");
24 file_lock lock(sofile+".lock");
25 dl = dlopen(sofile.c_str(),RTLD_LAZY);
26 lock.unlock();
27 if(!dl)
28 throw konforka::exception(CODEPOINT,"failed to dlopen: "+string(dlerror()));
29 egg = (egg_t)dlsym(dl,"_egg");
30 if(!egg)
31 throw konforka::exception(CODEPOINT,"failed to dlsym: "+string(dlerror()));
32 }
33 component_so::~component_so() {
34 for(free_chickens_t::iterator i=chickens_free.begin();i!=chickens_free.end();i++)
35 delete *i;
36 chickens_free.clear();
37 if(!chickens_used.empty())
38 throw konforka::exception(CODEPOINT,"attempt to destroy the component in use");
39 dlclose(dl);
40 }
41
42 bool component_so::is_uptodate() const {
43 struct stat st;
44 if(stat(sofile.c_str(),&st))
45 throw konforka::exception(CODEPOINT,"failed to stat() shared object");
46 return stso.st_mtime==st.st_mtime;
47 }
48
49 acomponent* component_so::allocate_chicken() {
50 acomponent *rv;
51 if(!chickens_free.empty()) {
52 rv = chickens_free.front();
53 chickens_free.pop_front();
54 }else{
55 rv = (*egg)();
56 }
57 assert(chickens_used.find(rv)==chickens_used.end());
58 chickens_used[rv]=1;
59 return rv;
60 }
61
62 void component_so::allocate_chicken(acomponent* ac) {
63 used_chickens_t::iterator i = chickens_used.find(ac);
64 if(i!=chickens_used.end()) {
65 i->second++;
66 }else{
67 free_chickens_t::iterator i;
68 for(i=chickens_free.begin();*i!=ac && i!=chickens_free.end();i++);
69 if(i==chickens_free.end())
70 throw konforka::exception(CODEPOINT,"hens rarely adopt chickens");
71 chickens_free.erase(i);
72 chickens_used[ac]=1;
73 }
74 }
75
76 void component_so::deallocate_chicken(acomponent* ac) {
77 used_chickens_t::iterator i = chickens_used.find(ac);
78 if(i==chickens_used.end())
79 throw konforka::exception(CODEPOINT,"you can't deallocate what is not allocated");
80 i->second--;
81 if(i->second>0)
82 return;
83 chickens_used.erase(i);
84 chickens_free.push_front(ac);
85 }
86
87 /*
88 * so_component
89 */
90
91 so_component::so_component(component_so *h,sitecing_interface *scif)
92 : hen(h), ac(NULL) {
93 if(!hen)
94 throw konforka::exception(CODEPOINT,"can't get an egg from the null-hen");
95 ac = hen->allocate_chicken();
96 ac->__set_interface(scif);
97 }
98
99 void so_component::attach(component_so *h,acomponent *a) {
100 detach(); hen = h; ac = a;
101 if(!ac)
102 throw konforka::exception(CODEPOINT,"trying to clone null-chicken");
103 if(!hen)
104 throw konforka::exception(CODEPOINT,"trying to clone orphan chicken");
105 hen->allocate_chicken(ac);
106 }
107 void so_component::detach() {
108 if(hen && ac)
109 hen->deallocate_chicken(ac);
110 }
111
112}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <unistd.h>
5 #include <fnmatch.h>
6 #include <cassert>
7 #include <stdexcept>
8 using namespace std;
9 #include <dotconf.h>
10 #include "sitecing/configuration.h"
11 #include "sitecing/sitecing_util.h"
12 #include "sitecing/scoreboard.h"
13#endif
14
15namespace sitecing {
16
17 configuration::configuration()
18 : flags(0), autobuild(false) { }
19 configuration::configuration(const string& cfile,bool ab)
20 : flags(0), autobuild(ab) {
21 parse(cfile);
22 }
23
24 enum dc_ctx {
25 DCC_ROOT = 1,
26 DCC_PATH = 2,
27 DCC_SCRC = 4
28 };
29 struct dc_context {
30 dc_ctx ctx;
31 configuration* cf;
32 list<config_options*> co;
33 };
34
35 static DOTCONF_CB(dco_root_source) { dc_context *dcc = (dc_context*)ctx;
36 dcc->cf->root_source = cmd->data.str;
37 dcc->cf->flags |= configuration::flag_root_source;
38 return NULL;
39 }
40 static DOTCONF_CB(dco_root_intermediate) { dc_context *dcc = (dc_context*)ctx;
41 dcc->cf->root_intermediate = cmd->data.str;
42 dcc->cf->flags |= configuration::flag_root_intermediate;
43 return NULL;
44 }
45 static DOTCONF_CB(dco_root_so) { dc_context *dcc = (dc_context*)ctx;
46 dcc->cf->root_so = cmd->data.str;
47 dcc->cf->flags |= configuration::flag_root_so;
48 return NULL;
49 }
50 static DOTCONF_CB(dco_listen_socket) { dc_context *dcc = (dc_context*)ctx;
51 dcc->cf->listen_socket = cmd->data.str;
52 dcc->cf->flags |= configuration::flag_listen_socket;
53 return NULL;
54 }
55 static DOTCONF_CB(dco_rc_file_name) { dc_context *dcc = (dc_context*)ctx;
56 dcc->cf->rc_file_name = cmd->data.str;
57 dcc->cf->flags |= configuration::flag_rc_file_name;
58 return NULL;
59 }
60 static DOTCONF_CB(dco_min_children) { dc_context *dcc = (dc_context*)ctx;
61 if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS)
62 return "MinChildren is too big";
63 dcc->cf->min_children = cmd->data.value;
64 dcc->cf->flags |= configuration::flag_min_children;
65 return NULL;
66 }
67 static DOTCONF_CB(dco_max_children) { dc_context *dcc = (dc_context*)ctx;
68 if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS)
69 return "MaxChildren is too big";
70 dcc->cf->max_children = cmd->data.value;
71 dcc->cf->flags |= configuration::flag_max_children;
72 return NULL;
73 }
74 static DOTCONF_CB(dco_min_spare_children) { dc_context *dcc = (dc_context*)ctx;
75 if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS)
76 return "MinSpareChildren is too big";
77 dcc->cf->min_spare_children = cmd->data.value;
78 dcc->cf->flags |= configuration::flag_min_spare_children;
79 return NULL;
80 }
81 static DOTCONF_CB(dco_max_spare_children) { dc_context *dcc = (dc_context*)ctx;
82 if(cmd->data.value>=MAX_SITECING_SCOREBOARD_SLOTS)
83 return "MaxSpareChildren is too big";
84 dcc->cf->max_spare_children = cmd->data.value;
85 dcc->cf->flags |= configuration::flag_max_spare_children;
86 return NULL;
87 }
88 static DOTCONF_CB(dco_requests_per_child) { dc_context *dcc = (dc_context*)ctx;
89 dcc->cf->requests_per_child = cmd->data.value;
90 dcc->cf->flags |= configuration::flag_requests_per_child;
91 return NULL;
92 }
93 static DOTCONF_CB(dco_multi_process) { dc_context *dcc = (dc_context*)ctx;
94 dcc->cf->multi_process = cmd->data.value;
95 dcc->cf->flags |= configuration::flag_multi_process;
96 return NULL;
97 }
98 static DOTCONF_CB(dco_user) { dc_context *dcc = (dc_context*)ctx;
99 dcc->cf->user = cmd->data.str;
100 dcc->cf->flags |= configuration::flag_user;
101 return NULL;
102 }
103 static DOTCONF_CB(dco_group) { dc_context *dcc = (dc_context*)ctx;
104 dcc->cf->group = cmd->data.str;
105 dcc->cf->flags |= configuration::flag_group;
106 return NULL;
107 }
108 static DOTCONF_CB(dco_chroot) { dc_context *dcc = (dc_context*)ctx;
109 dcc->cf->chroot = cmd->data.str;
110 dcc->cf->flags |= configuration::flag_chroot;
111 return NULL;
112 }
113 static DOTCONF_CB(dco_pid_file) { dc_context *dcc = (dc_context*)ctx;
114 dcc->cf->pid_file = cmd->data.str;
115 dcc->cf->flags |= configuration::flag_pid_file;
116 return NULL;
117 }
118 static DOTCONF_CB(dco_daemonize) { dc_context *dcc = (dc_context*) ctx;
119 dcc->cf->daemonize = cmd->data.value;
120 dcc->cf->flags |= configuration::flag_daemonize;
121 return NULL;
122 }
123
124 static DOTCONF_CB(dco_path) { dc_context *dcc = (dc_context*)ctx;
125 string path = cmd->data.str;
126 if(path[path.length()-1]=='>')
127 path.erase(path.length()-1);
128 // TODO: normalize path
129 dcc->co.push_front(&(dcc->cf->specs[path]));
130 dcc->ctx = DCC_PATH; // TODO: stack it, instead
131 return NULL;
132 }
133 static DOTCONF_CB(dco__path) { dc_context *dcc = (dc_context*)ctx;
134 dcc->co.pop_front();
135 assert(dcc->co.size());
136 dcc->ctx = DCC_ROOT; // TODO: stack it, instead
137 return NULL;
138 }
139
140 static DOTCONF_CB(dco_skeleton) { dc_context *dcc = (dc_context*)ctx;
141 dcc->co.front()->skeleton = cmd->data.str;
142 dcc->co.front()->flags |= config_options::flag_skeleton;
143 return NULL;
144 }
145 static DOTCONF_CB(dco_cpp_flags) { dc_context *dcc = (dc_context*)ctx;
146 for(char **arg=cmd->data.list;*arg;arg++)
147 dcc->co.front()->cpp_flags.push_back(*arg);
148 dcc->co.front()->flags |= config_options::flag_cpp_flags;
149 return NULL;
150 }
151 static DOTCONF_CB(dco_ld_flags) { dc_context *dcc = (dc_context*)ctx;
152 for(char **arg=cmd->data.list;*arg;arg++)
153 dcc->co.front()->ld_flags.push_back(*arg);
154 dcc->co.front()->flags |= config_options::flag_ld_flags;
155 return NULL;
156 }
157 static DOTCONF_CB(dco_intermediate_deps) { dc_context *dcc = (dc_context*) ctx;
158 for(char **arg=cmd->data.list;*arg;arg++)
159 dcc->co.front()->intermediate_deps.push_back(*arg);
160 dcc->co.front()->flags |= config_options::flag_intermediate_deps;
161 return NULL;
162 }
163 static DOTCONF_CB(dco_so_deps) { dc_context *dcc = (dc_context*) ctx;
164 for(char **arg=cmd->data.list;*arg;arg++)
165 dcc->co.front()->so_deps.push_back(*arg);
166 dcc->co.front()->flags |= config_options::flag_so_deps;
167 return NULL;
168 }
169 static DOTCONF_CB(dco_build) { dc_context *dcc = (dc_context*)ctx;
170 dcc->co.front()->build = cmd->data.value;
171 dcc->co.front()->flags |= config_options::flag_build;
172 return NULL;
173 }
174 static DOTCONF_CB(dco_cpp_deps) { dc_context *dcc = (dc_context*)ctx;
175 dcc->co.front()->cpp_deps = cmd->data.value;
176 dcc->co.front()->flags |= config_options::flag_cpp_deps;
177 return NULL;
178 }
179 static DOTCONF_CB(dco_exception_handler) { dc_context *dcc = (dc_context*)ctx;
180 dcc->co.front()->exception_handler = cmd->data.str;
181 dcc->co.front()->flags |= config_options::flag_exception_handler;
182 return NULL;
183 }
184 static DOTCONF_CB(dco_http_status_handler) { dc_context *dcc = (dc_context*)ctx;
185 if(cmd->arg_count!=2)
186 return "Invalid number of arguments";
187 dcc->co.front()->http_status_handlers[cmd->data.list[0]] = cmd->data.list[1];
188 dcc->co.front()->flags |= config_options::flag_http_status_handlers;
189 return NULL;
190 }
191 static DOTCONF_CB(dco_action) { dc_context *dcc = (dc_context*)ctx;
192 if(cmd->arg_count<2)
193 return "Invalid number of arguments";
194 try {
195 char **arg=cmd->data.list;
196 dcc->co.front()->action_handlers.push_back(config_options::action_handler_t(arg[0],arg[1]));
197 for(arg+=2;*arg;arg++)
198 dcc->co.front()->action_handlers.back().args.push_back(*arg);
199 dcc->co.front()->flags |= config_options::flag_action_handlers;
200 }catch(exception& e) {
201 return "Error processing Action directive"; // XXX: could be done better
202 }
203 return NULL;
204 }
205 static DOTCONF_CB(dco_auto_build_files) { dc_context *dcc = (dc_context*)ctx;
206 if(!( dcc->cf && dcc->cf->autobuild))
207 return NULL;
208 for(char **arg=cmd->data.list;*arg;arg++)
209 dcc->co.front()->auto_build_files.push_back(*arg);
210 dcc->co.front()->flags |= config_options::flag_auto_build_files;
211 return NULL;
212 }
213
214 static const configoption_t dc_options[] = {
215 { "RootSource", ARG_STR, dco_root_source, NULL, DCC_ROOT },
216 { "RootIntermediate", ARG_STR, dco_root_intermediate, NULL, DCC_ROOT },
217 { "RootSO", ARG_STR, dco_root_so, NULL, DCC_ROOT },
218 { "ListenSocket", ARG_STR, dco_listen_socket, NULL, DCC_ROOT },
219 { "RCFileName", ARG_STR, dco_rc_file_name, NULL, DCC_ROOT },
220 { "MinChildren", ARG_INT, dco_min_children, NULL, DCC_ROOT },
221 { "MaxChildren", ARG_INT, dco_max_children, NULL, DCC_ROOT },
222 { "MinSpareChildren", ARG_INT, dco_min_spare_children, NULL, DCC_ROOT },
223 { "MaxSpareChildren", ARG_INT, dco_max_spare_children, NULL, DCC_ROOT },
224 { "RequestsPerChild", ARG_INT, dco_requests_per_child, NULL, DCC_ROOT },
225 { "MultiProcess", ARG_TOGGLE, dco_multi_process, NULL, DCC_ROOT },
226 { "User", ARG_STR, dco_user, NULL, DCC_ROOT },
227 { "Group", ARG_STR, dco_group, NULL, DCC_ROOT },
228 { "Chroot", ARG_STR, dco_chroot, NULL, DCC_ROOT },
229 { "PidFile", ARG_STR, dco_pid_file, NULL, DCC_ROOT },
230 { "Daemonize", ARG_TOGGLE, dco_daemonize, NULL, DCC_ROOT },
231 { "<Path", ARG_STR, dco_path, NULL, DCC_ROOT },
232 { "Skeleton", ARG_STR, dco_skeleton, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
233 { "CPPFLAGS", ARG_LIST, dco_cpp_flags, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
234 { "LDFLAGS", ARG_LIST, dco_ld_flags, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
235 { "Build", ARG_TOGGLE, dco_build, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
236 { "CPPDeps", ARG_TOGGLE, dco_cpp_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
237 { "ExceptionHandler", ARG_STR, dco_exception_handler, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
238 { "HTTPStatusHandler", ARG_LIST, dco_http_status_handler, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
239 { "IntermediateDeps", ARG_LIST, dco_intermediate_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
240 { "SODeps", ARG_LIST, dco_so_deps, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
241 { "Action", ARG_LIST, dco_action, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
242 { "AutoBuildFiles", ARG_LIST, dco_auto_build_files, NULL, DCC_ROOT|DCC_PATH|DCC_SCRC },
243 { "</Path>", ARG_NONE, dco__path, NULL, DCC_PATH },
244 LAST_OPTION
245 };
246
247 static const char *dc_context_checker(command_t *cmd,unsigned long mask) {
248 dc_context *dcc = (dc_context*)cmd->context;
249 if( (mask==CTX_ALL) || ((mask&dcc->ctx)==dcc->ctx) )
250 return NULL;
251 return "misplaced option";
252 }
253 static FUNC_ERRORHANDLER(dc_error_handler) {
254 throw konforka::exception(CODEPOINT,string("error parsing config file: ")+msg);
255 }
256
257 bool loaded_options::is_valid() {
258 struct stat nst;
259 if(stat(source_file.c_str(),&nst))
260 return false;
261 if(st.st_mtime!=nst.st_mtime)
262 return false;
263 return true;
264 }
265
266 loaded_options *configuration::lookup_loaded_options(const string& target) {
267 // we assume 'target' is a directory with trailing slash appended
268 string scrc = root_source+target;
269 if(flags&flag_rc_file_name)
270 scrc += rc_file_name;
271 else
272 scrc += ".scrc";
273 // TODO: normalize me, anyway.
274 if(access(scrc.c_str(),R_OK))
275 return 0; // TODO FIXME: this approach leaves already loaded .scrcs around in case of removal
276 loaded_specs_t::iterator i = loaded_specs.find(target);
277 if(i==loaded_specs.end() || !i->second.is_valid()) {
278 if(i!=loaded_specs.end())
279 loaded_specs.erase(i);
280 pair<loaded_specs_t::iterator,bool> ii = loaded_specs.insert(loaded_specs_t::value_type(target,loaded_options()));
281 assert(ii.first!=loaded_specs.end());
282 ii.first->second.parse(this,scrc);
283 i = ii.first;
284 }
285 assert(i!=loaded_specs.end());
286 return &(i->second);
287 }
288
289 config_options::action_handler_t *config_options::lookup_action_handler(const string& target) {
290 for(action_handlers_t::iterator i=action_handlers.begin();i!=action_handlers.end();++i) {
291 if(i->regex.search(target))
292 return &*i;
293 }
294 return NULL;
295 }
296
297 string config_options::lookup_http_status_handler(const string& status) {
298 http_status_handlers_t::const_iterator i = http_status_handlers.find(status);
299 string rv;
300 if(i!=http_status_handlers.end())
301 rv = i->second;
302 return rv;
303 }
304
305 string configuration::lookup_http_status_handler(const string& target,const string& status) {
306 string t = "/";
307 t += normalize_path(target,strip_leading_slash);
308 string rv;
309 for(;;) {
310 if(t[t.length()-1]=='/') {
311 loaded_options* lo = lookup_loaded_options(t);
312 if( lo && (lo->flags&config_options::flag_http_status_handlers) ) {
313 rv = lo->lookup_http_status_handler(status);
314 if(!rv.empty())
315 return rv;
316 }
317 }
318 specs_t::iterator i = specs.find(t);
319 if( i!=specs.end() && (i->second.flags&&config_options::flag_http_status_handlers) ) {
320 rv = i->second.lookup_http_status_handler(status);
321 if(!rv.empty())
322 return rv;
323 }
324 if(t.empty())
325 return rv;
326 string::size_type sl=t.rfind('/');
327 if(sl==string::npos) {
328 t.erase();
329 }else{
330 if(sl==(t.length()-1))
331 t.erase(sl);
332 else
333 t.erase(sl+1);
334 }
335 }
336 }
337
338 config_options::action_handler_t *configuration::lookup_action_handler(const string& target) {
339 string t = "/";
340 t += normalize_path(target,strip_leading_slash);
341 for(;;) {
342 if(t[t.length()-1]=='/') {
343 loaded_options* lo = lookup_loaded_options(t);
344 if( lo && (lo->flags&config_options::flag_action_handlers) ) {
345 config_options::action_handler_t *rv = lo->lookup_action_handler(target);
346 if(rv)
347 return rv;
348 }
349 }
350 specs_t::iterator i = specs.find(t);
351 if( i!=specs.end() && (i->second.flags&&config_options::flag_action_handlers) ) {
352 config_options::action_handler_t *rv = i->second.lookup_action_handler(target);
353 if(rv)
354 return rv;
355 }
356 if(t.empty())
357 return NULL;
358 string::size_type sl=t.rfind('/');
359 if(sl==string::npos) {
360 t.erase();
361 }else{
362 if(sl==(t.length()-1))
363 t.erase(sl);
364 else
365 t.erase(sl+1);
366 }
367 }
368 }
369
370 config_options* configuration::lookup_config(const string& target,int flag) {
371 string t = "/"; // always assume leading slash
372 t += normalize_path(target,strip_leading_slash);
373 // XXX: reconsider precedence
374 for(;;) {
375 if(t[t.length()-1]=='/') {
376 loaded_options* lo = lookup_loaded_options(t);
377 if( lo && (lo->flags&flag)==flag )
378 return lo;
379 }
380 specs_t::iterator i = specs.find(t);
381 if( i!=specs.end() && (i->second.flags&flag)==flag )
382 return &(i->second);
383 if(t.empty())
384 return NULL;
385 string::size_type sl=t.rfind('/');
386 if(sl==string::npos) {
387 t.erase();
388 }else{
389 if(sl==(t.length()-1))
390 t.erase(sl);
391 else
392 t.erase(sl+1);
393 }
394 }
395 }
396
397 bool config_options::match_autobuild_files(const char *fn,bool &rv) {
398 for(list<string>::reverse_iterator i=auto_build_files.rbegin();i!=auto_build_files.rend();++i) {
399 const char *pat = i->c_str();
400 bool plus = true;
401 if((*pat)=='+')
402 pat++;
403 else if((*pat)=='-') {
404 plus = false;
405 pat++;
406 }
407 if(!fnmatch(pat,fn,FNM_NOESCAPE|FNM_PATHNAME|FNM_PERIOD)) {
408 rv = plus;
409 return true;
410 }
411 }
412 return false;
413 }
414
415 bool configuration::match_autobuild_files(const string& target,const char *fn) {
416 string t = "/";
417 t += normalize_path(target,strip_leading_slash|strip_trailing_slash);
418 t += "/";
419 bool rv = false;
420 for(;;) {
421 if(t[t.length()-1]=='/') {
422 loaded_options* lo = lookup_loaded_options(t);
423 if(lo && (lo->flags&config_options::flag_auto_build_files) && lo->match_autobuild_files(fn,rv) )
424 return rv;
425 }
426 specs_t::iterator i = specs.find(t);
427 if( i!=specs.end() && (i->second.flags&config_options::flag_auto_build_files) && i->second.match_autobuild_files(fn,rv) )
428 return rv;
429 if(t.empty())
430 return rv;
431 string::size_type sl=t.rfind('/');
432 if(sl==string::npos) {
433 t.erase();
434 }else{
435 if(sl==(t.length()-1))
436 t.erase(sl);
437 else
438 t.erase(sl+1);
439 }
440 }
441 }
442
443 void configuration::parse(const string& cfile) {
444 struct dc_context dcc;
445 dcc.cf = this;
446 dcc.ctx = DCC_ROOT;
447 dcc.co.push_front(&root_options());
448 configfile_t *cf = dotconf_create((char*)cfile.c_str(),dc_options,(context_t*)&dcc,CASE_INSENSITIVE);
449 if(!cf)
450 throw konforka::exception(CODEPOINT,"failed to dotconf_create()");
451 cf->errorhandler = (dotconf_errorhandler_t) dc_error_handler;
452 cf->contextchecker = (dotconf_contextchecker_t) dc_context_checker;
453 if(!dotconf_command_loop(cf))
454 throw konforka::exception(CODEPOINT,"failed to dotconf_command_loop()");
455 dotconf_cleanup(cf);
456 }
457
458 void loaded_options::parse(configuration *config,const string& cfile) {
459 struct dc_context dcc;
460 dcc.cf = config;
461 dcc.ctx = DCC_SCRC;
462 dcc.co.push_front(this);
463 configfile_t *cf = dotconf_create((char*)cfile.c_str(),dc_options,(context_t*)&dcc,CASE_INSENSITIVE);
464 if(!cf)
465 throw konforka::exception(CODEPOINT,"failed to dotconf_create()");
466 cf->errorhandler = (dotconf_errorhandler_t) dc_error_handler;
467 cf->contextchecker = (dotconf_contextchecker_t) dc_context_checker;
468 if(!dotconf_command_loop(cf))
469 throw konforka::exception(CODEPOINT,"failed to dotconf_command_loop()");
470 dotconf_cleanup(cf);
471 source_file = cfile;
472 stat(cfile.c_str(),&st); // TODO: handle errors?
473 }
474}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <konforka/exception.h>
8 using namespace std;
9 #include "sitecing/file_factory.h"
10#endif
11
12namespace sitecing {
13
14 bool file_factory::is_uptodate(const string& dst,file_list_t* deps) {
15 file_list_t deplist;
16 file_list_t *fl = deps?deps:&deplist;
17 get_dependencies(dst,*fl);
18 struct stat stdst;
19 if(stat(dst.c_str(),&stdst))
20 return false;
21 for(file_list_t::const_iterator i=fl->begin();i!=fl->end();i++) {
22 struct stat stdep;
23 if(stat(i->c_str(),&stdep))
24 return false;
25 if(stdst.st_mtime<stdep.st_mtime)
26 return false;
27 if(!is_uptodate(*i))
28 return false;
29 }
30 return true;
31 }
32
33 void file_factory::make(const string& dst) {
34 try {
35 depth++;
36 if(depth>25)
37 throw konforka::exception(CODEPOINT,"recursed too deeply.");
38 file_list_t deps;
39 if(!is_uptodate(dst,&deps)) {
40 for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++)
41 make(*i);
42 build(dst);
43 }
44 depth--;
45 }catch(konforka::exception& ke) {
46 depth--;
47 ke.see(CODEPOINT);
48 throw;
49 }catch(...) {
50 depth--;
51 throw;
52 }
53 }
54
55}
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 @@
1#ifndef __PCH_H
2#define __PCH_H
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <sys/wait.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/ipc.h>
10#include <sys/shm.h>
11#include <sys/sem.h>
12#include <errno.h>
13#include <dlfcn.h>
14#include <fnmatch.h>
15
16#include <dotconf.h>
17
18#include <cstdarg>
19#include <cassert>
20#include <iostream>
21#include <fstream>
22
23#include <vector>
24using namespace std;
25
26#include <konforka/exception.h>
27
28#include "sitecing/acomponent.h"
29#include "sitecing/cgi_component.h"
30#include "sitecing/component_factory.h"
31#include "sitecing/sitecing_util.h"
32#include "sitecing/sitecing_exception.h"
33#include "sitecing/component_so.h"
34#include "sitecing/configuration.h"
35#include "sitecing/file_factory.h"
36#include "sitecing/sitecing_interface_cgi.h"
37#include "sitecing/sitespace.h"
38#include "sitecing/util.h"
39#include "sitecing/scoreboard.h"
40#include "sitecing/process_manager.h"
41
42#include "sitecing/sitecing_parser.h"
43#include "sitecing/sitecing_enflesher.h"
44
45#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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/wait.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <cassert>
10 #include <string>
11 #include <konforka/exception.h>
12 using namespace std;
13 #include "sitecing/process_manager.h"
14#endif
15
16namespace sitecing {
17
18 process_manager::process_manager()
19 : min_children(1), max_children(MAX_SITECING_SCOREBOARD_SLOTS),
20 min_spare_children(0), max_spare_children(-1), finishing(false),
21 die_humbly(false) {
22 }
23 process_manager::~process_manager() {
24 if(die_humbly)
25 return;
26 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
27 scoreboard_slot *sslot = sboard.get_slot(tmp);
28 if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
29 kill(sslot->pid,SIGTERM);
30 }
31 collect_dead_souls(true);
32 }
33
34 void process_manager::manage() {
35 while(!finishing) {
36 manage_children();
37 // XXX: is it the way it should be?
38 sleep(10);
39 wait_for_children();
40 }
41 collect_dead_souls(true);
42 }
43
44 void process_manager::collect_dead_souls(bool actively) {
45 for(int tries=5;(tries>0) && (sboard.count_slots(scoreboard_slot::state_free)!=MAX_SITECING_SCOREBOARD_SLOTS);tries--) {
46 if(actively) {
47 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
48 scoreboard_slot *sslot = sboard.get_slot(tmp);
49 if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
50 kill(sslot->pid,SIGTERM);
51 }
52 }
53 wait_for_children(false);
54 // XXX: again.. is it the right way?
55 sleep(1);
56 }
57 }
58
59 void process_manager::wait_for_children(bool hang) {
60 int status;
61 int o = WUNTRACED;
62 if(!hang)
63 o|=WNOHANG;
64 while(sboard.count_slots(scoreboard_slot::state_free)<MAX_SITECING_SCOREBOARD_SLOTS) {
65 pid_t pid = waitpid(-1,&status,o);
66 if(!pid)
67 return;
68 if(pid<0) {
69 if(errno==EINTR)
70 return;
71 throw konforka::exception(CODEPOINT,"failed to waitpid()");
72 }
73 assert(pid);
74 int slot = sboard.get_slot_by_pid(pid);
75 sboard.free_slot(slot);
76 if(hang)
77 return;
78 }
79 }
80
81 void process_manager::manage_children() {
82 if(!spawn_children())
83 kill_children();
84 else
85 sleep(1); // just to get some rest.
86 }
87
88 bool process_manager::spawn_children() {
89 int total_children = 0;
90 int idle_children = 0;
91 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
92 switch(sboard.get_slot(tmp)->state) {
93 case scoreboard_slot::state_free:
94 break;
95 case scoreboard_slot::state_idle:
96 idle_children++;
97 default:
98 total_children++;
99 break;
100 }
101 }
102 int total_lack = 0;
103 if(total_children<min_children)
104 total_lack = min_children-total_children;
105 int idle_lack = 0;
106 if(idle_children<min_spare_children)
107 idle_lack = min_spare_children-idle_children;
108 bool rv = false;
109 for(;(idle_lack>0 || total_lack>0) && (total_children<max_children);idle_lack--,total_lack--,total_children++) {
110 spawn_child();
111 rv = true;
112 }
113 return rv;
114 }
115
116 bool process_manager::kill_children() {
117 int idle_children = 0;
118 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
119 if(sboard.get_slot(tmp)->state==scoreboard_slot::state_idle)
120 idle_children++;
121 }
122 int idle_excess = idle_children-max_spare_children;
123 bool rv = false;
124 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS && idle_excess>0;tmp++) {
125 scoreboard_slot *sslot = sboard.get_slot(tmp);
126 if((sslot->state==scoreboard_slot::state_idle) && (sslot->pid>0)) {
127 kill(sslot->pid,SIGTERM);
128 idle_excess--;
129 rv = true;
130 }
131 }
132 return rv;
133 }
134
135 void process_manager::spawn_child() {
136 int slot = sboard.allocate_slot();
137 pid_t pid = fork();
138 if(pid<0) {
139 sboard.free_slot(slot);
140 throw konforka::exception(CODEPOINT,"failed to fork()");
141 }
142 if(!pid) {
143 // child
144 sboard.get_slot(slot)->pid = getpid();
145 process(slot);
146 _exit(0);
147 }
148 // parent
149 sboard.get_slot(slot)->pid = pid;
150 }
151
152}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/ipc.h>
7 #include <sys/shm.h>
8 #include <cassert>
9 #include <string>
10 #include <konforka/exception.h>
11 using namespace std;
12 #include "sitecing/scoreboard.h"
13#endif
14
15namespace sitecing {
16
17 scoreboard::scoreboard()
18 : shmid(-1), slots(NULL) {
19 shmid = shmget(IPC_PRIVATE,MAX_SITECING_SCOREBOARD_SLOTS*sizeof(scoreboard_slot),IPC_CREAT|0600);
20 if(shmid<0)
21 throw konforka::exception(CODEPOINT,"failed to shmget()");
22 slots = (scoreboard_slot*)shmat(shmid,NULL,0);
23 if(shmctl(shmid,IPC_RMID,NULL))
24 throw konforka::exception(CODEPOINT,"failed to shmctl()");
25 if(!slots)
26 throw konforka::exception(CODEPOINT,"failed to shmat()");
27 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++)
28 slots[tmp].state=scoreboard_slot::state_free;
29 }
30 scoreboard::~scoreboard() {
31 shmdt(slots);
32 }
33
34 int scoreboard::allocate_slot() {
35 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
36 if(slots[tmp].state==scoreboard_slot::state_free) {
37 slots[tmp].state=scoreboard_slot::state_allocated;
38 slots[tmp].pid=0;
39 return tmp;
40 }
41 }
42 throw konforka::exception(CODEPOINT,"out of scoreboard slots");
43 }
44 void scoreboard::free_slot(int slot) {
45 assert(slot>=0 && slot<MAX_SITECING_SCOREBOARD_SLOTS);
46 if(slots[slot].state==scoreboard_slot::state_free)
47 throw konforka::exception(CODEPOINT,"freeing unallocated slot");
48 slots[slot].state=scoreboard_slot::state_free;
49 }
50
51 scoreboard_slot *scoreboard::get_slot(int slot) {
52 assert(slot>=0 && slot<MAX_SITECING_SCOREBOARD_SLOTS);
53 return &slots[slot];
54 }
55 int scoreboard::get_slot_by_pid(pid_t pid) {
56 for(int rv=0;rv<MAX_SITECING_SCOREBOARD_SLOTS;rv++)
57 if( (slots[rv].state!=scoreboard_slot::state_free) && (slots[rv].pid == pid) )
58 return rv;
59 throw konforka::exception(CODEPOINT,"no such process");
60 }
61
62 int scoreboard::count_slots(enum scoreboard_slot::_state state) {
63 int rv = 0;
64 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
65 if(slots[tmp].state==state)
66 rv++;
67 }
68 return rv;
69 }
70
71}
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 @@
1%{
2#include <iostream>
3#include <fstream>
4#include <cassert>
5#include <stdexcept>
6using namespace std;
7#include "sitecing/sitecing_exception.h"
8using namespace sitecing;
9#define sitecing_enflesher_flexlexer_once
10#include "sitecing/sitecing_enflesher.h"
11#include "sitecing/sitecing_parser.h"
12#undef yyFlexLexer
13#define yyFlexLexer sitecing_enflesherFlexLexer
14%}
15%option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug
16
17 ID[A-Za-z_][A-Za-z0-9_]*
18
19%%
20
21 ^\%\%\#[^\n]+\n{
22 string line = yytext;
23 line.erase(0,3);
24 line.erase(line.length()-1);
25 outs.flush();
26 outs.close();
27 outs.clear();
28 outs.open((parser.output_basename+line).c_str(),ios::trunc);
29 if(!outs.good())
30 throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
31 anchor();
32 anchoraged = true;
33}
34 ^\%\%[^\n]+\n{
35 string line = yytext;
36 line.erase(0,2);
37 line.erase(line.length()-1);
38 outs.flush();
39 outs.close();
40 outs.clear();
41 outs.open((parser.output_basename+line).c_str(),ios::trunc);
42 if(!outs.good())
43 throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
44 anchoraged = false;
45}
46
47 \<\%component_basename\%\>outs << parser.component_basename; anchor_time = true;
48 \<\%impl\%\> outs << parser.impl; anchor_time = true;
49 \<\%member_functions:impl\%\>{
50 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
51 outs << i->type << " " << parser.class_name << "::";
52 if(i->name.empty()) {
53 outs << parser.class_name << "()";
54 bool first = true;
55 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
56 if(i->initializer.empty())
57 continue;
58 if(first) {
59 outs << ":";
60 first=false;
61 }else{
62 outs << ",";
63 }
64 if(i->bComponent) {
65 outs << i->name << "(NULL)";
66 }else {
67 outs << i->name << "(" << i->initializer << ")";
68 }
69 }
70 }else if(i->name == "~")
71 outs << "~" << parser.class_name << "()";
72 else
73 outs << i->name << i->args;
74 outs << "{\n" << i->body << "\n}\n";
75 }
76 anchor_time = true;
77}
78 \<\%class_name\%\> outs << parser.class_name; anchor_time = true;
79 \<\%baseclass_header\%\>outs << parser.base_header; anchor_time = true;
80 \<\%decl\%\> outs << parser.decl; anchor_time = true;
81 \<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true;
82 \<\%member_variables:decl\%\>{
83 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
84 if(i->bComponent) {
85 if(i->type.empty()) {
86 i->type = parser.factory.get_classname(i->initializer);
87 }
88 if(i->bTypeOnly) {
89 outs << "typedef " << i->type << " " << i->name << ";\n";
90 }else{
91 outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n";
92 }
93 }else{
94 outs << i->type << " " << i->name << ";\n";
95 }
96 }
97 anchor_time = true;
98}
99 \<\%member_functions:decl\%\>{
100 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
101 (i->name.empty()?outs:outs << "virtual ")
102 << i->type << " ";
103 if(i->name.empty()) {
104 outs << parser.class_name << "()";
105 }else if(i->name == "~")
106 outs << "~" << parser.class_name << "()";
107 else
108 outs << i->name << i->args;
109 outs << ";\n";
110 }
111 anchor_time = true;
112}
113 \<\%imports:list\%\> {
114 for(sitecing_parser::member_variables_t::const_iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
115 if(i->bComponent)
116 outs << i->initializer << endl;
117 }
118 anchor_time = true;
119}
120 \<\%imports:includes\%\>{
121 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
122 if(i->bComponent)
123 outs << "\n#include \"" << i->initializer << ".h\"\n";
124 }
125 anchor_time = true;
126}
127 \<\%imports:import\%\>{
128 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
129 if(!i->bComponent)
130 continue;
131 if(i->bTypeOnly)
132 continue;
133 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";
134 }
135 anchor_time = true;
136}
137
138 \<\%base_component\%\> {
139 // TODO:
140 anchor_time = true;
141}
142
143 \<\%ancestors:includes\%\>{
144 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
145 outs << "#include \"" << i->path << ".h\"\n";
146 }
147 anchor_time = true;
148}
149 \<\%ancestors:component_list\%\>{
150 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
151 outs << i->path << "\n";
152 }
153 anchor_time = true;
154}
155 \<\%ancestors:base_clause_part\%\>{
156 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
157 outs << ", virtual public " << parser.factory.get_classname(i->path);
158 }
159}
160 \<\%ancestors:typedefs\%\> {
161 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
162 outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n";
163 }
164 anchor_time = true;
165}
166 \<\%ancestors:import\%\> {
167 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
168 outs << i->name << "::__do_imports();\n";
169 }
170 anchor_time = true;
171}
172
173 \n {
174 if(anchor_time)
175 anchor();
176 ECHO;
177}
178 . ECHO;
179
180%%
181
182void sitecing_enflesher::LexerOutput(const char *buf,int size) {
183 outs.write(buf,size);
184}
185
186void sitecing_enflesher::enflesh() {
187 ifstream ifs(parser.skeleton.c_str());
188 if(!ifs.good())
189 throw preprocessor_error(CODEPOINT,"failed to open skeleton file");
190 switch_streams(&ifs,NULL);
191 yylex();
192}
193
194void sitecing_enflesher::anchor() {
195 if(!anchoraged)
196 return;
197 outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
198 anchor_time = false;
199}
200/*
201 * vim:set ft=lex:
202 */
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 @@
1#include <cassert>
2#include "sitecing/sitecing_interface_cgi.h"
3
4namespace sitecing {
5
6 sitecing_interface_cgi::sitecing_interface_cgi(sitespace *s)
7 : sitecing_interface(&prebuffer), ss(s), cgigw(NULL) {
8 }
9
10 void sitecing_interface_cgi::prepare(kingate::cgi_gateway *cg) {
11 cgigw = cg;
12 headers.clear();
13 headers["Content-Type"] = "text/html";
14 prebuffer.str("");
15 }
16
17 void sitecing_interface_cgi::flush() {
18 assert(cgigw);
19 for(headers_t::const_iterator i=headers.begin();i!=headers.end();i++)
20 cgigw->out() << i->first << ": " << i->second << "\n";
21 (cgigw->out() << "\n").write(prebuffer.str().c_str(),prebuffer.tellp());
22 cgigw->out().flush();
23 }
24
25}
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 @@
1%{
2 /*
3 * XXX: I have a strong feeling that this parser should be completely rewritten.
4 */
5#include <iostream>
6#include <fstream>
7#include <cassert>
8#include <stdexcept>
9using namespace std;
10#include "sitecing/sitecing_util.h"
11#include "sitecing/sitecing_exception.h"
12using namespace sitecing;
13#define sitecing_parser_flexlexer_once
14#include "sitecing/sitecing_parser.h"
15#include "sitecing/sitecing_enflesher.h"
16#undef yyFlexLexer
17#define yyFlexLexer sitecing_parserFlexLexer
18%}
19%x SLASHSTAR_COMMENT SLASHSLASH_COMMENT STRING
20%x CODELINE CLASSLINE DECLLINE IMPLLINE DECLBLOCK IMPLBLOCK VARLINE VARINIT
21%x IMPORTLINE IMPORTCOMPONENT
22%x IMPORTTYPELINE IMPORTTYPECOMPONENT
23%x DERIVELINE DERIVECOMPONENT
24%x CONSTRUCTOR DESTRUCTOR CODEMETHODLINE CODEMETHODARGS
25%x CODEMETHODBLOCK INLINE METHODLINE METHODARGS METHODBLOCK CODEBLOCK OUTPUTBLOCK
26%option 8bit c++ verbose noyywrap yyclass="sitecing_parser" prefix="sitecing_parser" stack yylineno
27
28 WHITESPACE[ \t]
29 ID [A-Za-z_][A-Za-z0-9_]*
30 NOIDCHAR[^A-Za-z0-9_]
31
32%%
33
34<INITIAL>{
35 ^\%\%class{WHITESPACE}+{
36 // TODO: signal error if we already have class name acquired from source.
37 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments|modus_operandi::flag_devour_whitespace));
38 BEGIN(CLASSLINE);
39 }
40 ^\%\%decl{WHITESPACE}+{
41 modi.push_front(modus_operandi(0));
42 anchor();
43 BEGIN(DECLLINE);
44 }
45 ^\%\%impl{WHITESPACE}+{
46 modi.push_front(modus_operandi(0));
47 anchor();
48 BEGIN(IMPLLINE);
49 }
50 \<\%decl\> {
51 modi.push_front(modus_operandi(0));
52 anchor();
53 BEGIN(DECLBLOCK);
54 }
55 \<\%impl\> {
56 modi.push_front(modus_operandi(0));
57 anchor();
58 BEGIN(IMPLBLOCK);
59 }
60 ^\%\%var{WHITESPACE}+{
61 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
62 anchor();
63 BEGIN(VARLINE);
64 }
65 ^\%\%import{WHITESPACE}+{
66 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
67 BEGIN(IMPORTLINE);
68 }
69 ^\%\%import_type{WHITESPACE}+ {
70 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
71 BEGIN(IMPORTTYPELINE);
72 }
73 ^\%\%derive{WHITESPACE}+{
74 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
75 BEGIN(DERIVELINE);
76 }
77 \<\%constructor\>{
78 modi.push_front(modus_operandi());
79 anchor();
80 BEGIN(CONSTRUCTOR);
81 }
82 \<\%destructor\>{
83 modi.push_front(modus_operandi());
84 anchor();
85 BEGIN(DESTRUCTOR);
86 }
87 \<\%codemethod{WHITESPACE}+{
88 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
89 anchor();
90 BEGIN(CODEMETHODLINE);
91 }
92 \<\%method{WHITESPACE}+ {
93 modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
94 anchor();
95 BEGIN(METHODLINE);
96 }
97 <<EOF>>{
98 assert(modi.size()==1);
99 M().modify(modus_operandi::modus_preop);
100 LexerOutput(";",1);
101 return 0;
102 }
103}
104 <<EOF>>throw preprocessor_error(CODEPOINT,"unexpected end of file",lineno());
105
106<CODEBLOCK,CODEMETHODBLOCK>{
107 "<%output>"{
108 anchor();
109 yy_push_state(OUTPUTBLOCK);
110 }
111}
112
113<METHODLINE>{
114 {WHITESPACE}+{
115 modus_operandi& m = modi.front();
116 if(!m.output.empty()) {
117 if(!m._lastid.empty()) {
118 if(!m._type.empty()) m._type += ' ';
119 m._type += m._lastid;
120 }
121 m._lastid = m.output;
122 m.output.clear();
123 }
124 }
125 \*{
126 modus_operandi& m = modi.front();
127 ECHO;
128 if(!m._lastid.empty()) {
129 if(!m._type.empty()) m._type += ' ';
130 m._type += m._lastid;
131 }
132 m._lastid = m.output;
133 m.output.clear();
134 }
135 \({
136 modus_operandi& m = modi.front();
137 if(m.output.empty()) {
138 m._name=m._lastid;
139 }else{
140 if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy...
141 if(!m._type.empty()) m._type += ' ';
142 m._type += m._lastid;
143 }
144 m._name = m.output;
145 m.output.clear();
146 }
147 ECHO;
148 BEGIN(METHODARGS);
149 }
150}
151<METHODARGS>{
152 \%\>{
153 modus_operandi& m = modi.front();
154 m._args = m.output;
155 m.output.clear();
156 anchor();
157 BEGIN(METHODBLOCK);
158 }
159}
160
161<INITIAL,METHODBLOCK,OUTPUTBLOCK>{
162 \<\%{WHITESPACE}+{
163 M().modify(modus_operandi::modus_postop);
164 anchor();
165 LexerOutput("(",1);
166 yy_push_state(INLINE);
167 }
168 ^\%{WHITESPACE}{
169 M().modify(modus_operandi::modus_code);
170 anchor();
171 yy_push_state(CODELINE);
172 }
173 \<\%code\>{
174 M().modify(modus_operandi::modus_code);
175 anchor();
176 yy_push_state(CODEBLOCK);
177 }
178 "</%output>" {
179 if(YY_START!=OUTPUTBLOCK) throw preprocessor_error(CODEPOINT,"unexpected tag",lineno());
180 M().modify(modus_operandi::modus_code);
181 anchor();
182 yy_pop_state();
183 }
184}
185
186 <INLINE>\%\>LexerOutput(")",1); M().modus=modus_operandi::modus_preop; yy_pop_state();
187 <CODELINE>\nyy_pop_state();
188
189<CODEMETHODLINE>{
190 {WHITESPACE}+{
191 modus_operandi& m = modi.front();
192 if(!m.output.empty()) {
193 if(!m._lastid.empty()) {
194 if(!m._type.empty()) m._type += ' ';
195 m._type += m._lastid;
196 }
197 m._lastid = m.output;
198 m.output.clear();
199 }
200 }
201 \*{
202 modus_operandi& m = modi.front();
203 ECHO;
204 if(!m._lastid.empty()) {
205 if(!m._type.empty()) m._type += ' ';
206 m._type += m._lastid;
207 }
208 m._lastid = m.output;
209 m.output.clear();
210 }
211 \({
212 modus_operandi& m = modi.front();
213 if(m.output.empty()) {
214 m._name=m._lastid;
215 }else{
216 if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy...
217 if(!m._type.empty()) m._type += ' ';
218 m._type += m._lastid;
219 }
220 m._name = m.output;
221 m.output.clear();
222 }
223 ECHO;
224 BEGIN(CODEMETHODARGS);
225 }
226}
227<CODEMETHODARGS>{
228 \%\>{
229 modus_operandi& m = modi.front();
230 m._args = m.output;
231 m.output.clear();
232 m.flags=0;
233 anchor();
234 BEGIN(CODEMETHODBLOCK);
235 }
236}
237
238<IMPORTLINE>{
239 {WHITESPACE}+{ }
240 {ID}{
241 if(!modi.front()._name.empty())
242 throw preprocessor_error(CODEPOINT,"syntax error",lineno());
243 modi.front()._name = yytext;
244 }
245 \= {
246 modi.front().output.clear();
247 BEGIN(IMPORTCOMPONENT);
248 }
249}
250<IMPORTCOMPONENT>{
251 {WHITESPACE}+{ }
252 \n{
253 modus_operandi& m = M();
254 string::size_type t = m.output.find_first_not_of(" \t");
255 if(t!=string::npos)
256 m.output.erase(0,t);
257 t = m.output.find_last_not_of(" \t;");
258 if(t!=string::npos)
259 m.output.erase(t+1);
260 if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') {
261 m.output.erase(0,1);
262 m.output.erase(m.output.length()-1);
263 }
264 string c = combine_path(component_basename,m.output);
265 member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true));
266 modi.pop_front();
267 BEGIN(INITIAL);
268 }
269}
270
271<IMPORTTYPELINE>{
272 {WHITESPACE}+{ }
273 {ID}{
274 if(!modi.front()._name.empty())
275 throw preprocessor_error(CODEPOINT,"syntax error",lineno());
276 modi.front()._name = yytext;
277 }
278 \= {
279 modi.front().output.clear();
280 BEGIN(IMPORTTYPECOMPONENT);
281 }
282}
283<IMPORTTYPECOMPONENT>{
284 {WHITESPACE}+{ }
285 \n{
286 modus_operandi& m = M();
287 string::size_type t = m.output.find_first_not_of(" \t");
288 if(t!=string::npos)
289 m.output.erase(0,t);
290 t = m.output.find_last_not_of(" \t;");
291 if(t!=string::npos)
292 m.output.erase(t+1);
293 if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') {
294 m.output.erase(0,1);
295 m.output.erase(m.output.length()-1);
296 }
297 string c = combine_path(component_basename,m.output);
298 member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true,true));
299 modi.pop_front();
300 BEGIN(INITIAL);
301 }
302}
303
304<DERIVELINE>{
305 {WHITESPACE}+{ }
306 {ID}{
307 if(!modi.front()._name.empty())
308 throw preprocessor_error(CODEPOINT,"syntax_error",lineno());
309 modi.front()._name = yytext;
310 }
311 \= {
312 modi.front().output.clear();
313 BEGIN(DERIVECOMPONENT);
314 }
315}
316<DERIVECOMPONENT>{
317 {WHITESPACE}+{ }
318 \n {
319 modus_operandi& m = M();
320 string::size_type t = m.output.find_first_not_of(" \t");
321 if(t!=string::npos)
322 m.output.erase(0,t);
323 t = m.output.find_last_not_of(" \t;");
324 if(t!=string::npos)
325 m.output.erase(t+1);
326 if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') {
327 m.output.erase(0,1);
328 m.output.erase(m.output.length()-1);
329 }
330 string c = combine_path(component_basename,m.output);
331 ancestor_classes.push_back(ancestor_class(m._name,normalize_path(c,strip_leading_slash)));
332 modi.pop_front();
333 BEGIN(INITIAL);
334 }
335}
336
337<VARLINE>{
338 {WHITESPACE}+{
339 modus_operandi& m = modi.front();
340 if(!m.output.empty()) {
341 if(!m._lastid.empty()) {
342 if(!m._type.empty()) m._type += ' ';
343 m._type += m._lastid;
344 }
345 m._lastid = m.output;
346 m.output.clear();
347 }
348 }
349 \*{
350 modus_operandi& m = modi.front();
351 ECHO;
352 if(!m._lastid.empty()) {
353 if(!m._type.empty()) m._type += ' ';
354 m._type += m._lastid;
355 }
356 m._lastid = m.output;
357 m.output.clear();
358 }
359 \;|\n|\={
360 modus_operandi& m = modi.front();
361 if(m.output.empty()) {
362 m._name=m._lastid;
363 }else{
364 if(!m._lastid.empty()) { // XXX: lastid should never be emtpy, I believe?
365 if(!m._type.empty()) m._type += ' ';
366 m._type += m._lastid;
367 }
368 m._name=m.output;
369 m.output.clear();
370 }
371 BEGIN(VARINIT);
372 if(*yytext!='=')
373 unput('\n');
374 }
375}
376<VARINIT>{
377 \n{
378 modus_operandi& m = modi.front();
379 string::size_type t = m.output.find_first_not_of(" \t");
380 if(t!=string::npos)
381 m.output.erase(0,t);
382 t = m.output.find_last_not_of(" \t;");
383 if(t!=string::npos)
384 m.output.erase(t+1);
385 member_variables.push_back(member_variable(m._type,m._name,m.output));
386 if(!m.output.empty())
387 have_initializers=true;
388 modi.pop_front();
389 BEGIN(INITIAL);
390 }
391}
392 <DECLLINE>\n{
393 ECHO;
394 decl += modi.front().output;
395 modi.pop_front();
396 BEGIN(INITIAL);
397}
398 <IMPLLINE>\n{
399 ECHO;
400 impl += modi.front().output;
401 modi.pop_front();
402 BEGIN(INITIAL);
403}
404 <CLASSLINE>\n{
405 class_name = modi.front().output;
406 modi.pop_front();
407 BEGIN(INITIAL);
408}
409<CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK>{
410 "/*"{
411 yy_push_state(SLASHSTAR_COMMENT);
412 if(!M().devour_comments()) {
413 ECHO;
414 }
415 }
416 "//"{
417 yy_push_state(SLASHSLASH_COMMENT);
418 if(!M().devour_comments()) {
419 ECHO;
420 }
421 }
422 \" {
423 yy_push_state(STRING);
424 ECHO;
425 }
426 \'\\.\'{
427 ECHO;
428 }
429}
430
431<INITIAL,METHODBLOCK,OUTPUTBLOCK>{
432 \"soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\\"",2);
433 \nsoft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\n",2);
434 \rsoft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\r",2);
435 \tsoft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\t",2);
436 \bsoft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\b",2);
437 \asoft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\a",2);
438 .soft_anchor(); M().modify(modus_operandi::modus_text); ECHO;
439 {WHITESPACE}+soft_anchor(); M().modify(modus_operandi::modus_text); ECHO;
440}
441
442<DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,METHODBLOCK,CODEBLOCK>{
443 \<\/\%decl\>{
444 if(YY_START!=DECLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
445 decl += modi.front().output;
446 modi.pop_front();
447 BEGIN(INITIAL);
448 }
449 \<\/\%impl\>{
450 if(YY_START!=IMPLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
451 impl += modi.front().output;
452 modi.pop_front();
453 BEGIN(INITIAL);
454 }
455 \<\/\%constructor\>{
456 if(YY_START!=CONSTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
457 member_functions.push_back(member_function("","","",modi.front().output));
458 have_constructor = true;
459 modi.pop_front();
460 BEGIN(INITIAL);
461 }
462 \<\/\%destructor\>{
463 if(YY_START!=DESTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
464 member_functions.push_back(member_function("","~","",modi.front().output));
465 modi.pop_front();
466 BEGIN(INITIAL);
467 }
468 \<\/\%codemethod\>{
469 if(YY_START!=CODEMETHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
470 modus_operandi& m = modi.front();
471 member_functions.push_back(member_function(m._type,m._name,m._args,m.output));
472 modi.pop_front();
473 BEGIN(INITIAL);
474 }
475 \<\/%method\> {
476 if(YY_START!=METHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
477 modus_operandi& m = modi.front();
478 m.modify(modus_operandi::modus_code);
479 member_functions.push_back(member_function(m._type,m._name,m._args,m.output));
480 modi.pop_front();
481 BEGIN(INITIAL);
482 }
483 \<\/%code\> {
484 if(YY_START!=CODEBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
485 yy_pop_state();
486 }
487 \n ECHO;
488}
489
490<SLASHSTAR_COMMENT>{
491 "*/"{
492 if(!M().devour_comments()) {
493 ECHO;
494 }
495 yy_pop_state();
496 unput(' ');
497 }
498 \n{
499 if(!M().devour_comments()) {
500 ECHO;
501 }
502 }
503}
504<SLASHSLASH_COMMENT>{
505 \n{
506 if(!M().devour_comments()) {
507 ECHO;
508 }
509 yy_pop_state();
510 if(YY_START!=CODEBLOCK && YY_START!=CODEMETHODBLOCK && YY_START!=IMPLBLOCK && YY_START!=DECLBLOCK)
511 unput('\n');
512 }
513}
514 <SLASHSTAR_COMMENT,SLASHSLASH_COMMENT>.{
515 if(!M().devour_comments()) {
516 ECHO;
517 }
518}
519<STRING>{
520 \\.ECHO;
521 \"ECHO; yy_pop_state();
522 .ECHO;
523}
524
525 {WHITESPACE}+{
526 if(!(M().flags&modus_operandi::flag_devour_whitespace)) {
527 ECHO;
528 }
529}
530
531%%
532
533sitecing_parser::sitecing_parser(component_factory& f)
534 : factory(f), have_initializers(false), have_constructor(false),
535 base_class("sitecing::cgi_component"),
536 base_header("sitecing/cgi_component.h"),
537 skeleton(__SC_DEFAULT_SKELETON) {
538 }
539
540void sitecing_parser::preprocess(const string& in) {
541 ifstream ifs(in.c_str(),ios::in);
542 if(!ifs.good())
543 throw preprocessor_error(CODEPOINT,"failed to open input file");
544 input_file = in;
545 modi.push_front(modus_operandi(0));
546 switch_streams(&ifs,NULL);
547 if(yylex())
548 throw preprocessor_error(CODEPOINT,"unknown error");
549 member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output));
550 if(have_initializers && !have_constructor)
551 member_functions.push_back(member_function("","","",""));
552 sitecing_enflesher enflesher(*this);
553 enflesher.enflesh();
554}
555
556void sitecing_parser::LexerOutput(const char* buf,int size) {
557 assert(modi.size());
558 M().output.append(buf,size);
559}
560
561static const char *modus_transitions
562 [sitecing_parser::modus_operandi::modi]
563 [sitecing_parser::modus_operandi::modi] = {
564// To:
565// code preop postop text From:
566 { "", "(*(__SCIF->out))", "(*(__SCIF->out))<<", "(*(__SCIF->out))<<\"" }, // code
567 { ";", "", "<<", "<<\"" }, // preop
568 { NULL, NULL, "", "\"" }, // postop
569 { "\";", "\"", "\"<<", "" } // text
570};
571
572void sitecing_parser::modus_operandi::modify(modus_t m) {
573 const char * x = modus_transitions[modus][m];
574 assert(x);
575 output += x;
576 modus = m;
577}
578
579void sitecing_parser::soft_anchor() {
580 if(M().modus!=modus_operandi::modus_text)
581 anchor();
582}
583void sitecing_parser::anchor() {
584 if(M().modus==modus_operandi::modus_text)
585 M().modify(modus_operandi::modus_preop);
586 M().output += "\n#line ";
587 char tmp[7];
588 snprintf(tmp,sizeof(tmp),"%d",lineno());
589 M().output += tmp;
590 M().output += " \"";
591 M().output += input_file;
592 M().output += "\"\n";
593}
594/* 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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <sys/ipc.h>
9 #include <sys/sem.h>
10 #include <errno.h>
11 #include <iostream>
12 #include <fstream>
13 #include <cassert>
14 #include "sitecing/sitecing_util.h"
15#endif
16
17namespace sitecing {
18
19 /*
20 * XXX: all of these utilities could be sheerly optimized.
21 */
22
23 string normalize_path(const string& path,int opts) {
24 const char *s = path.c_str();
25 string rv;
26 string::size_type notslash = 0;
27 if( (*s)=='.' && s[1]=='/' )
28 s+=2;
29 if(opts&strip_leading_slash)
30 for(;(*s) && (*s)=='/';s++);
31 for(;*s;s++) {
32 if( (*s)=='/' ) {
33 if(s[1]=='/')
34 continue;
35 if(s[1]=='.' && s[2]=='/') {
36 s+=2;
37 continue;
38 }
39 }
40 if(opts&restrict_dotdot) {
41 if(
42 ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' )// "^../"
43 || ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)"
44 )
45 throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered");
46 }
47 rv += *s;
48 if( (*s) != '/' )
49 notslash=rv.length();
50 }
51 if(!(opts&strip_trailing_slash))
52 notslash++;
53 if(notslash<rv.length())
54 rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash
55 return rv;
56 }
57
58 string strip_prefix(const string& str,const string& prefix) {
59 if(str.compare(0,prefix.length(),prefix))
60 throw utility_no_prefix(CODEPOINT,"no such prefix");
61 return str.substr(prefix.length());
62 }
63
64 string strip_suffix(const string& str,const string& suffix) {
65 if(str.compare(str.length()-suffix.length(),suffix.length(),suffix))
66 throw utility_no_suffix(CODEPOINT,"no such suffix");
67 return str.substr(0,str.length()-suffix.length());
68 }
69
70 string dir_name(const string& filename) {
71 string::size_type sl = filename.find_last_of('/');
72 if(sl==string::npos)
73 return ""; // no slashes -- no dir.
74 string::size_type nosl = filename.find_last_not_of('/',sl);
75 if(nosl==string::npos)
76 return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir?
77 return filename.substr(0,nosl+1);
78 }
79
80 void make_path(const string& path,mode_t mode) {
81 struct stat st;
82 for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) {
83 if(!sl)
84 continue;
85 string p = path.substr(0,sl);
86 if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) {
87 if(mkdir(p.c_str(),mode))
88 throw konforka::exception(CODEPOINT,"failed to mkdir()");
89 }
90 }
91 if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) {
92 if(mkdir(path.c_str(),mode))
93 throw konforka::exception(CODEPOINT,"failed to mkdir()");
94 }
95 }
96
97 void file_lock::lock(const string& f) {
98 unlock();
99 fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
100 if(fd<0)
101 throw konforka::exception(CODEPOINT,"failed to open/create lockfile");
102 try {
103 lock();
104 }catch(konforka::exception& ke) {
105 ke.see(CODEPOINT);
106 close(fd); fd=-1;
107 throw;
108 }catch(...) {
109 close(fd); fd=-1;
110 throw;
111 }
112 }
113 void file_lock::lock() {
114 assert(fd>=0);
115 struct flock fl;
116 fl.l_type = F_WRLCK;
117 fl.l_whence=SEEK_SET;
118 fl.l_start=fl.l_len=0;
119 for(int tries=3;tries;tries--) {
120 if(!fcntl(fd,F_SETLK,&fl))
121 return;
122 sleep(8);
123 }
124 throw konforka::exception(CODEPOINT,"failed to obtain file lock");
125 }
126 void file_lock::unlock() {
127 if(fd<0)
128 return;
129 struct flock fl;
130 fl.l_type = F_UNLCK;
131 fl.l_whence=SEEK_SET;
132 fl.l_start=fl.l_len=0;
133 int rv = fcntl(fd,F_SETLK,&fl);
134 close(fd);
135 fd=-1;
136 if(rv)
137 throw konforka::exception(CODEPOINT,"failed to release file lock");
138 }
139
140 void pid_file::set(const string& f,bool u) {
141 ofstream of(f.c_str(),ios::trunc);
142 if(!of)
143 throw konforka::exception(CODEPOINT,"failed to open file for writing pid");
144 of << getpid() << endl;
145 of.close();
146 file_name = f;
147 unlink_pid = u;
148 }
149 void pid_file::unlink() {
150 if(!unlink_pid)
151 return;
152 ::unlink(file_name.c_str());
153 }
154
155 void semaphore::init() {
156 deinit();
157 semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600);
158 if(semid<0)
159 throw konforka::exception(CODEPOINT,"failed to semget()");
160 if(semctl(semid,0,SETVAL,1))
161 throw konforka::exception(CODEPOINT,"failed to semctl()");
162 }
163 void semaphore::deinit() {
164 if(semid<0)
165 return;
166 semctl(semid,0,IPC_RMID,0);
167 }
168 void semaphore::on() {
169 assert(semid>=0);
170 struct sembuf sb;
171 sb.sem_num=0;
172 sb.sem_op=-1;
173 sb.sem_flg = SEM_UNDO;
174 while(semop(semid,&sb,1)<0) {
175 if(errno!=EINTR)
176 throw konforka::exception(CODEPOINT,"failed to semop()");
177 }
178 }
179 void semaphore::off() {
180 assert(semid>=0);
181 struct sembuf sb;
182 sb.sem_num=0;
183 sb.sem_op=1;
184 sb.sem_flg = SEM_UNDO;
185 while(semop(semid,&sb,1)<0) {
186 if(errno!=EINTR)
187 throw konforka::exception(CODEPOINT,"failed to semop()");
188 }
189 }
190
191 void semaphore_lock::lock() {
192 assert(sem);
193 if(locked)
194 return;
195 sem->on();
196 locked = true;
197 }
198 void semaphore_lock::unlock() {
199 if(!sem)
200 return;
201 if(!locked)
202 return;
203 sem->off();
204 locked=false;
205 }
206
207 string combine_path(const string& origin,const string& relative,int opts) {
208 string r = normalize_path(relative,0);
209 string rv;
210 // XXX: what to do if relative is empty is a question, really.
211 if(r.empty()) {
212 return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash);
213 }else{
214 if(r[0]=='/') {
215 r.erase(0,1);
216 }else{
217 rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash);
218 }
219 }
220 string::size_type lsl = rv.rfind('/');
221 for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) {
222 assert(sl!=0);
223 if(sl==1 && r[0]=='.') {
224 // it's a "./"
225 r.erase(0,2);
226 }else if(sl==2 && r[0]=='.' && r[1]=='.') {
227 // we have a "../"
228 if(lsl==string::npos) {
229 if(rv.empty() && (opts&fail_beyond_root))
230 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
231 rv.clear();
232 }else{
233 rv.erase(lsl);
234 lsl = rv.rfind('/');
235 }
236 r.erase(0,3);
237 }else{
238 // we have a "something/"
239 lsl = rv.length();
240 rv += '/';
241 rv += r.substr(0,sl);
242 r.erase(0,sl+1);
243 }
244 }
245 if(r.empty())
246 return rv+'/';
247 if(r.length()==2 && r[0]=='.' && r[0]=='.') {
248 if(lsl==string::npos) {
249 if(rv.empty() & (opts&fail_beyond_root))
250 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
251 return "/";
252 }else{
253 rv.erase(lsl+1);
254 return rv;
255 }
256 }
257 rv += '/';
258 rv += r;
259 return rv;
260 }
261
262 void auto_chdir::pushdir(const string& td,bool ap) {
263 char *tmp = get_current_dir_name();
264 assert(tmp);
265 saved_pwd = tmp;
266 free(tmp);
267 autopop=ap;
268 if(chdir(td.c_str()))
269 throw konforka::exception(CODEPOINT,"failed to chdir()");
270 }
271 void auto_chdir::popdir() {
272 autopop=false;
273 if(chdir(saved_pwd.c_str()))
274 throw konforka::exception(CODEPOINT,"failed to chdir()");
275 // XXX: or should it be thrown? after all we call it from destructor...
276 }
277
278}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <cassert>
5 #include "sitecing/sitespace.h"
6 #include "sitecing/sitecing_util.h"
7#endif
8
9namespace sitecing {
10
11 sitespace::sitespace(configuration& c)
12 : config(c), factory(c) { }
13
14 sitespace::~sitespace() {
15 for(sentenced_t::iterator i = sentenced.begin();i!=sentenced.end();++i) {
16 assert((*i)->chickens_used.empty());
17 delete *i;
18 }
19 }
20
21 so_component sitespace::fetch(const string& c,sitecing_interface* scif) {
22 execute_sentenced();
23 string sobase = normalize_path(c);
24 string sopath = factory.root_so+sobase+".so";
25 config_options *co_build = config.lookup_config(sobase,config_options::flag_build);
26 if( (!co_build) || co_build->build )
27 factory.make(sopath);
28 components_t::iterator i = components.find(sopath);
29 if(i!=components.end()) {
30 if(i->second->is_uptodate())
31 return so_component(i->second,scif);
32 if(i->second->chickens_used.empty()) {
33 delete i->second;
34 }else{
35 sentenced.push_back(i->second);
36 }
37 components.erase(i);
38 }
39 pair<components_t::iterator,bool> ins = components.insert(components_t::value_type(sopath,new component_so(sopath)));
40 return so_component(ins.first->second,scif);
41 }
42
43 void sitespace::execute_sentenced() {
44 for(sentenced_t::iterator i = sentenced.begin();i!=sentenced.end();++i) {
45 if((*i)->chickens_used.empty()) {
46 delete *i;
47 sentenced.erase(i);
48 }
49 }
50 }
51
52}
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 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <cassert>
5 #include "sitecing/util.h"
6#endif
7
8namespace sitecing {
9
10 static const char *unsafeChars = "<>& \n\"";
11
12 string html_escape(const string& str,int flags) {
13 string rv = str;
14 string::size_type screwed = 0;
15 for(;;) {
16 screwed = rv.find_first_of(unsafeChars,screwed);
17 if(screwed == string::npos)
18 break;
19 while(screwed<rv.length() && strchr(unsafeChars,rv.at(screwed))) {
20 char danger = rv.at(screwed);
21 switch(danger) {
22 case '<':
23 rv.replace(screwed,1,"&lt;"); screwed+=4;
24 break;
25 case '>':
26 rv.replace(screwed,1,"&gt;"); screwed+=4;
27 break;
28 case '&':
29 rv.replace(screwed,1,"&amp;"); screwed+=5;
30 break;
31 case ' ':
32 if(flags&html_escape_nbsp) {
33 rv.replace(screwed,1,"&nbsp;"); screwed+=6;
34 }else
35 screwed++;
36 break;
37 case '\n':
38 if(flags&html_escape_br) {
39 if(flags&html_escape_br_noslash) {
40 rv.replace(screwed,1,"<br>\n"); screwed += 5;
41 }else{
42 rv.replace(screwed,1,"<br/>\n"); screwed += 6;
43 }
44 }else
45 screwed++;
46 break;
47 case '\"':
48 if(flags&html_escape_quot) {
49 rv.replace(screwed,1,"&quot;"); screwed+=6;
50 }else
51 screwed++;
52 break;
53 default:
54 assert(false);
55 break;
56 }
57 }
58 }
59 return rv;
60 }
61
62 void checkpoint::set() {
63 point = stream->tellp();
64 if(last_will==will_intestate)
65 last_will = will_rollback;
66 }
67
68 void checkpoint::make_will(will_t lw) {
69 last_will = lw;
70 }
71
72 void checkpoint::rollback() {
73 stream->seekp(point);
74 if(last_will == will_rollback)
75 last_will = will_intestate;
76 }
77 void checkpoint::commit() {
78 point = stream->tellp();
79 if(last_will == will_rollback)
80 last_will = will_intestate;
81 }
82
83}
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 @@
1Makefile.in
2Makefile
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 @@
1pkgdata_DATA = component.skel
2
3EXTRA_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 @@
1%%#.cc
2#include "<%component_basename%>.h"
3#undef __THIS_CLASS
4#define __THIS_CLASS <%class_name%>
5<%impl%>
6
7<%member_functions:impl%>
8
9void *<%class_name%>::__the_most_derived_this() {
10 return this;
11}
12void <%class_name%>::__do_imports() {
13 __base_class::__do_imports();
14 <%ancestors:import%>
15 <%imports:import%>
16}
17
18extern "C" sitecing::acomponent* _egg () {
19 return dynamic_cast<sitecing::acomponent*>(new <%class_name%>());
20}
21%%#.h
22#ifndef __<%class_name%>_H
23#define __<%class_name%>_H
24#include "<%baseclass_header%>"
25<%ancestors:includes%>
26<%imports:includes%>
27#undef __THIS_CLASS
28#define __THIS_CLASS <%class_name%>
29<%decl%>
30
31class <%class_name%> : virtual public <%baseclass_name%><%ancestors:base_clause_part%> {
32 public:
33 typedef <%baseclass_name%> __base_class;
34 typedef <%class_name%> __this_class;
35 <%ancestors:typedefs%>
36 <%member_variables:decl%>
37
38 <%member_functions:decl%>
39
40 virtual void *__the_most_derived_this();
41 virtual void __do_imports();
42};
43
44#undef __THIS_CLASS
45#endif /* __<%class_name%>_H */
46%%.imports
47<%imports:list%>
48%%.classname
49<%class_name%>
50%%.basecomponent
51<%base_component%>
52%%.ancestors
53<%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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3bindir=@bindir@
4libdir=@libdir@
5includedir=@includedir@
6
7Name: sitecing
8Description: site-C-ing web site development engine
9Version: @VERSION@
10Requires: kingate konforka
11Cflags: -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 @@
1Makefile.in
2sitecing-build
3sitecing-fastcgi
4COPYING.o
5.libs
6.deps
7COPYING.cc
8Makefile
9*.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 @@
1bin_PROGRAMS = sitecing-fastcgi sitecing-build
2
3INCLUDES = -I${top_srcdir}/include ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \
4 ${PCREPP_CFLAGS}
5LIBS += ${top_builddir}/lib/libsitecing.la ${KINGATE_LIBS} ${DOTCONF_LIBS} \
6 ${PCREPP_LIBS}
7
8sitecing_fastcgi_SOURCES = sitecing-fastcgi.cc \
9 COPYING.cc
10sitecing_fastcgi_LDFLAGS = -rdynamic
11sitecing_fastcgi_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la
12
13sitecing_build_SOURCES = sitecing-build.cc \
14 COPYING.cc
15sitecing_build_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la
16
17COPYING.cc: ${top_srcdir}/COPYING
18 echo "const char * COPYING =" >$@ || (rm $@;exit 1)
19 sed 's/"/\\"/g' $< | sed 's/^/\"/' | sed 's/$$/\\n\"/' >>$@ || (rm $@;exit 1)
20 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 @@
1#include <sys/types.h>
2#include <dirent.h>
3#include <getopt.h>
4#include <iostream>
5#include <memory>
6#include <fstream>
7#include <cassert>
8#include <set>
9using namespace std;
10#include "sitecing/sitecing_util.h"
11#include "sitecing/util.h"
12#include "sitecing/sitespace.h"
13#include "sitecing/sitecing_interface_cgi.h"
14#include "sitecing/cgi_component.h"
15#include "sitecing/configuration.h"
16#include "sitecing/magic.h"
17#include "sitecing/sitecing_exception.h"
18#include "sitecing/exception.h"
19using namespace sitecing;
20
21#include "config.h"
22#define PHEADER PACKAGE "-build Version " VERSION
23#define PCOPY "Copyright (c) 2004 Klever Group"
24
25static sitespace* site_space = NULL;
26typedef pair<dev_t,ino_t> the_inode_t;
27set<the_inode_t> built_inodes;
28
29void build_component(const string& component) {
30 assert(site_space);
31 cerr << "Building " << component << endl;
32 try {
33 site_space->factory.make(site_space->config.root_so+component+".so");
34 }catch(compile_error& ce) {
35 ce.see(CODEPOINT);
36 ifstream err((site_space->config.root_intermediate+ce.component_path+".stderr").c_str(),ios::in);
37 if(err) {
38 cerr << err.rdbuf();
39 }
40 throw;
41 }catch(preprocessor_error& pe) {
42 pe.see(CODEPOINT);
43 cerr << site_space->config.root_source << pe.component_name << ":" << pe.line_number << ":" << pe.what() << endl;
44 throw;
45 }
46}
47
48void build_imports(const string& component);
49
50void build_with_imports(const string& component) {
51 assert(site_space);
52 struct stat st;
53 string cp = site_space->config.root_source+component;
54 if(!lstat(cp.c_str(),&st)) {
55 if(built_inodes.find(the_inode_t(st.st_dev,st.st_ino))!=built_inodes.end())
56 return;
57 built_inodes.insert(the_inode_t(st.st_dev,st.st_ino));
58 }
59 build_component(component);
60 build_imports(component);
61}
62
63void build_imports(const string& component) {
64 assert(site_space);
65 ifstream ifs((site_space->config.root_intermediate+component+".imports").c_str(),ios::in);
66 cerr << "Building components imported by " << component << endl;
67 if(ifs) {
68 string import;
69 while(!ifs.eof()) {
70 ifs >> import;
71 if(!import.empty())
72 build_with_imports(import);
73 }
74 }
75}
76
77void build_http_status_handlers(const string& target) {
78 assert(site_space);
79 set<string> stop_list;
80 string t = "/";
81 t += normalize_path(target,strip_leading_slash);
82 for(;;) {
83 if(t[t.length()-1]=='/') {
84 loaded_options* lo = site_space->config.lookup_loaded_options(t);
85 if( lo && (lo->flags&config_options::flag_http_status_handlers) ) {
86 for(config_options::http_status_handlers_t::const_iterator i=lo->http_status_handlers.begin();i!=lo->http_status_handlers.end();++i) {
87 if(stop_list.find(i->first)==stop_list.end()) {
88 build_with_imports(i->second);
89 stop_list.insert(i->first);
90 }
91 }
92 }
93 }
94 configuration::specs_t::iterator i=site_space->config.specs.find(t);
95 if( i!=site_space->config.specs.end() && (i->second.flags&config_options::flag_http_status_handlers) ) {
96 for(config_options::http_status_handlers_t::const_iterator ii=i->second.http_status_handlers.begin();ii!=i->second.http_status_handlers.end();++i) {
97 if(stop_list.find(ii->first)==stop_list.end()) {
98 build_with_imports(ii->second);
99 stop_list.insert(ii->first);
100 }
101 }
102 }
103 if(t.empty())
104 return;
105 string::size_type sl=t.rfind('/');
106 if(sl==string::npos) {
107 t.erase();
108 }else{
109 if(sl==(t.length()-1))
110 t.erase(sl);
111 else
112 t.erase(sl+1);
113 }
114 }
115}
116
117void build_target(const string& target) {
118 assert(site_space);
119 string action = target;
120 config_options::action_handler_t *ah = site_space->config.lookup_action_handler(target);
121 if(ah)
122 action = ah->action;
123 build_with_imports(action);
124}
125
126void build(const string& target) {
127 assert(site_space);
128 build_http_status_handlers(target);
129 config_options *co_exception_handler = site_space->config.lookup_config(target,config_options::flag_exception_handler);
130 if(co_exception_handler) {
131 string handler = co_exception_handler->exception_handler;
132 build_with_imports(handler);
133 }
134 string target_source = site_space->config.root_source+target;
135 struct stat st;
136 if(stat(target_source.c_str(),&st))
137 throw konforka::exception(CODEPOINT,"failed to stat() target");
138 if(S_ISREG(st.st_mode)) {
139 build_target(target);
140 }else if(S_ISDIR(st.st_mode)) {
141 build_http_status_handlers(target);
142 DIR *d=opendir(target_source.c_str());
143 if(!d)
144 throw konforka::exception(CODEPOINT,"failed to opendir()");
145 for(struct dirent *de=readdir(d);de;de=readdir(d)) {
146 if(!strcmp(de->d_name,"."))
147 continue;
148 if(!strcmp(de->d_name,".."))
149 continue;
150 string subtarget = normalize_path(target+"/"+de->d_name);
151 struct stat sts;
152 if(stat((site_space->config.root_source+subtarget).c_str(),&sts))
153 throw konforka::exception(CODEPOINT,"failed to stat() subtarget");
154 if(S_ISDIR(sts.st_mode)) {
155 build(subtarget);
156 }else{
157 if(site_space->config.match_autobuild_files(target,de->d_name)){
158 build_target(subtarget);
159 }
160 }
161 }
162 closedir(d);
163 }
164}
165
166int main(int argc,char **argv) {
167 try {
168 string config_file = "sitecing.conf";
169 while(true) {
170 static struct option opts[] = {
171 { "help", no_argument, 0, 'h' },
172 { "usage", no_argument, 0, 'h' },
173 { "version", no_argument, 0, 'V' },
174 { "license", no_argument, 0, 'L' },
175 { "config", required_argument, 0, 'f' },
176 { NULL, 0, 0, 0 }
177 };
178 int c = getopt_long(argc,argv,"f:hVL",opts,NULL);
179 if(c==-1)
180 break;
181 switch(c) {
182 case 'h':
183 cerr << PHEADER << endl
184 << PCOPY << endl << endl
185 << " -h, --help" << endl
186 << " --usage display this text" << endl
187 << " -V, --version display version number" << endl
188 << " -L, --license show license" << endl
189 << " -f filename, --config=filename" << endl
190 << " specify configuration file to use" << endl;
191 exit(0);
192 break;
193 case 'V':
194 cerr << VERSION << endl;
195 exit(0);
196 break;
197 case 'L':
198 extern const char *COPYING;
199 cerr << COPYING << endl;
200 exit(0);
201 break;
202 case 'f':
203 config_file = optarg;
204 break;
205 default:
206 cerr << "Huh??" << endl;
207 break;
208 }
209 }
210 configuration config(config_file,true);
211 if(!(config.flags&configuration::flag_root_source))
212 throw konforka::exception(CODEPOINT,"Unspecified root for sources");
213 if(!(config.flags&configuration::flag_root_intermediate))
214 throw konforka::exception(CODEPOINT,"Unspecified root for intermediate files");
215 if(!(config.flags&configuration::flag_root_so))
216 throw konforka::exception(CODEPOINT,"Unspecified root for shared objects");
217 sitespace ss(config);
218 site_space = &ss;
219 if(optind<argc) {
220 for(int narg=optind;narg<argc;narg++) {
221 const char *arg = argv[narg];
222 build(arg);
223 }
224 }else
225 build("/");
226 return 0;
227 }catch(exception& e) {
228 cerr << "Oops: " << e.what() << endl;
229 return 1;
230 }
231}
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 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <signal.h>
4#include <getopt.h>
5#include <pwd.h>
6#include <grp.h>
7#include <errno.h>
8#include <syslog.h>
9#include <iostream>
10#include <memory>
11#include <typeinfo>
12using namespace std;
13#include "kingate/fastcgi.h"
14#include "kingate/cgi_gateway.h"
15using namespace kingate;
16#include "sitecing/sitecing_util.h"
17#include "sitecing/util.h"
18#include "sitecing/sitespace.h"
19#include "sitecing/sitecing_interface_cgi.h"
20#include "sitecing/cgi_component.h"
21#include "sitecing/configuration.h"
22#include "sitecing/magic.h"
23#include "sitecing/sitecing_exception.h"
24#include "sitecing/exception.h"
25#include "sitecing/process_manager.h"
26using namespace sitecing;
27
28#include "config.h"
29#define PHEADER PACKAGE " Version " VERSION
30#define PCOPY "Copyright (c) 2004 Klever Group"
31
32class cdummyClass : public acomponent {
33 public:
34 void main(int _magic,va_list _args) {}
35 void *__the_most_derived_this() { return NULL; }
36} cdummyInstance;
37class adummyClass : public cgi_component {
38 public:
39 void main(int _magic,va_list _args) {}
40 void *__the_most_derived_this() { return NULL; }
41} adummyInstance;
42
43class sitecing_fastcgi_pm : public process_manager {
44 public:
45 configuration config;
46 fcgi_socket *fss;
47 semaphore sem;
48 bool multi;
49 uid_t uid;
50 gid_t gid;
51 pid_file pidfile;
52
53 sitecing_fastcgi_pm(const string& config_file);
54 ~sitecing_fastcgi_pm();
55
56 void process(int slot);
57
58 void run();
59 void give_up_privs();
60};
61
62sitecing_fastcgi_pm::sitecing_fastcgi_pm(const string& config_file)
63 : config(config_file), multi(false) {
64 if(( (config.flags&configuration::flag_user) || (config.flags&configuration::flag_group) || (config.flags&configuration::flag_chroot) ) && geteuid() )
65 throw konforka::exception(CODEPOINT,"can't use User, Group or Chroot when started without root privileges");
66 if(config.flags&configuration::flag_user) {
67 struct passwd *ptmp = getpwnam(config.user.c_str());
68 if(ptmp) {
69 uid = ptmp->pw_uid;
70 }else{
71 errno=0;
72 uid = strtol(config.user.c_str(),NULL,0);
73 if(errno)
74 throw konforka::exception(CODEPOINT,"failed to resolve User value to uid");
75 }
76 }
77 if(config.flags&configuration::flag_group) {
78 struct group *gtmp = getgrnam(config.group.c_str());
79 if(gtmp) {
80 gid = gtmp->gr_gid;
81 }else{
82 errno=0;
83 gid = strtol(config.group.c_str(),NULL,0);
84 if(errno)
85 throw konforka::exception(CODEPOINT,"failed to resolve Group value to gid");
86 }
87 }
88 if(!(config.flags&configuration::flag_root_source))
89 throw konforka::exception(CODEPOINT,"unspecified root for sources");
90 if(!(config.flags&configuration::flag_root_intermediate))
91 throw konforka::exception(CODEPOINT,"unspecified root for intermediate files");
92 if(!(config.flags&configuration::flag_root_so))
93 throw konforka::exception(CODEPOINT,"unspecified root for shared objects");
94 if(config.flags&configuration::flag_min_children)
95 min_children = config.min_children;
96 if(config.flags&configuration::flag_max_children)
97 max_children = config.max_children;
98 if(config.flags&configuration::flag_min_spare_children)
99 min_spare_children = config.min_spare_children;
100 if(config.flags&configuration::flag_max_spare_children)
101 max_spare_children = config.max_spare_children;
102 if(max_children<min_spare_children)
103 throw konforka::exception(CODEPOINT,"inconsistent numbers of MaxChildren and MinSpareChildren");
104 if(min_children>max_spare_children && max_spare_children>=0)
105 throw konforka::exception(CODEPOINT,"inconsistent numbers of MinChildren and MaxSpareChildren");
106 if(config.flags&configuration::flag_multi_process) {
107 multi = config.multi_process;
108 }else{
109 if(config.flags&configuration::flag_listen_socket)
110 multi = true;
111 else
112 multi = false;
113 }
114 fss = (config.flags&configuration::flag_listen_socket)?new fcgi_socket(config.listen_socket.c_str(),5):new fcgi_socket(0);
115 if(!fss)
116 throw konforka::exception(CODEPOINT,"failed to establish listening socket");
117 if(config.flags&configuration::flag_daemonize && config.daemonize) {
118 pid_t pf = fork();
119 if(pf<0)
120 throw konforka::exception(CODEPOINT,"failed to fork()");
121 if(pf) {
122 die_humbly=true;
123 _exit(0);
124 }
125 }
126 if(config.flags&configuration::flag_pid_file) {
127 pidfile.set(config.pid_file);
128 }
129 if(multi)
130 sem.init();
131 }
132sitecing_fastcgi_pm::~sitecing_fastcgi_pm() {
133 if(fss)
134 delete fss;
135}
136
137void sitecing_fastcgi_pm::process(int slot) {
138 signal(SIGINT,SIG_DFL);
139 signal(SIGABRT,SIG_DFL);
140 signal(SIGTERM,SIG_DFL);
141 give_up_privs();
142 scoreboard_slot *sslot = sboard.get_slot(slot);
143 try {
144 sitespace ss(config);
145 fcgi_socket& fs = *fss;
146 sitecing_interface_cgi scif(&ss);
147 string component_path;
148 string action;
149 config_options::action_handler_t *action_handler;
150 int rpc = 0;
151 if(config.flags&configuration::flag_requests_per_child)
152 rpc = config.requests_per_child;
153 for(int req=0;(rpc<=0) || (req<rpc);rpc++) {
154 semaphore_lock sl;
155 if(multi) {
156 sslot->state = scoreboard_slot::state_idle;
157 sl.sem = &sem;
158 sl.lock();
159 }
160 sslot->state = scoreboard_slot::state_accept;
161 fcgi_interface fi(fs);
162 sslot->state = scoreboard_slot::state_processing;
163 if(multi)
164 sl.unlock();
165 cgi_gateway gw(fi);
166 scif.prepare(&gw);
167 try {
168 component_path = normalize_path(gw.get_meta("PATH_INFO"),strip_leading_slash|strip_trailing_slash);
169 string full_component_path;
170 while(true) {
171 full_component_path = config.root_source+'/'+component_path;
172 if(!access(full_component_path.c_str(),F_OK))
173 break;
174 string::size_type sl = component_path.rfind('/');
175 if(sl==string::npos)
176 throw konforka::exception(CODEPOINT,"can't find the target component");
177 component_path.erase(sl);
178 }
179 action = component_path;
180 action_handler = config.lookup_action_handler(component_path);
181 if(action_handler) {
182 action = action_handler->action;
183 }
184 string pwd = dir_name(full_component_path);
185 if(chdir(pwd.c_str()))
186 throw konforka::exception(CODEPOINT,"failed to chdir() into document's directory");
187 so_component soc = ss.fetch(action,&scif);
188 if(action_handler) {
189 soc.ac->run(__magic_action,
190 config.root_source.c_str(), config.root_intermediate.c_str(), config.root_so.c_str(),
191 &(action_handler->args)
192 );
193 }else{
194 soc.ac->main(0,NULL);
195 }
196 }catch(http_status& hs) {
197 scif.headers["Status"] = hs.status+" "+hs.message;
198 string hshp = config.lookup_http_status_handler(component_path,hs.status);
199 if(!hshp.empty()) {
200 so_component hsh = ss.fetch(hshp,&scif); // TODO: handle error trying to handle status
201 hsh.ac->run(__magic_http_status,config.root_source.c_str(),config.root_intermediate.c_str(),
202 config.root_so.c_str(),action.c_str(),&hs);
203 }
204 }catch(compile_error& ce) {
205 config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
206 if(co_exception_handler) {
207 so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
208 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());
209 }else{
210 ce.see(CODEPOINT);
211 throw;
212 }
213 }catch(preprocessor_error& pe) {
214 config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
215 if(co_exception_handler) {
216 so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
217 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);
218 }else{
219 pe.see(CODEPOINT);
220 throw;
221 }
222 }catch(exception& e) {
223 config_options *co_exception_handler = config.lookup_config(component_path,config_options::flag_exception_handler);
224 if(co_exception_handler) {
225 so_component eh = ss.fetch(co_exception_handler->exception_handler,&scif); // TODO: handle error trying to handle error.
226 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);
227 }
228 }
229 scif.flush();
230 }
231 }catch(exception& e) {
232 cerr << "->Oops: " << e.what() << endl;
233 }
234}
235
236void sitecing_fastcgi_pm::run() {
237 if(multi)
238 manage();
239 else
240 process(0);
241}
242
243void sitecing_fastcgi_pm::give_up_privs() {
244 if(config.flags&configuration::flag_chroot) {
245 if(chroot(config.chroot.c_str()))
246 throw konforka::exception(CODEPOINT,"failed to chroot()");
247 }
248 if(config.flags&configuration::flag_group) {
249 if((getgid()!=gid) && setgid(gid))
250 throw konforka::exception(CODEPOINT,"failed to setgid()");
251 }
252 if(config.flags&configuration::flag_user) {
253 if((getuid()!=uid) && setuid(uid))
254 throw konforka::exception(CODEPOINT,"failed to setuid()");
255 }
256}
257
258static sitecing_fastcgi_pm* _process_manager = NULL;
259
260static void lethal_signal_handler(int signum) {
261 _process_manager->finishing=true;
262}
263
264int main(int argc,char **argv) {
265 const char* id = *argv;
266 const char* t;
267 while(t = index(id,'/')) {
268 id=t; id++;
269 }
270 openlog(id,LOG_PERROR|LOG_PID,LOG_USER);
271 try {
272 string config_file = "sitecing.conf";
273 while(true) {
274 static struct option opts[] = {
275 { "help", no_argument, 0, 'h' },
276 { "usage", no_argument, 0, 'h' },
277 { "version", no_argument, 0, 'V' },
278 { "license", no_argument, 0, 'L' },
279 { "config", required_argument, 0, 'f' },
280 { NULL, 0, 0, 0 }
281 };
282 int c = getopt_long(argc,argv,"f:hVL",opts,NULL);
283 if(c==-1)
284 break;
285 switch(c) {
286 case 'h':
287 cerr << PHEADER << endl
288 << PCOPY << endl << endl
289 << " -h, --help" << endl
290 << " --usage display this text" << endl
291 << " -V, --version display version number" << endl
292 << " -L, --license show license" << endl
293 << " -f filename, --config=filename" << endl
294 << " specify configuration file to use" << endl;
295 exit(0);
296 break;
297 case 'V':
298 cerr << VERSION << endl;
299 exit(0);
300 break;
301 case 'L':
302 extern const char *COPYING;
303 cerr << COPYING << endl;
304 exit(0);
305 break;
306 case 'f':
307 config_file = optarg;
308 break;
309 default:
310 cerr << "Huh??" << endl;
311 break;
312 }
313 }
314 sitecing_fastcgi_pm sfpm(config_file);
315 _process_manager = &sfpm;
316 signal(SIGINT,lethal_signal_handler);
317 signal(SIGABRT,lethal_signal_handler);
318 signal(SIGTERM,lethal_signal_handler);
319 sfpm.run();
320 }catch(exception& e) {
321 /* cerr << "Oops: " << e.what() << endl; */
322 syslog(LOG_ERR,"uncaught exception: %s",e.what());
323 }
324 closelog();
325}