Index: trunk/src/port.c
===================================================================
--- trunk/src/port.c	(Revision 2364)
+++ trunk/src/port.c	(Arbeitskopie)
@@ -19,6 +19,7 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#include <locale.h>
 #include <time.h>
 
 #include "backend.h"
@@ -83,25 +84,33 @@
 
 /*-------------------------------------------------------------------------*/
 char *
-time_string (mp_int t)
+time_fstring (mp_int t, const char* str, Bool localized)
 
-/* Return a textual representation of the time <t>. */
-
+/* Return a textual representation of the time <t> according to the format
+ * string <str>. Doesn't cache because it would be necessary to 
+ * save the format string and compare.
+ * If localized is true, this function sets the locale according to the 
+ * environment variable before calling strftime and resets it afterwards.
+ * TODO: It would be nicer to allocate the result buffer dynamically
+ * TODO::for using longer format strings. */
 {
-    static char result[80];
-    struct tm *tm;
-    mp_int last_time = -1;
-
-    if (t != last_time)
-    {
-        time_t ti = (time_t)t;
-        last_time = t;
-        tm = localtime(&ti);
-        strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S %Y", tm);
+    static char result[512];
+    struct tm *tm; // broken-down time struct
+    
+    time_t ti = (time_t)t;
+    tm = localtime(&ti);
+    if (!localized) {
+        setlocale(LC_TIME, "C");
+        strftime(result, sizeof(result)-1, str, tm);
+        setlocale(LC_TIME, "");
     }
+    else
+        strftime(result, sizeof(result)-1, str, tm);
+    
     return result;
-} /* time_string() */
+} /* time_fstring() */
 
+
 /*-------------------------------------------------------------------------*/
 char *
 utime_string (mp_int t, mp_int ut)
@@ -112,18 +121,13 @@
     static char result[80];
     struct tm *tm;
     size_t len;
-    mp_int last_t = -1, last_ut = -1;
 
-    if (t != last_t || ut != last_ut)
-    {
-        time_t ti = (time_t)t;
-        last_t= t;
-        last_ut= ut;
-        tm = localtime(&ti);
-        len = strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S:", tm);
-        sprintf(result+len, "%06ld", ut);
-        strftime(result+len+6, sizeof(result)-7-len, " %Y", tm);
-    }
+    time_t ti = (time_t)t;
+    tm = localtime(&ti);
+    len = strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S:", tm);
+    sprintf(result+len, "%06ld", ut);
+    strftime(result+len+6, sizeof(result)-7-len, " %Y", tm);
+    
     return result;
 } /* utime_string() */
 
Index: trunk/src/port.h
===================================================================
--- trunk/src/port.h	(Revision 2364)
+++ trunk/src/port.h	(Arbeitskopie)
@@ -427,7 +427,7 @@
 
 extern char current_time_stamp[];
 extern mp_int get_current_time(void);
-extern char * time_string(mp_int);
+extern char * time_fstring(mp_int t, const char* str, Bool localized);
 extern char * utime_string(mp_int, mp_int);
 extern char * time_stamp(void);
 extern char *xmemmem(const char *, size_t, const char *, size_t);
Index: trunk/src/efuns.c
===================================================================
--- trunk/src/efuns.c	(Revision 2364)
+++ trunk/src/efuns.c	(Arbeitskopie)
@@ -8626,16 +8626,19 @@
  *
  * Interpret the argument clock as number of seconds since Jan,
  * 1st, 1970, 0.00 and convert it to a nice date and time string.
+ * TODO: In this case, the result string will be cached and tabled.
  *
  * Alternatively, accept an array of two ints: the first is <clock>
  * value as in the first form, the second int is the number of
  * microseconds elapsed in the current second.
