diff --git a/doc/pages/0_context.txt b/doc/pages/0_context.txt
new file mode 100644
index 0000000..b414d2c
--- /dev/null
+++ b/doc/pages/0_context.txt
@@ -0,0 +1,63 @@
+:sig
+Request* context;
+
+:ServerState* server
+Contains the current server state
+
+:StringMap params
+All FastCGI server parameters
+
+:StringMap get
+The current request's GET variables
+
+:StringMap post
+The current request's POST variables
+
+:StringMap cookies
+Cookies that have been transmitted by the browser
+
+:StringMap session
+The current session
+
+:String session_id
+ID of the session cookie
+
+String session_name
+Name of the session cookie
+
+:DTree var
+Variable user-defined data
+
+:std::vector uploaded_files
+Files that have been uploaded in the current request
+
+:StringMap header
+Headers to be sent back to the browser
+
+:StringList set_cookies;
+Cookies that should be sent back to the browser
+
+:u64 random_seed
+The current request's "random" noise generator seed
+
+:u64 random_index
+The current request's "random" noise generator index position
+
+:MemoryArena* mem
+Contains the current request's memory arena
+
+:bool flags.log_request
+Whether the request should be logged
+
+:Stats
+ u32 stats.bytes_written
+ f64 stats.time_init
+ f64 stats.time_start
+ f64 stats.time_end
+
+:invoke(String file_name, [DTree& call_param])
+Invokes the UCE file 'file_name'
+
+
+
+
diff --git a/doc/pages/basename.txt b/doc/pages/basename.txt
new file mode 100644
index 0000000..9b14648
--- /dev/null
+++ b/doc/pages/basename.txt
@@ -0,0 +1,12 @@
+:sig
+String basename(String fn)
+
+:params
+fn : raw filename
+return value : the file's name
+
+:desc
+Isolates the file name component from a path/file name.
+
+:see
+>sys
diff --git a/doc/pages/context.txt b/doc/pages/context.txt
deleted file mode 100644
index 881801b..0000000
--- a/doc/pages/context.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-:sig
-Request* context;
-//
-struct Request {
-
- ServerState* server;
-
- StringMap params;
- StringMap get;
- StringMap post;
- StringMap cookies;
- StringMap session;
-
- DTree var;
-
- String session_id = "";
- String session_name = "";
- std::vector uploaded_files;
-
- StringMap header;
- StringList set_cookies;
-
- u64 random_seed;
- u64 random_index;
-
- MemoryArena* mem;
-
- String in;
- std::vector ob_stack;
- std::ostringstream* ob;
- String out;
- String err;
-
- bool is_finished = false;
-
- struct Flags {
- bool log_request = true;
- } flags;
-
- struct Stats {
- u32 bytes_written;
- f64 time_init;
- f64 time_start;
- f64 time_end;
- } stats;
-
- void invoke(String file_name);
- void invoke(String file_name, DTree& call_param);
-
- void ob_start();
-
-};
-
-:desc
-
-
-
diff --git a/doc/pages/date.txt b/doc/pages/date.txt
new file mode 100644
index 0000000..7e0c918
--- /dev/null
+++ b/doc/pages/date.txt
@@ -0,0 +1,125 @@
+:sig
+String date(String format = "", u64 timestamp = 0)
+
+:params
+format : formatting string specifying the date format
+timestamp : optional timestamp value, defaults to current time
+return value : a formatted date
+
+:desc
+Returns a formatted date. This is based on the Linux date() command. The formatting string supports the following sequences:
+:pre
+ %% a literal %
+
+ %a locale's abbreviated weekday name (e.g., Sun)
+
+ %A locale's full weekday name (e.g., Sunday)
+
+ %b locale's abbreviated month name (e.g., Jan)
+
+ %B locale's full month name (e.g., January)
+
+ %c locale's date and time (e.g., Thu Mar 3 23:05:25 2005)
+
+ %C century; like %Y, except omit last two digits (e.g., 20)
+
+ %d day of month (e.g., 01)
+
+ %D date; same as %m/%d/%y
+
+ %e day of month, space padded; same as %_d
+
+ %F full date; like %+4Y-%m-%d
+
+ %g last two digits of year of ISO week number (see %G)
+
+ %G year of ISO week number (see %V); normally useful only
+ with %V
+
+ %h same as %b
+
+ %H hour (00..23)
+
+ %I hour (01..12)
+
+ %j day of year (001..366)
+
+ %k hour, space padded ( 0..23); same as %_H
+
+ %l hour, space padded ( 1..12); same as %_I
+
+ %m month (01..12)
+
+ %M minute (00..59)
+
+ %n a newline
+
+ %N nanoseconds (000000000..999999999)
+
+ %p locale's equivalent of either AM or PM; blank if not known
+
+ %P like %p, but lower case
+
+ %q quarter of year (1..4)
+
+ %r locale's 12-hour clock time (e.g., 11:11:04 PM)
+
+ %R 24-hour hour and minute; same as %H:%M
+
+ %s seconds since 1970-01-01 00:00:00 UTC
+
+ %S second (00..60)
+
+ %t a tab
+
+ %T time; same as %H:%M:%S
+
+ %u day of week (1..7); 1 is Monday
+
+ %U week number of year, with Sunday as first day of week
+ (00..53)
+
+ %V ISO week number, with Monday as first day of week (01..53)
+
+ %w day of week (0..6); 0 is Sunday
+
+ %W week number of year, with Monday as first day of week
+ (00..53)
+
+ %x locale's date representation (e.g., 12/31/99)
+
+ %X locale's time representation (e.g., 23:13:48)
+
+ %y last two digits of year (00..99)
+
+ %Y year
+
+ %z +hhmm numeric time zone (e.g., -0400)
+
+ %:z +hh:mm numeric time zone (e.g., -04:00)
+
+ %::z +hh:mm:ss numeric time zone (e.g., -04:00:00)
+
+ %:::z numeric time zone with : to necessary precision (e.g.,
+ -04, +05:30)
+
+ %Z alphabetic time zone abbreviation (e.g., EDT)
+
+ By default, date pads numeric fields with zeroes. The following
+ optional flags may follow '%':
+
+ - (hyphen) do not pad the field
+
+ _ (underscore) pad with spaces
+
+ 0 (zero) pad with zeros
+
+ + pad with zeros, and put '+' before future years with >4
+ digits
+
+ ^ use upper case if possible
+
+ # use opposite case if possible
+
+:see
+>time
diff --git a/doc/pages/dirname.txt b/doc/pages/dirname.txt
new file mode 100644
index 0000000..4c21233
--- /dev/null
+++ b/doc/pages/dirname.txt
@@ -0,0 +1,12 @@
+:sig
+String dirname(String fn)
+
+:params
+fn : raw filename
+return value : the directory's name
+
+:desc
+Isolates the directory name component from a path/file name.
+
+:see
+>sys
diff --git a/doc/pages/draw_float.txt b/doc/pages/draw_float.txt
index dfd240b..5a1b3fd 100644
--- a/doc/pages/draw_float.txt
+++ b/doc/pages/draw_float.txt
@@ -9,3 +9,5 @@ return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_float(), but context->random_index is used for the 'index' value and context->random_seed is used for the seed. After this function has been called, the context->random_index is increased by one. At the start of every request, context->random_seed is automatically populated with a new seed value.
+:see
+>noise
diff --git a/doc/pages/draw_int.txt b/doc/pages/draw_int.txt
index 4a60084..236b744 100644
--- a/doc/pages/draw_int.txt
+++ b/doc/pages/draw_int.txt
@@ -9,3 +9,5 @@ return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_int(), but context->random_index is used for the 'index' value and context->random_seed is used for the seed. After this function has been called, the context->random_index is increased by one. At the start of every request, context->random_seed is automatically populated with a new seed value.
+:see
+>noise
diff --git a/doc/pages/encode_query.txt b/doc/pages/encode_query.txt
new file mode 100644
index 0000000..67acf25
--- /dev/null
+++ b/doc/pages/encode_query.txt
@@ -0,0 +1,12 @@
+:sig
+String encode_query(StringMap map)
+
+:params
+q : StringMap containing URL parameters to be encoded
+return value : a string with the encoded parameters
+
+:desc
+Encodes a StringMap containing URL parameters into a single String.
+
+:see
+>uri
diff --git a/doc/pages/expand_path.txt b/doc/pages/expand_path.txt
new file mode 100644
index 0000000..0a82d22
--- /dev/null
+++ b/doc/pages/expand_path.txt
@@ -0,0 +1,12 @@
+:sig
+String expand_path(String path)
+
+:params
+path : a relative path
+return value : expanded version of the 'path'
+
+:desc
+Converts a relative path name into an absolute path, using the current working directory as a base.
+
+:see
+>sys
diff --git a/doc/pages/file_exists.txt b/doc/pages/file_exists.txt
new file mode 100644
index 0000000..5b09447
--- /dev/null
+++ b/doc/pages/file_exists.txt
@@ -0,0 +1,12 @@
+:sig
+bool file_exists(String path)
+
+:params
+path : the path name to be checked
+return value : true if the file exists
+
+:desc
+Checks whether the file or path specified by 'path' exists.
+
+:see
+>sys
diff --git a/doc/pages/file_get_contents.txt b/doc/pages/file_get_contents.txt
new file mode 100644
index 0000000..2ff26e4
--- /dev/null
+++ b/doc/pages/file_get_contents.txt
@@ -0,0 +1,12 @@
+:sig
+String file_get_contents(String file_name)
+
+:params
+file_name : file name of file that should be read
+return value : String containing the file's contents
+
+:desc
+Reads the file identified by 'file_name' and returns it as a String. If the file cannot be read, this function will return an empty string.
+
+:see
+>sys
diff --git a/doc/pages/file_mtime.txt b/doc/pages/file_mtime.txt
new file mode 100644
index 0000000..be5bddb
--- /dev/null
+++ b/doc/pages/file_mtime.txt
@@ -0,0 +1,13 @@
+:sig
+time_t file_mtime(String file_name)
+
+:params
+file_name : name of the file
+return value : Unix time stamp of the file's last modification
+
+:desc
+Retrieves the last modification date of 'file_name' as a Unix timestamp.
+
+:see
+>sys
+>time
diff --git a/doc/pages/file_put_contents.txt b/doc/pages/file_put_contents.txt
new file mode 100644
index 0000000..fdecc37
--- /dev/null
+++ b/doc/pages/file_put_contents.txt
@@ -0,0 +1,13 @@
+:sig
+bool file_put_contents(String file_name, String content)
+
+:params
+file_name : file name of file that should be written
+content : content that should be written
+return value : true if write was successful
+
+:desc
+Writes the String 'content' into a file identified by 'file_name'. Any pre-existing content of the file will be overwritten.
+
+:see
+>sys
diff --git a/doc/pages/filter.txt b/doc/pages/filter.txt
index fb2873b..db12c41 100644
--- a/doc/pages/filter.txt
+++ b/doc/pages/filter.txt
@@ -9,3 +9,6 @@ return value : a new list
:desc
Returns a list containing the members of 'items' for which 'f' returned boolean true.
+
+:see
+>string
diff --git a/doc/pages/first.txt b/doc/pages/first.txt
index 731a094..98457f1 100644
--- a/doc/pages/first.txt
+++ b/doc/pages/first.txt
@@ -8,3 +8,5 @@ return value : first of the 'args' that was not empty.
:desc
Given a variable number of String parameters, the first() function returns the first of these parameters that was not empty. Leading and trailing whitespace characters are not considered, resulting in a string that contains only whitespace characters being considered empty.
+:see
+>string
diff --git a/doc/pages/generate_float.txt b/doc/pages/generate_float.txt
index aff7df3..1f23c67 100644
--- a/doc/pages/generate_float.txt
+++ b/doc/pages/generate_float.txt
@@ -11,3 +11,6 @@ return value : noise value
:desc
Generates a noise value between 'from' and 'to', given the 'index' and 'seed' numbers.
+
+:see
+>noise
diff --git a/doc/pages/generate_int.txt b/doc/pages/generate_int.txt
index 1e179ab..2152938 100644
--- a/doc/pages/generate_int.txt
+++ b/doc/pages/generate_int.txt
@@ -11,3 +11,6 @@ return value : noise value
:desc
Generates a noise value between 'from' and 'to', given the 'index' and 'seed' numbers.
+
+:see
+>noise
diff --git a/doc/pages/get_cwd.txt b/doc/pages/get_cwd.txt
new file mode 100644
index 0000000..3c68e43
--- /dev/null
+++ b/doc/pages/get_cwd.txt
@@ -0,0 +1,11 @@
+:sig
+String get_cwd()
+
+:params
+return value : the current working directory
+
+:desc
+Returns the current working directory.
+
+:see
+>sys
diff --git a/doc/pages/gmdate.txt b/doc/pages/gmdate.txt
new file mode 100644
index 0000000..e29f761
--- /dev/null
+++ b/doc/pages/gmdate.txt
@@ -0,0 +1,125 @@
+:sig
+String gmdate(String format = "", u64 timestamp = 0)
+
+:params
+format : formatting string specifying the date format
+timestamp : optional timestamp value, defaults to current time
+return value : a formatted date
+
+:desc
+Returns a formatted date in the GMT/UTC timezone. This is based on the Linux date() command. The formatting string supports the following sequences:
+:pre
+ %% a literal %
+
+ %a locale's abbreviated weekday name (e.g., Sun)
+
+ %A locale's full weekday name (e.g., Sunday)
+
+ %b locale's abbreviated month name (e.g., Jan)
+
+ %B locale's full month name (e.g., January)
+
+ %c locale's date and time (e.g., Thu Mar 3 23:05:25 2005)
+
+ %C century; like %Y, except omit last two digits (e.g., 20)
+
+ %d day of month (e.g., 01)
+
+ %D date; same as %m/%d/%y
+
+ %e day of month, space padded; same as %_d
+
+ %F full date; like %+4Y-%m-%d
+
+ %g last two digits of year of ISO week number (see %G)
+
+ %G year of ISO week number (see %V); normally useful only
+ with %V
+
+ %h same as %b
+
+ %H hour (00..23)
+
+ %I hour (01..12)
+
+ %j day of year (001..366)
+
+ %k hour, space padded ( 0..23); same as %_H
+
+ %l hour, space padded ( 1..12); same as %_I
+
+ %m month (01..12)
+
+ %M minute (00..59)
+
+ %n a newline
+
+ %N nanoseconds (000000000..999999999)
+
+ %p locale's equivalent of either AM or PM; blank if not known
+
+ %P like %p, but lower case
+
+ %q quarter of year (1..4)
+
+ %r locale's 12-hour clock time (e.g., 11:11:04 PM)
+
+ %R 24-hour hour and minute; same as %H:%M
+
+ %s seconds since 1970-01-01 00:00:00 UTC
+
+ %S second (00..60)
+
+ %t a tab
+
+ %T time; same as %H:%M:%S
+
+ %u day of week (1..7); 1 is Monday
+
+ %U week number of year, with Sunday as first day of week
+ (00..53)
+
+ %V ISO week number, with Monday as first day of week (01..53)
+
+ %w day of week (0..6); 0 is Sunday
+
+ %W week number of year, with Monday as first day of week
+ (00..53)
+
+ %x locale's date representation (e.g., 12/31/99)
+
+ %X locale's time representation (e.g., 23:13:48)
+
+ %y last two digits of year (00..99)
+
+ %Y year
+
+ %z +hhmm numeric time zone (e.g., -0400)
+
+ %:z +hh:mm numeric time zone (e.g., -04:00)
+
+ %::z +hh:mm:ss numeric time zone (e.g., -04:00:00)
+
+ %:::z numeric time zone with : to necessary precision (e.g.,
+ -04, +05:30)
+
+ %Z alphabetic time zone abbreviation (e.g., EDT)
+
+ By default, date pads numeric fields with zeroes. The following
+ optional flags may follow '%':
+
+ - (hyphen) do not pad the field
+
+ _ (underscore) pad with spaces
+
+ 0 (zero) pad with zeros
+
+ + pad with zeros, and put '+' before future years with >4
+ digits
+
+ ^ use upper case if possible
+
+ # use opposite case if possible
+
+:see
+>time
diff --git a/doc/pages/intval.txt b/doc/pages/int_val.txt
similarity index 100%
rename from doc/pages/intval.txt
rename to doc/pages/int_val.txt
diff --git a/doc/pages/join.txt b/doc/pages/join.txt
index f21e8b1..d622e92 100644
--- a/doc/pages/join.txt
+++ b/doc/pages/join.txt
@@ -9,3 +9,5 @@ return value : a string containing items joined by 'delim'
:desc
Joins the items contained in 'l' into a single String.
+:see
+>string
diff --git a/doc/pages/ls.txt b/doc/pages/ls.txt
new file mode 100644
index 0000000..f1e0511
--- /dev/null
+++ b/doc/pages/ls.txt
@@ -0,0 +1,12 @@
+:sig
+StringList ls(String path)
+
+:params
+path : a filesystem path
+return value : list of directory entries
+
+:desc
+Returns a list of files and subdirectories within the given 'path'.
+
+:see
+>sys
diff --git a/doc/pages/make_session_id.txt b/doc/pages/make_session_id.txt
new file mode 100644
index 0000000..66f721f
--- /dev/null
+++ b/doc/pages/make_session_id.txt
@@ -0,0 +1,11 @@
+:sig
+String make_session_id()
+
+:params
+return value : a new session ID
+
+:desc
+Creates a session ID
+
+:see
+>uri
diff --git a/doc/pages/memcache_command.txt b/doc/pages/memcache_command.txt
new file mode 100644
index 0000000..700e8c5
--- /dev/null
+++ b/doc/pages/memcache_command.txt
@@ -0,0 +1,13 @@
+:sig
+String memcache_command(u64 connection, String command)
+
+:params
+connection : connection handle
+command : string containing the Memcache command
+return value : string containing the Memcache server's response
+
+:desc
+Executes a command on an open memcache connection.
+
+:see
+>memcache
diff --git a/doc/pages/memcache_connect.txt b/doc/pages/memcache_connect.txt
new file mode 100644
index 0000000..ebbe17f
--- /dev/null
+++ b/doc/pages/memcache_connect.txt
@@ -0,0 +1,13 @@
+:sig
+u64 memcache_connect(String host = "127.0.0.1", short port = 11211)
+
+:params
+host : optional host name of the memcache server, defaults to local address 127.0.0.1
+port : optional memcache server's port, defaults to 11211
+return value : the connection handle (or -1 if an error occurred)
+
+:desc
+Connects to a memcache server instance.
+
+:see
+>memcache
diff --git a/doc/pages/memcache_delete.txt b/doc/pages/memcache_delete.txt
new file mode 100644
index 0000000..e0bd946
--- /dev/null
+++ b/doc/pages/memcache_delete.txt
@@ -0,0 +1,13 @@
+:sig
+bool memcache_delete(u64 connection, String key)
+
+:params
+connection : connection handle
+key : key string
+return value : true if the operation was successful
+
+:desc
+Deletes entry specified by the 'key'.
+
+:see
+>memcache
diff --git a/doc/pages/memcache_get.txt b/doc/pages/memcache_get.txt
new file mode 100644
index 0000000..c7f2c9b
--- /dev/null
+++ b/doc/pages/memcache_get.txt
@@ -0,0 +1,14 @@
+:sig
+String memcache_get(u64 connection, String key, String default_value = "")
+
+:params
+connection : connection handle
+key : key string
+default_value : optional default value
+return value : value that was returned by the Memcache server
+
+:desc
+Retrieves a value from an existing connection to a Memcache server.
+
+:see
+>memcache
diff --git a/doc/pages/memcache_get_multiple.txt b/doc/pages/memcache_get_multiple.txt
new file mode 100644
index 0000000..cdf1a02
--- /dev/null
+++ b/doc/pages/memcache_get_multiple.txt
@@ -0,0 +1,13 @@
+:sig
+StringMap memcache_get_multiple(u64 connection, StringList keys)
+
+:params
+connection : connection handle
+keys : a list of strings containing the keys to be retrieved
+return value : a StringMap with the retrieved entries
+
+:desc
+Retrieves a bunch of entries all at once.
+
+:see
+>memcache
diff --git a/doc/pages/memcache_set.txt b/doc/pages/memcache_set.txt
new file mode 100644
index 0000000..a67457c
--- /dev/null
+++ b/doc/pages/memcache_set.txt
@@ -0,0 +1,15 @@
+:sig
+bool memcache_set(u64 connection, String key, String value, u64 expires_in = 60*60)
+
+:params
+connection : connection handle
+key : the entry's key
+value : the value to be set
+expires_in : optional expiration timeout, defaults to one hour
+return value : true if the operation was successful
+
+:desc
+Stores a 'value' on the Memcache server.
+
+:see
+>memcache
diff --git a/doc/pages/microtime.txt b/doc/pages/microtime.txt
new file mode 100644
index 0000000..9c42f29
--- /dev/null
+++ b/doc/pages/microtime.txt
@@ -0,0 +1,11 @@
+:sig
+f64 microtime()
+
+:params
+return value : current Unix timestamp
+
+:desc
+Returns a 64 bit float containing the current Unix timestamp with millisecond accuracy or better.
+
+:see
+>time
diff --git a/doc/pages/mkdir.txt b/doc/pages/mkdir.txt
new file mode 100644
index 0000000..e9da8fa
--- /dev/null
+++ b/doc/pages/mkdir.txt
@@ -0,0 +1,12 @@
+:sig
+bool mkdir(String path)
+
+:params
+path : the path name to be created
+return value : returns true if the directory was successfully created
+
+:desc
+Creates a directory stated by 'path'
+
+:see
+>sys
diff --git a/doc/pages/nibble.txt b/doc/pages/nibble.txt
index 30e1064..fd44f8c 100644
--- a/doc/pages/nibble.txt
+++ b/doc/pages/nibble.txt
@@ -9,4 +9,5 @@ return value : string before first occurrence of 'delim'
:desc
Returns the part of 'haystack' before the first occurrence of 'delim', removing the corresponding part from 'haystack' (including 'delim'). If the substring 'delim' does not occurr in 'haystack', the entire string is returned and 'haystack' is set to an empty string.
-
+:see
+>string
diff --git a/doc/pages/noise01.txt b/doc/pages/noise01.txt
index 487e9e6..dd8aff8 100644
--- a/doc/pages/noise01.txt
+++ b/doc/pages/noise01.txt
@@ -8,3 +8,6 @@ return value : a noise value from 0 to 1
:desc
Generates a noise value in the range from 0 to 1 for the given 'index' and 'seed' values.
+
+:see
+>noise
diff --git a/doc/pages/noise32.txt b/doc/pages/noise32.txt
index 72fd746..8fe7a2a 100644
--- a/doc/pages/noise32.txt
+++ b/doc/pages/noise32.txt
@@ -8,3 +8,6 @@ return value : a noise value given the 'index' and 'seed' values.
:desc
Generates a noise value for the given 'index' and 'seed' values.
+
+:see
+>noise
diff --git a/doc/pages/noise64.txt b/doc/pages/noise64.txt
index dea885e..9e7f0d1 100644
--- a/doc/pages/noise64.txt
+++ b/doc/pages/noise64.txt
@@ -8,3 +8,6 @@ return value : a noise value given the 'index' and 'seed' values.
:desc
Generates a noise value for the given 'index' and 'seed' values.
+
+:see
+>noise
diff --git a/doc/pages/ob_clear.txt b/doc/pages/ob_clear.txt
index 8401478..02d4c02 100644
--- a/doc/pages/ob_clear.txt
+++ b/doc/pages/ob_clear.txt
@@ -2,7 +2,10 @@
void ob_clear()
:params
--
+(none)
:desc
Discard the current output buffer.
+
+:see
+>ob
diff --git a/doc/pages/ob_get.txt b/doc/pages/ob_get.txt
index b159e87..20492ea 100644
--- a/doc/pages/ob_get.txt
+++ b/doc/pages/ob_get.txt
@@ -6,3 +6,6 @@ return value : content of the current output buffer
:desc
Returns the contents of the current output buffer.
+
+:see
+>ob
diff --git a/doc/pages/ob_get_clear.txt b/doc/pages/ob_get_clear.txt
index 9a72953..124080d 100644
--- a/doc/pages/ob_get_clear.txt
+++ b/doc/pages/ob_get_clear.txt
@@ -6,3 +6,6 @@ return value : content of the current output buffer
:desc
Returns the contents of the current output buffer and then discards the buffer.
+
+:see
+>ob
diff --git a/doc/pages/ob_start.txt b/doc/pages/ob_start.txt
index 473d44d..14e3273 100644
--- a/doc/pages/ob_start.txt
+++ b/doc/pages/ob_start.txt
@@ -2,8 +2,10 @@
void ob_start()
:params
--
+(none)
:desc
Starts a new output buffer. All subsequent output will be directed into this buffer.
+:see
+>ob
diff --git a/doc/pages/parse_query.txt b/doc/pages/parse_query.txt
new file mode 100644
index 0000000..e3a569e
--- /dev/null
+++ b/doc/pages/parse_query.txt
@@ -0,0 +1,12 @@
+:sig
+StringMap parse_query(String q)
+
+:params
+q : string containing URL parameters
+return value : a StringMap containing the parameters
+
+:desc
+Decodes a string of the format 'a=b&c=d' into a StringMap containing keyed entries.
+
+:see
+>uri
diff --git a/doc/pages/parse_time.txt b/doc/pages/parse_time.txt
new file mode 100644
index 0000000..a32f7cb
--- /dev/null
+++ b/doc/pages/parse_time.txt
@@ -0,0 +1,12 @@
+:sig
+u64 parse_time(String time_string)
+
+:params
+time_string : a string containing a date and/or time in text form
+return value : the interpreted 'time_string' as a Unix timestamp
+
+:desc
+Attempts to parse the given 'time_string' into a Unix timestamp.
+
+:see
+>time
diff --git a/doc/pages/set_cwd.txt b/doc/pages/set_cwd.txt
new file mode 100644
index 0000000..755aca1
--- /dev/null
+++ b/doc/pages/set_cwd.txt
@@ -0,0 +1,11 @@
+:sig
+void set_cwd(String path)
+
+:params
+path : the new working directory
+
+:desc
+Sets a new working directory.
+
+:see
+>sys
diff --git a/doc/pages/sha1.txt b/doc/pages/sha1.txt
new file mode 100644
index 0000000..98181b7
--- /dev/null
+++ b/doc/pages/sha1.txt
@@ -0,0 +1,10 @@
+:sig
+String sha1(String s, bool as_binary = false)
+
+:params
+s : data to be hashed
+as_binary : when set to false, returns hash in hexadecimal notation (defaults to false)
+return value : the resulting hash value
+
+:desc
+Returns the sha1 hash of 's'.
diff --git a/doc/pages/shell_escape.txt b/doc/pages/shell_escape.txt
new file mode 100644
index 0000000..f55f1a6
--- /dev/null
+++ b/doc/pages/shell_escape.txt
@@ -0,0 +1,12 @@
+:sig
+String shell_escape(String raw)
+
+:params
+raw : string that should be escaped
+return value : escaped version of 'raw'
+
+:desc
+Escapes a parameter for shell_exec
+
+:see
+>sys
diff --git a/doc/pages/shell_exec.txt b/doc/pages/shell_exec.txt
new file mode 100644
index 0000000..8c2cdf1
--- /dev/null
+++ b/doc/pages/shell_exec.txt
@@ -0,0 +1,12 @@
+:sig
+String shell_exec(String cmd)
+
+:params
+cmd : string that contains the shell command line to be executed
+return value : output of the command execution
+
+:desc
+Executes a Linux shell command and returns the generated output
+
+:see
+>sys
diff --git a/doc/pages/socket_close.txt b/doc/pages/socket_close.txt
new file mode 100644
index 0000000..691cf57
--- /dev/null
+++ b/doc/pages/socket_close.txt
@@ -0,0 +1,11 @@
+:sig
+void socket_close(u64 sockfd)
+
+:params
+sockfd : socket handle
+
+:desc
+Closes an existing socket connection.
+
+:see
+>socket
diff --git a/doc/pages/socket_connect.txt b/doc/pages/socket_connect.txt
new file mode 100644
index 0000000..b78f9c6
--- /dev/null
+++ b/doc/pages/socket_connect.txt
@@ -0,0 +1,13 @@
+:sig
+u64 socket_connect(String host, short port)
+
+:params
+host : host name
+port : port number
+return value : the socket handle
+
+:desc
+Opens a socket connection to the given 'host' and 'port'.
+
+:see
+>socket
diff --git a/doc/pages/socket_read.txt b/doc/pages/socket_read.txt
new file mode 100644
index 0000000..7df62a8
--- /dev/null
+++ b/doc/pages/socket_read.txt
@@ -0,0 +1,14 @@
+:sig
+String socket_read(u64 sockfd, u32 max_length = 1024*128, u32 timeout = 1);
+
+:params
+sockfd : socket handle
+max_length : optional maximum data size, defaults to 128kBytes
+timeout : optional operation timeout, defaults to one second
+return value : string containing the data that was read
+
+:desc
+Reads data from a socket connection.
+
+:see
+>socket
diff --git a/doc/pages/socket_write.txt b/doc/pages/socket_write.txt
new file mode 100644
index 0000000..5d2cb66
--- /dev/null
+++ b/doc/pages/socket_write.txt
@@ -0,0 +1,13 @@
+:sig
+bool socket_write(u64 sockfd, String data)
+
+:params
+sockfd : socket handle
+data : a string containing the data to be written to the socket
+return value : true if the write operation was successful
+
+:desc
+Writes a string of 'data' to the given socket.
+
+:see
+>socket
diff --git a/doc/pages/split.txt b/doc/pages/split.txt
index 3c918d8..484a7a1 100644
--- a/doc/pages/split.txt
+++ b/doc/pages/split.txt
@@ -9,3 +9,5 @@ return value : a list of strings
:desc
Splits 'str' into multiple strings based on the given delimiter 'delim'.
+:see
+>string
diff --git a/doc/pages/time.txt b/doc/pages/time.txt
new file mode 100644
index 0000000..63cfb45
--- /dev/null
+++ b/doc/pages/time.txt
@@ -0,0 +1,11 @@
+:sig
+u64 time()
+
+:params
+return value : second-accurate current Unix timestamp
+
+:desc
+Returns a 64 bit integer containing the current Unix timestamp.
+
+:see
+>time
diff --git a/doc/pages/trim.txt b/doc/pages/trim.txt
index 0612b43..ed679ba 100644
--- a/doc/pages/trim.txt
+++ b/doc/pages/trim.txt
@@ -8,3 +8,5 @@ return value : string with leading and trailing whitespace characters removed
:desc
Returns a string where leading an trailing whitespace characters have been trimmed off.
+:see
+>string
diff --git a/doc/pages/unlink.txt b/doc/pages/unlink.txt
new file mode 100644
index 0000000..5d80d53
--- /dev/null
+++ b/doc/pages/unlink.txt
@@ -0,0 +1,11 @@
+:sig
+void unlink(String file_name)
+
+:params
+file_name : name of the file
+
+:desc
+Deletes the file identified by 'file_name'.
+
+:see
+>sys
diff --git a/doc/pages/uri_decode.txt b/doc/pages/uri_decode.txt
new file mode 100644
index 0000000..eb5df91
--- /dev/null
+++ b/doc/pages/uri_decode.txt
@@ -0,0 +1,12 @@
+:sig
+String uri_decode(String s)
+
+:params
+s : string containing URI encoded data
+return value : a string that contains the decoded version of 's'
+
+:desc
+Decodes an URI-encoded string 's'.
+
+:see
+>uri
diff --git a/doc/pages/uri_encode.txt b/doc/pages/uri_encode.txt
new file mode 100644
index 0000000..65cc486
--- /dev/null
+++ b/doc/pages/uri_encode.txt
@@ -0,0 +1,12 @@
+:sig
+String uri_encode(String s)
+
+:params
+s : string that should be encoded
+return value : an URI-encoded version of 's'
+
+:desc
+URI-encodes a string.
+
+:see
+>uri
diff --git a/src/fastcgi/src/fcgicc.cc b/src/fastcgi/src/fcgicc.cc
index fa54b91..c5ac77b 100644
--- a/src/fastcgi/src/fcgicc.cc
+++ b/src/fastcgi/src/fcgicc.cc
@@ -53,6 +53,7 @@ FastCGIServer::RequestInfo::RequestInfo() :
in_closed(false),
output_closed(false)
{
+
}
@@ -71,6 +72,7 @@ FastCGIServer::FastCGIServer()
FastCGIServer::~FastCGIServer()
{
+
if(my_pid != parent_pid) // if we're a child process, we must not close the handles
return;
@@ -214,6 +216,7 @@ FastCGIServer::process(int timeout_ms)
if (posix_con == -1)
throw std::runtime_error("accept() failed");
read_sockets[posix_con] = new Connection();
+ read_sockets[posix_con]->posix_con = posix_con;
}
for (std::map::iterator it = read_sockets.begin();
@@ -377,6 +380,7 @@ FastCGIServer::process_connection_read(Connection& connection)
request_arena->clear();
switch_to_arena(request_arena);
RequestInfo* new_request = new RequestInfo();
+ new_request->resources.fcgi_socket = connection.posix_con;
new_request->mem = request_arena;
new_request->stats.time_init = microtime();
switch_to_system_alloc();
diff --git a/src/fastcgi/src/fcgicc.h b/src/fastcgi/src/fcgicc.h
index cc36d4c..6a3fa69 100644
--- a/src/fastcgi/src/fcgicc.h
+++ b/src/fastcgi/src/fcgicc.h
@@ -77,6 +77,7 @@ protected:
Connection();
RequestList requests;
+ u64 posix_con = 0;
std::string input_buffer;
std::string output_buffer;
bool close_responsibility;
diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp
index 6570f1e..94bc9e8 100644
--- a/src/lib/functionlib.cpp
+++ b/src/lib/functionlib.cpp
@@ -386,68 +386,3 @@ String ob_get_close()
return(result);
}
-#define BIT_NOISE1 0xB5297A4D
-#define BIT_NOISE2 0x68E31DA4
-#define BIT_NOISE3 0x1B56C4E9
-
-// based on Squirrel3 https://www.youtube.com/watch?v=LWFzPP8ZbdU&t=2666s
-u32 noise32(u32 index, u32 seed)
-{
- u32 r = index;
- r *= BIT_NOISE1;
- r += seed;
- r ^= (r >> 8);
- r += BIT_NOISE2;
- r ^= (r << 8);
- r *= BIT_NOISE3;
- r ^= (r >> 8);
- return(r);
-}
-
-#define BIT_NOISE61 0x5134811636f8cc8a
-#define BIT_NOISE62 0xb8E31DA41B56C4E9
-#define BIT_NOISE63 0x18cd227aaa1168c1
-
-u64 noise64(u64 index, u64 seed)
-{
- u64 r = index;
- r *= BIT_NOISE61;
- r += seed;
- r ^= (r >> 8);
- r += BIT_NOISE62;
- r ^= (r << 8);
- r *= BIT_NOISE63;
- r ^= (r >> 8);
- return(r);
-}
-
-#define MAX_64 0xffffffffffffffff
-
-f64 noise01(u64 index, u64 seed)
-{
- return((float)noise64(index, seed)/(float)MAX_64);
-}
-
-u64 generate_int(u64 from, u64 to, u64 index, u64 seed)
-{
- u64 b = 1 + to - from;
- return(from + (noise64(index, seed) % b));
-}
-
-#include
-f64 generate_float(f64 from, f64 to, u64 index, u64 seed, f64 decimal_precision)
-{
- f64 b = to - from;
- return(from + fmod( decimal_precision*(f64)noise64(index, seed), b));
-}
-
-u64 draw_int(u64 from, u64 to)
-{
- return(generate_int(from, to, context->random_index++, context->random_seed));
-}
-
-f64 draw_float(f64 from, f64 to, f64 decimal_precision)
-{
- return(generate_float(from, to, context->random_index++, context->random_seed, decimal_precision));
-}
-
diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h
index 7bd6a78..81b2deb 100644
--- a/src/lib/functionlib.h
+++ b/src/lib/functionlib.h
@@ -46,10 +46,3 @@ void ob_clear();
String ob_get_clear();
String ob_get();
-u32 noise32(u32 index, u32 seed = 0);
-u64 noise64(u64 index, u64 seed = 0);
-f64 noise01(u64 index, u64 seed = 0);
-u64 generate_int(u64 from, u64 to, u64 index, u64 seed = 0);
-f64 generate_float(f64 from, f64 to, u64 index, u64 seed = 0, f64 decimal_precision = 0.000000000001);
-u64 draw_int(u64 from, u64 to);
-f64 draw_float(f64 from, f64 to, f64 decimal_precision = 0.000000000001);
diff --git a/src/lib/hash.cpp b/src/lib/hash.cpp
index 298f52b..2f48a75 100644
--- a/src/lib/hash.cpp
+++ b/src/lib/hash.cpp
@@ -273,3 +273,69 @@ sha1(String s, bool as_binary)
result += to_hex(v[i], 2);
return(result);
}
+
+#define BIT_NOISE1 0xB5297A4D
+#define BIT_NOISE2 0x68E31DA4
+#define BIT_NOISE3 0x1B56C4E9
+
+// based on Squirrel3 https://www.youtube.com/watch?v=LWFzPP8ZbdU&t=2666s
+u32 noise32(u32 index, u32 seed)
+{
+ u32 r = index;
+ r *= BIT_NOISE1;
+ r += seed;
+ r ^= (r >> 8);
+ r += BIT_NOISE2;
+ r ^= (r << 8);
+ r *= BIT_NOISE3;
+ r ^= (r >> 8);
+ return(r);
+}
+
+#define BIT_NOISE61 0x5134811636f8cc8a
+#define BIT_NOISE62 0xb8E31DA41B56C4E9
+#define BIT_NOISE63 0x18cd227aaa1168c1
+
+u64 noise64(u64 index, u64 seed)
+{
+ u64 r = index;
+ r *= BIT_NOISE61;
+ r += seed;
+ r ^= (r >> 8);
+ r += BIT_NOISE62;
+ r ^= (r << 8);
+ r *= BIT_NOISE63;
+ r ^= (r >> 8);
+ return(r);
+}
+
+#define MAX_64 0xffffffffffffffff
+
+f64 noise01(u64 index, u64 seed)
+{
+ return((float)noise64(index, seed)/(float)MAX_64);
+}
+
+u64 generate_int(u64 from, u64 to, u64 index, u64 seed)
+{
+ u64 b = 1 + to - from;
+ return(from + (noise64(index, seed) % b));
+}
+
+#include
+f64 generate_float(f64 from, f64 to, u64 index, u64 seed, f64 decimal_precision)
+{
+ f64 b = to - from;
+ return(from + fmod( decimal_precision*(f64)noise64(index, seed), b));
+}
+
+u64 draw_int(u64 from, u64 to)
+{
+ return(generate_int(from, to, context->random_index++, context->random_seed));
+}
+
+f64 draw_float(f64 from, f64 to, f64 decimal_precision)
+{
+ return(generate_float(from, to, context->random_index++, context->random_seed, decimal_precision));
+}
+
diff --git a/src/lib/hash.h b/src/lib/hash.h
index 23b0067..2df0edd 100644
--- a/src/lib/hash.h
+++ b/src/lib/hash.h
@@ -7,3 +7,13 @@ By Steve Reid
String sha1(String s, bool as_binary = false);
+
+u32 noise32(u32 index, u32 seed = 0);
+u64 noise64(u64 index, u64 seed = 0);
+f64 noise01(u64 index, u64 seed = 0);
+
+u64 generate_int(u64 from, u64 to, u64 index, u64 seed = 0);
+f64 generate_float(f64 from, f64 to, u64 index, u64 seed = 0, f64 decimal_precision = 0.000000000001);
+
+u64 draw_int(u64 from, u64 to);
+f64 draw_float(f64 from, f64 to, f64 decimal_precision = 0.000000000001);
diff --git a/src/lib/mysql-connector.cpp b/src/lib/mysql-connector.cpp
index dbf5082..3c3e0e2 100644
--- a/src/lib/mysql-connector.cpp
+++ b/src/lib/mysql-connector.cpp
@@ -42,6 +42,11 @@ bool MySQL::connect(String host, String username, String password)
}
String MySQL::escape(String raw, char quote_char)
+{
+ return(mysql_escape(raw, quote_char));
+}
+
+String mysql_escape(String raw, char quote_char)
{
String result;
result.append(1, quote_char);
diff --git a/src/lib/mysql-connector.h b/src/lib/mysql-connector.h
index 11b909a..59c866b 100644
--- a/src/lib/mysql-connector.h
+++ b/src/lib/mysql-connector.h
@@ -31,3 +31,37 @@ struct MySQL {
DTree get_pending_result();
};
+
+MySQL* mysql_connect(String host = "localhost", String username = "root", String password = "")
+{
+ MySQL* m = new MySQL();
+ m->connect(host, username, password);
+ return(m);
+}
+
+void mysql_disconnect(MySQL* m)
+{
+ m->disconnect();
+}
+
+String mysql_error(MySQL* m)
+{
+ return(m->error());
+}
+
+String mysql_escape(String raw, char quote_char);
+
+DTree mysql_query(MySQL* m, String q)
+{
+ return(m->query(q));
+}
+
+DTree mysql_query(MySQL* m, String q, StringMap params)
+{
+ return(m->query(q, params));
+}
+
+u64 mysql_insert_id(MySQL* m)
+{
+ return(m->insert_id);
+}
diff --git a/src/lib/sys.cpp b/src/lib/sys.cpp
index f7b84de..c762d6c 100644
--- a/src/lib/sys.cpp
+++ b/src/lib/sys.cpp
@@ -423,6 +423,44 @@ void spawn_subprocess(std::function exec_after_spawn)
}
}
+pid_t task(String key, std::function exec_after_spawn, u64 timeout)
+{
+ String status_file_name = context->server->config.BIN_DIRECTORY + "/task-" + key;
+ String status_file = file_get_contents(status_file_name);
+ pid_t p;
+ if(status_file != "")
+ {
+ p = int_val(status_file);
+ if(kill(p, 0) == 0) // process is still running
+ {
+ printf("(P) worker process '%s' already running: PID %i\n", key.c_str(), p);
+ return(p);
+ }
+ //printf("(P) worker process '%s' had crashed: PID %i\n", key.c_str(), p);
+ unlink(status_file_name);
+ }
+ p = fork();
+ if(p == 0)
+ {
+ my_pid = getpid();
+ file_put_contents(status_file_name, std::to_string(my_pid));
+
+ close(context->resources.fcgi_socket);
+ context->resources.fcgi_socket = 0;
+ //printf("(C) child procress started, PID:%i\n", my_pid);
+ //prctl(PR_SET_PDEATHSIG, SIGHUP);
+ exec_after_spawn();
+ unlink(status_file_name);
+ printf("(P) worker process '%s' terminated: PID %i\n", key.c_str(), my_pid);
+ exit(0);
+ }
+ else
+ {
+ printf("(P) worker process '%s' spawned: PID %i\n", key.c_str(), p);
+ return(p);
+ }
+}
+
void on_child_exit(int sig)
{
pid_t pid;
diff --git a/src/lib/sys.h b/src/lib/sys.h
index ee9a022..817ff9a 100644
--- a/src/lib/sys.h
+++ b/src/lib/sys.h
@@ -39,3 +39,4 @@ pid_t parent_pid = 0;
pid_t my_pid = 0;
void on_segfault(int sig);
+pid_t task(String key, std::function exec_after_spawn, u64 timeout = 60*10);
diff --git a/src/lib/types.h b/src/lib/types.h
index 9878a50..5cc9f03 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -268,6 +268,7 @@ struct Request {
struct Resources {
std::vector sockets;
std::vector mysql_connections;
+ u64 fcgi_socket = 0;
} resources;
void invoke(String file_name);
diff --git a/test/index.uce b/test/index.uce
index 18b1a9b..f6301ee 100644
--- a/test/index.uce
+++ b/test/index.uce
@@ -26,6 +26,7 @@ RENDER()