summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Adam Chlipala <adam@chlipala.net>2011-12-04 14:40:12 -0500
committerGravatar Adam Chlipala <adam@chlipala.net>2011-12-04 14:40:12 -0500
commit226fb11ff2da90b7b68dad1b29b9688f880a06a3 (patch)
tree86de944318bf3610af01258c455ceacfd450c307
parent87e2e610a69b268d10a22a7142a44a2c0afd4799 (diff)
timeFormat .urp directive
-rw-r--r--doc/manual.tex1
-rw-r--r--include/types.h2
-rw-r--r--lib/js/urweb.js11
-rw-r--r--src/c/urweb.c54
-rw-r--r--src/cjr_print.sml3
-rw-r--r--src/compiler.sml1
-rw-r--r--src/jscomp.sml1
-rw-r--r--src/settings.sig3
-rw-r--r--src/settings.sml6
-rw-r--r--tests/showTime.ur8
-rw-r--r--tests/showTime.urp4
11 files changed, 42 insertions, 52 deletions
diff --git a/doc/manual.tex b/doc/manual.tex
index 0c64da4c..fbb17581 100644
--- a/doc/manual.tex
+++ b/doc/manual.tex
@@ -176,6 +176,7 @@ Here is the complete list of directive forms. ``FFI'' stands for ``foreign func
\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 --git a/include/types.h b/include/types.h
index 91089ef3..c401b38f 100644
--- a/include/types.h
+++ b/include/types.h
@@ -96,6 +96,8 @@ typedef struct {
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 --git a/lib/js/urweb.js b/lib/js/urweb.js
index 5f1566a3..c6e55907 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -114,11 +114,14 @@ function round(n) {
// 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 --git a/src/c/urweb.c b/src/c/urweb.c
index 8ebd9a2f..270443c6 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -2151,40 +2151,14 @@ uw_unit uw_Basis_htmlifyBool_w(uw_context ctx, uw_Basis_bool b) {
#define TIME_FMT "%x %X"
#define TIME_FMT_PG "%Y-%m-%d %T"
-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;
+uw_Basis_string uw_Basis_timeToString(uw_context, uw_Basis_time);
- 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>";
+uw_Basis_string uw_Basis_htmlifyTime(uw_context ctx, uw_Basis_time t) {
+ 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 @@ uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) {
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 @@ uw_Basis_string uw_Basis_timef(uw_context ctx, const char *fmt, uw_Basis_time t)
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);
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index d51cc4ee..a5015041 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -3391,7 +3391,8 @@ fun p_file env (ds, ps) =
"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 --git a/src/compiler.sml b/src/compiler.sml
index 6c88010b..1318b561 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -799,6 +799,7 @@ fun parseUrp' accLibs fname =
| SOME n => minHeap := n)
| "alwaysInline" => Settings.addAlwaysInline arg
| "noXsrfProtection" => Settings.addNoXsrfProtection arg
+ | "timeFormat" => Settings.setTimeFormat arg
| _ => ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'");
read ()
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 16043ba5..7a5bf85d 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -1324,6 +1324,7 @@ fun process file =
val script =
if !foundJavaScript then
lines ^ urlRules ^ String.concat (rev (#script st))
+ ^ "\ntime_format = \"" ^ String.toCString (Settings.getTimeFormat ()) ^ "\";\n"
else
""
in
diff --git a/src/settings.sig b/src/settings.sig
index e3c2e7cd..8f82c8a5 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -230,4 +230,7 @@ signature SETTINGS = sig
val addNoXsrfProtection : string -> unit
val checkNoXsrfProtection : string -> bool
+
+ val setTimeFormat : string -> unit
+ val getTimeFormat : unit -> string
end
diff --git a/src/settings.sml b/src/settings.sml
index f4022cf9..922638f5 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -280,7 +280,7 @@ val jsFuncsBase = basisM [("alert", "alert"),
("now", "now"),
("timeToString", "showTime"),
- ("htmlifyTime", "showTime"),
+ ("htmlifyTime", "showTimeHtml"),
("toSeconds", "toSeconds"),
("addSeconds", "addSeconds"),
("diffInSeconds", "diffInSeconds"),
@@ -621,4 +621,8 @@ val noXsrfProtection = ref SS.empty
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 --git a/tests/showTime.ur b/tests/showTime.ur
new file mode 100644
index 00000000..e439d6a6
--- /dev/null
+++ b/tests/showTime.ur
@@ -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>
diff --git a/tests/showTime.urp b/tests/showTime.urp
new file mode 100644
index 00000000..7ef7e20b
--- /dev/null
+++ b/tests/showTime.urp
@@ -0,0 +1,4 @@
+timeFormat %H:%M %Y
+rewrite url ShowTime/*
+
+showTime