# HG changeset patch # User Adam Chlipala # Date 1323027612 18000 # Node ID 438561303d02b17b534682088c3a5e90c8d7e7f3 # Parent 3621f486ce72550b2d1d5da95a5d4fb7e02459c0 timeFormat .urp directive diff -r 3621f486ce72 -r 438561303d02 doc/manual.tex --- a/doc/manual.tex Sat Dec 03 17:25:51 2011 -0500 +++ b/doc/manual.tex Sun Dec 04 14:40:12 2011 -0500 @@ -176,6 +176,7 @@ \item \texttt{serverOnly Module.ident} registers an FFI function or transaction that may only be run on the server. \item \texttt{sigfile PATH} sets a path where your application should look for a key to use in cryptographic signing. This is used to prevent cross-site request forgery attacks for any form handler that both reads a cookie and creates side effects. If the referenced file doesn't exist, an application will create it and read its saved data on future invocations. You can also initialize the file manually with any contents at least 16 bytes long; the first 16 bytes will be treated as the key. \item \texttt{sql FILENAME} sets where to write an SQL file with the commands to create the expected database schema. The default is not to create such a file. +\item \texttt{timeFormat FMT} accepts a time format string, as processed by the POSIX C function \texttt{strftime()}. This controls the default rendering of $\mt{time}$ values, via the $\mt{show}$ instance for $\mt{time}$. \item \texttt{timeout N} sets to \texttt{N} seconds the amount of time that the generated server will wait after the last contact from a client before determining that that client has exited the application. Clients that remain active will take the timeout setting into account in determining how often to ping the server, so it only makes sense to set a high timeout to cope with browser and network delays and failures. Higher timeouts can lead to more unnecessary client information taking up memory on the server. The timeout goes unused by any page that doesn't involve the \texttt{recv} function, since the server only needs to store per-client information for clients that receive asynchronous messages. \end{itemize} diff -r 3621f486ce72 -r 438561303d02 include/types.h --- a/include/types.h Sat Dec 03 17:25:51 2011 -0500 +++ b/include/types.h Sun Dec 04 14:40:12 2011 -0500 @@ -96,6 +96,8 @@ void (*on_error)(uw_context, char *); uw_periodic *periodics; // 0-terminated array + + uw_Basis_string time_format; } uw_app; #define ERROR_BUF_LEN 1024 diff -r 3621f486ce72 -r 438561303d02 lib/js/urweb.js --- a/lib/js/urweb.js Sat Dec 03 17:25:51 2011 -0500 +++ b/lib/js/urweb.js Sun Dec 04 14:40:12 2011 -0500 @@ -114,11 +114,14 @@ // Time, represented as counts of microseconds since the epoch +var time_format = "%c"; + function showTime(tm) { - var newDate = new Date(); - newDate.setTime(tm / 1000); - var r = newDate.toUTCString(); - return r; + return strftime(time_format, tm); +} + +function showTimeHtml(tm) { + return eh(showTime(tm)); } function now() { diff -r 3621f486ce72 -r 438561303d02 src/c/urweb.c --- a/src/c/urweb.c Sat Dec 03 17:25:51 2011 -0500 +++ b/src/c/urweb.c Sun Dec 04 14:40:12 2011 -0500 @@ -2151,40 +2151,14 @@ #define TIME_FMT "%x %X" #define TIME_FMT_PG "%Y-%m-%d %T" +uw_Basis_string uw_Basis_timeToString(uw_context, uw_Basis_time); + uw_Basis_string uw_Basis_htmlifyTime(uw_context ctx, uw_Basis_time t) { - size_t len; - char *r; - struct tm stm = {}; - stm.tm_isdst = -1; - - if (localtime_r(&t.seconds, &stm)) { - uw_check_heap(ctx, TIMES_MAX); - r = ctx->heap.front; - len = strftime(r, TIMES_MAX, TIME_FMT, &stm); - ctx->heap.front += len+1; - return r; - } else - return "Invalid time"; + return uw_Basis_htmlifyString(ctx, uw_Basis_timeToString(ctx, t)); } uw_unit uw_Basis_htmlifyTime_w(uw_context ctx, uw_Basis_time t) { - size_t len; - char *r; - struct tm stm = {}; - stm.tm_isdst = -1; - - if (localtime_r(&t.seconds, &stm)) { - uw_check(ctx, TIMES_MAX); - r = ctx->page.front; - len = strftime(r, TIMES_MAX, TIME_FMT, &stm); - ctx->page.front += len; - } else { - uw_check(ctx, 20); - strcpy(ctx->page.front, "Invalid time"); - ctx->page.front += 19; - } - - return uw_unit_v; + return uw_Basis_htmlifyString_w(ctx, uw_Basis_timeToString(ctx, t)); } char *uw_Basis_htmlifySource(uw_context ctx, uw_Basis_source src) { @@ -2724,22 +2698,6 @@ return "True"; } -uw_Basis_string uw_Basis_timeToString(uw_context ctx, uw_Basis_time t) { - size_t len; - char *r; - struct tm stm = {}; - stm.tm_isdst = -1; - - if (localtime_r(&t.seconds, &stm)) { - uw_check_heap(ctx, TIMES_MAX); - r = ctx->heap.front; - len = strftime(r, TIMES_MAX, TIME_FMT, &stm); - ctx->heap.front += len+1; - return r; - } else - return ""; -} - uw_Basis_string uw_Basis_timef(uw_context ctx, const char *fmt, uw_Basis_time t) { size_t len; char *r; @@ -2756,6 +2714,10 @@ return ""; } +uw_Basis_string uw_Basis_timeToString(uw_context ctx, uw_Basis_time t) { + return uw_Basis_timef(ctx, ctx->app->time_format, t); +} + uw_Basis_int *uw_Basis_stringToInt(uw_context ctx, uw_Basis_string s) { char *endptr; uw_Basis_int n = strtoll(s, &endptr, 10); diff -r 3621f486ce72 -r 438561303d02 src/cjr_print.sml --- a/src/cjr_print.sml Sat Dec 03 17:25:51 2011 -0500 +++ b/src/cjr_print.sml Sun Dec 04 14:40:12 2011 -0500 @@ -3391,7 +3391,8 @@ "uw_db_init", "uw_db_begin", "uw_db_commit", "uw_db_rollback", "uw_db_close", "uw_handle", "uw_input_num", "uw_cookie_sig", "uw_check_url", "uw_check_mime", "uw_check_requestHeader", "uw_check_responseHeader", - case onError of NONE => "NULL" | SOME _ => "uw_onError", "my_periodics"], + case onError of NONE => "NULL" | SOME _ => "uw_onError", "my_periodics", + "\"" ^ String.toCString (Settings.getTimeFormat ()) ^ "\""], string "};", newline] end diff -r 3621f486ce72 -r 438561303d02 src/compiler.sml --- a/src/compiler.sml Sat Dec 03 17:25:51 2011 -0500 +++ b/src/compiler.sml Sun Dec 04 14:40:12 2011 -0500 @@ -799,6 +799,7 @@ | SOME n => minHeap := n) | "alwaysInline" => Settings.addAlwaysInline arg | "noXsrfProtection" => Settings.addNoXsrfProtection arg + | "timeFormat" => Settings.setTimeFormat arg | _ => ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'"); read () diff -r 3621f486ce72 -r 438561303d02 src/jscomp.sml --- a/src/jscomp.sml Sat Dec 03 17:25:51 2011 -0500 +++ b/src/jscomp.sml Sun Dec 04 14:40:12 2011 -0500 @@ -1324,6 +1324,7 @@ val script = if !foundJavaScript then lines ^ urlRules ^ String.concat (rev (#script st)) + ^ "\ntime_format = \"" ^ String.toCString (Settings.getTimeFormat ()) ^ "\";\n" else "" in diff -r 3621f486ce72 -r 438561303d02 src/settings.sig --- a/src/settings.sig Sat Dec 03 17:25:51 2011 -0500 +++ b/src/settings.sig Sun Dec 04 14:40:12 2011 -0500 @@ -230,4 +230,7 @@ val addNoXsrfProtection : string -> unit val checkNoXsrfProtection : string -> bool + + val setTimeFormat : string -> unit + val getTimeFormat : unit -> string end diff -r 3621f486ce72 -r 438561303d02 src/settings.sml --- a/src/settings.sml Sat Dec 03 17:25:51 2011 -0500 +++ b/src/settings.sml Sun Dec 04 14:40:12 2011 -0500 @@ -280,7 +280,7 @@ ("now", "now"), ("timeToString", "showTime"), - ("htmlifyTime", "showTime"), + ("htmlifyTime", "showTimeHtml"), ("toSeconds", "toSeconds"), ("addSeconds", "addSeconds"), ("diffInSeconds", "diffInSeconds"), @@ -621,4 +621,8 @@ fun addNoXsrfProtection s = noXsrfProtection := SS.add (!noXsrfProtection, s) fun checkNoXsrfProtection s = SS.member (!noXsrfProtection, s) +val timeFormat = ref "%c" +fun setTimeFormat v = timeFormat := v +fun getTimeFormat () = !timeFormat + end diff -r 3621f486ce72 -r 438561303d02 tests/showTime.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/showTime.ur Sun Dec 04 14:40:12 2011 -0500 @@ -0,0 +1,8 @@ +fun main () : transaction page = + tm <- now; + s <- source tm; + return + Server: {[tm]}
+ Client: +