Browse Source

Merged last changes from trunk to brunch svn merge -r 437:470 /framework/trunk (empty)

Branch copied to trunk svn merge /framework/trunk@470 /framework/branches/new-templates@470
master
Artyom Beilis 15 years ago
parent
commit
ffe3f1c939
26 changed files with 2365 additions and 74 deletions
  1. +22
    -11
      Makefile.am
  2. +104
    -0
      base_view.cpp
  3. +134
    -0
      base_view.h
  4. +9
    -5
      cache_interface.cpp
  5. +8
    -0
      config.txt
  6. +42
    -2
      configure.in
  7. +663
    -0
      cppcms_tmpl_cc
  8. +45
    -0
      form.h
  9. +16
    -2
      hello_world.cpp
  10. +16
    -0
      hello_world_skin1.tmpl
  11. +16
    -0
      hello_world_skin2.tmpl
  12. +25
    -0
      hello_world_view.h
  13. +16
    -0
      hello_world_view1.tmpl
  14. +60
    -0
      manager.cpp
  15. +11
    -3
      manager.h
  16. +8
    -0
      transtext/Makefile.am
  17. +399
    -0
      transtext/lambda.cpp
  18. +37
    -0
      transtext/locale/he/LC_MESSAGES/test.po
  19. +339
    -0
      transtext/mo_file.cpp
  20. +12
    -0
      transtext/mo_file.h
  21. +28
    -0
      transtext/test.cpp
  22. +67
    -0
      transtext/trans_factory.cpp
  23. +93
    -0
      transtext/transtext.cpp
  24. +66
    -0
      transtext/transtext.h
  25. +83
    -30
      worker_thread.cpp
  26. +46
    -21
      worker_thread.h

+ 22
- 11
Makefile.am View File

@@ -1,17 +1,28 @@
SUBDIRS = ./transtext

noinst_PROGRAMS = hello_world.fcgi
dist_bin_SCRIPTS = cppcms_tmpl_cc

hello_world_fcgi_SOURCES = hello_world.cpp hello_world_view1.cpp hello_world_view2.cpp
hello_world_fcgi_LDADD = libcppcms.la transtext/libcppcmstranstext.la
hello_world_fcgi_CXXFLAGS= -Wall -I./transtext


hello_world_fcgi_SOURCES = hello_world.cpp
hello_world_fcgi_LDADD = libcppcms.la
hello_world_fcgi_CXXFLAGS=-Wall

hello_world_view1.cpp: hello_world_skin1.tmpl hello_world_view1.tmpl
./cppcms_tmpl_cc hello_world_skin1.tmpl hello_world_view1.tmpl -o hello_world_view1.cpp -n view1 -d test

hello_world_view2.cpp: hello_world_skin2.tmpl hello_world_view1.tmpl
./cppcms_tmpl_cc hello_world_skin2.tmpl hello_world_view1.tmpl -o hello_world_view2.cpp -n view2 -d test

lib_LTLIBRARIES = libcppcms.la
libcppcms_la_SOURCES = global_config.cpp manager.cpp \
url.cpp worker_thread.cpp text_tool.cpp\
cache_interface.cpp base_cache.cpp thread_cache.cpp scgi.cpp
libcppcms_la_SOURCES = global_config.cpp manager.cpp url.cpp worker_thread.cpp \
text_tool.cpp cache_interface.cpp base_cache.cpp thread_cache.cpp scgi.cpp \
base_view.cpp

libcppcms_la_LDFLAGS = -version-info 0:0:0
libcppcms_la_CXXFLAGS = -Wall
libcppcms_la_LIBADD = @CPPCMS_LIBS@
libcppcms_la_LDFLAGS = -no-undefined -version-info 0:0:0
libcppcms_la_LIBADD = @CPPCMS_LIBS@ transtext/libcppcmstranstext.la
libcppcms_la_CXXFLAGS = -Wall -I./transtext

if EN_FORK_CACHE
libcppcms_la_SOURCES += process_cache.cpp
@@ -19,12 +30,12 @@ endif

if EN_FCGI_BACKEND
libcppcms_la_SOURCES += fcgi.cpp
endif
endif

nobase_pkginclude_HEADERS = global_config.h text_tool.h url.h cppcms_error.h \
manager.h worker_thread.h fcgi.h cache_interface.h archive.h \
base_cache.h thread_cache.h cgicc_connection.h scgi.h cgi_api.h \
process_cache.h shmem_allocator.h posix_mutex.h config.h cgi.h
process_cache.h shmem_allocator.h posix_mutex.h config.h cgi.h base_view.h

if EN_TCP_CACHE
libcppcms_la_SOURCES += tcp_cache.cpp


+ 104
- 0
base_view.cpp View File

@@ -0,0 +1,104 @@
#include "base_view.h"
#include "worker_thread.h"

namespace cppcms {

string base_view::escape(string const &s)
{
string content;
unsigned i,len=s.size();
content.reserve(len*3/2);
for(i=0;i<len;i++) {
char c=s[i];
switch(c){
case '<': content+="&lt;"; break;
case '>': content+="&gt;"; break;
case '&': content+="&amp;"; break;
case '\"': content+="&quot;"; break;
default: content+=c;
}
}
return content;
}

string base_view::urlencode(string const &s)
{
string content;
unsigned i,len=s.size();
content.reserve(3*len);
for(i=0;i<len;i++){
char c=s[i];
if( ('a'<=c && c<='z')
|| ('A'<=c && c<='Z')
|| ('0'<=c && c<='9'))
{
content+=c;
}
else {
switch(c) {
case '-':
case '_':
case '.':
case '~':
case '!':
case '*':
case '\'':
case '(':
case ')':
case ';':
case ':':
case '@':
case '&':
case '=':
case '+':
case '$':
case ',':
case '/':
case '?':
case '%':
case '#':
case '[':
case ']':
content+=c;
break;
default:
{
char buf[4];
snprintf(buf,sizeof(buf),"%%%02x",(unsigned)(c));
content.append(buf,3);
}
};
}
};
return content;
}

namespace details {

views_storage &views_storage::instance() {
static views_storage this_instance;
return this_instance;
};

void views_storage::add_view(string t,string v,view_factory_t f)
{
storage[t][v]=f;
}

void views_storage::remove_views(string t)
{
storage.erase(t);
}

base_view *views_storage::fetch_view(string t,string v,base_view::settings s,base_content *c)
{
templates_t::iterator p=storage.find(t);
if(p==storage.end()) return NULL;
template_views_t::iterator p2=p->second.find(v);
if(p2==p->second.end()) return NULL;
view_factory_t &f=p2->second;
return f(s,c);
}

};
}// CPPCMS

+ 134
- 0
base_view.h View File

@@ -0,0 +1,134 @@
#ifndef CPPCMS_BASEVIEW_H
#define CPPCMS_BASEVIEW_H

#include <boost/format.hpp>
#include <boost/function.hpp>
#include <ostream>
#include <sstream>
#include <string>
#include <map>
#include "worker_thread.h"
#include "cppcms_error.h"
#include "config.h"

namespace cppcms {
using namespace std;

// Just simple polimorphic class
class base_content {
public:
virtual ~base_content() {};
};

class base_view {
public:
struct settings {
worker_thread *worker;
ostream *output;
settings(worker_thread *w) : worker(w) , output(&w->get_cout()) {};
settings(worker_thread *w,ostream *o) : worker(w), output(o) {};
};
protected:
worker_thread &worker;
ostream &cout;

base_view(settings s) :
worker(*s.worker),
cout(*s.output)
{
}

template<typename T>
string escape(T const &v)
{
ostringstream s;
s<<v;
return s.str();
};

string escape(string const &s);

inline string raw(string s) { return s; };
inline string intf(int val,string f){
return (format(f) % val).str();
};
string strftime(std::tm const &t,string f)
{
char buf[128];
buf[0]=0;
std::strftime(buf,sizeof(buf),f.c_str(),&t);
return buf;
};
string date(std::tm const &t) { return strftime(t,"%Y-%m-%d"); };
string time(std::tm const &t) { return strftime(t,"%H:%M"); };
string timesec(std::tm const &t) { return strftime(t,"%T"); };
string escape(std::tm const &t) { return strftime(t,"%Y-%m-%d %T"); }

string urlencode(string const &s);

inline boost::format format(string const &f){
boost::format frm(f);
frm.exceptions(0);
return frm;
};
public:
virtual void render() {};
virtual ~base_view() {};
};

namespace details {

template<typename T,typename VT>
struct view_builder {
base_view *operator()(base_view::settings s,base_content *c) {
VT *p=dynamic_cast<VT *>(c);
if(!p) throw cppcms_error("Incorrect content type");
return new T(s,*p);
};
};

class views_storage {
public:
typedef boost::function<base_view *(base_view::settings s,base_content *c)> view_factory_t;
private:
typedef map<string,view_factory_t> template_views_t;
typedef map<string,template_views_t> templates_t;

templates_t storage;
public:

void add_view( string template_name,
string view_name,
view_factory_t);
void remove_views(string template_name);
base_view *fetch_view(string template_name,string view_name,base_view::settings ,base_content *c);
static views_storage &instance();
};

}; // DETAILS


}; // CPPCMS

#define cppcms_view(X) \
do { \
void X##_symbol(); \
X##_symbol(); \
} while(0)


