ide: Skylark support, Skylark: tutorial

git-svn-id: svn://ultimatepp.org/upp/trunk@5188 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2012-07-14 17:43:57 +00:00
parent bd1509651b
commit 0968b272e2
17 changed files with 1494 additions and 1054 deletions

View file

@ -401,7 +401,7 @@ void CodeEditor::InitKeywords()
"CLASSNAME", "THISBACK", "THISBACK1", "THISBACK2", "THISBACK3", "THISBACK4",
"PTEBACK", "PTEBACK1", "PTEBACK2", "PTEBACK3", "PTEBACK4",
"QUOTE", "XASSERT", "NEVER", "XNEVER", "CHECK", "XCHECK", "ASSERT",
"NAMESPACE_UPP", "END_UPP_NAMESPACE", "NEVER_",
"NAMESPACE_UPP", "END_UPP_NAMESPACE", "NEVER_", "SKYLARK",
NULL
};
static const char *upp_logs[] = {

View file

@ -64,7 +64,14 @@ void SetIniFile(const char *name) {
ReloadIniFile();
}
static
void sIniSet(int64& version)
{
version = s_ini_version;
}
static
bool sIniChanged(int64& version)
{
if(version != s_ini_version) {
@ -119,6 +126,7 @@ String IniString::operator=(const String& s)
{
Mutex::Lock __(sMtx);
(*ref_fn)() = s;
sIniSet(version);
return s;
}
@ -171,6 +179,7 @@ IniInt::operator int() {
int IniInt::operator=(int b) {
Mutex::Lock __(sMtx);
sIniSet(version);
return value = b;
}
@ -193,6 +202,7 @@ IniInt64::operator int64()
int64 IniInt64::operator=(int64 b)
{
Mutex::Lock __(sMtx);
sIniSet(version);
return value = b;
}
@ -215,6 +225,7 @@ IniDouble::operator double()
double IniDouble::operator=(double b)
{
Mutex::Lock __(sMtx);
sIniSet(version);
return value = b;
}
@ -237,6 +248,7 @@ IniBool::operator bool() {
bool IniBool::operator=(bool b) {
Mutex::Lock __(sMtx);
sIniSet(version);
return value = b;
}

View file

@ -111,7 +111,7 @@ String AsJSON(const Value& v, const String& sep, bool pretty)
if(IsNumber(v))
return Format("%.16g", (double)v);
if(IsString(v))
return AsCString((String)v, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON);
return AsCString((String)v, INT_MAX, NULL, ASCSTRING_JSON);
if(IsNull(v))
return "null";
#ifdef SVO_VALUE

View file

@ -4,9 +4,9 @@ Value ParseJSON(const char *s);
inline String AsJSON(int i) { return IsNull(i) ? "null" : AsString(i); }
inline String AsJSON(double n) { return IsNull(n) ? "null" : AsString(n); }
inline String AsJSON(bool b) { return b ? "true" : "false"; }
inline String AsJSON(const String& s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
inline String AsJSON(const WString& s) { return AsCString(s.ToString(), INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
inline String AsJSON(const char *s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
inline String AsJSON(const String& s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_JSON); }
inline String AsJSON(const WString& s) { return AsCString(s.ToString(), INT_MAX, NULL, ASCSTRING_JSON); }
inline String AsJSON(const char *s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_JSON); }
String AsJSON(const Value& v, const String& indent, bool pretty);
String AsJSON(const Value& v, bool pretty = false);

View file

@ -668,6 +668,21 @@ Array<Parser::Decl> Parser::Declaration0(bool l0, bool more)
break;
}
Qualifier();
if(l0 && lex == tk_SKYLARK && lex[1] == '(') {
++lex;
++lex;
Decl& a = r.Add();
a.name = lex.GetId();
a.function = true;
Decl& p = a.param.Add();
p.name = "http";
p.type = "Http";
p.natural = "Http& http";
Key(',');
lex.GetText();
Key(')');
return r;
}
bool isdestructor = Key('~');
if(l0 && context.typenames.Find(lex) >= 0 && lex[1] == '(' && lex.IsId()) {
Decl& a = r.Add();

View file

@ -79,3 +79,5 @@ CPPID(for)
CPPID(try)
CPPID(catch)
CPPID(do)
CPPID(SKYLARK)

View file

@ -1,296 +1,300 @@
#include "Skylark.h"
#ifdef PLATFORM_POSIX
#include <sys/wait.h>
#endif
#ifdef PLATFORM_WIN32
#include <wincon.h>
#endif
namespace Upp {
String GetThreadName()
{
return FormatIntBase(Thread::GetCurrentId() % 33, 35);
}
namespace Ini {
INI_BOOL(skylark_log, false, "Trace of Skylark");
};
#ifdef PLATFORM_WIN32
BOOL WINAPI SkylarkApp::CtrlCHandlerRoutine(__in DWORD dwCtrlType)
{
LOG("Ctrl+C handler");
TheApp().quit = true;
Cout() << "Ctrl + C\n";
TcpSocket h;
h.Connect("127.0.0.1", TheApp().port);
h.Put("quit");
return TRUE;
}
#endif
void SkylarkApp::WorkThread()
{
RunThread();
}
void SkylarkApp::ThreadRun()
{
WorkThread();
}
void SkylarkApp::RunThread()
{
if(SQL.IsOpen()) {
SQL.ClearError();
SQLR.ClearError();
SQL.GetSession().ThrowOnError();
SQLR.GetSession().ThrowOnError();
}
for(;;) {
TcpSocket request;
accept_mutex.Enter();
if(quit) {
accept_mutex.Leave();
break;
}
SKYLARKLOG("Waiting for accept ");
bool b = request.Accept(server);
accept_mutex.Leave();
if(quit)
break;
if(b) {
SKYLARKLOG("Accepted ");
#ifdef PLATFORM_POSIX
if(prefork)
alarm(timeout);
#endif
Http http(*this);
http.Dispatch(request);
#ifdef PLATFORM_POSIX
if(prefork)
alarm(0);
#endif
SKYLARKLOG("Finished ");
}
else {
SKYLARKLOG("Accept failed: " << request.GetErrorDesc());
#ifdef _DEBUG
break;
#endif
}
}
}
void SkylarkApp::Main()
{
Buffer<Thread> uwt(threads);
for(int i = 0; i < threads; i++)
Thread::Start(THISBACK(ThreadRun));
while(Thread::GetCount())
Sleep(100);
}
void SkylarkApp::Broadcast(int signal)
{
#ifdef PLATFORM_POSIX
if(getpid() == main_pid)
for(int i = 0; i < child_pid.GetCount(); i++)
kill(child_pid[i], signal);
#endif
}
void SkylarkApp::Signal(int signal)
{
#ifdef PLATFORM_POSIX
switch(signal) {
case SIGTERM:
case SIGHUP:
quit = true;
Broadcast(signal);
break;
case SIGINT:
Broadcast(signal);
exit(0);
break;
case SIGALRM:
if(getpid() != TheApp().main_pid) {
// "Timeout - session stoped"
exit(0);
}
break;
}
#endif
}
void SkylarkApp::SignalHandler(int signal)
{
TheApp().Signal(signal);
}
void DisableHUP()
{
#ifdef PLATFORM_POSIX
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigprocmask(SIG_BLOCK, &mask, NULL);
#endif
}
void EnableHUP()
{
#ifdef PLATFORM_POSIX
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
#endif
}
void SkylarkApp::Run()
{
// DisableHUP();
if(static_dir.GetCount() == 0)
static_dir = root + "/static";
SqlSession::PerThread();
SqlId::UseQuotes();
FinalizeViews();
#ifdef PLATFORM_WIN32
SetConsoleCtrlHandler(CtrlCHandlerRoutine, true);
#endif
main_pid = getpid();
quit = false;
#if defined(PLATFORM_POSIX) && defined(_DEBUG)
// Avoid the need to close running server in debug mode...
int qq = 0;
for(;;) {
if(server.Listen(port, 5))
break;
Cout() << "Trying to start listening (other process using the same port?) " << ++qq << "\n";
Sleep(1000);
}
#else
if(!server.Listen(port, 5)) {
SKYLARKLOG("Cannot open server socket!");
Exit(1);
}
#endif
SKYLARKLOG("Starting Skylark, current static path: " << path);
#ifdef PLATFORM_POSIX
if(prefork) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SignalHandler;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGALRM, &sa, NULL);
// EnableHUP();
while(!quit) {
while(child_pid.GetCount() < prefork && !quit) {
pid_t p = fork();
if(p == 0) {
Main();
return;
}
else
if(p > 0)
child_pid.Add(p);
else {
// "cant create new process"
Broadcast(SIGINT);
abort();
}
}
int status = 0;
pid_t p = wait(&status);
if(p > 0) {
int q = FindIndex(child_pid, p);
if(q >= 0)
child_pid.Remove(q);
}
}
Broadcast(SIGTERM);
int status = 0;
for(int i = 0; i < child_pid.GetCount(); i++)
waitpid(child_pid[i], &status, 0);
// "server stopped";
}
else
#endif
Main();
#if defined(_DEBUG) && defined(POSIX)
FileDelete(pidf);
#endif
SKYLARKLOG("ExitSkylark");
}
void SkylarkApp::SqlError(Http& http)
{
}
void SkylarkApp::InternalError(Http& http)
{
}
void SkylarkApp::NotFound(Http& http)
{
}
void SkylarkApp::Unauthorized(Http& http)
{
}
SkylarkApp *SkylarkApp::app;
SkylarkApp& SkylarkApp::TheApp()
{
ASSERT(app);
return *app;
}
const SkylarkConfig& SkylarkApp::Config()
{
ASSERT(app);
return *app;
}
SkylarkApp::SkylarkApp()
{
ASSERT(!app);
path = GetEnv("UPP_ASSEMBLY__");
app = this;
threads = 3 * CPU_Cores() + 1;
port = 8001;
use_caching = true;
#ifdef _DEBUG
prefork = 0;
timeout = 0;
#else
prefork = 1;
timeout = 300;
#endif
}
SkylarkApp::~SkylarkApp()
{
app = NULL;
}
#include "Skylark.h"
#ifdef PLATFORM_POSIX
#include <sys/wait.h>
#endif
#ifdef PLATFORM_WIN32
#include <wincon.h>
#endif
namespace Upp {
String GetThreadName()
{
return FormatIntBase(Thread::GetCurrentId() % 33, 35);
}
namespace Ini {
INI_BOOL(skylark_log, false, "Trace of Skylark");
};
#ifdef PLATFORM_WIN32
BOOL WINAPI SkylarkApp::CtrlCHandlerRoutine(__in DWORD dwCtrlType)
{
LOG("Ctrl+C handler");
TheApp().quit = true;
Cout() << "Ctrl + C\n";
TcpSocket h;
h.Connect("127.0.0.1", TheApp().port);
h.Put("quit");
return TRUE;
}
#endif
void SkylarkApp::WorkThread()
{
RunThread();
}
void SkylarkApp::ThreadRun()
{
WorkThread();
}
void SkylarkApp::RunThread()
{
if(SQL.IsOpen()) {
SQL.ClearError();
SQLR.ClearError();
SQL.GetSession().ThrowOnError();
SQLR.GetSession().ThrowOnError();
}
for(;;) {
TcpSocket request;
accept_mutex.Enter();
if(quit) {
accept_mutex.Leave();
break;
}
SKYLARKLOG("Waiting for accept ");
bool b = request.Accept(server);
accept_mutex.Leave();
if(quit)
break;
if(b) {
SKYLARKLOG("Accepted ");
#ifdef PLATFORM_POSIX
if(prefork)
alarm(timeout);
#endif
Http http(*this);
http.Dispatch(request);
#ifdef PLATFORM_POSIX
if(prefork)
alarm(0);
#endif
SKYLARKLOG("Finished ");
}
else {
SKYLARKLOG("Accept failed: " << request.GetErrorDesc());
#ifdef _DEBUG
break;
#endif
}
}
}
void SkylarkApp::Main()
{
Buffer<Thread> uwt(threads);
for(int i = 0; i < threads; i++)
Thread::Start(THISBACK(ThreadRun));
while(Thread::GetCount())
Sleep(100);
}
void SkylarkApp::Broadcast(int signal)
{
#ifdef PLATFORM_POSIX
if(getpid() == main_pid)
for(int i = 0; i < child_pid.GetCount(); i++)
kill(child_pid[i], signal);
#endif
}
void SkylarkApp::Signal(int signal)
{
#ifdef PLATFORM_POSIX
switch(signal) {
case SIGTERM:
case SIGHUP:
quit = true;
Broadcast(signal);
break;
case SIGINT:
Broadcast(signal);
exit(0);
break;
case SIGALRM:
if(getpid() != TheApp().main_pid) {
// "Timeout - session stoped"
exit(0);
}
break;
}
#endif
}
void SkylarkApp::SignalHandler(int signal)
{
TheApp().Signal(signal);
}
void DisableHUP()
{
#ifdef PLATFORM_POSIX
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigprocmask(SIG_BLOCK, &mask, NULL);
#endif
}
void EnableHUP()
{
#ifdef PLATFORM_POSIX
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
#endif
}
void SkylarkApp::Run()
{
// DisableHUP();
if(static_dir.GetCount() == 0)
static_dir = root + "/static";
SqlSession::PerThread();
SqlId::UseQuotes();
FinalizeViews();
#ifdef PLATFORM_WIN32
SetConsoleCtrlHandler(CtrlCHandlerRoutine, true);
#endif
main_pid = getpid();
quit = false;
#ifdef _DEBUG
// Avoid the need to close running server in debug mode...
int qq = 0;
for(;;) {
if(server.Listen(port, 5))
break;
Cout() << "Trying to start listening (other process using the same port?) " << ++qq << "\n";
Sleep(1000);
}
#else
if(!server.Listen(port, 5)) {
SKYLARKLOG("Cannot open server socket!");
Exit(1);
}
#endif
SKYLARKLOG("Starting Skylark, current static path: " << path);
#ifdef PLATFORM_POSIX
if(prefork) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SignalHandler;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGALRM, &sa, NULL);
// EnableHUP();
while(!quit) {
while(child_pid.GetCount() < prefork && !quit) {
pid_t p = fork();
if(p == 0) {
Main();
return;
}
else
if(p > 0)
child_pid.Add(p);
else {
// "cant create new process"
Broadcast(SIGINT);
abort();
}
}
int status = 0;
pid_t p = wait(&status);
if(p > 0) {
int q = FindIndex(child_pid, p);
if(q >= 0)
child_pid.Remove(q);
}
}
Broadcast(SIGTERM);
int status = 0;
for(int i = 0; i < child_pid.GetCount(); i++)
waitpid(child_pid[i], &status, 0);
// "server stopped";
}
else
#endif
Main();
#if defined(_DEBUG) && defined(POSIX)
FileDelete(pidf);
#endif
SKYLARKLOG("ExitSkylark");
}
void SkylarkApp::SqlError(Http& http)
{
}
void SkylarkApp::InternalError(Http& http)
{
}
void SkylarkApp::NotFound(Http& http)
{
}
void SkylarkApp::Unauthorized(Http& http)
{
}
void SkylarkApp::BadRequest(Http& http)
{
}
SkylarkApp *SkylarkApp::app;
SkylarkApp& SkylarkApp::TheApp()
{
ASSERT(app);
return *app;
}
const SkylarkConfig& SkylarkApp::Config()
{
ASSERT(app);
return *app;
}
SkylarkApp::SkylarkApp()
{
ASSERT(!app);
path = GetEnv("UPP_ASSEMBLY__");
app = this;
threads = 3 * CPU_Cores() + 1;
port = 8001;
use_caching = true;
#ifdef _DEBUG
prefork = 0;
timeout = 0;
#else
prefork = 1;
timeout = 300;
#endif
}
SkylarkApp::~SkylarkApp()
{
app = NULL;
}
};

View file

@ -1,394 +1,402 @@
#include "Skylark.h"
#define LLOG(x) //DLOG(x)
#define LDUMP(x) //DDUMP(x)
#define LDUMPC(x) //DDUMPC(x)
#define LDUMPM(x) //DDUMPM(x)
#define LTIMING(x) //RTIMING(x)
namespace Upp {
enum { DISPATCH_VARARGS = -1 };
struct DispatchNode : Moveable<DispatchNode> {
VectorMap<String, int> subnode;
void (*view)(Http&);
int argpos;
int method;
bool post_raw;
String id;
enum { GET, POST };
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
};
static Vector<DispatchNode>& sDispatchMap()
{
static Vector<DispatchNode> x;
return x;
}
static VectorMap<String, Vector<String> >& sLinkMap()
{
static VectorMap<String, Vector<String> > x;
return x;
}
static Index<uintptr_t>& sViewIndex()
{
static Index<uintptr_t> x;
return x;
}
void DumpDispatchMap()
{
Vector<DispatchNode>& DispatchMap = sDispatchMap();
for(int i = 0; i < DispatchMap.GetCount(); i++) {
LLOG("-------------");
String sub;
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
}
}
Vector<String> *GetUrlViewLinkParts(const String& id)
{
int q = sLinkMap().Find(id);
if(q < 0)
return NULL;
return &sLinkMap()[q];
}
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
{
int q = sViewIndex().Find((uintptr_t)view);
if(q < 0)
throw Exc("Invalid view");
if(q < 0)
return String();
StringBuffer out;
MakeLink(out, sLinkMap()[q], arg);
return out;
}
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
{
LLOG("RegisterView " << path);
Vector<String>& linkpart = sLinkMap().GetAdd(id);
sViewIndex().FindAdd((uintptr_t)view);
Vector<DispatchNode>& DispatchMap = sDispatchMap();
int method = DispatchNode::GET;
bool post_raw = false;
int q = path.Find(':');
if(q >= 0) {
if(path.Mid(q + 1) == "POST")
method = DispatchNode::POST;
if(path.Mid(q + 1) == "POST_RAW") {
method = DispatchNode::POST;
post_raw = true;
}
path = path.Mid(0, q);
}
Vector<String> h = Split(path, '/');
if(DispatchMap.GetCount() == 0)
DispatchMap.Add();
q = 0;
int linkargpos = 0;
for(int i = 0; i < h.GetCount(); i++) {
String s = h[i];
LLOG(" Node " << h[i]);
DispatchNode& n = DispatchMap[q];
if(*s == '*') {
int argpos = Null;
if(IsDigit(s[1]))
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
else
if(s[1] == '*')
argpos = DISPATCH_VARARGS;
q = DispatchMap.GetCount();
LLOG(" Adding arg " << argpos << ": " << q);
n.subnode.Add(Null, q);
DispatchMap.Add();
DispatchMap[q].argpos = argpos;
if(primary)
linkpart.Add(String(linkargpos++, 1));
}
else {
if(primary)
linkpart.Add(s);
q = n.subnode.Get(s, -1);
if(q < 0) {
q = DispatchMap.GetCount();
LLOG(" Adding " << s << ": " << q);
n.subnode.Add(s, q);
DispatchMap.Add();
}
}
}
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
DispatchMap[q].view = view;
DispatchMap[q].method = method;
DispatchMap[q].id = id;
DispatchMap[q].post_raw = post_raw;
// DumpDispatchMap();
}
struct ViewData {
void (*view)(Http&);
String id;
String path;
};
static Array<ViewData>& sViewData()
{
static Array<ViewData> x;
return x;
}
void RegisterView(void (*view)(Http&), const char *id, const char *path)
{
Array<ViewData>& v = sViewData();
ViewData& w = v.Add();
w.view = view;
w.id = id;
w.path = path;
}
void SkylarkApp::FinalizeViews()
{
Array<ViewData>& w = sViewData();
for(int i = 0; i < w.GetCount(); i++) {
const ViewData& v = w[i];
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
Vector<String> h = Split(ReplaceVars(root + '/' + v.path, view_var, '$'), ';');
for(int i = 0; i < h.GetCount(); i++)
RegisterView0(v.view, v.id, h[i], i == 0);
}
w.Clear();
}
struct BestDispatch {
void (*view)(Http&);
int matched_parts;
int matched_params;
Vector<String>& arg;
String id;
bool post_raw;
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
};
void GetBestDispatch(int method,
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
BestDispatch& bd, int matched_parts, int matched_params)
{
Vector<DispatchNode>& DispatchMap = sDispatchMap();
if(ii >= part.GetCount()) {
if(n.view && n.method == method &&
(matched_parts > bd.matched_parts ||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
bd.arg <<= arg;
bd.view = n.view;
bd.matched_parts = matched_parts;
bd.id = n.id;
bd.post_raw = n.post_raw;
}
if(!bd.view) {
int q = n.subnode.Find(String());
while(q >= 0) {
const DispatchNode& an = DispatchMap[n.subnode[q]];
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
bd.view = an.view;
bd.id = n.id;
bd.arg.Clear();
break;
}
q = n.subnode.FindNext(q);
}
}
return;
}
int qq = n.subnode.Get(part[ii], -1);
if(qq >= 0)
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
int q = n.subnode.Find(String());
while(q >= 0) {
int qq = n.subnode[q];
int ac = arg.GetCount();
const DispatchNode& an = DispatchMap[qq];
int apos = an.argpos;
LLOG(" *" << qq << " apos: " << apos);
if(apos == DISPATCH_VARARGS) {
if(an.view && an.method == method &&
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
bd.arg <<= arg;
bd.arg.Append(part, ii, part.GetCount() - ii);
bd.view = an.view;
bd.matched_parts = matched_parts;
bd.id = an.id;
}
}
else {
String pv;
if(IsNull(apos))
arg.Add(part[ii]);
else {
String& at = arg.At(apos);
pv = at;
at = part[ii];
}
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
if(!IsNull(apos))
arg[apos] = pv;
}
arg.SetCount(ac);
q = n.subnode.FindNext(q);
}
}
void Http::Dispatch(TcpSocket& socket)
{
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
if(hdr.Read(socket)) {
int len = GetLength();
content = socket.GetAll(len);
LLOG("--------------------------------------------");
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
LDUMP(content);
String r;
var.Clear();
arg.Clear();
LTIMING("Request processing");
request_content_type = GetHeader("content-type");
String rc = ToLower(request_content_type);
bool post = hdr.GetMethod() == "POST";
if(post)
if(rc.StartsWith("application/x-www-form-urlencoded"))
ParseRequest(content);
else
if(rc.StartsWith("multipart/"))
ReadMultiPart(content);
String uri = hdr.GetURI();
int q = uri.Find('?');
if(q >= 0) {
if(!post)
ParseRequest(~uri + q + 1);
uri.Trim(q);
}
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
const String& h = hdr.fields[i];
int q = 0;
for(;;) {
int qq = h.Find('=', q);
if(qq < 0)
break;
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
qq++;
q = h.Find(';', qq);
if(q < 0) {
var.Add('@' + id, UrlDecode(h.Mid(qq)));
break;
}
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
q++;
}
}
var.GetAdd("static") = app.static_dir;
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
LDUMPM(var);
Vector<String> part = Split(uri, '/');
for(int i = 0; i < part.GetCount(); i++)
part[i] = UrlDecode(part[i]);
LDUMPC(part);
Vector<String> a;
BestDispatch bd(arg);
if(DispatchMap.GetCount())
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
LDUMPC(arg);
response.Clear();
if(bd.view) {
try {
if(SQL.IsOpen())
SQL.Begin();
LoadSession();
session_dirty = false;
if(post && !bd.post_raw) {
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
if(id != (*this)[".__identity__"])
throw AuthExc("identity error");
}
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
Upp::SetLanguage(lang);
var.GetAdd(".__lang__") = lang;
var.GetAdd(".language") = ToLower(LNGAsText(lang));
viewid = bd.id;
LDUMP(viewid);
(*bd.view)(*this);
if(session_dirty)
SaveSession();
if(SQL.IsOpen())
SQL.Commit();
}
catch(SqlExc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << "Internal server error<br>"
<< "SQL ERROR: " << e;
code = 500;
code_text = "Internal server error";
app.SqlError(*this);
}
catch(AuthExc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << e;
code = 403;
code_text = "Unauthorized";
app.Unauthorized(*this);
}
catch(Exc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << "Internal server error<br>"
<< e;
code = 500;
code_text = "Internal server error";
app.InternalError(*this);
}
}
else {
response << "Page not found";
code = 404;
code_text = "Not found";
app.NotFound(*this);
}
r.Clear();
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
if(redirect.GetCount()) {
SKYLARKLOG("Redirect to: " << redirect);
r << "HTTP/1.1 " << code << " Found\r\n";
r << "Location: " << redirect << "\r\n";
}
else {
r <<
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
"Server: U++\r\n"
"Content-Length: " << response.GetCount() << "\r\n"
"Connection: close\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: " << content_type << "\r\n";
for(int i = 0; i < cookies.GetCount(); i++)
r << cookies[i];
r << "\r\n";
}
socket.PutAll(r);
socket.PutAll(response);
}
}
#include "Skylark.h"
#define LLOG(x) //DLOG(x)
#define LDUMP(x) //DDUMP(x)
#define LDUMPC(x) //DDUMPC(x)
#define LDUMPM(x) //DDUMPM(x)
#define LTIMING(x) //RTIMING(x)
namespace Upp {
enum { DISPATCH_VARARGS = -1 };
struct DispatchNode : Moveable<DispatchNode> {
VectorMap<String, int> subnode;
void (*view)(Http&);
int argpos;
int method;
bool post_raw;
String id;
enum { GET, POST };
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
};
static Vector<DispatchNode>& sDispatchMap()
{
static Vector<DispatchNode> x;
return x;
}
static VectorMap<String, Vector<String> >& sLinkMap()
{
static VectorMap<String, Vector<String> > x;
return x;
}
static Index<uintptr_t>& sViewIndex()
{
static Index<uintptr_t> x;
return x;
}
void DumpDispatchMap()
{
Vector<DispatchNode>& DispatchMap = sDispatchMap();
for(int i = 0; i < DispatchMap.GetCount(); i++) {
LLOG("-------------");
String sub;
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
}
}
Vector<String> *GetUrlViewLinkParts(const String& id)
{
int q = sLinkMap().Find(id);
if(q < 0)
return NULL;
return &sLinkMap()[q];
}
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
{
int q = sViewIndex().Find((uintptr_t)view);
if(q < 0)
throw Exc("Invalid view");
if(q < 0)
return String();
StringBuffer out;
MakeLink(out, sLinkMap()[q], arg);
return out;
}
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
{
LLOG("RegisterView " << path);
Vector<String>& linkpart = sLinkMap().GetAdd(id);
sViewIndex().FindAdd((uintptr_t)view);
Vector<DispatchNode>& DispatchMap = sDispatchMap();
int method = DispatchNode::GET;
bool post_raw = false;
int q = path.Find(':');
if(q >= 0) {
if(path.Mid(q + 1) == "POST")
method = DispatchNode::POST;
if(path.Mid(q + 1) == "POST_RAW") {
method = DispatchNode::POST;
post_raw = true;
}
path = path.Mid(0, q);
}
Vector<String> h = Split(path, '/');
if(DispatchMap.GetCount() == 0)
DispatchMap.Add();
q = 0;
int linkargpos = 0;
for(int i = 0; i < h.GetCount(); i++) {
String s = h[i];
LLOG(" Node " << h[i]);
DispatchNode& n = DispatchMap[q];
if(*s == '*') {
int argpos = Null;
if(IsDigit(s[1]))
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
else
if(s[1] == '*')
argpos = DISPATCH_VARARGS;
q = DispatchMap.GetCount();
LLOG(" Adding arg " << argpos << ": " << q);
n.subnode.Add(Null, q);
DispatchMap.Add();
DispatchMap[q].argpos = argpos;
if(primary)
linkpart.Add(String(linkargpos++, 1));
}
else {
if(primary)
linkpart.Add(s);
q = n.subnode.Get(s, -1);
if(q < 0) {
q = DispatchMap.GetCount();
LLOG(" Adding " << s << ": " << q);
n.subnode.Add(s, q);
DispatchMap.Add();
}
}
}
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
DispatchMap[q].view = view;
DispatchMap[q].method = method;
DispatchMap[q].id = id;
DispatchMap[q].post_raw = post_raw;
// DumpDispatchMap();
}
struct ViewData {
void (*view)(Http&);
String id;
String path;
};
static Array<ViewData>& sViewData()
{
static Array<ViewData> x;
return x;
}
void RegisterHandler(void (*view)(Http&), const char *id, const char *path)
{
Array<ViewData>& v = sViewData();
ViewData& w = v.Add();
w.view = view;
w.id = id;
w.path = path;
}
void SkylarkApp::FinalizeViews()
{
Array<ViewData>& w = sViewData();
for(int i = 0; i < w.GetCount(); i++) {
const ViewData& v = w[i];
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
Vector<String> h = Split(ReplaceVars(root + '/' + v.path, view_var, '$'), ';');
for(int i = 0; i < h.GetCount(); i++)
RegisterView0(v.view, v.id, h[i], i == 0);
}
w.Clear();
}
struct BestDispatch {
void (*view)(Http&);
int matched_parts;
int matched_params;
Vector<String>& arg;
String id;
bool post_raw;
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
};
void GetBestDispatch(int method,
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
BestDispatch& bd, int matched_parts, int matched_params)
{
Vector<DispatchNode>& DispatchMap = sDispatchMap();
if(ii >= part.GetCount()) {
if(n.view && n.method == method &&
(matched_parts > bd.matched_parts ||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
bd.arg <<= arg;
bd.view = n.view;
bd.matched_parts = matched_parts;
bd.id = n.id;
bd.post_raw = n.post_raw;
}
if(!bd.view) {
int q = n.subnode.Find(String());
while(q >= 0) {
const DispatchNode& an = DispatchMap[n.subnode[q]];
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
bd.view = an.view;
bd.id = n.id;
bd.arg.Clear();
break;
}
q = n.subnode.FindNext(q);
}
}
return;
}
int qq = n.subnode.Get(part[ii], -1);
if(qq >= 0)
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
int q = n.subnode.Find(String());
while(q >= 0) {
int qq = n.subnode[q];
int ac = arg.GetCount();
const DispatchNode& an = DispatchMap[qq];
int apos = an.argpos;
LLOG(" *" << qq << " apos: " << apos);
if(apos == DISPATCH_VARARGS) {
if(an.view && an.method == method &&
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
bd.arg <<= arg;
bd.arg.Append(part, ii, part.GetCount() - ii);
bd.view = an.view;
bd.matched_parts = matched_parts;
bd.id = an.id;
}
}
else {
String pv;
if(IsNull(apos))
arg.Add(part[ii]);
else {
String& at = arg.At(apos);
pv = at;
at = part[ii];
}
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
if(!IsNull(apos))
arg[apos] = pv;
}
arg.SetCount(ac);
q = n.subnode.FindNext(q);
}
}
void Http::Dispatch(TcpSocket& socket)
{
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
if(hdr.Read(socket)) {
int len = GetLength();
content = socket.GetAll(len);
LLOG("--------------------------------------------");
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
LDUMP(content);
String r;
var.Clear();
arg.Clear();
LTIMING("Request processing");
request_content_type = GetHeader("content-type");
String rc = ToLower(request_content_type);
bool post = hdr.GetMethod() == "POST";
if(post)
if(rc.StartsWith("application/x-www-form-urlencoded"))
ParseRequest(content);
else
if(rc.StartsWith("multipart/"))
ReadMultiPart(content);
String uri = hdr.GetURI();
int q = uri.Find('?');
if(q >= 0) {
if(!post)
ParseRequest(~uri + q + 1);
uri.Trim(q);
}
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
const String& h = hdr.fields[i];
int q = 0;
for(;;) {
int qq = h.Find('=', q);
if(qq < 0)
break;
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
qq++;
q = h.Find(';', qq);
if(q < 0) {
var.Add('@' + id, UrlDecode(h.Mid(qq)));
break;
}
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
q++;
}
}
var.GetAdd("static") = app.static_dir;
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
LDUMPM(var);
Vector<String> part = Split(uri, '/');
for(int i = 0; i < part.GetCount(); i++)
part[i] = UrlDecode(part[i]);
LDUMPC(part);
Vector<String> a;
BestDispatch bd(arg);
if(DispatchMap.GetCount())
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
LDUMPC(arg);
response.Clear();
if(bd.view) {
try {
if(SQL.IsOpen())
SQL.Begin();
LoadSession();
session_dirty = false;
if(post && !bd.post_raw) {
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
if(id != (*this)[".__identity__"])
throw AuthExc("identity error");
}
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
Upp::SetLanguage(lang);
var.GetAdd(".__lang__") = lang;
var.GetAdd(".language") = ToLower(LNGAsText(lang));
viewid = bd.id;
LDUMP(viewid);
(*bd.view)(*this);
if(session_dirty)
SaveSession();
if(SQL.IsOpen())
SQL.Commit();
}
catch(SqlExc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << "Internal server error<br>"
<< "SQL ERROR: " << e;
code = 500;
code_text = "Internal server error";
app.SqlError(*this);
}
catch(AuthExc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << e;
code = 403;
code_text = "Unauthorized";
app.Unauthorized(*this);
}
catch(BadRequestExc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << "Bad request";
code = 400;
code_text = "Bad request";
app.Unauthorized(*this);
}
catch(Exc e) {
if(SQL.IsOpen())
SQL.Rollback();
response << "Internal server error<br>"
<< e;
code = 500;
code_text = "Internal server error";
app.InternalError(*this);
}
}
else {
response << "Page not found";
code = 404;
code_text = "Not found";
app.NotFound(*this);
}
r.Clear();
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
if(redirect.GetCount()) {
SKYLARKLOG("Redirect to: " << redirect);
r << "HTTP/1.1 " << code << " Found\r\n";
r << "Location: " << redirect << "\r\n";
}
else {
r <<
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
"Server: U++\r\n"
"Content-Length: " << response.GetCount() << "\r\n"
"Connection: close\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: " << content_type << "\r\n";
for(int i = 0; i < cookies.GetCount(); i++)
r << cookies[i];
r << "\r\n";
}
socket.PutAll(r);
socket.PutAll(response);
}
}
};

View file

@ -1,142 +1,144 @@
void MakeLink(StringBuffer& out, const Vector<String>& part, const Vector<Value>& arg);
class Renderer {
protected:
VectorMap<String, Value> var;
int lang;
Renderer& Link(const char *id, void (*view)(Http&), const Vector<Value>& arg);
const One<Exe>& GetTemplate(const char *template_name);
public:
Renderer& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
Renderer& operator()(const ValueMap& map);
Renderer& operator()(const char *id, void (*view)(Http&));
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1);
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2);
Renderer& operator()(const Sql& sql);
Renderer& operator()(Fields rec);
SqlUpdate Update(SqlId table);
SqlInsert Insert(SqlId table);
Value operator[](const char *id) const { return var.Get(id, Null); }
String RenderString(const String& template_name);
Value Render(const String& template_name) { return Raw(RenderString(template_name)); }
Renderer& Render(const char *id, const String& template_name);
Renderer() { lang = LNG_ENGLISH; }
virtual ~Renderer();
};
class Http : public Renderer {
SkylarkApp& app;
HttpHeader hdr;
String content;
String viewid;
Vector<String> arg;
String session_id;
VectorMap<String, Value> session_var;
bool session_dirty;
String redirect;
int code;
String code_text;
String response;
String content_type;
String request_content_type;
VectorMap<String, String> cookies;
void ParseRequest(const char *s);
void ReadMultiPart(const String& content);
String SessionFile(const String& sid);
void LoadSession();
void SaveSession();
public:
Http& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
Http& operator()(const ValueMap& map) { Renderer::operator()(map); return *this; }
Http& operator()(const char *id, void (*view)(Http&)) { Renderer::operator()(id, view); return *this; }
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1) { Renderer::operator()(id, view, arg1); return *this; }
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2) { Renderer::operator()(id, view, arg1, arg2); return *this; }
Http& operator()(const Sql& sql) { Renderer::operator()(sql); return *this; }
Http& operator()(Fields rec) { Renderer::operator()(rec); return *this; }
Http& Render(const char *id, const String& template_name) { Renderer::Render(id, template_name); return *this; }
Value Render(const String& template_name) { return Renderer::Render(template_name); }
void Dispatch(TcpSocket& socket);
String GetHeader(const char *s) const { return hdr[s]; }
int GetLength() const { return atoi(GetHeader("content-length")); }
String GetViewId() const { return viewid; }
Value operator[](const char *id) const { return Renderer::operator[](id); }
String operator[](int i) const { return i >= 0 && i < arg.GetCount() ? arg[i] : String(); }
int Int(const char *id) const;
int Int(int i) const;
int GetParamCount() const { return arg.GetCount(); }
Http& ContentType(const char *s) { content_type = s; return *this; }
Http& Content(const char *s, const Value& data);
Http& operator<<(const Value& s);
Http& SetRawCookie(const char *id, const String& value,
Time expires = Null, const char *path = NULL,
const char *domain = NULL, bool secure = false, bool httponly = false);
Http& SetCookie(const char *id, const String& value,
Time expires = Null, const char *path = NULL,
const char *domain = NULL, bool secure = false, bool httponly = false);
Http& ClearSession();
Http& SessionSet(const char *id, const Value& value);
Http& NewIdentity() { SessionSet("__identity__", Null); return *this; }
Http& NewSessionId();
Http& SetLanguage(int lang);
Http& Response(int code_, const String& ctext) { code = code_; code_text = ctext; return *this; }
Http& RenderResult(const char *template_name);
Http& Redirect(const char *url, int code_ = 302) { code = code_; redirect = url; return *this; }
Http& Redirect(void (*view)(Http&), const Vector<Value>& arg);
Http& Redirect(void (*view)(Http&));
Http& Redirect(void (*view)(Http&), const Value& v1);
Http& Redirect(void (*view)(Http&), const Value& v1, const Value& v2);
Http& Ux(const char *id, const String& text);
Http& UxRender(const char *id, const char *template_name);
Http& UxSet(const char *id, const String& value);
Http& UxRun(const String& js_code);
String GetResponse() const { return response; }
const SkylarkApp& App() const { return app; }
Http(SkylarkApp& app);
};
String HttpResponse(int code, const char *phrase, const String& data, const char *content_type = NULL);
void RegisterView(void (*view)(Http&), const char *id, const char *path);
#define SKYLARK(name, path) void name(Http& http); INITBLOCK { UPP::RegisterView(name, #name, path); } void name(Http& http)
Vector<String> *GetUrlViewLinkParts(const String& id);
String MakeLink(void (*view)(Http&), const Vector<Value>& arg);
enum {
SESSION_FORMAT_BINARY, SESSION_FORMAT_JSON, SESSION_FORMAT_XML
};
void MakeLink(StringBuffer& out, const Vector<String>& part, const Vector<Value>& arg);
class Renderer {
protected:
VectorMap<String, Value> var;
int lang;
Renderer& Link(const char *id, void (*view)(Http&), const Vector<Value>& arg);
const One<Exe>& GetTemplate(const char *template_name);
public:
Renderer& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
Renderer& operator()(const ValueMap& map);
Renderer& operator()(const char *id, void (*view)(Http&));
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1);
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2);
Renderer& operator()(const Sql& sql);
Renderer& operator()(Fields rec);
Renderer& operator()(const SqlSelect& row_sel);
Renderer& operator()(const char *id, const SqlSelect& sel);
SqlUpdate Update(SqlId table);
SqlInsert Insert(SqlId table);
Value operator[](const char *id) const { return var.Get(id, Null); }
String RenderString(const String& template_name);
Value Render(const String& template_name) { return Raw(RenderString(template_name)); }
Renderer& Render(const char *id, const String& template_name);
Renderer() { lang = LNG_ENGLISH; }
virtual ~Renderer();
};
class Http : public Renderer {
SkylarkApp& app;
HttpHeader hdr;
String content;
String viewid;
Vector<String> arg;
String session_id;
VectorMap<String, Value> session_var;
bool session_dirty;
String redirect;
int code;
String code_text;
String response;
String content_type;
String request_content_type;
VectorMap<String, String> cookies;
void ParseRequest(const char *s);
void ReadMultiPart(const String& content);
String SessionFile(const String& sid);
void LoadSession();
void SaveSession();
public:
Http& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
Http& operator()(const ValueMap& map) { Renderer::operator()(map); return *this; }
Http& operator()(const char *id, void (*view)(Http&)) { Renderer::operator()(id, view); return *this; }
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1) { Renderer::operator()(id, view, arg1); return *this; }
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2) { Renderer::operator()(id, view, arg1, arg2); return *this; }
Http& operator()(const Sql& sql) { Renderer::operator()(sql); return *this; }
Http& operator()(Fields rec) { Renderer::operator()(rec); return *this; }
Http& operator()(const SqlSelect& row_sel) { Renderer::operator()(row_sel); return *this; }
Http& operator()(const char *id, const SqlSelect& sel) { Renderer::operator()(id, sel); return *this; }
Http& Render(const char *id, const String& template_name) { Renderer::Render(id, template_name); return *this; }
Value Render(const String& template_name) { return Renderer::Render(template_name); }
String GetHeader(const char *s) const { return hdr[s]; }
int GetLength() const { return atoi(GetHeader("content-length")); }
String GetViewId() const { return viewid; }
Value operator[](const char *id) const { return Renderer::operator[](id); }
int Int(const char *id) const;
String operator[](int i) const { return i >= 0 && i < arg.GetCount() ? arg[i] : String(); }
int Int(int i) const;
int GetParamCount() const { return arg.GetCount(); }
Http& ContentType(const char *s) { content_type = s; return *this; }
Http& Content(const char *s, const Value& data);
Http& operator<<(const Value& s);
Http& SetRawCookie(const char *id, const String& value,
Time expires = Null, const char *path = NULL,
const char *domain = NULL, bool secure = false, bool httponly = false);
Http& SetCookie(const char *id, const String& value,
Time expires = Null, const char *path = NULL,
const char *domain = NULL, bool secure = false, bool httponly = false);
Http& ClearSession();
Http& SessionSet(const char *id, const Value& value);
Http& NewIdentity() { SessionSet("__identity__", Null); return *this; }
Http& NewSessionId();
Http& SetLanguage(int lang);
Http& Response(int code_, const String& ctext) { code = code_; code_text = ctext; return *this; }
Http& RenderResult(const char *template_name);
Http& Redirect(const char *url, int code_ = 302) { code = code_; redirect = url; return *this; }
Http& Redirect(void (*view)(Http&), const Vector<Value>& arg);
Http& Redirect(void (*view)(Http&));
Http& Redirect(void (*view)(Http&), const Value& v1);
Http& Redirect(void (*view)(Http&), const Value& v1, const Value& v2);
Http& Ux(const char *id, const String& text);
Http& UxRender(const char *id, const char *template_name);
Http& UxSet(const char *id, const String& value);
Http& UxRun(const String& js_code);
String GetResponse() const { return response; }
void Dispatch(TcpSocket& socket);
const SkylarkApp& App() const { return app; }
Http(SkylarkApp& app);
};
void RegisterHandler(void (*handler)(Http& http), const char *id, const char *path);
#define SKYLARK(name, path) void name(Http& http); INITBLOCK { UPP::RegisterHandler(name, #name, path); } void name(Http& http)
Vector<String> *GetUrlViewLinkParts(const String& id);
String MakeLink(void (*view)(Http&), const Vector<Value>& arg);
enum {
SESSION_FORMAT_BINARY, SESSION_FORMAT_JSON, SESSION_FORMAT_XML
};