+ * In this case the result will not be cached as the value is very
+ * unlikely to be the same in 2 consecutive calls.
  */
 
 {
     char *ts, *cp;
     string_t *rc;
-
+    
     if (sp->type != T_NUMBER)
     {
         if (VEC_SIZE(sp->u.vec) != 2)
@@ -8647,28 +8650,49 @@
         if (sp->u.vec->item[1].type != T_NUMBER)
             errorf("Bad arg 1 to ctime(): Element 1 is '%s', expected 'int'.\n"
                  , efun_arg_typename(sp->u.vec->item[1].type));
+        
         ts = utime_string( sp->u.vec->item[0].u.number
                          , sp->u.vec->item[1].u.number);
+        
+        /* If the string contains nl characters, extract the substring
+         * before the first one. Else just copy the (volatile) result
+         * we got.
+         */
+        cp = strchr(ts, '\n');
+        if (cp)
+        {
+            int len = cp - ts;
+            memsafe(rc = new_n_mstring(ts, len), len, "ctime() result");
+        }
+        else
+        {
+            memsafe(rc = new_mstring(ts), strlen(ts), "ctime() result");
+        }
     }
     else
     {
-        ts = time_string(sp->u.number);
-    }
-
-    /* If the string contains nl characters, extract the substring
-     * before the first one. Else just copy the (volatile) result
-     * we got.
-     */
-    cp = strchr(ts, '\n');
-    if (cp)
-    {
-        int len = cp - ts;
-        memsafe(rc = new_n_mstring(ts, len), len, "ctime() result");
-    }
-    else
-    {
-        memsafe(rc = new_mstring(ts), strlen(ts), "ctime() result");
-    }
+      ts = time_fstring(sp->u.number, "%a %b %d %H:%M:%S %Y", 0);
+            
+      /* If the string contains nl characters, extract the substring
+       * before the first one. Else just copy the (volatile) result
+       * we got.
+       * Table strings, because they are probably used more then once. 
+       */
+        cp = strchr(ts, '\n');
+        if (cp)
+        {
+            int len = cp - ts;
+            memsafe(rc = new_n_tabled(ts, len), len,
+                    "ctime() result");
+        }
+        else
+        {
+            memsafe(rc = new_tabled(ts), strlen(ts),
+                    "ctime() result");
+        }
+    
+    }  // if (sp->type != T_NUMBER)
+    
     free_svalue(sp);
     put_string(sp, rc);
     return sp;
@@ -8734,5 +8758,143 @@
     return sp;
 } /* f_utime() */
 
+/*-------------------------------------------------------------------------*/
+svalue_t *
+f_mktime (svalue_t *sp)
+
+/* EFUN mktime()
+ *
+ *   int time(int* datum)
+ *
+ * Return the unix timestamp (number of seconds ellapsed since 1. Jan 1970, 
+ * 0.0:0 GMT) of the date given in the array datum. datum being an array
+ * like the one localtime() or gmtime() return:
+ *   int TM_SEC   (0) : Seconds (0..59)
+ *   int TM_MIN   (1) : Minutes (0..59)
+ *   int TM_HOUR  (2) : Hours (0..23)
+ *   int TM_MDAY  (3) : Day of the month (1..31)
+ *   int TM_MON   (4) : Month of the year (0..11)
+ *   int TM_YEAR  (5) : Year (e.g.  2001)
+ *   int TM_WDAY  (6) : Day of the week (Sunday = 0)
+ *   int TM_YDAY  (7) : Day of the year (0..365)
+ *   int TM_ISDST (8) : TRUE: Daylight saving time
+ * TM_YDAY and TM_WDAY are ignored (but must also be ints).
+ *
+ */
+{
+    struct tm * pTm; // broken-down time structure for mktime()
+    time_t      clk; // unix timestamp corresponding to datum
+    vector_t  * v;   // just for convenience, stores argument array 
+    int i; 
+
+    v = sp->u.vec;
+    if (VEC_SIZE(v) != 9)
+        errorf("Bad arg 1 to mktime(): Invalid array size %ld, expected 2.\n"
+                 , (long)VEC_SIZE(v));
+    // all elements must be ints.
+    for(i=0; i<VEC_SIZE(v); i++) 
+    {
+        if ( v->item[i].type != T_NUMBER)
+            errorf("Bad arg 1 to ctime(): Element %d is '%s', expected 'int'.\n"
+                 ,i, efun_arg_typename(v->item[0].type));
+    }
+
+    // create the time structure
+    xallocate(pTm, sizeof(*pTm), "broken-down time structure for mktime()");
+    pTm->tm_sec   = v->item[TM_SEC].u.number;
+    pTm->tm_min   = v->item[TM_MIN].u.number;
+    pTm->tm_hour  = v->item[TM_HOUR].u.number;
+    pTm->tm_mday  = v->item[TM_MDAY].u.number;
+    pTm->tm_mon   = v->item[TM_MON].u.number;
+    pTm->tm_year  = v->item[TM_YEAR].u.number - 1900;
+    pTm->tm_isdst = v->item[TM_ISDST].u.number;
+    
+    clk = mktime(pTm);
+
+    // free time structure first
+    xfree(pTm);
+    
+    if (clk == -1)
+        errorf("Specified date/time cannot be represented as unix timestamp.\n");
+    
+    // free argument and put result.
+    free_svalue(sp);
+    put_number(sp, (uint32)clk);
+    
+    return sp;
+} /* f_mktime() */
+
+/*-------------------------------------------------------------------------*/
+svalue_t *
+v_strftime(svalue_t *sp, int num_arg)
+/* EFUN strftime()
+ *
+ *   string strftime()
+ *   string strftime(string fmt)
+ *   string strftime(int clock)
+ *   string strftime(string fmt, int clock)
+ *   string strftime(string fmt, int clock, int localized)
+ *
+ * Interpret the argument clock as number of seconds since Jan,
+ * 1st, 1970, 0.00 and convert it to a nice date and time string.
+ * The formatstring must be given in fmt and may contain the placeholders
+ * defined in 'man 3 strftime'.
+ * If localized == MY_TRUE then the time string will be created with the
+ * locale set in the environment variable LC_TIME
+ * Defaults: fmt="%c", clock=current_time, localized=MY_TRUE
+ * NOTE: the returned string will have at most 511 Characters.
+ * TODO: Implement caching of the result.
+ * TODO: instead of using pxalloc, efuns.c may implement support functions 
+ * TODO::for the GC, which mark the appropriate blocks as referenced.
+ */
+
+{
+    char *ts;
+    string_t *rc = NULL;  // ergebnisstring
+    
+    /* Begin of arguments on the stack */
+    svalue_t *arg = sp - num_arg + 1;
+    
+    // defaults:
+    Bool localized = MY_TRUE;
+    mp_int clk = current_time;
+    char *cfmt = "%c";
+    
+    // evaluate arguments
+    switch(num_arg) {
+        case 3:
+            localized = (Bool)arg[2].u.number;
+            // fall-through
+        case 2:
+            if (arg[1].u.number < 0)
+                errorf("Bad arg 2 to strftime(): got %ld, expected 0 .. %ld\n",
+                        arg[1].u.number, PINT_MAX);
+            clk = arg[1].u.number;
+            // fall-through
+        case 1:
+            // empty strings default to "%c" => only set fmt if non-empty
+            if (arg[0].type == T_STRING && mstrsize(arg[0].u.str)) {
+                cfmt = get_txt(arg[0].u.str);
+            }
+            else if (arg[0].type == T_NUMBER) {
+                if (num_arg>1) // bei > 1 argument nur strings erlaubt
+                    vefun_exp_arg_error(1, TF_STRING, sp->type, sp);
+                else if (arg[0].u.number >= 0)
+                    clk = arg[0].u.number;
+                else
+                    errorf("Bad argument 1 to strftime(): got %ld, expected 0 .. %ld\n",
+                        arg[0].u.number, PINT_MAX);
+            }
+            break;
+    }
+
+    ts = time_fstring(clk,cfmt,localized); 
+    memsafe(rc = new_tabled(ts), strlen(ts)+sizeof(string_t), "strftime() result");
+    
+    sp = pop_n_elems(num_arg, sp);
+    push_string(sp, rc);
+    
+    return sp;
+} /* f_strftime() */
+
 /***************************************************************************/