#if defined(HAVE_CPP_0X_AUTO)
# define CPPCMS_TYPEOF(x) auto
#elif defined(HAVE_CPP_0X_DECLTYPE)
# define CPPCMS_TYPEOF(x) decltype(x)
#elif defined(HAVE_GCC_TYPEOF)
# define CPPCMS_TYPEOF(x) typeof(x)
#elif defined(HAVE_WORKING_BOOST_TYPEOF)
# include <boost/typeof/typeof.hpp>
# define CPPCMS_TYPEOF(x) BOOST_TYPEOF(x)
#else
# error "No useful C++0x auto/decltype/typeof method for this compiler"
#endif


#endif

+ 9
- 5
cache_interface.cpp View File

@@ -41,9 +41,10 @@ string deflate(string const &text,long level,long length)

bool cache_iface::fetch_page(string const &key)
{
string tmp;
if(!cms->caching_module) return false;
if(cms->caching_module->fetch_page(key,cms->out,cms->gzip)) {
string tmp;
if(cms->caching_module->fetch_page(key,tmp,cms->gzip)) {
cms->cout<<tmp;
cms->gzip_done=true;
return true;
}
@@ -56,10 +57,13 @@ void cache_iface::store_page(string const &key,time_t timeout)
archive a;
long level=cms->app.config.lval("gzip.level",-1);
long length=cms->app.config.lval("gzip.buffer",-1);
string compr=deflate(cms->out,level,length);
a<<(cms->out)<<compr;
string tmp=cms->out_buf.str();
cms->out_buf.str("");

string compr=deflate(tmp,level,length);
a<<tmp<<compr;
if(cms->gzip){
cms->out=compr;
cms->cout<<compr;
cms->gzip_done=true;
}
cms->caching_module->store(key,triggers,timeout,a);


+ 8
- 0
config.txt View File

@@ -54,3 +54,11 @@ server.socket = "/tmp/hello-fastcgi.socket" # Default is "" -- use default s
# cache.ports = { 12000 12000 } # The ports tcp_cache_servers listen on
# Make sure all servers occure in SAME order in all clients


# Localization
locale.dir="./transtext/locale" # path to locale directory
locale.lang_list = { "he" "en" } # list of supported languages
locale.lang_default = "he" # default language (default first one)
locale.domain_list = { "app" "test" } # list of supported domains
locale.domain_default = "test" # default domain (default first one)


+ 42
- 2
configure.in View File

@@ -11,7 +11,7 @@ AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)

AC_LANG_CPLUSPLUS
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([Makefile transtext/Makefile])

AC_ARG_ENABLE(forkcache,[AS_HELP_STRING([--disable-forkcache],[Disable shared memory cache])])
AC_ARG_ENABLE(fastcgi,[AS_HELP_STRING([--disable-fastcgi],[Disable fastcgi interface])])
@@ -40,7 +40,7 @@ fi
if test "x$enable_fastcgi" != "xno" ; then
AC_CHECK_LIB(fcgi++,main,[
have_fcgi=yes
CPPCMS_LIBS="-lfcgi++ $CPPCMS_LIBS"
CPPCMS_LIBS="-lfcgi++ -lfcgi $CPPCMS_LIBS"
AC_DEFINE([EN_FCGI_BACKEND],[],["Enable fastcgi backend"])
],
[ echo "======================================================================"
@@ -49,6 +49,45 @@ if test "x$enable_fastcgi" != "xno" ; then
echo "You still have scgi and cgi API" ])
fi

have_auto_type_detection=no

AC_TRY_COMPILE([#include <list>
],
[std::list<int> l; auto p=l.begin();],
[AC_DEFINE([HAVE_CPP_0X_AUTO],[],["Have C++0x auto"])
have_auto_type_detection=yes
echo "C++0x auto... ok" ],[echo "C++0x auto... not supported"])
AC_TRY_COMPILE([#include <list>
],
[std::list<int> l; decltype(l.begin()) p=l.begin();],
[AC_DEFINE([HAVE_CPP_0X_DECLTYPE],[],["Have C++0x decltype"])
have_auto_type_detection=yes
echo "C++0x decltype... ok"],[echo "C++0x decltype... not supported"])
AC_TRY_COMPILE([#include <list>
],
[std::list<int> l; typeof(l.begin()) p=l.begin();],
[AC_DEFINE([HAVE_GCC_TYPEOF],[],["Have g++ typeof"])
have_auto_type_detection=yes
echo "g++ typeof... ok"],[echo "g++ typeof... not supported"])
AC_TRY_COMPILE([#include <list>
#include <vector>
#include #include <boost/typeof/typeof.hpp>
],
[ {std::list<int> l; BOOST_TYPEOF(l.begin()) p=l.begin(); BOOST_TYPEOF(*p) &refp=*p;}
{std::vector<int> l; BOOST_TYPEOF(l.begin()) p=l.begin(); BOOST_TYPEOF(*p) &refp=*p;}],
[AC_DEFINE([HAVE_WORKING_BOOST_TYPEOF],[],["Have working BOOST_TYPEOF"])
have_auto_type_detection=yes
echo "Useful BOOST_TYPEOF... ok"],[echo "Useful BOOST_TYPEOF... not supported"])

if test x$have_auto_type_detection != xyes ; then
echo "No useful type detection method for this compiler found"
echo "Supported methods: C++0x auto, C++0x decltype, Boost.Typeof, GCC typeof"
exit -1
fi




AM_CONDITIONAL(EN_FORK_CACHE,[test "x$have_mm" == "xyes" ])
AM_CONDITIONAL(EN_FCGI_BACKEND,[test "x$have_fcgi" == "xyes" ])

@@ -99,6 +138,7 @@ fi
AM_CONDITIONAL(EN_TCP_CACHE,[test "x$have_asio" == "xyes" ])

AC_CHECK_LIB(cgicc,main,[CPPCMS_LIBS="-lcgicc $CPPCMS_LIBS"],[echo "cgicc not found" ; exit -1])
AC_CHECK_LIB(dl,dlopen,[CPPCMS_LIBS="-ldl $CPPCMS_LIBS"],[])
AC_CHECK_LIB(pthread,pthread_sigmask,[],[echo "Pthreads library not found" ; exit -1])
AC_CHECK_LIB(boost_regex,main,[
CPPCMS_LIBS="-lboost_regex $CPPCMS_LIBS"


+ 663
- 0
cppcms_tmpl_cc View File

@@ -0,0 +1,663 @@
#!/usr/bin/env python

import os
import re
import sys

variable_match=r'([a-zA-Z]\w*)(((\.|->)([a-zA-Z]\w*))*)'
str_match=r'"([^"\\]|\\[^"]|\\")*"'

def interleave(*args):
for idx in range(0, max(len(arg) for arg in args)):
for arg in args:
try:
yield arg[idx]
except IndexError:
continue

def output(s):
global stack
global file_name
global line_number
global output_fd
output_fd.write('\t' * len(stack) + '#line %d "%s"' % (line_number,file_name)+'\n' + \
'\t'*len(stack) + s + '\n')

class tmpl_descr:
def __init__(self,start,size):
self.start_id=start
self.param_num=size

class namespace_block:
pattern=r'^<%\s*namespace\s+(\w+)\s*(at\s*(\w+)\s*)?%>$'
type='namespace'
def use(self,m):
self.internal_namespace=0
global namespace_name
if m.group(1)=='vary':
if namespace_name!='':
self.internal_namespace=0
else:
error_exit("Can't use `vary' namespace without external one")
else: # m.group(1)!='vary'
if namespace_name=='':
namespace_name=m.group(1)
self.internal_namespace=1
else:
error_exit("Can't define both external and non-vary namespace")

output( "namespace %s {" % namespace_name)
self.reset_gettext=0
if m.group(2):
global spec_gettext
if not spec_gettext:
spec_gettext=m.group(3)
self.reset_gettext=1
global stack
stack.append(self)
def on_end(self):
global namespace_name
output( "} // end of namespace %s" % namespace_name)
if self.internal_namespace:
namespace_name=''
if self.reset_gettext:
global spec_gettext
spec_gettext=''


def write_class_loader():
global class_list
output( "namespace {")
output( " struct loader {")
output( " loader(){")
output( " using namespace cppcms::details;")
output( " views_storage &_VS_ref=views_storage::instance();")
list_of_views={}
for class_def in class_list:
list_of_views[class_def.namespace]=""
if class_def.content_name!='':
output( ' _VS_ref.add_view("%s","%s",view_builder<%s::%s,%s>());' \
% (class_def.namespace,class_def.name,class_def.namespace,class_def.name,class_def.content_name))
else:
output( ' _VS_ref.add_view("%s","%s",simple_view_builder<%s::%s>());' \
% (class_def.namespace,class_def.name,class_def.namespace,class_def.name))
output( " };")
output( ' ~loader() { ')
output( " using namespace cppcms::details;")
output( " views_storage &_VS_ref=views_storage::instance();")
for ns in list_of_views:
output( ' _VS_ref.remove_views("%s");' % ns)
output( ' }')
output( " } loader_entry;")
output( "} // empty namespace ")
output( 'extern "C" { // Dummy extern symbols to insure full link' )
for ns in list_of_views:
output( '\tvoid load_view_%s(){}' % ns )
output( '} // extern C' )

def gettext_domain():
global spec_gettext
if spec_gettext:
return spec_gettext
global namespace_name
return namespace_name

class class_block:
pattern=r'^<%\s*class\s+(\w+)\s+(uses\s+(\w+(::\w+)?))?\s+(extends\s+(\w+(::\w+)?))?\s*%>$'
type='class'
def declare(self):
if self.extends=='' :
constructor='cppcms::base_view(_s)'
self.extends='cppcms::base_view'
else:
constructor='%s(_s,_content)' % self.extends;
output( "struct %s :public %s" % (self.class_name , self.extends ))
output( "{")
if self.uses!='' :
output( "\t%s &content;" % self.uses)
output( "\tcppcms::transtext::trans const *tr;" )
output( "\t%s(cppcms::base_view::settings _s,%s &_content): %s,content(_content)" % ( self.class_name,self.uses,constructor ))
else:
output( "\t%s(cppcms::base_view::settings _s): %s" % ( self.class_name,constructor ))
output("\t{")
output('\t\ttr=_s.worker->domain_gettext("%s");' % gettext_domain() )
output("\t};")

def use(self,m):
self.class_name=m.group(1)
if m.group(2):
self.uses=m.group(3)
else:
self.uses=''
if m.group(5):
self.extends=m.group(6)
else:
self.extends=''
self.declare();
global stack
if len(stack)!=1 or stack[-1].type!='namespace':
error_exit("You must define class inside namespace block only")
stack.append(self)
global class_list
global namespace_name
class information:
content_name=self.uses
name=self.class_name
namespace=namespace_name
class_list.append(information())
def on_end(self):
output( "}; // end of class %s" % self.class_name)



class template_block:
pattern=r'^<%\s*template\s+([a-zA-Z]\w*)\s*\(([\w\s,:\&]*)\)\s*%>$'
type='template'
plist=[]
def create_parameters(self,lst):
pattern=r'^\s*((\w+(::\w+)*)\s*(const)?\s*(\&)?\s*(\w+))\s*(,(.*))?$'
m=re.match(pattern,lst)
res=[]
while m:
global tmpl_seq
id=m.group(2)
if tmpl_seq.has_key(id):
error_exit("Duplicate definition of patameter %s" % id)
for v in self.plist:
del tmpl_seq[v]
return ""
tmpl_seq[id]=''
res.append(m.group(1))
self.plist.append(id)
if m.group(8):
lst=m.group(8)
m=re.match(pattern,lst)
else:
return ','.join(res)
for v in self.plist:
del tmpl_seq[v]
error_exit("Wrong expression %s" % lst)


def use(self,m):
self.name=m.group(1)
params=""
if m.group(2) and not re.match('^\s*$',m.group(2)):
params=self.create_parameters(m.group(2))
output( "virtual void %s(%s) {" % (self.name,params) )
global stack
if len(stack)==0 or stack[-1].type!='class':
error_exit("You must define template inside class block only")
stack.append(self)
global current_template
current_template=self.name
global ignore_inline
ignore_inline=0

def on_end(self):
output( "} // end of template %s" % self.name)
global ignore_inline
ignore_inline=1


def inline_content(s):
global ignore_inline
if not ignore_inline:
output( 'cout<<"%s";' % to_string(s))

def error_exit(x):
global exit_flag
global file_name
global line_number
sys.stderr.write("Error: %s in file %s, line %d\n" % (x,file_name,line_number))
exit_flag=1

def to_string(s):
res=''
for c in s:
global stack
if c=='\n':
res+="\\n\""+"\n"+"\t"*len(stack)+"\t\""
elif c=="\t":
res+="\\t"
elif c=="\v":
res+="\\v"
elif c=="\b":
res+="\\b"
elif c=="\r":
res+="\\r"
elif c=="\f":
res+="\\f"
elif c=="\a":
res+="\\a"
elif c=="\\":
res+="\\\\"
elif c=="\"":
res+="\\\""
elif ord(c)>0 and ord(c)<32:
res+="%03o" % ord(c)
else:
res+=c

return res


def make_ident(val):
m=re.match('^'+variable_match+'$',val)
global tmpl_seq
if tmpl_seq.has_key(m.group(1)):
return val
return "content." + val

class foreach_block:
pattern=r'^<%\s*foreach\s+([a-zA-Z]\w*)\s+in\s+(' + variable_match +')\s*%>$'
type='foreach'
has_item=0
has_separator=0
separator_label=''
on_first_label=''
def use(self,m):
self.ident=m.group(1)
self.seq_name=make_ident(m.group(2))
global tmpl_seq
if tmpl_seq.has_key(self.ident):
error_exit("Nested sequences with same name")
tmpl_seq[self.ident]='';
output( "if(%s.begin()!=%s.end()) {" % (self.seq_name,self.seq_name) )
global stack
stack.append(self)

def on_end(self):
if not self.has_item:
error_exit("foreach without item")

global tmpl_seq
del tmpl_seq[self.ident]
output( "}" )

def prepare_foreach(seq,ident,has_separator):
output( "for(CPPCMS_TYPEOF(%(s)s.begin()) %(i)s_ptr=%(s)s.begin(),%(i)s_ptr_end=%(s)s.end();%(i)s_ptr!=%(i)s_ptr_end;++%(i)s_ptr) {" \
% { 's' :seq, 'i' : ident })
output( "CPPCMS_TYPEOF(*%s_ptr) &%s=*%s_ptr;" % (ident,ident,ident))
if has_separator:
output( "if(%s_ptr!=%s.begin()) {" % (ident,seq))

class separator_block:
pattern=r'^<%\s*separator\s*%>'
type='separator'
def use(self,m):
global stack
if len(stack)==0 or stack[len(stack)-1].type!='foreach':
error_exit("separator without foreach")
return
foreachb=stack[len(stack)-1]
if foreachb.has_separator:
error_exit("two separators for one foreach")
foreachb.has_separator=1
prepare_foreach(foreachb.seq_name,foreachb.ident,1)

class item_block:
pattern=r'^<%\s*item\s*%>'
type='item'
def use(self,m):
global stack
if not stack or stack[-1].type!='foreach':
error_exit("item without foreach")
return
foreachb=stack[-1]
if foreachb.has_item:
error_exit("Two items for one foreach");
if foreachb.has_separator:
output( "} // end of separator")
else:
prepare_foreach(foreachb.seq_name,foreachb.ident,0)
foreachb.has_item=1
stack.append(self)
def on_end(self):
output( "} // end of item" )

class empty_block:
pattern=r'^<%\s*empty\s*%>'
type='empty'
def use(self,m):
global stack
if not stack or stack[-1].type!='foreach':
error_exit("empty without foreach")
return
forb=stack.pop()
if not forb.has_item:
error_exit("Unexpected empty - item missed?")
output( " } else {")
self.ident=forb.ident
stack.append(self)
def on_end(self):
output( "} // end of empty")
global tmpl_seq
del tmpl_seq[self.ident]


class else_block:
pattern=r'^<%\s*else\s*%>$'
type='else'
def on_end(self):
output("}")
def use(self,m):
prev=stack.pop()
if prev.type!='if' and prev.type!='elif':
error_exit("elif without if");
output( "}else{")
stack.append(self)

class if_block:
pattern=r'^<%\s*(if|elif)\s+((not\s+|not\s+empty\s+|empty\s+)?('+variable_match+')|\((.+)\)|)\s*%>$'
type='if'
def prepare(self):
output( "if(%s) {" % self.ident)

def on_end(self):
output( "} // endif")

def use(self,m):
global stack
self.type=m.group(1)
if m.group(4):
if m.group(4)=='rtl':
self.ident='(std::strcmp(tr->gettext("LTR"),"RTL")==0)'
else:
self.ident=make_ident(m.group(4))
if m.group(3):
if re.match('.*empty',m.group(3)):
self.ident=self.ident + '.empty()'
if re.match('not.*',m.group(3)):
self.ident="!("+self.ident+")"
else:
self.ident=m.group(10)
if self.type == 'if' :
self.prepare()
stack.append(self)
else: # type == elif
if stack :
prev=stack.pop()
if prev.type!='if' and prev.type!='elif':
error_exit("elif without if");
output( "}")
output( "else")
self.prepare()
stack.append(self)
else:
error_exit("Unexpeced elif");
# END ifop

class end_block:
pattern=r'^<%\s*end(\s+(\w+))?\s*%>';
def use(self,m):
global stack
if not stack:
error_exit("Unexpeced 'end'");
else:
obj=stack.pop();
if m.group(1):
if obj.type!=m.group(2):
error_exit("End of %s does not match block %s" % (m.group(2) , obj.type));
obj.on_end()

class error_com:
pattern=r'^<%(.*)%>$'
def use(self,m):
error_exit("unknown command `%s'" % m.group(1))


class cpp_include_block:
pattern=r'^<%\s*c\+\+\s+(.*)%>$'
def use(self,m):
output( m.group(1));


class base_show:
mark='('+variable_match+r')\s*(\|(.*))?'
base_pattern='^\s*'+mark + '$'
def get_params(self,s):
pattern='^\s*(('+variable_match+')|('+str_match+')|(\-?\d+(\.\d*)?))\s*(,(.*))?$'
res=[]
m=re.match(pattern,s)
while m:
if m.group(2):
res.append(make_ident(m.group(2)))
elif m.group(8):
res.append(m.group(8))
elif m.group(10):
res.append(m.group(10))
if m.group(13):
s=m.group(13)
m=re.match(pattern,s)
else:
return res
error_exit("Invalid parameters: `%s'" % s )
return []
def prepare(self,s):
m=re.match(self.base_pattern,s)
if not m:
error_exit("No variable")
return [];
var=make_ident(m.group(1))
if not m.group(8):
return "escape(%s)" % var
filters=m.group(8)
expr='^\s*(ext\s+)?(\w+)\s*(\((([^"\)]|'+str_match + ')*)\))?\s*(\|(.*))?$'
m=re.match(expr,filters)
while m:
if m.group(1):
func="content."+m.group(2)
else:
func=m.group(2)
if m.group(3):
params=','.join([var]+self.get_params(m.group(4)))
else:
params=var
var=func+"("+params+")"
if m.group(8):
filters=m.group(8)
m=re.match(expr,filters)
else:
return var
error_exit("Seems to be a problem in expression %s" % filters)
return "";

class filters_show_block(base_show):
pattern=r'^<%\s*('+ variable_match + r'\s*(\|.*)?)%>$'
def use(self,m):
expr=self.prepare(m.group(1));
if expr!="":
output('cout<<%s;' % expr)

def make_format_params(s):
pattern=r'^(([^,\("]|'+str_match+'|\(([^"\)]|'+str_match+')*\))+)(,(.*))?$'
params=[]
m=re.match(pattern,s)
s_orig=s
while m.group(1):
res=base_show().prepare(m.group(1))
if res:
params.append(res)
if not m.group(6):
return params
s=m.group(7)
m=re.match(pattern,s)
error_exit("Seems to be wrong parameters list [%s]" % s_orig)
return []

class ngettext_block:
pattern=r'^<%\s*ngt\s*('+str_match+')\s*,\s*('+str_match+')\s*,\s*('+variable_match+')\s*(using(.*))?\s*%>$'
def use(self,m):
s1=m.group(1)
s2=m.group(3)
idt=make_ident(m.group(5))
params=[]
if m.group(11):
params=make_format_params(m.group(12))
if not params:
output( "cout<<tr->ngettext(%s,%s,%s);" % (s1,s2,idt))
else:
output( "cout<<(format(tr->ngettext(%s,%s,%s)) %% %s );" % (s1,s2,idt, ' % '.join(params)))

class gettext_block:
pattern=r'^<%\s*gt\s*('+str_match+')\s*(using(.*))?\s*%>$'
def use(self,m):
s=m.group(1)
params=[]
if m.group(3):
params=make_format_params(m.group(4))
if not params:
output( "cout<<tr->gettext(%s);" % s)
else:
output( "cout<<(format(tr->gettext(%s)) %% %s );" % (s , ' % '.join(params)))


class include_block:
pattern=r'^<%\s*include\s+([a-zA_Z]\w*(::\w+)?)\s*\(\s*(.*)\)\s*%>$';
def use(self,m):
if m.group(3):
params=base_show().get_params(m.group(3))
else:
params=[]
output( "%s(%s);" % (m.group(1) , ','.join(params)))

def fetch_content(content):
tmp=''
for row in re.split('\n',content):
global line_number
global file_name
line_number+=1
l1=re.split(r'<%([^"%]|"([^"\\]|\\[^"]|\\")*"|%[^>])*%>',row)
n=0
for l2 in re.finditer(r'<%([^"%]|"([^"\\]|\\[^"]|\\")*"|%[^>])*%>',row):
yield tmp+l1[n]
tmp=''
yield l2.group(0)
n+=3
tmp+=l1[n]+'\n'
yield tmp

def main():
global stack
all=[]
indx=1
global namespace_name
global output_file
global exit_flag
while indx < len(os.sys.argv):
if os.sys.argv[indx]=='-n':
if indx+1>=len(os.sys.argv):
sys.stderr.write("-n should be followed by namespace name\n")
exit_flag=1
return
else:
namespace_name=os.sys.argv[indx+1];
indx+=1
elif os.sys.argv[indx]=='-o':
if indx+1>=len(os.sys.argv):
sys.stderr.write("-o should be followed by output file name\n")
exit_flag=1
return
else:
output_file=os.sys.argv[indx+1]
indx+=1
elif os.sys.argv[indx]=='-d':
if indx+1>=len(os.sys.argv):
sys.stderr.write("-d should followed by gettext domain name\n")
exit_flag=1
return
else:
global spec_gettext
spec_gettext=os.sys.argv[indx+1]
indx+=1
else:
all.append(os.sys.argv[indx])
indx+=1
if not all:
sys.stderr.write("No input file names given\n")
exit_flag=1
return
global output_fd
if output_file!='':
output_fd=open(output_file,"w")
for file in all:
global file_name
global line_number
line_number=0
file_name=file
f=open(file,'r')
content=f.read()
f.close()
for x in fetch_content(content):
if x=='' : continue
if len(stack)==0:
if re.match(r"^\s*$",x):
continue
elif not re.match(r"<\%.*\%>",x):
error_exit("Content is not allowed outside template blocks")
continue
matched=0
for c in [ namespace_block(), class_block(), if_block(), template_block(), end_block(), else_block(), \
cpp_include_block(),\
gettext_block(),ngettext_block(),\
foreach_block(), item_block(), empty_block(),separator_block(),\
include_block(),\
filters_show_block(), error_com()]:
m = re.match(c.pattern,x)
if m :
c.use(m)
matched=1
break
if not matched:
inline_content(x)


if stack:
error_exit("Unexpected end of file %s" % file)
global class_list
if class_list and exit_flag==0:
write_class_loader()

#######################
# MAIN
#######################


output_file=''
output_fd=sys.stdout
namespace_name=''
file_name=''
labels_counter=0
tmpl_seq={}
template_parameters={}
templates_map={}
parameters_counter=2
stack=[]
class_list=[]
exit_flag=0
current_template=''
spec_gettext=''
ignore_inline=1

################
main()
################

if output_fd!=sys.stderr:
output_fd.close()

if exit_flag!=0 and output_file!='':
try:
os.unlink(output_file)
except:
pass

sys.exit(exit_flag)

+ 45
- 0
form.h View File

@@ -0,0 +1,45 @@
#ifndef CPPCMS_FORM_H
#define CPPCMS_FORM_H

namespace cppcms {

class base_form_entry : public boost::noncopyable {
char const *id;
char const *name
public:
base_form_entry(base_form *f,char const *_id,char const *_name) : id(_id),name(w->gettext(_name)) { f->add(this); }
virtual string render_html_input() = 0;
virtual string get_title() = 0;
virtual bool validate() = 0
virtual ~base_form_entry(){};
};

class form_int : public base_form_entry {
bool test;
int low,high;
string id,name;
public:
int value;
Integer(char const *id,char const *name,int default_val=0) : test(false), value(default_val) {};
Integer(string id,string name,int l,int h) : test(true),low(l),high(h) {};
virtual bool validate();
private:

};

class base_form : public boost::noncopyable {
vector<base_form_entry *> this_methods
protected:
void add(base_form_entry *entry);
base_form *operator &(base_form_entry *entry) { add(entry) };
};

struct String {
std::string value;
String();
String(int min_len);
};

}

#endif

+ 16
- 2
hello_world.cpp View File

@@ -1,16 +1,30 @@
#include "worker_thread.h"
#include "manager.h"
#include "hello_world_view.h"

using namespace cppcms;

class my_hello_world : public worker_thread {
public:
my_hello_world(manager const &s) : worker_thread(s) {};
my_hello_world(manager const &s) : worker_thread(s)
{
use_template("view2");
};
virtual void main();
};

void my_hello_world::main()
{
out+="<h1>Simple Hello World test application.</h1>\n";
view::hello v;

v.title="Cool";
v.msg=gettext("Hello World");

for(int i=0;i<15;i++)
v.numbers.push_back(i);
v.lst.push_back(view::data("Hello",10));
v.ok=true;
render("hello",v);
}

int main(int argc,char ** argv)


+ 16
- 0
hello_world_skin1.tmpl View File

@@ -0,0 +1,16 @@
<% c++ #include "hello_world_view.h" %>
<% namespace vary %>
<% class master uses view::master %>
<% template render() %>
<html>
<title>Skin1 :: <% title %></title>
<body>
<% include body() %>
</body>
</html>
<% end template %>
<% template body() %>
<% end template %>
<% end class %>
<% end namespace %>


+ 16
- 0
hello_world_skin2.tmpl View File

@@ -0,0 +1,16 @@
<% c++ #include "hello_world_view.h" %>
<% namespace vary %>
<% class master uses view::master %>
<% template render() %>
<html>
<title>Skin2:: <% title %></title>
<body>
<% include body() %>
</body>
</html>
<% end template %>
<% template body() %>
<% end template %>
<% end class %>
<% end namespace %>


+ 25
- 0
hello_world_view.h View File

@@ -0,0 +1,25 @@
#include "base_view.h"
#include <list>

class my_hello_world;
namespace view {

struct master : public cppcms::base_content {
std::string title;
bool ok;
};

struct data {
std::string name;
int val;
data(char const *n="",int v=0) : name(n),val(v){}
};

struct hello : public master {
std::string msg;
std::list<int> numbers;
std::list<data> lst;
};

};


+ 16
- 0
hello_world_view1.tmpl View File

@@ -0,0 +1,16 @@
<% namespace vary %>
<% class hello uses view::hello extends master %>
<% template body() %>
<% if rtl %><% end %>
<% if not empty title %><h1><% title %></h1><% end %>
<p><% msg %></p>
<% foreach x in numbers %>
<ul>
<% item %>
<li><% ngt "passed one day","passed %d days",x using x %></li>
<% end %>
</ul>
<% end %>
<% end template %>
<% end class %>
<% end namespace %>

+ 60
- 0
manager.cpp View File

@@ -4,6 +4,8 @@

#include "manager.h"
#include "cgicc_connection.h"
#include <dlfcn.h>
#include <dirent.h>
#include <poll.h>
#include <signal.h>
#include <errno.h>
@@ -13,10 +15,12 @@
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <algorithm>
#include "thread_cache.h"
#include "scgi.h"
#include "cgi.h"


#ifdef EN_FORK_CACHE
# include "process_cache.h"
#endif
@@ -511,12 +515,44 @@ void manager::execute()
if(!web_app.get()) {
set_mod(get_mod());
}
if(!gettext.get()){
set_gettext(get_gettext());
}
if(!workers.get()) {
throw cppcms_error("No workers factory set up");
}

load_templates();
web_app->execute();
}

void manager::load_templates()
{
string ext=config.sval("templates.ext",".so");
unsigned len=ext.size();
vector<string> const &dirs=config.slist("templates.dirs");
for(vector<string>::const_iterator dir=dirs.begin();dir!=dirs.end();++dir) {
DIR *d=::opendir(dir->c_str());
if(!d) continue;
for(struct dirent *entry=::readdir(d);entry;entry=::readdir(d)) {
string filename=entry->d_name;
if( filename.size()>len &&
filename.substr(filename.size()-len,len) == ext )
{
void *handler=::dlopen((*dir + "/" + filename).c_str(),RTLD_LAZY);
if(handler) templates_list.push_back(handler);
}
}
::closedir(d);
}
}

manager::~manager()
{
for_each(templates_list.begin(),templates_list.end(),::dlclose);
}

void manager::set_worker(base_factory *w)
{
workers=auto_ptr<base_factory>(w);
@@ -537,6 +573,30 @@ void manager::set_mod(web_application *m)
web_app=auto_ptr<web_application>(m);
}

transtext::trans_factory *manager::get_gettext()
{
transtext::trans_factory *tmp=NULL;
try{
tmp=new transtext::trans_factory();
tmp->load( config.sval ("locale.dir",""),
config.slist("locale.lang_list"),
config.sval ("locale.lang_default",""),
config.slist ("locale.domain_list"),
config.sval ("locale.domain_default",""));
return tmp;
}
catch(...){
delete tmp;
throw;
}
}

void manager::set_gettext(transtext::trans_factory *s)
{
gettext=auto_ptr<transtext::trans_factory>(s);
}

manager::manager()
{
config.load(0,NULL);


+ 11
- 3
manager.h View File

@@ -1,5 +1,5 @@
#ifndef _THREAD_POOL_H
#define _THREAD_POOL_H
#ifndef CPPCMS_MANAGER_H
#define CPPCMS_MANAGER_H

#include <pthread.h>
#include <string>
@@ -11,6 +11,7 @@
#include "cache_interface.h"
#include "cgi_api.h"
#include "posix_mutex.h"
#include "transtext.h"

#include <boost/shared_ptr.hpp>

@@ -209,6 +210,9 @@ class manager : private boost::noncopyable {
cache_factory *get_cache_factory();
cgi_api *get_api();
web_application *get_mod();
transtext::trans_factory *get_gettext();
list<void *> templates_list;
void load_templates();
public:
cppcms_config config;
auto_ptr<cache_factory> cache;
@@ -216,16 +220,20 @@ public:
auto_ptr<base_factory> workers;
auto_ptr<web_application> web_app;

auto_ptr<transtext::trans_factory> gettext;

void set_worker(base_factory *w);
void set_cache(cache_factory *c);
void set_api(cgi_api *a);
void set_mod(web_application *m);
void set_gettext(transtext::trans_factory *);

manager();
manager(char const *file);
manager(int argc, char **argv);
~manager();
void execute();
};

}
#endif /* _THREAD_POOL_H */
#endif /* CPPCMS_MANAGER_H */

+ 8
- 0
transtext/Makefile.am View File

@@ -0,0 +1,8 @@
noinst_PROGRAMS = test
test_SOURCES = test.cpp
test_LDADD = libcppcmstranstext.la
lib_LTLIBRARIES=libcppcmstranstext.la
libcppcmstranstext_la_SOURCES = transtext.cpp lambda.cpp mo_file.cpp trans_factory.cpp
libcppcmstranstext_la_LDFLAGS = -no-undefined
noinst_HEADERS = mo_file.h
nobase_pkginclude_HEADERS = transtext.h

+ 399
- 0
transtext/lambda.cpp View File

@@ -0,0 +1,399 @@
#include "transtext.h"
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <cassert>
#ifdef DEBUG_LAMBDA
#include <iostream>
using namespace std;
#endif

#ifdef DEBUG_LAMBDA
#define LOG(x) x
#else
#define LOG(x)
#endif

namespace cppcms {
namespace transtext {

namespace lambda {
struct identity : public plural {
virtual int operator()(int n) const { LOG(cout<<"id("<<n<<")\n";) return n; };
};

struct unary : public plural {
plural *op1;
unary(plural *ptr): op1(ptr) {};
virtual ~unary() { delete op1; };
};


struct binary : public plural {
plural *op1,*op2;
binary(plural *p1,plural *p2): op1(p1),op2(p2) {};
virtual ~binary() { delete op1; delete op2; };
};

struct number : public plural {
int val;
number(int v) : val(v) {};
virtual int operator()(int n) const { LOG(cout<<"value="<<val<<endl;) return val; };
};

#ifdef DEBUG_LAMBDA
#define UNOP(name,oper) \
struct name: public unary { name(plural *op) : unary(op) {};\
virtual int operator()(int n) const { int v=(*op1)(n); cerr<<#oper<<v<<endl; return oper(v); }; };

#define BINOP(name,oper) \
struct name : public binary { name(plural *p1,plural *p2) : binary(p1,p2) {}; virtual int operator()(int n) const \
{ int v1=(*op1)(n); int v2=(*op2)(n); cout<<v1<<#oper<<v2<<endl; return v1 oper v2; }; };

#define BINOPD(name,oper) \
struct name : public binary { \
name(plural *p1,plural *p2) : binary(p1,p2) {};\
virtual int operator()(int n) const { int v1=(*op1)(n); int v2=(*op2)(n); \
cout<<v1<<#oper<<v2<<endl; \
return v2==0 ? 0 : v1 oper v2; };\
};
#else
#define UNOP(name,oper) \
struct name: public unary { name(plural *op) : unary(op) {}; virtual int operator()(int n) const { return oper (*op1)(n); }; };

#define BINOP(name,oper) \
struct name : public binary { name(plural *p1,plural *p2) : binary(p1,p2) {}; virtual int operator()(int n) const { return (*op1)(n) oper (*op2)(n); }; };

#define BINOPD(name,oper) \
struct name : public binary { \
name(plural *p1,plural *p2) : binary(p1,p2) {};\
virtual int operator()(int n) const { int v1=(*op1)(n); int v2=(*op2)(n); return v2==0 ? 0 : v1 oper v2; };\
};
#endif
enum { END = 0 , SHL = 256, SHR, GTE,LTE, EQ, NEQ, AND, OR, NUM, VARIABLE };

UNOP(l_not,!)
UNOP(minus,-)
UNOP(bin_not,~)

BINOP(mul,*)
BINOPD(div,/)
BINOPD(mod,%)
static int level10[]={3,'*','/','%'};

BINOP(add,+)
BINOP(sub,-)
static int level9[]={2,'+','-'};

BINOP(shl,<<)
BINOP(shr,>>)
static int level8[]={2,SHL,SHR};

BINOP(gt,>)
BINOP(lt,<)
BINOP(gte,>=)
BINOP(lte,<=)
static int level7[]={4,'<','>',GTE,LTE};

BINOP(eq,==)
BINOP(neq,!=)
static int level6[]={2,EQ,NEQ};

BINOP(bin_and,&)
static int level5[]={1,'&'};

BINOP(bin_xor,^)
static int level4[]={1,'^'};

BINOP(bin_or,|)
static int level3[]={1,'|'};

BINOP(l_and,&&)
static int level2[]={1,AND};

BINOP(l_or,||)
static int level1[]={1,OR};

struct conditional : public plural {
plural *op1,*op2,*op3;
conditional(plural *p1,plural *p2,plural *p3): op1(p1),op2(p2),op3(p3) {};
virtual ~conditional() { delete op1; delete op2; delete op3; };
virtual int operator()(int n) const { return (*op1)(n) ? (*op2)(n) : (*op3)(n); };
};


plural *bin_factory(int value,plural *left,plural *right)
{
switch(value) {
case '/': return new div(left,right);
case '*': return new mul(left,right);
case '%': return new mod(left,right);
case '+': return new add(left,right);
case '-': return new sub(left,right);
case SHL: return new shl(left,right);
case SHR: return new shr(left,right);
case '>': return new gt(left,right);
case '<': return new lt(left,right);
case GTE: return new gte(left,right);
case LTE: return new lte(left,right);
case EQ: return new eq(left,right);
case NEQ: return new neq(left,right);
case '&': return new bin_and(left,right);
case '^': return new bin_xor(left,right);
case '|': return new bin_or (left,right);
case AND: return new l_and(left,right);
case OR: return new l_or(left,right);
default:
delete left;
delete right;
return NULL;
}
}

plural *un_factory(int value,plural *op)
{
switch(value) {
case '!': return new l_not(op);
case '~': return new bin_not(op);
case '-': return new minus(op);
default:
delete op;
return NULL;
}
}

static inline bool is_in(int v,int *p)
{
int len=*p;
p++;
while(len && *p!=v) { p++;len--; }
return len;
}


class tockenizer {
char const *text;
int pos;
int next_tocken;
int int_value;
void step()
{
while(text[pos] && isblank(text[pos])) pos++;
char const *ptr=text+pos;
char *tmp_ptr;
if(strncmp(ptr,"<<",2)==0) { pos+=2; next_tocken=SHL; }
else if(strncmp(ptr,">>",2)==0) { pos+=2; next_tocken=SHR; }
else if(strncmp(ptr,"&&",2)==0) { pos+=2; next_tocken=AND; }
else if(strncmp(ptr,"||",2)==0) { pos+=2; next_tocken=OR; }
else if(strncmp(ptr,"<=",2)==0) { pos+=2; next_tocken=LTE; }
else if(strncmp(ptr,">=",2)==0) { pos+=2; next_tocken=GTE; }
else if(strncmp(ptr,"==",2)==0) { pos+=2; next_tocken=EQ; }
else if(strncmp(ptr,"!=",2)==0) { pos+=2; next_tocken=NEQ; }
else if(*ptr=='n') { pos++; next_tocken=VARIABLE; }
else if(isdigit(*ptr)) { int_value=strtol(text+pos,&tmp_ptr,0); pos=tmp_ptr-text; next_tocken=NUM; }
else if(*ptr=='\0') { next_tocken=0; }
else { next_tocken=*ptr; pos++; }
#ifdef DEBUG_LAMBDA
if(next_tocken>=' ' && next_tocken<=127)
std::cout<<"Tocken:"<<(char)next_tocken<<'\n';
else if(next_tocken==NUM)
std::cout<<"Number:"<<int_value<<"\n";
else if(next_tocken==VARIABLE)
std::cout<<"Variale\n";
else
std::cout<<"TockenID:"<<next_tocken<<'\n';
#endif
}
public:
tockenizer(char const *s) { text=s; pos=0; step(); };
int get(int *val=NULL){
int iv=int_value;
int res=next_tocken;
step();
if(val && res==NUM){
*val=iv;
}
return res;
};
int next(int *val=NULL) {
if(val && next_tocken==NUM) {
*val=int_value;
return NUM;
}
return next_tocken;
}
};


#define BINARY_EXPR(expr,hexpr,list) \
plural *expr() \
{ \
LOG(std::cout<< #expr<<'\n';) \
plural *op1=NULL,*op2=NULL; \
if((op1=hexpr())==NULL) goto error; \
while(is_in(t.next(),list)) { \
LOG(cout<<"Concate with "<<(char)t.next()<<endl;) \
int o=t.get(); \
if((op2=hexpr())==NULL) goto error; \
op1=bin_factory(o,op1,op2); \
assert(op1); \
op2=NULL; \
} \
return op1; \
error: \
delete op1; \
delete op2; \
return NULL; \
}

struct parser {
tockenizer &t;
parser(tockenizer &tin) : t(tin) {};

plural *value_expr()
{
LOG(std::cout<<"Value\n";)
plural *op=NULL;
if(t.next()=='(') {
LOG(std::cout<<"Value ()\n";)
t.get();
if((op=cond_expr())==NULL) goto error;
if(t.get()!=')') goto error;
return op;
}
else if(t.next()==NUM) {
int value;
t.get(&value);
LOG(std::cout<<"Value ("<<value<<")\n";)
return new number(value);
}
else if(t.next()==VARIABLE) {
t.get();
LOG(std::cout<<"Value (n)\n";)
return new identity();
}
return NULL;
error:
delete op;
return NULL;
};

plural *un_expr()
{
plural *op1=NULL;
static int level_unary[]={3,'-','!','~'};
if(is_in(t.next(),level_unary)) {
int op=t.get();
if((op1=un_expr())==NULL)
goto error;
switch(op) {
case '-':
LOG(std::cout<<"Unary(-)\n";)
return new minus(op1);
case '!':
LOG(std::cout<<"Unary(!)\n";)
return new l_not(op1);
case '~':
LOG(std::cout<<"Unary(~)\n";)
return new bin_not(op1);
default:
goto error;
}
}
else {
LOG(std::cout<<"Unary... none\n";)
return value_expr();
}
error:
delete op1;
return NULL;
};

BINARY_EXPR(l10,un_expr,level10);
BINARY_EXPR(l9,l10,level9);
BINARY_EXPR(l8,l9,level8);
BINARY_EXPR(l7,l8,level7);
BINARY_EXPR(l6,l7,level6);
BINARY_EXPR(l5,l6,level5);
BINARY_EXPR(l4,l5,level4);
BINARY_EXPR(l3,l4,level3);
BINARY_EXPR(l2,l3,level2);
BINARY_EXPR(l1,l2,level1);

plural *cond_expr()
{
plural *cond=NULL,*case1=NULL,*case2=NULL;
if((cond=l1())==NULL)
goto error;
if(t.next()=='?') {
LOG(std::cout<<"Condtion... make\n";)
t.get();
if((case1=cond_expr())==NULL)
goto error;
if(t.get()!=':')
goto error;
if((case2=cond_expr())==NULL)
goto error;
}
else {
LOG(std::cout<<"Condtion... none\n";)
return cond;
}
return new conditional(cond,case1,case2);
error:
delete cond;
delete case1;
delete case2;
return NULL;
}
public:
plural *compile()
{
plural *res=cond_expr();
if(res && t.next()!=END) {
delete res;
return NULL;
};
return res;
}
};
#ifdef DEBUG_LAMBDA
string printtree(plural *p)
{
identity *pi=dynamic_cast<identity *>(p);
if(pi) { return string("n"); };
unary *pu=dynamic_cast<unary *>(p);
if(pu) { return string(typeid(*pu).name())+"("+printtree(pu->op1)+")"; }
binary *pb=dynamic_cast<binary *>(p);
if(pb) { return string(typeid(*pb).name())+"("+printtree(pb->op1)+","+printtree(pb->op2)+")"; };
number *pn=dynamic_cast<number *>(p);
if(pn) { char buf[32]; snprintf(buf,sizeof(buf),"(%d)",pn->val); return string(buf); };
conditional *pc=dynamic_cast<conditional *>(p);
if(pc) { return "("+printtree(pc->op1)+")?("+printtree(pc->op2)+"):("+printtree(pc->op3)+")"; };
return string("PLURAL");
}
#endif

plural *compile(char const *str)
{
LOG(cout<<"Compiling:["<<str<<"]\n";)
tockenizer t(str);
parser p(t);
plural *tmp=p.compile();
#ifdef DEBUG_LAMBDA
cout<<printtree(tmp)<<endl;
for(int i=0;i<15;i++) {
cout<<"f("<<i<<")="<<(*tmp)(i)<<endl;
}
#endif
return tmp;
}


} // namespace lambda

} //Öł Namespace gettext

} // namespace cppcms



+ 37
- 0
transtext/locale/he/LC_MESSAGES/test.po View File

@@ -0,0 +1,37 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-04-25 23:28+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural= n!=1 ? n>10 ? 3 : n==2 ? 2 : 1 : 0 ;\n"

msgid "hello\n"
msgstr "shalom\n"

msgid "LTR"
msgstr "RTL"

msgid "LANG"
msgstr "Hebrew"

msgid "Hello %1%, %2%"
msgstr "Shalom %1%, %2%"

msgid "passed one day"
msgid_plural "passed %d days"
msgstr[0] "avar yom ehad"
msgstr[1] "avru %d yamim"
msgstr[2] "avru yomaim"
msgstr[3] "avru %d yom"

+ 339
- 0
transtext/mo_file.cpp View File

@@ -0,0 +1,339 @@
#include "mo_file.h"
/********************************************************
* This file was adopted by Artyom Tonkikh for *
* purouses of thread safe gettext implementation *
********************************************************/
/*
The MIT License
Copyright (c) 2007 Jonathan Blow (jon [at] number-none [dot] com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This code is designed to be a very simple drop-in method for reading .mo
files, which are a standard format for storing text strings to help with
internationalization.
For more information, see: http://www.gnu.org/software/gettext/manual/gettext.html
Unfortunately the gettext code is unwieldy. For a simple program like
a video game, we just want to look up some strings in a pre-baked file,
which is what this code does.
We assume that you started with a .po file (which is a human-readable format
containing all the strings) and then compiled it into a .mo file (which is
a binary format that can be efficiently read into memory all in one chunk).
This code then reads straight from the .mo file, so there is no extra
string allocation and corresponding memory fragmentation.
You can generate a .mo file from a .po file using programs such as poedit
or msgfmt.
This code assumes you compiled the hash table into the .mo file. It also
doesn't attempt to care about the encoding of your text; it assumes you
already know what that is. (I use UTF-8 which seems like the only sane
choice).
There's no good reason that this is a C++ file, rather than a C file; I just
wrote it that way originally. You can trivially get rid of the C++-ness if
you want it to compile as straight C.
Send questions to jon [at] number-none [dot] com.
21 December 2007
*/
// From the header file:
namespace thr_safe_gettext {
struct Localization_Text {
Localization_Text(char const*);
~Localization_Text();
void abort();
void *mo_data;
int reversed;
int num_strings;
int original_table_offset;
int translated_table_offset;
int hash_num_entries;
int hash_offset;
};
// From the .cpp fie:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
// This is just the common hashpjw routine, pasted in:
#define HASHWORDBITS 32
inline unsigned long hashpjw(const char *str_param) {
unsigned long hval = 0;
unsigned long g;
const char *s = str_param;
while (*s) {
hval <<= 4;
hval += (unsigned char) *s++;
g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
if (g != 0) {
hval ^= g >> (HASHWORDBITS - 8);
hval ^= g;
}
}
return hval;
}
// Here is the actual code:
// Read an entire file into memory. Replace this with any equivalent function.
#ifdef WIN32
#define fileno _fileno
#define fstat _fstat
#define stat _stat
#endif
int os_read_entire_file(FILE *file, void **data_return) {
assert(file);
int descriptor = fileno(file);
struct stat file_stats;
int result = fstat(descriptor, &file_stats);
if (result == -1) return -1;
int length = file_stats.st_size;
unsigned char *data = new unsigned char[length];
fseek(file, 0, SEEK_SET);
int success = fread((void *)data, length, 1, file);
if (success < 1) {
delete [] data;
return -1;
}
*data_return = data;
return length;
}
// Swap the endianness of a 4-byte word.
// On some architectures you can replace my_swap4 with an inlined instruction.
inline unsigned long my_swap4(unsigned long result) {
unsigned long c0 = (result >> 0) & 0xff;
unsigned long c1 = (result >> 8) & 0xff;
unsigned long c2 = (result >> 16) & 0xff;
unsigned long c3 = (result >> 24) & 0xff;
return (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
}
inline int read4_from_offset(Localization_Text *loc, int offset) {
unsigned long *ptr = (unsigned long *)(((char *)loc->mo_data) + offset);
if (loc->reversed) {
return my_swap4(*ptr);
} else {
return *ptr;
}
}
inline char *get_source_string(Localization_Text *loc, int index,int *len=NULL) {
int addr_offset = loc->original_table_offset + 8 * index;
int string_len = read4_from_offset(loc, addr_offset);
int string_offset = read4_from_offset(loc, addr_offset+4);
char *t = ((char *)loc->mo_data) + string_offset;
if(len) *len=string_len;
return t;
}
inline char *get_translated_string(Localization_Text *loc, int index, int *len=NULL) {
int addr_offset = loc->translated_table_offset + 8 * index;
if(len) *len=read4_from_offset(loc, addr_offset);
int string_offset = read4_from_offset(loc, addr_offset+4);
char *t = ((char *)loc->mo_data) + string_offset;
return t;
}
static bool label_matches(Localization_Text *loc, char const *s, int index) {
char *t = get_source_string(loc, index);
if (strcmp(s, t) == 0) return true;
return false;
}
inline int get_target_index(Localization_Text *loc, char const *s) {
unsigned long V = hashpjw(s);
int S = loc->hash_num_entries;
int hash_cursor = V % S;
int orig_hash_cursor = hash_cursor;
int increment = 1 + (V % (S - 2));
while (1) {
unsigned int index = read4_from_offset(loc, loc->hash_offset + 4 * hash_cursor);
if (index == 0) break;
index--; // Because entries in the table are stored +1 so that 0 means empty.
if (label_matches(loc, s, index)) return index;
// if (index_empty(loc, index)) break;
hash_cursor += increment;
hash_cursor %= S;
if (hash_cursor == orig_hash_cursor) break;
}
return -1;
}
Localization_Text::Localization_Text(char const *filename) {
mo_data = NULL;
num_strings = 0;
original_table_offset = 0;
translated_table_offset = 0;
hash_num_entries = 0;
hash_offset = 0;
FILE *f = fopen(filename, "rb");
if (!f) return;
void *data;
int length = os_read_entire_file(f, &data); // Replace this with any function that will read an entire file and return it in a block of newly-allocated memory.
fclose(f);
if (length < 0) return; // os_read_entire_file returns -1 on failure.
if (length < 24) { // There has to be at least this much in the header...
abort();
return;
}
mo_data = data;
unsigned long *long_ptr = (unsigned long *)data;
const unsigned long TARGET_MAGIC = 0x950412DE;
const unsigned long TARGET_MAGIC_REVERSED = 0xDE120495;
unsigned long magic = long_ptr[0];
if (magic == TARGET_MAGIC) {
reversed = 0;
} else if (magic == TARGET_MAGIC_REVERSED) {
reversed = 1;
} else {
abort();
return;
}
num_strings = read4_from_offset(this, 8);
original_table_offset = read4_from_offset(this, 12);
translated_table_offset = read4_from_offset(this, 16);
hash_num_entries = read4_from_offset(this, 20);
hash_offset = read4_from_offset(this, 24);
if (hash_num_entries == 0) { // We expect a hash table to be there; if it's not, bail.
abort();
return;
}
}
void Localization_Text::abort() {
delete [] (char *)mo_data;
mo_data = NULL;
return;
}
Localization_Text::~Localization_Text() {
if (mo_data) delete [] ((char *)mo_data);
}
//
// Call text_lookup to go from a source string to a translated string.
// This is the main entry point that you would use. (The only other
// entry point is to construct a Localization_Text() to initialize
// things.)
//
extern "C" char const *thr_safe_gettext_text_lookup(void *the_localization_text, char const *s,int std_id)
{
Localization_Text *loc = (Localization_Text *)the_localization_text;
if (!loc || !loc->mo_data) return NULL;
int len;
int target_index = get_target_index(loc, s);
if (target_index == -1) return NULL; // Maybe we want to log an error?
char *tmp=get_translated_string(loc, target_index, &len);
char *p=tmp;
while(std_id>0 && p-tmp<len) {
if(*p)
p++;
else{
p++;
std_id--;
}
}
if(p-tmp<len)
return p;
else
return NULL;
}
extern "C" void *thr_safe_gettext_load(char const *mo_file)
{
return new Localization_Text(mo_file);
}
extern "C" void thr_safe_gettext_unload(void *ptr)
{
delete (Localization_Text*)ptr;
}
} // END OF thr_safe_gettext namespace

+ 12
- 0
transtext/mo_file.h View File

@@ -0,0 +1,12 @@
#ifndef MO_FILE
#define MO_FILE

extern "C" {

void *thr_safe_gettext_load(char const *mo_file);
void thr_safe_gettext_unload(void *ptr);
char const *thr_safe_gettext_text_lookup(void *the_localization_text, char const *s,int std_id);

};

#endif

+ 28
- 0
transtext/test.cpp View File

@@ -0,0 +1,28 @@
#include "transtext.h"
#include <stdio.h>
#include <cstdlib>

using namespace cppcms::transtext;


int main(int argc,char **argv)
{
trans_factory tf;

vector<string> domains;
domains.push_back("test");
vector<string> langs;
langs.push_back("en");
langs.push_back("he");
tf.load("./locale",langs,"",domains,"");

int i;
for(i=0;i<15;i++) {
printf(tf.get("he","").ngettext("passed one day","passed %d days",i),i);
putchar('\n');
printf(tf.get("en","").ngettext("passed one day","passed %d days",i),i);
putchar('\n');
}

return 0;
}

+ 67
- 0
transtext/trans_factory.cpp View File

@@ -0,0 +1,67 @@
#include "transtext.h"

using namespace std;

namespace cppcms {

namespace transtext {

static const trans default_trans;

trans const &trans_factory::get(string lang,string domain) const
{
map<string,map<string,boost::shared_ptr<trans> > >::const_iterator p;

if(lang.empty()) lang=default_lang;
if(domain.empty()) domain=default_domain;

if((p=langs.find(lang))==langs.end()) {
return default_trans;
}
else {
map<string,boost::shared_ptr<trans> >::const_iterator p2;
if((p2=p->second.find(domain))==p->second.end()) {
return default_trans;
}
return *(p2->second);
}
}

void trans_factory::load(
string const &locale_dir,
vector<string> const &lang_list,
string const &lang_def,
vector<string> const &domain_list,
string const &domain_def)
{
if(lang_list.empty() || domain_list.empty()) {
return;
}

default_lang=lang_def;
default_domain=domain_def;

if(default_lang.empty()) default_lang=lang_list[0];
if(default_domain.empty()) default_domain=domain_list[0];

typedef vector<string>::const_iterator it_t;

for(it_t lang=lang_list.begin(),le=lang_list.end();lang!=le;++lang)
{
for(it_t domain=domain_list.begin(),de=domain_list.end();de!=domain;++domain) {
boost::shared_ptr<trans_thread_safe> tr(new trans_thread_safe());
tr->load(lang->c_str(),domain->c_str(),locale_dir.c_str());
langs[*lang][*domain]=tr;
}
}
}


trans_factory::~trans_factory()
{
}


} // namespace transtext

} // namespace cppcms

+ 93
- 0
transtext/transtext.cpp View File

@@ -0,0 +1,93 @@
#include "transtext.h"
#include "mo_file.h"
#include <cstring>
#include <cstdlib>
#include <ctype.h>
#include <string>
#include <iostream>

namespace cppcms {

namespace transtext {
using namespace lambda;
using namespace std;

struct default_plural : public plural {
int operator()(int n) const { return n==1 ? 0 : 1; };
~default_plural() {};
};

trans_thread_safe::trans_thread_safe()
{
data=NULL;
converter=new default_plural;
}

trans_thread_safe::~trans_thread_safe()
{
if(data){
thr_safe_gettext_unload(data);
}
delete converter;
}

static plural *get_converter(char const *header)
{
char const *ptr,*ptr2;
string tmp;
plural *result;
if(!header) goto error;
ptr=strstr(header,"Plural-Forms:");
if(!ptr) goto error;
ptr=strstr(ptr,"plural");
if(!ptr) goto error;
if(ptr[6]=='s') { // Prevent detecting plurals as plural
ptr=strstr(ptr+6,"plural");
}
if(!ptr) goto error;
ptr+=6;
while(*ptr && isblank(*ptr)) ptr++;
if(*ptr!='=') goto error;
ptr++;
ptr2=strstr(ptr,";");
if(!ptr2) goto error;
tmp.append(ptr,ptr2-ptr);
result=compile(tmp.c_str());
if(!result) goto error;
return result;
error:
return new default_plural();
}

void trans_thread_safe::load(char const * locale,char const *domain_name, char const * dirname)
{
if(data) thr_safe_gettext_unload(data);
string path_to_mo_file=string(dirname)+"/" + locale +"/LC_MESSAGES/" + domain_name + ".mo";

data=thr_safe_gettext_load(path_to_mo_file.c_str());
char const *header=thr_safe_gettext_text_lookup(data,"",0);
delete converter;
converter=get_converter(header);
}

char const *trans_thread_safe::gettext(char const *s) const
{
char const *t=thr_safe_gettext_text_lookup(data,s,0);
return t ? t : s;
}

char const *trans_thread_safe::ngettext(char const *s,char const *p,int n) const
{
int idx=(*converter)(n);
if(idx<0) idx=0;
char const *t=thr_safe_gettext_text_lookup(data,s,idx);
if(!t) {
return n==1 ? s : p;
}
return t;
}


} // namespace transtex

} // namespace cppcms

+ 66
- 0
transtext/transtext.h View File

@@ -0,0 +1,66 @@
#ifndef CPPCMS_TRANSTEXT_H
#define CPPCMS_TRANSTEXT_H

#include <map>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>

namespace cppcms {

namespace transtext {
using namespace std;

namespace lambda {
struct plural { // INTERFACE
virtual int operator()(int n) const = 0;
virtual ~plural(){};
};
plural *compile(char const *expr);

}; // END OF NAMESPACE LAMBDA

class trans {
public:
trans() {};
virtual ~trans() {};
virtual void load(char const * locale,char const *domain_name, char const * dirname) {};
virtual char const *gettext(char const *s) const { return s; };
virtual char const *ngettext(char const *s,char const *p,int n) const { return n==1 ? s:p; };
char const *operator()(char const *str) const { return gettext(str); };
char const *operator()(char const *single,char const *plural,int n) const { return ngettext(single,plural,n); };
};

class trans_thread_safe : public trans {
lambda::plural *converter;
void *data;
public:
trans_thread_safe();
virtual ~trans_thread_safe();
virtual void load(char const * locale,char const *domain_name, char const * dirname);
virtual char const *gettext(char const *s) const;
virtual char const *ngettext(char const *single,char const *plural,int n) const;
lambda::plural const & num2idx_conv() const { return *converter; };
int num2idx(int n) const { return (*converter)(n); };
};

class trans_factory {
map<string,map<string,boost::shared_ptr<trans> > > langs;
string default_lang;
string default_domain;
public:
trans const &get(string lang,string domain) const;
void load( string const &locale_dir,
vector<string> const &lang_list,
string const &lang_def,
vector<string> const &domain_list,
string const &domain_def);
~trans_factory();
};

} // namespace transtext
} // namespace cppcms


#endif

+ 83
- 30
worker_thread.cpp View File

@@ -1,6 +1,7 @@
#include "worker_thread.h"
#include "global_config.h"
#include "thread_cache.h"
#include "base_view.h"

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
@@ -10,22 +11,63 @@
using namespace cgicc;
namespace cppcms {

worker_thread::worker_thread(manager const &s) :
url(this),
app(s),
cache(this),
cout(&(this->out_buf))
{
caching_module=app.cache->get();
static const transtext::trans tr;
gt=&tr;
} ;

worker_thread::~worker_thread()
{
app.cache->del(caching_module);
}
void worker_thread::main()
{
out="<h1>Hello World</h2>\n";
cout<<"<h1>Hello World</h2>\n";
}
void worker_thread::set_header(HTTPHeader *h)
{
response_header=auto_ptr<HTTPHeader>(h);
};
void worker_thread::add_header(string s) {
other_headers.push_back(s);
};

void worker_thread::set_cookie(cgicc::HTTPCookie const &c)
{
response_header->setCookie(c);
}

void worker_thread::set_lang(string const &s)
{
lang=s;
gt=&app.gettext->get(s,"");
}

transtext::trans const *worker_thread::domain_gettext(string const &domain)
{
return &app.gettext->get(lang,domain);
}

HTTPHeader &worker_thread::header()
{
return *response_header;
}

void worker_thread::run(cgicc_connection &cgi_conn)
{
cgi=&cgi_conn.cgi();
env=&(cgi->getEnvironment());
ostream &cout=cgi_conn.cout();

ostream &cgi_out=cgi_conn.cout();
other_headers.clear();
out.clear();
out.reserve(app.config.lval("server.buffer_reserve",16000));
cache.reset();
set_lang("");
out_buf.str("");

set_header(new HTTPHTMLHeader);

@@ -48,10 +90,12 @@ void worker_thread::run(cgicc_connection &cgi_conn)
}
catch(std::exception const &e) {
string msg=e.what();
set_header(new HTTPStatusHeader(500,msg));
out="<html><body><p>"+msg+"</p><body></html>";
cgi_out<<HTTPStatusHeader(500,msg);
cgi_out<<"<html><body><p>"+msg+"</p><body></html>";
gzip=gzip_done=false;
other_headers.clear();
out_buf.str("");
return;
}

if(app.config.lval("server.disable_xpowered_by",0)==0) {
@@ -59,53 +103,62 @@ void worker_thread::run(cgicc_connection &cgi_conn)
}

for(list<string>::iterator h=other_headers.begin();h!=other_headers.end();h++) {
cout<<*h<<"\n";
cgi_out<<*h<<"\n";
}

string out=out_buf.str();
out_buf.str("");

if(gzip) {
if(out.size()>0) {
if(gzip_done){
cout<<"Content-Length: "<<out.size()<<"\n";
cgi_out<<"Content-Length: "<<out.size()<<"\n";
}
cout<<"Content-Encoding: gzip\n";
cout<<*response_header;
cgi_out<<"Content-Encoding: gzip\n";
cgi_out<<*response_header;
if(gzip_done) {
cout<<out;
cgi_out<<out;
}
else{
long level=app.config.lval("gzip.level",-1);
long length=app.config.lval("gzip.buffer",-1);
deflate(out,cout,level,length);
deflate(out,cgi_out,level,length);
}
}
else {
cout<<*response_header;
cgi_out<<*response_header;
}
}
else {
cout<<"Content-Length: "<<out.size()<<"\n";
cout<<*response_header;
cout<<out;
cgi_out<<"Content-Length: "<<out.size()<<"\n";
cgi_out<<*response_header;
cgi_out<<out;
}

// Clean Up
out.clear();
other_headers.clear();
response_header.reset();
cgi=NULL;
}

void worker_thread::init_internal()
void worker_thread::render(string tmpl,string name,base_content &content,ostream &out )
{
caching_module=app.cache->get();
}

worker_thread::~worker_thread()
using cppcms::details::views_storage;
base_view::settings s(this,&out);
auto_ptr<base_view> p(views_storage::instance().fetch_view(tmpl,name,s,&content));
if(!p.get()) throw cppcms_error("Template `"+name+"' not found in template set `" + tmpl +"'");
p->render();
};

void worker_thread::render(string tmpl,string name,base_content &content)
{
app.cache->del(caching_module);
}
render(tmpl,name,content,cout);
};

void worker_thread::render(string name,base_content &content,ostream &o)
{
render(current_template,name,content,o);
};

void worker_thread::render(string name,base_content &content)
{
render(current_template,name,content,cout);
};

}



+ 46
- 21
worker_thread.h View File

@@ -17,10 +17,12 @@
#include "cache_interface.h"
#include "base_cache.h"
#include "cgicc_connection.h"
#include "transtext.h"

namespace cppcms {

class manager;
class base_content;

using namespace std;
using cgicc::CgiEnvironment;
@@ -28,41 +30,64 @@ using cgicc::Cgicc;
using cgicc::HTTPHeader;

class worker_thread: private boost::noncopyable {
friend class url_parser;
friend class cache_iface;
friend class url_parser;
friend class cache_iface;
friend class base_view;

list<string> other_headers;
base_cache *caching_module;
bool gzip;
bool gzip_done;
stringbuf out_buf;

transtext::trans const *gt;
string lang;
auto_ptr<HTTPHeader> response_header;

protected:

url_parser url;
manager const &app;
Cgicc *cgi;
CgiEnvironment const *env;

auto_ptr<HTTPHeader> response_header;
list<string> other_headers;
void set_header(HTTPHeader*h){response_header=auto_ptr<HTTPHeader>(h);};
void add_header(string s) { other_headers.push_back(s); };
virtual void main();
cache_iface cache;
ostream cout;

// Output and Cahce
void set_header(HTTPHeader *h);
void add_header(string s);
void set_cookie(cgicc::HTTPCookie const &c);

cache_iface cache;
base_cache *caching_module;
bool gzip;
bool gzip_done;
string out;
void init_internal();
HTTPHeader &header();

void set_lang();
void set_lang(string const &s);

inline char const *gettext(char const *s) { return gt->gettext(s); };
inline char const *ngettext(char const *s,char const *p,int n) { return gt->ngettext(s,p,n); };


string current_template;

inline void use_template(string s="") { current_template=s; };

void render(string name,base_content &content);
void render(string templ,string name,base_content &content);
void render(string name,base_content &content,ostream &);
void render(string templ,string name,base_content &content,ostream &);
virtual void main();
public:
int id;
pthread_t pid;
ostream &get_cout() { return cout; }
transtext::trans const *domain_gettext(string const &domain);

void run(cgicc_connection &);

worker_thread(manager const &s) :
url(this),
app(s),
cache(this)
{
init_internal();
} ;
worker_thread(manager const &s);
virtual ~worker_thread();
};



Loading…
Cancel
Save