View file

@ -1,10 +1,10 @@
#ifndef _Iml_Iml_h
#define _Iml_Iml_h
#include <Draw/Draw.h>
#include <plugin/png/png.h>
#include <plugin/jpg/jpg.h>
#endif
#ifndef _Iml_Iml_h
#define _Iml_Iml_h
#include <Draw/Draw.h>
#include <plugin/png/png.h>
#include <plugin/jpg/jpg.h>
#include <Skylark/Skylark.h>
#endif

View file

@ -1,3 +1,10 @@
description "\377128,0,0";
uses
Draw,
plugin\png,
plugin\jpg;
file
Iml.h,
Lib.icpp;

View file

@ -1,6 +1,9 @@
#ifndef _Skylark_Iml_icpp_init_stub
#define _Skylark_Iml_icpp_init_stub
#define BLITZ_INDEX__ F565e623033e15f6c077dba0bc03cb2ea
#include "Draw/init"
#include "plugin\png/init"
#include "plugin\jpg/init"
#define BLITZ_INDEX__ F2cfe659668367946f7f2baa1fbeb2b5e
#include "Lib.icpp"
#undef BLITZ_INDEX__
#endif

View file

@ -1,96 +1,99 @@
#ifndef _Wpp_Wpp_h
#define _Wpp_Wpp_h
#include <Sql/Sql.h>
namespace Upp {
namespace Ini {
extern IniBool skylark_log;
};
String GetThreadName();
#define SKYLARKLOG(x) LOG_(Ini::skylark_log, GetThreadName() << ' ' << x)
class Renderer;
class Http;
struct SessionConfig {
String cookie;
String dir;
int format;
SqlId table, id_column, data_column, lastwrite_column;
int expire;
SessionConfig();
};
struct AuthExc : Exc {
AuthExc(const String& s) : Exc(s) {}
};
struct SkylarkConfig {
String root;
VectorMap<String, String> view_var;
String path;
String static_dir;
SessionConfig session;
int threads;
int port;
int prefork;
int timeout;
bool use_caching;
};
class SkylarkApp : protected SkylarkConfig {
TcpSocket server;
Mutex accept_mutex;
int main_pid;
Vector<int> child_pid;
bool quit;
void ThreadRun();
void Broadcast(int signal);
void Signal(int signal);
static void SignalHandler(int signal);
void Main();
void FinalizeViews();
static SkylarkApp *app;
#ifdef PLATFORM_WIN32
static BOOL WINAPI CtrlCHandlerRoutine(__in DWORD dwCtrlType);
#endif
typedef SkylarkApp CLASSNAME;
friend class Http;
public:
virtual void SqlError(Http& http);
virtual void InternalError(Http& http);
virtual void NotFound(Http& http);
virtual void Unauthorized(Http& http);
virtual void WorkThread();
void RunThread();
void Run();
static SkylarkApp& TheApp();
static const SkylarkConfig& Config();
SkylarkApp();
virtual ~SkylarkApp();
};
#include "Witz.h"
#include "Http.h"
};
#endif
#ifndef _Skylark_Skylark_h
#define _Skylark_Skylark_h
#include <Sql/Sql.h>
namespace Upp {
namespace Ini {
extern IniBool skylark_log;
};
String GetThreadName();
#define SKYLARKLOG(x) LOG_(Ini::skylark_log, GetThreadName() << ' ' << x)
class Renderer;
class Http;
struct SessionConfig {
String cookie;
String dir;
int format;
SqlId table, id_column, data_column, lastwrite_column;
int expire;
SessionConfig();
};
struct AuthExc : Exc {
AuthExc(const String& s) : Exc(s) {}
};
struct BadRequestExc : Exc {};
struct SkylarkConfig {
String root;
VectorMap<String, String> view_var;
String path;
String static_dir;
SessionConfig session;
int threads;
int port;
int prefork;
int timeout;
bool use_caching;
};
class SkylarkApp : protected SkylarkConfig {
TcpSocket server;
Mutex accept_mutex;
int main_pid;
Vector<int> child_pid;
bool quit;
void ThreadRun();
void Broadcast(int signal);
void Signal(int signal);
static void SignalHandler(int signal);
void Main();
void FinalizeViews();
static SkylarkApp *app;
#ifdef PLATFORM_WIN32
static BOOL WINAPI CtrlCHandlerRoutine(__in DWORD dwCtrlType);
#endif
typedef SkylarkApp CLASSNAME;
friend class Http;
public:
virtual void SqlError(Http& http);
virtual void InternalError(Http& http);
virtual void NotFound(Http& http);
virtual void Unauthorized(Http& http);
virtual void BadRequest(Http& http);
virtual void WorkThread();
void RunThread();
void Run();
static SkylarkApp& TheApp();
static const SkylarkConfig& Config();
SkylarkApp();
virtual ~SkylarkApp();
};
#include "Witz.h"
#include "Http.h"
};
#endif