-
Index: trunk/src/main.c
===================================================================
--- trunk/src/main.c	(Revision 2364)
+++ trunk/src/main.c	(Arbeitskopie)
@@ -267,6 +267,7 @@
 
     boot_time = (mp_int)time(NULL);
     setlocale(LC_CTYPE, ""); /* Use the locale defined in the LANG env var */
+    setlocale(LC_TIME, "");
     get_stack_direction();
     mb_init();
     init_interpret();
Index: trunk/src/efuns.h
===================================================================
--- trunk/src/efuns.h	(Revision 2364)
+++ trunk/src/efuns.h	(Arbeitskopie)
@@ -82,11 +82,13 @@
 extern svalue_t *tell_room(svalue_t *sp);
 
 extern svalue_t *f_ctime(svalue_t *);
+extern svalue_t *v_strftime(svalue_t *, int num_arg);
 extern svalue_t *v_debug_info(svalue_t *sp, int num_arg);
 extern svalue_t *f_rusage(svalue_t *sp);
 extern svalue_t *f_random(svalue_t *);
 extern svalue_t *f_shutdown(svalue_t *sp);
 extern svalue_t *f_time(svalue_t *);
+extern svalue_t *f_mktime(svalue_t *);
 extern svalue_t *f_utime(svalue_t *);
 
 #endif /* EFUNS_H__ */
Index: trunk/src/func_spec
===================================================================
--- trunk/src/func_spec	(Revision 2364)
+++ trunk/src/func_spec	(Arbeitskopie)
@@ -373,6 +373,8 @@
 mixed   restore_value(string);
 
 string  ctime(int*|int default: F_TIME);
+string  strftime(string|int|void, int|void, int|void);
+int     mktime(int*);
 int     random(int);
 int     time();
 int*    utime();
