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 @@ | |||
1 | configure | ||
2 | Makefile.in | ||
3 | Doxyfile | ||
4 | config.log | ||
5 | depcomp | ||
6 | config.guess | ||
7 | config.h | ||
8 | ltmain.sh | ||
9 | config.sub | ||
10 | INSTALL | ||
11 | sitecing.pc | ||
12 | NEWS | ||
13 | Makefile | ||
14 | config.status | ||
15 | stamp-h1 | ||
16 | doxydox | ||
17 | config.h.in | ||
18 | autom4te.cache | ||
19 | libtool | ||
20 | missing | ||
21 | aclocal.m4 | ||
22 | ylwrap | ||
23 | install-sh | ||
@@ -0,0 +1,3 @@ | |||
1 | Klever dissected: | ||
2 | Michael 'hacker' Krelin <hacker@klever.net> | ||
3 | Leonid Ivanov <kamel@klever.net> | ||
@@ -0,0 +1,19 @@ | |||
1 | Copyright (c) 2004-2005 Klever Group (http://www.klever.net/) | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
4 | this software and associated documentation files (the "Software"), to deal in | ||
5 | the Software without restriction, including without limitation the rights to | ||
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
7 | of the Software, and to permit persons to whom the Software is furnished to do | ||
8 | so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in all | ||
11 | copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | SOFTWARE. | ||
diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- a/dev/null +++ b/ChangeLog | |||
diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 0000000..b6e7ed2 --- a/dev/null +++ b/Doxyfile.in | |||
@@ -0,0 +1,247 @@ | |||
1 | # Doxyfile 1.3.9.1 | ||
2 | |||
3 | #--------------------------------------------------------------------------- | ||
4 | # Project related configuration options | ||
5 | #--------------------------------------------------------------------------- | ||
6 | PROJECT_NAME = @PACKAGE@ | ||
7 | PROJECT_NUMBER = @VERSION@ | ||
8 | OUTPUT_DIRECTORY = @builddir@/doxydox | ||
9 | CREATE_SUBDIRS = NO | ||
10 | OUTPUT_LANGUAGE = English | ||
11 | USE_WINDOWS_ENCODING = NO | ||
12 | BRIEF_MEMBER_DESC = YES | ||
13 | REPEAT_BRIEF = YES | ||
14 | ABBREVIATE_BRIEF = | ||
15 | ALWAYS_DETAILED_SEC = NO | ||
16 | INLINE_INHERITED_MEMB = NO | ||
17 | FULL_PATH_NAMES = YES | ||
18 | STRIP_FROM_PATH = include | ||
19 | STRIP_FROM_INC_PATH = include | ||
20 | SHORT_NAMES = NO | ||
21 | JAVADOC_AUTOBRIEF = NO | ||
22 | MULTILINE_CPP_IS_BRIEF = NO | ||
23 | DETAILS_AT_TOP = NO | ||
24 | INHERIT_DOCS = YES | ||
25 | DISTRIBUTE_GROUP_DOC = NO | ||
26 | TAB_SIZE = 8 | ||
27 | ALIASES = | ||
28 | OPTIMIZE_OUTPUT_FOR_C = NO | ||
29 | OPTIMIZE_OUTPUT_JAVA = NO | ||
30 | SUBGROUPING = YES | ||
31 | |||
32 | #--------------------------------------------------------------------------- | ||
33 | # Build related configuration options | ||
34 | #--------------------------------------------------------------------------- | ||
35 | |||
36 | EXTRACT_ALL = NO | ||
37 | EXTRACT_PRIVATE = NO | ||
38 | EXTRACT_STATIC = NO | ||
39 | EXTRACT_LOCAL_CLASSES = YES | ||
40 | EXTRACT_LOCAL_METHODS = NO | ||
41 | HIDE_UNDOC_MEMBERS = NO | ||
42 | HIDE_UNDOC_CLASSES = NO | ||
43 | HIDE_FRIEND_COMPOUNDS = NO | ||
44 | HIDE_IN_BODY_DOCS = NO | ||
45 | INTERNAL_DOCS = NO | ||
46 | CASE_SENSE_NAMES = YES | ||
47 | HIDE_SCOPE_NAMES = NO | ||
48 | SHOW_INCLUDE_FILES = NO | ||
49 | INLINE_INFO = YES | ||
50 | SORT_MEMBER_DOCS = YES | ||
51 | SORT_BRIEF_DOCS = NO | ||
52 | SORT_BY_SCOPE_NAME = YES | ||
53 | GENERATE_TODOLIST = YES | ||
54 | GENERATE_TESTLIST = YES | ||
55 | GENERATE_BUGLIST = YES | ||
56 | GENERATE_DEPRECATEDLIST= YES | ||
57 | ENABLED_SECTIONS = | ||
58 | MAX_INITIALIZER_LINES = 30 | ||
59 | SHOW_USED_FILES = NO | ||
60 | SHOW_DIRECTORIES = YES | ||
61 | |||
62 | #--------------------------------------------------------------------------- | ||
63 | # configuration options related to warning and progress messages | ||
64 | #--------------------------------------------------------------------------- | ||
65 | |||
66 | QUIET = NO | ||
67 | WARNINGS = YES | ||
68 | WARN_IF_UNDOCUMENTED = YES | ||
69 | WARN_IF_DOC_ERROR = YES | ||
70 | WARN_FORMAT = "$file:$line: $text" | ||
71 | WARN_LOGFILE = | ||
72 | |||
73 | #--------------------------------------------------------------------------- | ||
74 | # configuration options related to the input files | ||
75 | #--------------------------------------------------------------------------- | ||
76 | |||
77 | INPUT = \ | ||
78 | @srcdir@/include/sitecing/ | ||
79 | FILE_PATTERNS = *.h | ||
80 | RECURSIVE = NO | ||
81 | EXCLUDE = | ||
82 | EXCLUDE_SYMLINKS = NO | ||
83 | EXCLUDE_PATTERNS = | ||
84 | EXAMPLE_PATH = | ||
85 | EXAMPLE_PATTERNS = | ||
86 | EXAMPLE_RECURSIVE = NO | ||
87 | IMAGE_PATH = | ||
88 | INPUT_FILTER = | ||
89 | FILTER_PATTERNS = | ||
90 | FILTER_SOURCE_FILES = NO | ||
91 | |||
92 | #--------------------------------------------------------------------------- | ||
93 | # configuration options related to source browsing | ||
94 | #--------------------------------------------------------------------------- | ||
95 | |||
96 | SOURCE_BROWSER = NO | ||
97 | INLINE_SOURCES = NO | ||
98 | STRIP_CODE_COMMENTS = YES | ||
99 | REFERENCED_BY_RELATION = YES | ||
100 | REFERENCES_RELATION = YES | ||
101 | VERBATIM_HEADERS = YES | ||
102 | |||
103 | #--------------------------------------------------------------------------- | ||
104 | # configuration options related to the alphabetical class index | ||
105 | #--------------------------------------------------------------------------- | ||
106 | |||
107 | ALPHABETICAL_INDEX = YES | ||
108 | COLS_IN_ALPHA_INDEX = 2 | ||
109 | IGNORE_PREFIX = | ||
110 | |||
111 | #--------------------------------------------------------------------------- | ||
112 | # configuration options related to the HTML output | ||
113 | #--------------------------------------------------------------------------- | ||
114 | |||
115 | GENERATE_HTML = YES | ||
116 | HTML_OUTPUT = html | ||
117 | HTML_FILE_EXTENSION = .html | ||
118 | HTML_HEADER = | ||
119 | HTML_FOOTER = | ||
120 | HTML_STYLESHEET = | ||
121 | HTML_ALIGN_MEMBERS = YES | ||
122 | GENERATE_HTMLHELP = NO | ||
123 | CHM_FILE = | ||
124 | HHC_LOCATION = | ||
125 | GENERATE_CHI = NO | ||
126 | BINARY_TOC = NO | ||
127 | TOC_EXPAND = NO | ||
128 | DISABLE_INDEX = NO | ||
129 | ENUM_VALUES_PER_LINE = 4 | ||
130 | GENERATE_TREEVIEW = NO | ||
131 | TREEVIEW_WIDTH = 250 | ||
132 | |||
133 | #--------------------------------------------------------------------------- | ||
134 | # configuration options related to the LaTeX output | ||
135 | #--------------------------------------------------------------------------- | ||
136 | |||
137 | GENERATE_LATEX = NO | ||
138 | LATEX_OUTPUT = latex | ||
139 | LATEX_CMD_NAME = latex | ||
140 | MAKEINDEX_CMD_NAME = makeindex | ||
141 | COMPACT_LATEX = NO | ||
142 | PAPER_TYPE = a4wide | ||
143 | EXTRA_PACKAGES = | ||
144 | LATEX_HEADER = | ||
145 | PDF_HYPERLINKS = NO | ||
146 | USE_PDFLATEX = NO | ||
147 | LATEX_BATCHMODE = NO | ||
148 | LATEX_HIDE_INDICES = NO | ||
149 | |||
150 | #--------------------------------------------------------------------------- | ||
151 | # configuration options related to the RTF output | ||
152 | #--------------------------------------------------------------------------- | ||
153 | |||
154 | GENERATE_RTF = NO | ||
155 | RTF_OUTPUT = rtf | ||
156 | COMPACT_RTF = NO | ||
157 | RTF_HYPERLINKS = NO | ||
158 | RTF_STYLESHEET_FILE = | ||
159 | RTF_EXTENSIONS_FILE = | ||
160 | |||
161 | #--------------------------------------------------------------------------- | ||
162 | # configuration options related to the man page output | ||
163 | #--------------------------------------------------------------------------- | ||
164 | |||
165 | GENERATE_MAN = NO | ||
166 | MAN_OUTPUT = man | ||
167 | MAN_EXTENSION = .3 | ||
168 | MAN_LINKS = YES | ||
169 | |||
170 | #--------------------------------------------------------------------------- | ||
171 | # configuration options related to the XML output | ||
172 | #--------------------------------------------------------------------------- | ||
173 | |||
174 | GENERATE_XML = YES | ||
175 | XML_OUTPUT = xml | ||
176 | XML_SCHEMA = | ||
177 | XML_DTD = | ||
178 | XML_PROGRAMLISTING = YES | ||
179 | |||
180 | #--------------------------------------------------------------------------- | ||
181 | # configuration options for the AutoGen Definitions output | ||
182 | #--------------------------------------------------------------------------- | ||
183 | |||
184 | GENERATE_AUTOGEN_DEF = NO | ||
185 | |||
186 | #--------------------------------------------------------------------------- | ||
187 | # configuration options related to the Perl module output | ||
188 | #--------------------------------------------------------------------------- | ||
189 | |||
190 | GENERATE_PERLMOD = NO | ||
191 | PERLMOD_LATEX = NO | ||
192 | PERLMOD_PRETTY = YES | ||
193 | PERLMOD_MAKEVAR_PREFIX = | ||
194 | |||
195 | #--------------------------------------------------------------------------- | ||
196 | # Configuration options related to the preprocessor | ||
197 | #--------------------------------------------------------------------------- | ||
198 | |||
199 | ENABLE_PREPROCESSING = YES | ||
200 | MACRO_EXPANSION = NO | ||
201 | EXPAND_ONLY_PREDEF = NO | ||
202 | SEARCH_INCLUDES = YES | ||
203 | INCLUDE_PATH = | ||
204 | INCLUDE_FILE_PATTERNS = | ||
205 | PREDEFINED = | ||
206 | EXPAND_AS_DEFINED = | ||
207 | SKIP_FUNCTION_MACROS = YES | ||
208 | |||
209 | #--------------------------------------------------------------------------- | ||
210 | # Configuration::additions related to external references | ||
211 | #--------------------------------------------------------------------------- | ||
212 | |||
213 | TAGFILES = | ||
214 | GENERATE_TAGFILE = | ||
215 | ALLEXTERNALS = NO | ||
216 | EXTERNAL_GROUPS = YES | ||
217 | PERL_PATH = /usr/bin/perl | ||
218 | |||
219 | #--------------------------------------------------------------------------- | ||
220 | # Configuration options related to the dot tool | ||
221 | #--------------------------------------------------------------------------- | ||
222 | |||
223 | CLASS_DIAGRAMS = YES | ||
224 | HIDE_UNDOC_RELATIONS = YES | ||
225 | HAVE_DOT = @HAVE_DOT@ | ||
226 | CLASS_GRAPH = YES | ||
227 | COLLABORATION_GRAPH = YES | ||
228 | UML_LOOK = NO | ||
229 | TEMPLATE_RELATIONS = YES | ||
230 | INCLUDE_GRAPH = YES | ||
231 | INCLUDED_BY_GRAPH = YES | ||
232 | CALL_GRAPH = NO | ||
233 | GRAPHICAL_HIERARCHY = YES | ||
234 | DOT_IMAGE_FORMAT = png | ||
235 | DOT_PATH = @DOT@ | ||
236 | DOTFILE_DIRS = | ||
237 | MAX_DOT_GRAPH_WIDTH = 1024 | ||
238 | MAX_DOT_GRAPH_HEIGHT = 1024 | ||
239 | MAX_DOT_GRAPH_DEPTH = 0 | ||
240 | GENERATE_LEGEND = YES | ||
241 | DOT_CLEANUP = YES | ||
242 | |||
243 | #--------------------------------------------------------------------------- | ||
244 | # Configuration::additions related to the search engine | ||
245 | #--------------------------------------------------------------------------- | ||
246 | |||
247 | SEARCHENGINE = NO | ||
diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..68f550d --- a/dev/null +++ b/Makefile.am | |||
@@ -0,0 +1,27 @@ | |||
1 | SUBDIRS=include lib share src components | ||
2 | EXTRA_DIST= NEWS NEWS.xml NEWS.xsl | ||
3 | |||
4 | DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig | ||
5 | if HAVE_PKGCONFIG | ||
6 | pkgconfigdir=@PKGCONFIG_DIR@ | ||
7 | pkgconfig_DATA=sitecing.pc | ||
8 | endif | ||
9 | |||
10 | LOCAL_TARGETS= | ||
11 | if HAVE_DOXYGEN | ||
12 | LOCAL_TARGETS+=doxygen | ||
13 | endif | ||
14 | |||
15 | all-local: NEWS $(addprefix all-lota-,${LOCAL_TARGETS}) | ||
16 | clean-local: $(addprefix clean-lota-,${LOCAL_TARGETS}) | ||
17 | |||
18 | NEWS: NEWS.xsl NEWS.xml | ||
19 | ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml | ||
20 | |||
21 | all-lota-doxygen: doxydox/built | ||
22 | doxydox/built: $(wildcard ${top_srcdir}/include/sitecing/*.h) | ||
23 | ${DOXYGEN} | ||
24 | touch $@ | ||
25 | |||
26 | clean-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,')
')"/> | ||
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>
</xsl:text> | ||
21 | </xsl:template> | ||
22 | <xsl:template match="*|text()"/> | ||
23 | |||
24 | </xsl:stylesheet> | ||
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 @@ | |||
1 | dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
2 | dnl Outputs: | ||
3 | dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR | ||
4 | dnl AM_CONDTIONAL: HAVE_PKGCONFIG | ||
5 | AC_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 | |||
46 | dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
47 | dnl Outputs: | ||
48 | dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN | ||
49 | dnl AM_CONDTIONAL: HAVE_DOXYGEN | ||
50 | AC_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 | |||
64 | dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
65 | dnl Outputs: | ||
66 | dnl AC_SUBST: DOT HAVE_DOT | ||
67 | dnl AM_CONDITIONAL: HAVE_DOT | ||
68 | AC_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 | ||
78 | AC_SUBST([HAVE_DOT]) | ||
79 | AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"]) | ||
80 | ]) | ||
81 | |||
82 | dnl AC_WITH_PCRE([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
83 | dnl Outputs: | ||
84 | dnl AC_SUBST: PCRE_CONFIG PCRE_PREFIX PCRE_EXEC_PREFIX | ||
85 | dnl PCRE_VERSION PCRE_CFLAGS PCRE_LIBS | ||
86 | dnl PCRE_LIBS_POSIX PCRE_CFLAGS_POSIX | ||
87 | dnl AM_CONDITIONAL: HAVE_PCRE | ||
88 | dnl AC_DEFINE: HAVE_PCRE PCRE_VERSION | ||
89 | AC_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 | |||
148 | dnl AC_WITH_PCREPP([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
149 | dnl Outputs: | ||
150 | dnl AC_SUBST: PCREPP_CONFIG PCREPP_PREFIX PCREPP_EXEC_PREFIX | ||
151 | dnl PCREPP_VERSION PCREPP_CFLAGS PCREPP_LIBS | ||
152 | dnl AM_CONDITIONAL: HAVE_PCREPP | ||
153 | dnl AC_DEFINE: HAVE_PCREPP PCREPP_VERSION | ||
154 | AC_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 | ||
2 | WANT_AUTOMAKE=1.8 | ||
3 | export WANT_AUTOMAKE | ||
4 | libtoolize -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 @@ | |||
1 | Makefile.in | ||
2 | Makefile | ||
diff --git a/components/Makefile.am b/components/Makefile.am new file mode 100644 index 0000000..8a07ffc --- a/dev/null +++ b/components/Makefile.am | |||
@@ -0,0 +1,5 @@ | |||
1 | componentsdir = ${pkgdatadir}/components | ||
2 | |||
3 | components_DATA = exception_dev exception_prod | ||
4 | |||
5 | EXTRA_DIST = exception_dev exception_prod | ||
diff --git a/components/exception_dev b/components/exception_dev new file mode 100644 index 0000000..d8c84e1 --- a/dev/null +++ b/components/exception_dev | |||
@@ -0,0 +1,346 @@ | |||
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> <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 @@ | |||
1 | AC_INIT([sitecing], [0.0], [sitecing-bugs@klever.net]) | ||
2 | AC_CONFIG_SRCDIR([include/sitecing/sitecing_parser.h]) | ||
3 | AC_CONFIG_HEADER([config.h]) | ||
4 | AM_INIT_AUTOMAKE([dist-bzip2]) | ||
5 | |||
6 | AC_PROG_INSTALL | ||
7 | AC_PROG_AWK | ||
8 | AC_PROG_CXX | ||
9 | AC_PROG_CC | ||
10 | AM_PROG_LEX | ||
11 | AC_PROG_LIBTOOL | ||
12 | |||
13 | AC_HEADER_STDC | ||
14 | AC_CHECK_HEADERS([stdlib.h unistd.h]) | ||
15 | |||
16 | AC_C_CONST | ||
17 | |||
18 | AC_FUNC_MALLOC | ||
19 | AC_FUNC_REALLOC | ||
20 | |||
21 | AC_WITH_PKGCONFIG | ||
22 | |||
23 | PKG_CHECK_MODULES([KINGATE],[kingate-fcgi],,[ | ||
24 | AC_MSG_ERROR([no kingate library found, get it at http://kin.klever.net/kingate/]) | ||
25 | ]) | ||
26 | PKG_CHECK_MODULES([DOTCONF],[dotconf],,[ | ||
27 | AC_MSG_ERROR([no dotconf library found]) | ||
28 | ]) | ||
29 | |||
30 | AC_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 | |||
38 | AC_CHECK_LIB([dl],[dlopen],,[ | ||
39 | AC_MSG_ERROR([no dlopen library found]) | ||
40 | ]) | ||
41 | |||
42 | AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) | ||
43 | |||
44 | WANT_DOXYGEN="yes" | ||
45 | AC_ARG_ENABLE([doxygen], | ||
46 | AC_HELP_STRING([--disable-doxygen],[do not generate documentation]), | ||
47 | [ | ||
48 | test "${enableval}" = "no" && WANT_DOXYGEN="no" | ||
49 | ] | ||
50 | ) | ||
51 | if test "${WANT_DOXYGEN}" = "yes" ; then | ||
52 | AC_WITH_DOXYGEN | ||
53 | AC_WITH_DOT | ||
54 | else | ||
55 | AM_CONDITIONAL([HAVE_DOXYGEN],[false]) | ||
56 | AM_CONDITIONAL([HAVE_DOT],[false]) | ||
57 | fi | ||
58 | |||
59 | AC_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 | ]) | ||
69 | AC_OUTPUT | ||
diff --git a/include/.gitignore b/include/.gitignore new file mode 100644 index 0000000..3dda729 --- a/dev/null +++ b/include/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | Makefile.in | ||
2 | Makefile | ||
diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..88148d5 --- a/dev/null +++ b/include/Makefile.am | |||
@@ -0,0 +1,18 @@ | |||
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 | ||
5 | nobase_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 | |||
11 | namespace 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 | |||
14 | namespace 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 | |||
15 | namespace 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 | |||
16 | namespace 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 | |||
16 | namespace 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 | */ | ||
12 | namespace 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 | |||
12 | namespace 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 | |||
9 | namespace 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 | |||
11 | namespace 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 | |||
17 | namespace 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> | ||
6 | using 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 | |||
21 | class sitecing_parser; | ||
22 | /** | ||
23 | * The enfleshing of the skeleton file according to the in-memory parsed | ||
24 | * component source. | ||
25 | */ | ||
26 | class 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 | |||
11 | namespace 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 | |||
11 | namespace 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 | |||
16 | namespace 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> | ||
8 | using namespace std; | ||
9 | |||
10 | #include "sitecing/component_factory.h" | ||
11 | using 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 | */ | ||
29 | class 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 | |||
13 | namespace 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 | |||
16 | namespace 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 | |||
13 | namespace sitecing { | ||
14 | using namespace std; | ||
15 | |||
16 | /** | ||
17 | * the html_escape options enumeration. | ||
18 | */ | ||
19 | enum html_escape_options { | ||
20 | /** | ||
21 | * Turn spaces into | ||
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 " | ||
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 @@ | |||
1 | Makefile.in | ||
2 | sitecing_enflesher.cc | ||
3 | sitecing_parser.cc | ||
4 | .libs | ||
5 | .deps | ||
6 | Makefile | ||
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 @@ | |||
1 | lib_LTLIBRARIES = libsitecing.la | ||
2 | noinst_HEADERS = pch.h | ||
3 | |||
4 | INCLUDES = -I${top_srcdir}/include -I${top_builddir} ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \ | ||
5 | ${PCREPP_CFLAGS} | ||
6 | AM_CPPFLAGS = -D__SC_DEFAULT_SKELETON=\"${pkgdatadir}/component.skel\" | ||
7 | AM_LFLAGS = -olex.yy.c | ||
8 | |||
9 | libsitecing_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 | ||
21 | libsitecing_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 | |||
11 | namespace 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 | |||
7 | namespace 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 | |||
20 | namespace 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 | |||
14 | namespace 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 | |||
15 | namespace 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 | |||
12 | namespace 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> | ||
24 | using 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 | |||
16 | namespace 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 | |||
15 | namespace 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> | ||
6 | using namespace std; | ||
7 | #include "sitecing/sitecing_exception.h" | ||
8 | using 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 | |||
182 | void sitecing_enflesher::LexerOutput(const char *buf,int size) { | ||
183 | outs.write(buf,size); | ||
184 | } | ||
185 | |||
186 | void 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 | |||
194 | void 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 | |||
4 | namespace 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> | ||
9 | using namespace std; | ||
10 | #include "sitecing/sitecing_util.h" | ||
11 | #include "sitecing/sitecing_exception.h" | ||
12 | using 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 | |||
533 | sitecing_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 | |||
540 | void 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 | |||
556 | void sitecing_parser::LexerOutput(const char* buf,int size) { | ||
557 | assert(modi.size()); | ||
558 | M().output.append(buf,size); | ||
559 | } | ||
560 | |||
561 | static 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 | |||
572 | void 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 | |||
579 | void sitecing_parser::soft_anchor() { | ||
580 | if(M().modus!=modus_operandi::modus_text) | ||
581 | anchor(); | ||
582 | } | ||
583 | void 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 | |||
17 | namespace 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 | |||
9 | namespace 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 | |||
8 | namespace 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,"<"); screwed+=4; | ||
24 | break; | ||
25 | case '>': | ||
26 | rv.replace(screwed,1,">"); screwed+=4; | ||
27 | break; | ||
28 | case '&': | ||
29 | rv.replace(screwed,1,"&"); screwed+=5; | ||
30 | break; | ||
31 | case ' ': | ||
32 | if(flags&html_escape_nbsp) { | ||
33 | rv.replace(screwed,1," "); 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,"""); 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 @@ | |||
1 | Makefile.in | ||
2 | Makefile | ||
diff --git a/share/Makefile.am b/share/Makefile.am new file mode 100644 index 0000000..7947380 --- a/dev/null +++ b/share/Makefile.am | |||
@@ -0,0 +1,3 @@ | |||
1 | pkgdata_DATA = component.skel | ||
2 | |||
3 | EXTRA_DIST = component.skel | ||
diff --git a/share/component.skel b/share/component.skel new file mode 100644 index 0000000..f96c5b3 --- a/dev/null +++ b/share/component.skel | |||
@@ -0,0 +1,53 @@ | |||
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 | |||
9 | void *<%class_name%>::__the_most_derived_this() { | ||
10 | return this; | ||
11 | } | ||
12 | void <%class_name%>::__do_imports() { | ||
13 | __base_class::__do_imports(); | ||
14 | <%ancestors:import%> | ||
15 | <%imports:import%> | ||
16 | } | ||
17 | |||
18 | extern "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 | |||
31 | class <%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 @@ | |||
1 | prefix=@prefix@ | ||
2 | exec_prefix=@exec_prefix@ | ||
3 | bindir=@bindir@ | ||
4 | libdir=@libdir@ | ||
5 | includedir=@includedir@ | ||
6 | |||
7 | Name: sitecing | ||
8 | Description: site-C-ing web site development engine | ||
9 | Version: @VERSION@ | ||
10 | Requires: kingate konforka | ||
11 | Cflags: -I${includedir} | ||
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..6c2c79e --- a/dev/null +++ b/src/.gitignore | |||
@@ -0,0 +1,9 @@ | |||
1 | Makefile.in | ||
2 | sitecing-build | ||
3 | sitecing-fastcgi | ||
4 | COPYING.o | ||
5 | .libs | ||
6 | .deps | ||
7 | COPYING.cc | ||
8 | Makefile | ||
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 @@ | |||
1 | bin_PROGRAMS = sitecing-fastcgi sitecing-build | ||
2 | |||
3 | INCLUDES = -I${top_srcdir}/include ${KINGATE_CFLAGS} ${DOTCONF_CFLAGS} \ | ||
4 | ${PCREPP_CFLAGS} | ||
5 | LIBS += ${top_builddir}/lib/libsitecing.la ${KINGATE_LIBS} ${DOTCONF_LIBS} \ | ||
6 | ${PCREPP_LIBS} | ||
7 | |||
8 | sitecing_fastcgi_SOURCES = sitecing-fastcgi.cc \ | ||
9 | COPYING.cc | ||
10 | sitecing_fastcgi_LDFLAGS = -rdynamic | ||
11 | sitecing_fastcgi_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la | ||
12 | |||
13 | sitecing_build_SOURCES = sitecing-build.cc \ | ||
14 | COPYING.cc | ||
15 | sitecing_build_DEPENDENCIES = ${top_builddir}/lib/libsitecing.la | ||
16 | |||
17 | COPYING.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> | ||
9 | using 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" | ||
19 | using namespace sitecing; | ||
20 | |||
21 | #include "config.h" | ||
22 | #define PHEADER PACKAGE "-build Version " VERSION | ||
23 | #define PCOPY "Copyright (c) 2004 Klever Group" | ||
24 | |||
25 | static sitespace* site_space = NULL; | ||
26 | typedef pair<dev_t,ino_t> the_inode_t; | ||
27 | set<the_inode_t> built_inodes; | ||
28 | |||
29 | void 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 | |||
48 | void build_imports(const string& component); | ||
49 | |||
50 | void 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 | |||
63 | void 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 | |||
77 | void 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 | |||
117 | void 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 | |||
126 | void 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 | |||
166 | int 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> | ||
12 | using namespace std; | ||
13 | #include "kingate/fastcgi.h" | ||
14 | #include "kingate/cgi_gateway.h" | ||
15 | using 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" | ||
26 | using namespace sitecing; | ||
27 | |||
28 | #include "config.h" | ||
29 | #define PHEADER PACKAGE " Version " VERSION | ||
30 | #define PCOPY "Copyright (c) 2004 Klever Group" | ||
31 | |||
32 | class cdummyClass : public acomponent { | ||
33 | public: | ||
34 | void main(int _magic,va_list _args) {} | ||
35 | void *__the_most_derived_this() { return NULL; } | ||
36 | } cdummyInstance; | ||
37 | class 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 | |||
43 | class 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 | |||
62 | sitecing_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 | } | ||
132 | sitecing_fastcgi_pm::~sitecing_fastcgi_pm() { | ||
133 | if(fss) | ||
134 | delete fss; | ||
135 | } | ||
136 | |||
137 | void 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 | |||
236 | void sitecing_fastcgi_pm::run() { | ||
237 | if(multi) | ||
238 | manage(); | ||
239 | else | ||
240 | process(0); | ||
241 | } | ||
242 | |||
243 | void 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 | |||
258 | static sitecing_fastcgi_pm* _process_manager = NULL; | ||
259 | |||
260 | static void lethal_signal_handler(int signum) { | ||
261 | _process_manager->finishing=true; | ||
262 | } | ||
263 | |||
264 | int 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 | } | ||