View file

@ -1,60 +1,80 @@
#include "Skylark.h"
namespace Upp {
struct sFieldsToRenderer : public FieldOperator {
Renderer& http;
void Field(const char *name, Ref f) {
http(name, f);
}
sFieldsToRenderer(Renderer& http) : http(http) {}
};
Renderer& Renderer::operator()(Fields rec)
{
sFieldsToRenderer x(*this);
rec(x);
return *this;
}
Renderer& Renderer::operator()(const Sql& sql)
{
int n = sql.GetColumns();
for(int i = 0; i < n; i++)
(*this)(sql.GetColumnInfo(i).name, sql[i]);
return *this;
}
SqlUpdate Renderer::Update(SqlId table)
{
Vector<String> col = GetSchColumns(~table);
SqlUpdate u(table);
for(int i = 0; i < col.GetCount(); i++) {
String c = col[i];
int q = var.Find(c);
if(q < 0)
q = var.Find(ToLower(c));
if(q >= 0)
u(c, var[q]);
}
return u;
}
SqlInsert Renderer::Insert(SqlId table)
{
Vector<String> col = GetSchColumns(~table);
SqlInsert y(table);
for(int i = 0; i < col.GetCount(); i++) {
String c = col[i];
int q = var.Find(c);
if(q < 0)
q = var.Find(ToLower(c));
if(q >= 0)
y(c, var[q]);
}
return y;
}
#include "Skylark.h"
namespace Upp {
struct sFieldsToRenderer : public FieldOperator {
Renderer& http;
void Field(const char *name, Ref f) {
http(name, f);
}
sFieldsToRenderer(Renderer& http) : http(http) {}
};
Renderer& Renderer::operator()(Fields rec)
{
sFieldsToRenderer x(*this);
rec(x);
return *this;
}
Renderer& Renderer::operator()(const Sql& sql)
{
int n = sql.GetColumns();
for(int i = 0; i < n; i++)
(*this)(sql.GetColumnInfo(i).name, sql[i]);
return *this;
}
Renderer& Renderer::operator()(const SqlSelect& sel)
{
SqlR sql;
sql * sel;
if(!sql.Fetch())
throw BadRequestExc();
return operator()(sql);
}
Renderer& Renderer::operator()(const char *id, const SqlSelect& sel)
{
ValueArray list;
ValueMap vm;
SqlR sql;
sql * sel;
while(sql.Fetch(vm))
list.Add(vm);
return operator()(id, list);
}
SqlUpdate Renderer::Update(SqlId table)
{
Vector<String> col = GetSchColumns(~table);
SqlUpdate u(table);
for(int i = 0; i < col.GetCount(); i++) {
String c = col[i];
int q = var.Find(c);
if(q < 0)
q = var.Find(ToLower(c));
if(q >= 0)
u(c, var[q]);
}
return u;
}
SqlInsert Renderer::Insert(SqlId table)
{
Vector<String> col = GetSchColumns(~table);
SqlInsert y(table);
for(int i = 0; i < col.GetCount(); i++) {
String c = col[i];
int q = var.Find(c);
if(q < 0)
q = var.Find(ToLower(c));
if(q >= 0)
y(c, var[q]);
}
return y;
}
};

View file

@ -590,4 +590,347 @@ the value attribute of matching element. Not shown here, [*@5 UxRender]
is similar to Ux, but renders the text from witz template and
finally [*@5 UxRun] can be used to run any JavaScript code in the
client.&]
[s5; ]]
[s5; &]
[s3; 9. Connecting SQL database&]
[s5; Skylark naturally uses U`+`+ SQL support when dealing with persistent
storage, using `"session per`-thread`" mode. Because of this,
database session needs to be connected when starting each thread
`- this is done by overloading [@5 WorkThread] virtual method of
SkylarkApp:&]
[s7; &]
[s7; &]
[s7; #include <Skylark/Skylark.h>&]
[s7; #include <plugin/sqlite3/Sqlite3.h>&]
[s7; &]
[s7; using namespace Upp;&]
[s7; &]
[s7; #define MODEL <Skylark09/myapp.sch>&]
[s7; #define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>&]
[s7; #include <Sql/sch`_header.h>&]
[s7; #include <Sql/sch`_schema.h>&]
[s7; #include <Sql/sch`_source.h>&]
[s7; &]
[s7; SKYLARK(HomePage, `"`")&]
[s7; `{&]
[s7; -|Sql sql;&]
[s7; -|sql `* Select(ID, NAME, LASTNAME)&]
[s7; -| .From(PERSON)&]
[s7; -| .OrderBy(LASTNAME, NAME);&]
[s7; -|ValueArray person;&]
[s7; -|ValueMap vm;&]
[s7; -|while(sql.Fetch(vm))&]
[s7; -|-|person.Add(vm);&]
[s7; -|http(`"PERSON`", person)&]
[s7; -| .RenderResult(`"Skylark09/index`");&]
[s7; `}&]
[s7; &]
[s7; struct MyApp : SkylarkApp `{&]
[s7; -|[* virtual void WorkThread();]&]
[s7; &]
[s7; -|MyApp() `{&]
[s7; -|-|root `= `"myapp`";&]
[s7; -|-|threads `= 1; // Sqlite3 does not like threads...&]
[s7; -|#ifdef `_DEBUG&]
[s7; -|-|prefork `= 0;&]
[s7; -|-|use`_caching `= false;&]
[s7; -|#endif&]
[s7; -|`}&]
[s7; `};&]
[s7; &]
[s7; void InitModel()&]
[s7; `{&]
[s7; #ifdef `_DEBUG&]
[s7; -|SqlSchema sch(SQLITE3);&]
[s7; -|All`_Tables(sch);&]
[s7; -|SqlPerformScript(sch.Upgrade());&]
[s7; -|SqlPerformScript(sch.Attributes());&]
[s7; -|sch.SaveNormal();&]
[s7; #endif&]
[s7; `}&]
[s7; &]
[s7; void OpenSQL(Sqlite3Session`& sqlite3)&]
[s7; `{&]
[s7; -|if(!sqlite3.Open(ConfigFile(`"db`"))) `{&]
[s7; -|-|LOG(`"Can`'t create or open database file`\n`");&]
[s7; -|-|Exit(1);&]
[s7; -|`}&]
[s7; #ifdef `_DEBUG&]
[s7; -|sqlite3.LogErrors();&]
[s7; -|sqlite3.SetTrace();&]
[s7; #endif&]
[s7; -|SQL `= sqlite3;&]
[s7; `}&]
[s7; &]
[s7; [* void MyApp`::WorkThread()]&]
[s7; [* `{]&]
[s7; [* -|Sqlite3Session sqlite3;]&]
[s7; [* -|OpenSQL(sqlite3);]&]
[s7; [* -|RunThread();]&]
[s7; [* `}]&]
[s7; &]
[s7; void InitDB()&]
[s7; `{&]
[s7; -|Sqlite3Session sqlsession;&]
[s7; -|OpenSQL(sqlsession);&]
[s7; -|SqlSchema sch(SQLITE3);&]
[s7; -|All`_Tables(sch);&]
[s7; -|SqlPerformScript(sch.Upgrade());&]
[s7; -|SqlPerformScript(sch.Attributes());&]
[s7; &]
[s7; -|SQL `* Insert(PERSON)(NAME,`"Joe`")(LASTNAME,`"Smith`");&]
[s7; -|SQL `* Insert(PERSON)(NAME,`"Mike`")(LASTNAME,`"Carpenter`");&]
[s7; -|SQL `* Insert(PERSON)(NAME,`"Jon`")(LASTNAME,`"Goober`");&]
[s7; `}&]
[s7; &]
[s7; CONSOLE`_APP`_MAIN&]
[s7; `{&]
[s7; #ifdef `_DEBUG&]
[s7; -|StdLogSetup(LOG`_FILE`|LOG`_COUT);&]
[s7; -|Ini`::skylark`_log `= true;&]
[s7; #endif&]
[s7; &]
[s7; -|DeleteFile(ConfigFile(`"db`")); // for this example, always
create a new DB&]
[s7; -|InitDB();&]
[s7; &]
[s7; -|MyApp().Run();-|&]
[s7; `}&]
[s7; &]
[s7; &]
[s5; [* Skylark09/index.witz:]&]
[s7; <html>&]
[s7; <body>&]
[s7; <table border`=`"1`">&]
[s7; <tr>&]
[s7; <th>No.</th>&]
[s7; <th>First Name</th>&]
[s7; <th>Last Name</th>&]
[s7; </tr>&]
[s7; `$for(i in PERSON)&]
[s7; -|<tr>&]
[s7; -| <td>`$i.`_index.</td>&]
[s7; -| <td>`$i.NAME</td>&]
[s7; -| <td>`$i.LASTNAME</td>&]
[s7; -|</tr>-|&]
[s7; `$/&]
[s7; </table>&]
[s7; </body>&]
[s7; </html>&]
[s7; &]
[s7; &]
[s5; [* Skylark09/myapp.sch:]&]
[s7; TABLE`_(PERSON)&]
[s7; -|INT`_ (ID) PRIMARY`_KEY AUTO`_INCREMENT&]
[s7; -|STRING`_ (NAME, 200)&]
[s7; -|STRING`_ (LASTNAME, 200)&]
[s7; END`_TABLE&]
[s7; &]
[s7; &]
[s3; 10. Advanced SQL&]
[s5; Http class contains some advanced convenience support for dealing
with SQL databases:&]
[s5;i150;O0; It is possible to fill result set of SqlSelect into
witz variable as demonstrated by [@5 HomePage ]handler&]
[s5;i150;O0; Http`::Insert inserts a row to database, reading values
of columns based on known (from .sch file) names of columns from
equally named variables of shared variable space (which come
from POST or GET request), as demonstrated by [@5 SubmitNew].&]
[s5;i150;O0; Http`::Update updates a row in database, again based
on names of columns and shared variable space, as demonstrated
by [@5 SubmitEdit].&]
[s5;i150;O0; It is also possible to add shared variables based on
single row select, names being then same as names of columns,
as demonstrated by [@5 Edit].&]
[s5; &]
[s7; #include <Skylark/Skylark.h>&]
[s7; #include <plugin/sqlite3/Sqlite3.h>&]
[s7; &]
[s7; using namespace Upp;&]
[s7; &]
[s7; #define MODEL <Skylark09/myapp.sch>&]
[s7; #define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>&]
[s7; #include <Sql/sch`_header.h>&]
[s7; #include <Sql/sch`_schema.h>&]
[s7; #include <Sql/sch`_source.h>&]
[s7; &]
[s7; SKYLARK(HomePage, `"`")&]
[s7; `{&]
[s7; /`*&]
[s7; -|Sql sql;&]
[s7; -|sql `* Select(ID, NAME, LASTNAME)&]
[s7; -| .From(PERSON)&]
[s7; -| .OrderBy(LASTNAME, NAME);&]
[s7; -|ValueArray person;&]
[s7; -|ValueMap vm;&]
[s7; -|while(sql.Fetch(vm))&]
[s7; -|-|person.Add(vm);&]
[s7; `*/&]
[s7; -|[* http(`"PERSON`", Select(SqlAll()).From(PERSON).OrderBy(LASTNAME,
NAME))]&]
[s7; -|.RenderResult(`"Skylark10/index`");&]
[s7; `}&]
[s7; &]
[s7; SKYLARK(SubmitNew, `"create/submit:POST`")&]
[s7; `{&]
[s7; /`*&]
[s7; -|SQL `* Insert(PERSON)(NAME, http`[`"name`"`])(LASTNAME, http`[`"lastname`"`]);&]
[s7; `*/&]
[s7; -|[* SQL `* http.Insert(PERSON);]&]
[s7; -|http.Redirect(HomePage);&]
[s7; `}&]
[s7; &]
[s7; SKYLARK(New, `"create`")&]
[s7; `{&]
[s7; -|http(`"ACTION`", SubmitNew)&]
[s7; -|.RenderResult(`"Skylark10/Dialog`");&]
[s7; `}&]
[s7; &]
[s7; SKYLARK(SubmitEdit, `"edit/submit/`*:POST`")&]
[s7; `{&]
[s7; /`*&]
[s7; -|SQL `* Update(PERSON)&]
[s7; -|-|-|(NAME, http`[`"name`"`])&]
[s7; -|-|-|(LASTNAME, http`[`"lastname`"`])&]
[s7; -|-|-|.Where(ID `=`= http.Int(0));&]
[s7; -|;&]
[s7; `*/&]
[s7; -|[* SQL `* http.Update(PERSON).Where(ID `=`= http.Int(0));]&]
[s7; -|http.Redirect(HomePage);&]
[s7; `}&]
[s7; &]
[s7; SKYLARK(Edit, `"edit/`*`")&]
[s7; `{&]
[s7; -|int id `= http.Int(0);&]
[s7; /`*&]
[s7; -|Sql sql;&]
[s7; -|sql `* Select(NAME, LASTNAME).From(PERSON).Where(ID `=`= id);&]
[s7; -|if(!sql.Fetch()) `{&]
[s7; -|-|http.Redirect(HomePage);&]
[s7; -|-|return;&]
[s7; -|`}&]
[s7; -|http(`"NAME`", sql`[NAME`])(`"LASTNAME`", sql`[LASTNAME`]);&]
[s7; `*/&]
[s7; -|[* http]&]
[s7; [* -|-|(Select(SqlAll()).From(PERSON).Where(ID `=`= id))]&]
[s7; -|-|(`"ID`", id)&]
[s7; -|-|(`"ACTION`", SubmitEdit, id)&]
[s7; -|.RenderResult(`"Skylark10/Dialog`");&]
[s7; `}&]
[s7; &]
[s7; struct MyApp : SkylarkApp `{&]
[s7; -|virtual void WorkThread();&]
[s7; &]
[s7; -|MyApp() `{&]
[s7; -|-|root `= `"myapp`";&]
[s7; -|-|threads `= 1; // Sqlite3 does not like threads...&]
[s7; -|#ifdef `_DEBUG&]
[s7; -|-|prefork `= 0;&]
[s7; -|-|use`_caching `= false;&]
[s7; -|#endif&]
[s7; -|`}&]
[s7; `};&]
[s7; &]
[s7; void InitModel()&]
[s7; `{&]
[s7; #ifdef `_DEBUG&]
[s7; -|SqlSchema sch(SQLITE3);&]
[s7; -|All`_Tables(sch);&]
[s7; -|SqlPerformScript(sch.Upgrade());&]
[s7; -|SqlPerformScript(sch.Attributes());&]
[s7; -|sch.SaveNormal();&]
[s7; #endif&]
[s7; `}&]
[s7; &]
[s7; void OpenSQL(Sqlite3Session`& sqlite3)&]
[s7; `{&]
[s7; -|if(!sqlite3.Open(ConfigFile(`"db`"))) `{&]
[s7; -|-|LOG(`"Can`'t create or open database file`\n`");&]
[s7; -|-|Exit(1);&]
[s7; -|`}&]
[s7; #ifdef `_DEBUG&]
[s7; -|sqlite3.LogErrors();&]
[s7; -|sqlite3.SetTrace();&]
[s7; #endif&]
[s7; -|SQL `= sqlite3;&]
[s7; `}&]
[s7; &]
[s7; void MyApp`::WorkThread()&]
[s7; `{&]
[s7; -|Sqlite3Session sqlite3;&]
[s7; -|OpenSQL(sqlite3);&]
[s7; -|RunThread();&]
[s7; `}&]
[s7; &]
[s7; void InitDB()&]
[s7; `{&]
[s7; -|Sqlite3Session sqlsession;&]
[s7; -|OpenSQL(sqlsession);&]
[s7; -|SqlSchema sch(SQLITE3);&]
[s7; -|All`_Tables(sch);&]
[s7; -|SqlPerformScript(sch.Upgrade());&]
[s7; -|SqlPerformScript(sch.Attributes());&]
[s7; `}&]
[s7; &]
[s7; CONSOLE`_APP`_MAIN&]
[s7; `{&]
[s7; #ifdef `_DEBUG&]
[s7; -|StdLogSetup(LOG`_FILE`|LOG`_COUT);&]
[s7; -|Ini`::skylark`_log `= true;&]
[s7; #endif&]
[s7; &]
[s7; -|InitDB();&]
[s7; &]
[s7; -|MyApp().Run();-|&]
[s7; `}&]
[s7; &]
[s7; &]
[s5; [* Skylark10/index.witz:]&]
[s7; <html>&]
[s7; <body>&]
[s7; <table border`=`"1`">&]
[s7; <tr>&]
[s7; <th>No.</th>&]
[s7; <th>First Name</th>&]
[s7; <th>Last Name</th>&]
[s7; </tr>&]
[s7; `$for(i in PERSON)&]
[s7; -|<tr>&]
[s7; -| <td>`$(i.`_index `+ 1).</td>&]
[s7; -| <td>`$i.NAME</td>&]
[s7; -| <td>`$i.LASTNAME</td>&]
[s7; -| <td><a href`=`$Edit(i.ID)>Edit</a></td>&]
[s7; -|</tr>-|&]
[s7; `$/&]
[s7; </table>&]
[s7; <a href`=`$New>Create new</a>&]
[s7; </body>&]
[s7; </html>&]
[s7; &]
[s7; &]
[s5; [* Skylark10/dialog.witz:]&]
[s7; <html>&]
[s7; <body>&]
[s7; <FORM action`=`$ACTION method`=`"post`" accept`-charset`=`"utf`-8`"
enctype`=`"multipart/form`-data`">&]
[s7; `$post`_identity()&]
[s7; <P>&]
[s7; First name: <INPUT type`=`"text`" name`=`"name`" value`=`"`$NAME`"><BR>&]
[s7; Last name: <INPUT type`=`"text`" name`=`"lastname`" value`=`"`$LASTNAME`"><BR
>&]
[s7; <INPUT type`=`"submit`" value`=`"Send`" name`=`"OK`"/><BR>&]
[s7; </P>&]
[s7; </FORM>&]
[s7; </table>&]
[s7; </body>&]
[s7; </html>&]
[s7; &]
[s7; &]
[s5; [* Skylark10/myapp.sch:]&]
[s7; TABLE`_(PERSON)&]
[s7; -|INT`_ (ID) PRIMARY`_KEY AUTO`_INCREMENT&]
[s7; -|STRING`_ (NAME, 200)&]
[s7; -|STRING`_ (LASTNAME, 200)&]
[s7; END`_TABLE&]
[s7; &]
[s7; &]
[s7; ]]

View file

@ -17,6 +17,14 @@ void IdeFileIcon0(bool dir, const String& filename, Image& img)
break;
}
}
if(ext == ".html")
img = IdeCommonImg::html();
if(ext == ".css")
img = IdeCommonImg::css();
if(ext == ".witz")
img = IdeCommonImg::witz();
if(ext == ".js")
img = IdeCommonImg::js();
if(ext == ".usc")
img = IdeCommonImg::Script();
if(ext == ".lng" || ext == ".lngj" || ext == ".t" || ext == ".jt")
@ -89,12 +97,13 @@ void IdeFs(FileSel& fs) {
}
void SourceFs(FileSel& fs) {
String mask = "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp *.lay *.iml *.lng *.sch *.usc *.rc *.brc *.upt";
fs.Type("C++ files (*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp)", "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp");
fs.Type("Layout files (*.lay)", "*.lay");
fs.Type("Image files (*.iml)", "*.iml");
fs.Type("Language files (*.lng)", "*.lng");
fs.Type("Web development files (*.html *.js *.css *.witz)", "*.html *.js *.css *.witz");
fs.Type("Other special files (*.sch *.usc *.rc *.brc *.upt)", "*.sch *.usc *.rc *.brc *.upt");
String mask = "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp *.lay *.iml *.lng *.sch *.usc *.rc *.brc *.upt *.html *.js *.css *.witz";
fs.Type("All source files (" + mask + ")", mask);
IdeFs(fs);
}

View file

@ -13,62 +13,74 @@ IMAGE_ID(FFff)
IMAGE_ID(Source)
IMAGE_ID(Fast)
IMAGE_ID(ISource)
IMAGE_ID(js)
IMAGE_ID(html)
IMAGE_ID(css)
IMAGE_ID(witz)
IMAGE_ID(Script)
IMAGE_ID(Images)
IMAGE_ID(Language)
IMAGE_ID(IncludePath)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,237,154,223,107,28,85,20,199,239,63,32,20,124,40,136,224,67,20,132,130,32,216,167,72,138,15,34,98,173,136)
IMAGE_DATA(79,22,181,47,21,5,3,190,136,52,193,226,136,81,108,108,218,162,162,226,163,248,226,75,69,16,95,252,149,146,64,90)
IMAGE_DATA(232,214,180,89,109,146,182,70,177,173,63,98,91,220,180,82,237,143,175,51,179,123,103,238,220,57,231,254,218,217,100,183)
IMAGE_DATA(221,19,14,187,51,115,62,231,156,251,99,206,220,59,89,177,78,172,19,29,16,88,212,202,115,226,232,67,26,35,210,124)
IMAGE_DATA(201,107,22,31,70,222,161,45,44,79,248,234,243,22,158,82,87,158,85,23,222,34,38,222,67,187,71,58,84,12,164,132)
IMAGE_DATA(118,66,106,115,125,239,155,172,26,252,24,57,198,15,153,179,99,252,18,207,216,128,242,109,226,251,249,247,100,254,89,27)
IMAGE_DATA(2,231,47,217,23,132,86,47,221,92,12,110,199,65,86,13,126,140,28,227,135,204,217,49,126,137,103,108,64,249,54,241)
IMAGE_DATA(253,252,123,50,255,172,13,129,243,151,236,11,66,171,151,164,24,160,51,174,219,148,36,171,8,252,113,183,242,234,106,52)
IMAGE_DATA(2,127,204,73,4,55,237,84,254,237,242,55,123,251,171,226,215,64,154,43,3,118,112,168,74,228,83,157,168,189,149,109)
IMAGE_DATA(191,85,85,124,53,78,65,181,243,174,188,237,124,149,241,41,59,142,215,125,176,156,163,15,155,255,204,200,145,23,145,40)
IMAGE_DATA(239,249,213,118,26,248,140,141,207,20,62,9,31,44,159,48,186,154,120,42,119,143,248,5,113,136,111,20,135,248,206,62)
IMAGE_DATA(84,37,13,59,188,77,8,20,89,156,66,214,44,212,251,162,155,41,62,37,99,224,213,101,82,141,49,47,208,50,31,193)
IMAGE_DATA(124,238,199,206,171,121,235,199,33,241,139,237,240,139,95,206,163,179,241,237,90,129,172,82,49,160,158,78,94,246,147,147)
IMAGE_DATA(147,169,194,205,151,214,217,34,99,37,159,72,114,206,204,55,43,177,80,239,108,121,156,84,232,40,242,227,225,196,83,237)
IMAGE_DATA(203,89,176,79,251,140,151,125,37,85,242,66,225,245,235,54,62,255,67,27,60,156,120,82,51,150,93,245,24,251,63,103)
IMAGE_DATA(225,52,126,73,94,201,245,220,166,201,202,124,139,215,202,124,89,161,183,215,245,94,224,250,164,122,9,40,6,214,27,209)
IMAGE_DATA(166,119,224,99,12,224,51,118,32,175,95,219,140,127,47,15,161,241,247,70,252,241,251,125,248,121,105,8,11,243,155,241)
IMAGE_DATA(67,253,153,212,126,3,106,184,7,11,44,255,207,165,123,113,113,101,16,231,207,109,194,153,211,15,226,212,201,199,98,246)
IMAGE_DATA(105,204,126,63,156,218,111,196,37,12,94,187,202,242,231,207,109,192,95,203,131,248,237,236,67,113,236,39,48,63,191,13)
IMAGE_DATA(71,103,135,113,112,102,52,181,223,186,2,60,123,129,93,234,227,236,153,187,113,250,215,7,176,180,244,56,22,22,182,97)
IMAGE_DATA(110,110,24,135,15,143,96,122,250,245,212,126,215,47,192,251,39,121,254,167,83,67,113,206,143,198,109,126,42,102,95,64)
IMAGE_DATA(173,182,3,51,51,111,224,192,129,137,212,254,243,250,50,190,172,159,96,249,19,139,143,224,248,143,91,49,119,236,121,28)
IMAGE_DATA(169,189,140,67,135,198,48,61,181,15,223,126,243,81,106,127,164,254,65,220,31,175,177,252,252,241,39,113,236,232,115,113)
IMAGE_DATA(206,47,197,109,142,48,53,181,59,158,196,31,198,252,39,169,253,114,125,19,86,234,119,145,133,200,69,49,123,43,80,27)
IMAGE_DATA(96,138,222,146,162,23,136,167,104,108,243,221,118,224,171,209,150,61,208,104,52,20,222,44,169,205,254,47,128,79,191,38)
IMAGE_DATA(121,167,252,223,153,0,118,141,114,55,40,222,123,119,15,246,237,125,59,213,137,137,113,140,143,191,133,157,59,95,193,200)
IMAGE_DATA(200,142,38,255,226,253,192,246,1,157,115,238,195,255,182,172,199,229,45,119,134,22,6,254,254,189,81,139,1,21,215,167)
IMAGE_DATA(24,36,159,80,52,57,246,41,6,66,225,164,250,20,3,42,190,79,49,160,226,251,20,3,149,239,23,131,142,23,3,175)
IMAGE_DATA(62,36,138,129,79,65,168,180,24,152,146,246,177,5,234,185,10,75,135,80,219,4,133,43,241,250,4,208,183,9,182,248)
IMAGE_DATA(45,18,220,54,193,45,62,191,77,208,120,123,95,245,183,9,253,109,66,216,205,239,46,171,240,59,3,249,233,221,1,202)
IMAGE_DATA(141,35,60,223,25,144,188,90,12,18,49,191,51,40,250,214,139,129,253,157,65,49,63,189,24,152,222,25,20,10,134,146)
IMAGE_DATA(135,107,49,208,223,92,103,215,237,197,160,148,99,137,53,223,204,108,238,62,197,160,217,55,90,187,220,139,1,211,118,231)
IMAGE_DATA(98,80,102,253,138,65,105,238,48,237,101,11,153,225,92,79,23,131,170,36,168,35,228,96,41,75,4,189,152,24,89,157)
IMAGE_DATA(211,181,229,159,205,89,101,229,228,81,121,67,14,5,182,53,129,178,188,34,145,253,123,136,231,221,114,228,115,39,98,135)
IMAGE_DATA(240,84,254,137,88,242,39,125,164,5,189,60,142,78,124,192,248,9,33,139,154,166,194,30,155,244,19,192,173,174,164,63)
IMAGE_DATA(58,122,117,173,179,232,77,9,188,209,186,69,218,125,218,208,79,96,79,190,215,227,7,112,25,31,24,183,115,210,189,191)
IMAGE_DATA(64,44,72,37,43,3,145,28,231,75,59,231,149,65,198,105,234,178,50,80,109,35,221,135,101,101,32,237,66,86,6,142)
IMAGE_DATA(57,178,185,83,177,67,120,42,127,215,149,129,238,67,174,12,28,250,175,196,7,140,159,16,50,71,122,220,110,208,149,65)
IMAGE_DATA(247,166,151,8,245,4,115,237,88,24,255,108,147,169,108,235,19,223,39,150,91,238,190,19,208,191,205,171,227,163,221,190)
IMAGE_DATA(176,245,59,165,161,227,238,159,123,59,243,117,109,69,45,6,88,127,11,18,85,175,255,249,48,144,168,60,198,202,109,72)
IMAGE_DATA(148,112,5,27,111,98,69,185,195,210,239,45,54,227,73,182,177,191,196,229,219,125,145,125,138,242,96,52,217,156,135,137)
IMAGE_DATA(87,252,20,89,133,87,99,25,248,34,71,196,103,57,42,103,229,251,226,226,98,170,186,175,194,121,7,158,83,91,254,210)
IMAGE_DATA(238,74,124,227,168,170,241,108,255,73,54,249,46,89,249,157,106,23,199,83,90,106,191,37,190,170,108,124,166,159,29,218)
IMAGE_DATA(207,9,57,14,204,252,181,250,241,225,254,7,104,184,9,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(1408, 16)
IMAGE_DATA(120,156,237,155,207,107,29,85,20,199,231,79,40,184,112,35,184,136,130,80,16,4,187,138,164,184,16,23,214,138,184,40)
IMAGE_DATA(22,109,55,21,5,3,110,68,154,96,113,196,40,54,26,91,84,172,184,20,55,66,81,4,113,227,175,148,4,210,66,95)
IMAGE_DATA(77,155,167,77,108,107,20,219,106,137,105,49,177,82,197,230,235,204,36,119,222,157,59,231,220,123,238,157,121,201,123,237)
IMAGE_DATA(59,225,48,153,55,231,115,206,185,103,230,158,185,51,121,137,54,69,155,162,54,8,28,234,228,57,17,250,80,198,136,13)
IMAGE_DATA(95,234,152,195,135,149,23,140,133,229,9,95,61,222,193,83,42,229,89,149,240,14,177,241,30,218,57,210,166,102,160,36)
IMAGE_DATA(180,8,153,205,202,129,215,88,181,248,177,114,140,31,50,103,97,252,18,207,216,128,242,109,227,123,249,119,101,254,249,24)
IMAGE_DATA(2,175,95,178,22,132,214,47,157,220,12,110,195,81,86,45,126,172,28,227,135,204,89,24,191,196,51,54,160,124,219,248)
IMAGE_DATA(94,254,93,153,127,62,134,192,235,151,172,5,161,245,75,218,12,208,30,215,21,37,205,42,6,191,223,169,188,190,26,141)
IMAGE_DATA(193,239,115,18,67,166,237,202,191,42,127,179,143,191,46,126,3,100,117,101,192,158,28,170,19,249,116,39,234,217,202,245)
IMAGE_DATA(188,85,87,124,61,78,65,141,207,165,188,235,243,58,227,83,118,28,111,250,96,57,161,15,151,255,220,72,200,71,113,84)
IMAGE_DATA(126,230,215,199,105,225,115,54,249,164,176,37,124,176,124,202,152,106,227,169,220,61,226,23,68,16,223,42,130,248,98,31)
IMAGE_DATA(186,146,134,109,126,76,8,20,213,156,66,214,44,212,251,162,155,41,62,37,35,224,85,114,81,141,48,47,208,114,31,193)
IMAGE_DATA(124,203,143,155,215,243,54,247,67,226,23,199,225,23,191,156,71,123,227,187,181,6,89,167,102,64,221,157,188,236,199,199)
IMAGE_DATA(199,51,133,204,151,81,236,40,103,21,159,74,250,153,157,95,237,196,145,62,179,213,126,218,161,227,216,143,135,136,167,198)
IMAGE_DATA(215,98,193,222,237,115,94,213,74,169,226,35,141,55,143,187,248,214,15,42,240,16,241,164,230,44,187,234,177,214,191,197)
IMAGE_DATA(66,116,254,210,188,210,227,45,155,85,86,229,91,60,86,230,203,10,115,188,210,185,192,213,164,126,9,104,6,206,137,232)
IMAGE_DATA(210,219,241,33,250,240,41,123,34,87,174,111,195,63,215,6,176,244,231,22,92,250,253,94,252,60,63,128,185,217,109,248)
IMAGE_DATA(190,185,43,179,223,140,6,238,198,28,203,255,125,245,30,252,181,220,143,203,139,91,113,225,252,3,56,119,246,145,132,125)
IMAGE_DATA(18,211,223,13,102,246,91,112,21,253,215,255,99,249,203,139,155,241,199,66,63,126,187,248,96,18,251,49,204,206,238,198)
IMAGE_DATA(201,233,65,28,157,26,206,236,119,46,3,79,93,97,151,250,184,120,225,46,156,255,245,126,204,207,63,138,185,185,221,152)
IMAGE_DATA(153,25,196,241,227,67,152,156,124,37,179,223,255,11,240,222,89,158,255,233,220,64,146,243,195,201,152,159,72,216,103,209)
IMAGE_DATA(104,236,197,212,212,171,56,114,100,44,179,255,172,185,128,47,154,103,88,254,204,143,15,225,244,15,59,49,115,234,25,156)
IMAGE_DATA(104,188,128,99,199,70,48,57,113,16,223,124,253,65,102,127,162,121,40,169,199,203,44,63,123,250,113,156,58,249,116,146)
IMAGE_DATA(243,243,201,152,99,76,76,188,153,92,196,239,39,252,71,153,253,66,115,43,150,155,119,146,141,72,162,152,190,5,104,244)
IMAGE_DATA(49,77,111,94,211,43,196,93,52,177,249,118,15,240,229,240,154,61,176,180,180,164,241,118,201,108,62,249,28,248,248,43)
IMAGE_DATA(146,23,229,255,246,24,176,127,152,155,160,120,247,157,183,112,240,192,27,153,142,141,141,98,116,244,117,236,219,247,34,134)
IMAGE_DATA(134,246,174,242,207,221,7,236,233,51,57,113,13,255,221,126,43,174,109,191,35,180,49,240,243,247,70,109,6,84,92,159)
IMAGE_DATA(102,144,110,161,105,186,239,211,12,34,141,83,234,211,12,168,248,62,205,128,138,239,211,12,116,190,215,12,218,222,12,188)
IMAGE_DATA(106,72,52,3,159,134,80,107,51,176,37,237,99,11,52,91,26,57,10,66,61,38,104,92,137,55,47,0,243,49,193,21)
IMAGE_DATA(127,141,4,247,152,32,139,207,63,38,24,188,187,86,189,199,132,222,99,66,216,228,151,203,58,124,207,64,109,189,11,160)
IMAGE_DATA(77,156,200,243,157,1,201,235,205,32,21,251,59,131,162,111,179,25,184,223,25,20,243,51,155,129,237,157,65,161,97,104)
IMAGE_DATA(121,72,155,129,249,230,58,63,238,110,6,165,28,75,172,125,50,179,185,251,52,131,213,218,24,227,146,55,3,102,236,226)
IMAGE_DATA(102,80,102,253,154,65,233,218,97,198,203,54,50,203,103,93,221,12,234,146,160,66,168,147,165,45,17,204,102,98,101,77)
IMAGE_DATA(206,212,53,255,108,206,58,171,46,30,157,183,228,80,96,215,46,160,60,175,56,202,255,60,196,243,178,28,249,220,137,216)
IMAGE_DATA(33,60,149,127,42,142,252,73,31,89,67,47,159,71,17,31,112,254,162,72,53,53,67,35,119,108,210,79,0,183,190,146)
IMAGE_DATA(125,233,232,165,141,206,162,59,37,112,162,117,138,84,189,219,208,119,96,79,190,219,227,7,112,57,31,24,183,125,210,185)
IMAGE_DATA(223,64,44,72,45,43,131,40,221,111,45,237,196,43,131,156,51,84,178,50,208,109,99,211,135,99,101,160,236,66,86,6)
IMAGE_DATA(194,28,217,220,169,216,33,60,149,191,116,101,96,250,80,43,3,65,253,74,124,192,249,139,34,149,35,125,222,110,204,149)
IMAGE_DATA(129,135,84,25,8,176,18,92,140,140,85,234,233,163,192,122,250,32,89,161,143,146,173,193,217,124,144,177,76,63,76,30)
IMAGE_DATA(108,174,212,239,82,31,130,241,144,99,224,242,118,140,159,244,33,172,157,179,150,85,175,33,79,182,224,35,144,205,125,84)
IMAGE_DATA(96,221,178,65,255,194,236,236,200,54,17,248,112,242,154,159,42,241,249,137,32,20,27,159,126,151,221,220,42,149,242,101)
IMAGE_DATA(251,214,239,190,241,125,249,58,198,127,248,240,37,50,15,41,191,99,199,98,37,222,220,250,212,191,202,248,61,181,22,249)
IMAGE_DATA(31,114,29,133,141,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(1376, 16)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,237,148,97,10,128,48,8,133,61,194,238,213,133,186,189,181,31,110,42,110,234,42,40,232,193,35,130,190,167,115)
IMAGE_DATA(18,20,40,128,8,36,12,122,36,60,179,112,219,177,63,1,132,61,190,50,220,90,79,215,87,223,101,103,33,250,236,103)
IMAGE_DATA(144,61,145,77,158,213,183,24,254,110,241,220,154,213,25,222,44,84,157,133,89,244,58,214,93,58,247,218,122,149,179,140)
IMAGE_DATA(243,220,179,157,138,236,149,224,213,78,101,246,218,98,163,252,136,141,240,33,215,159,193,75,53,59,156,203,210,18,173,178)
IMAGE_DATA(228,100,134,96,239,200,72,178,34,99,145,109,25,23,216,95,31,212,1,40,156,179,185,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(160, 2)
IMAGE_DATA(120,156,237,152,75,78,196,48,12,134,115,1,164,217,33,113,35,196,133,88,246,68,28,168,71,96,9,75,22,30,50,144)
IMAGE_DATA(214,118,253,76,59,165,149,240,232,87,211,105,62,219,113,83,79,53,229,82,46,229,14,6,1,153,188,101,1,31,46,143)
IMAGE_DATA(252,172,137,175,249,48,121,193,151,202,151,193,30,91,188,199,238,201,175,205,191,135,39,243,58,242,143,152,198,39,117,12)
IMAGE_DATA(251,163,102,224,242,78,241,187,155,73,187,230,248,136,196,239,110,38,206,70,154,248,82,6,133,27,118,225,233,92,122,60)
IMAGE_DATA(11,175,177,25,94,51,139,79,232,56,86,155,1,28,43,37,110,171,222,48,204,143,211,16,132,185,153,248,153,88,177,220)
IMAGE_DATA(115,62,122,214,188,143,143,181,181,240,234,46,169,247,190,231,115,63,207,195,207,13,55,3,120,124,128,42,124,253,253,25)
IMAGE_DATA(160,170,157,195,231,19,84,9,174,192,227,45,182,44,11,118,27,255,178,19,47,178,31,111,11,14,119,111,212,197,57,255)
IMAGE_DATA(195,206,60,88,60,251,53,152,89,196,227,88,6,79,57,33,190,202,73,57,163,241,56,142,55,113,95,228,251,0,175,201)
IMAGE_DATA(203,191,205,251,250,126,112,176,24,175,214,175,177,117,220,216,54,150,214,165,241,146,22,235,119,226,99,169,241,149,58,7)
IMAGE_DATA(214,175,153,120,31,148,253,235,250,73,113,236,205,192,93,172,227,184,110,91,120,121,133,249,88,10,145,199,87,6,43,241)
IMAGE_DATA(106,182,73,124,54,47,91,11,146,231,188,6,154,83,147,200,163,248,18,131,207,37,30,139,179,220,135,87,11,22,167,163)
IMAGE_DATA(22,115,28,233,94,58,247,117,202,149,214,50,206,99,89,123,42,178,175,8,207,246,84,102,95,75,108,148,215,216,8,31)
IMAGE_DATA(210,157,254,51,216,194,50,93,112,193,2,184,5,50,217,166,164,15,194,110,225,35,201,18,31,157,236,228,99,5,251,111)
IMAGE_DATA(39,180,43,210,170,244,249,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(448, 6)