changeset 1629:438561303d02

timeFormat .urp directive
author Adam Chlipala <adam@chlipala.net>
date Sun, 04 Dec 2011 14:40:12 -0500
parents 3621f486ce72
children 4798ad652c94
files doc/manual.tex include/types.h lib/js/urweb.js src/c/urweb.c src/cjr_print.sml src/compiler.sml src/jscomp.sml src/settings.sig src/settings.sml tests/showTime.ur tests/showTime.urp
diffstat 11 files changed, 42 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- 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}
 
--- 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
--- 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() {
--- 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 "<i>Invalid time</i>";
+  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, "<i>Invalid time</i>");
-    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 "<Invalid time>";
-}
-
 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 "<Invalid time>";
 }
 
+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);
--- 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
--- 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 ()
--- 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
--- 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
--- 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
--- /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 <xml><body>
+      <b>Server:</b> {[tm]}<br/>
+      <b>Client:</b> <dyn signal={v <- signal s; return (txt v)}/>
+      <button value="Recalculate" onclick={tm <- now; set s tm}/>
+    </body></xml>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/showTime.urp	Sun Dec 04 14:40:12 2011 -0500
@@ -0,0 +1,4 @@
+timeFormat %H:%M %Y
+rewrite url ShowTime/*
+
+showTime