Simon Josefsson wrote:
> Yes, although I would prefer a wrapper to hide the complex strftime
> format string needed.
> 
> How about the API below?
> ...
> char *c_ctime_r (time_t timep, char *str, size_t len);

I think more arguments are needed.

* Hiding the "complex" format string is not the right approach.
  Rather, this format string is what makes the function flexible
  enough.
  What one can do, in order to help users with this format string, is:
    - a list of format string directives, like the one I added to
      strftime.h,
    - maybe some constants that expand to format strings, e.g.
        #define TIME_FORMAT_ISO_8601 "%Y-%m-%d %H:%M:%S"

* Many variants of such a simple function are possible:
    - (a) time_t vs. struct tm const * argument,
    - (b) interpret the arguments as UTC (from gmtime) vs.
      as local time (from localtime),
    - (c) uses nanoseconds, microseconds, milliseconds, or only seconds,
    - (d) obeys LC_TIME locale category vs. en_US / C locale,
    - (e) return value: uses preallocated buffer (for speed) vs. uses malloc.
  But we don't want to define 2 * 2 * 4 * 2 * 2 = 64 "simple" functions.

  I would propose 2 new functions, like this:
    - (a) one function taking a time_t, one function taking a struct tm const *.
    - (b) accept a 'bool' argument. A timezone_t argument is overkill, since
          most of the uses are either UTC or local time.
    - (c) accept an 'int ns' argument. Passing 0 if not needed is easy.
    - (d) accept a 'bool' argument.
    - (e) use the return value convention from GNU libunistring. It is
          designed to be easily specializable to "preallocated buffer" or
          "use malloc":
          "Functions returning a string result take a ‘(RESULTBUF, LENGTHP)’
           argument pair.  If RESULTBUF is not NULL and the result fits into
           ‘*LENGTHP’ units, it is put in RESULTBUF, and RESULTBUF is returned.
           Otherwise, a freshly allocated string is returned.  In both cases,
           ‘*LENGTHP’ is set to the length (number of units) of the returned
           string.  In case of error, NULL is returned and ‘errno’ is set."

  So, the functions that I would propose have the following prototype:
    char *str_from_time (char *resultbuf, size_t *lengthp,
                         bool i18n, const char *format,
                         time_t t,            bool local_time, int ns);
    char *str_from_tm   (char *resultbuf, size_t *lengthp,
                         bool i18n, const char *format,
                         struct tm const *tp, bool local_time, int ns);

  Migration from ctime:
    s = ctime (tp);
  =>
    char buf[64];
    size_t buf_size = sizeof (buf);
    s = str_from_time (buf, &buf_size, false, "%a %b %e %H:%M:%S %Y\n", *tp, 
true, 0);
    if (s == NULL) /* handle error case */;

  Migration from ctime_r:
    char buf[26];
    s = ctime_r (tp, buf);
  =>
    char buf[64];
    size_t buf_size = sizeof (buf);
    s = str_from_time (buf, &buf_size, false, "%a %b %e %H:%M:%S %Y\n", *tp, 
true, 0);
    if (s == NULL) /* handle error case */;

  Migration from asctime:
    s = asctime (tp);
  =>
    char buf[64];
    size_t buf_size = sizeof (buf);
    s = str_from_tm (buf, &buf_size, false, "%a %b %e %H:%M:%S %Y\n", tp, 
local_time, 0);
    if (s == NULL) /* handle error case */;

  Migration from asctime_r:
    char buf[26];
    s = asctime_r (tp, buf);
  =>
    char buf[64];
    size_t buf_size = sizeof (buf);
    s = str_from_tm (buf, &buf_size, false, "%a %b %e %H:%M:%S %Y\n", tp, 
local_time, 0);
    if (s == NULL) /* handle error case */;

* In which header file to declare the functions? I would propose <time.h>,
  since this makes migration from ctime(), ctime_r(), asctime(), asctime_r()
  easy.

Bruno




Reply via email to