Rewrite ustrftime(), so that (a) it uses wcsftime() where available,
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 22 Apr 2004 18:25:46 +0000 (18:25 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 22 Apr 2004 18:25:46 +0000 (18:25 +0000)
and (b) it doesn't trip over strange Unicode characters in the
format string.

git-svn-id: svn://svn.tartarus.org/sgt/halibut@4120 cda61777-01e9-0310-a592-d414129be87e

halibut.h
ustring.c

index f3de665..3205e46 100644 (file)
--- a/halibut.h
+++ b/halibut.h
@@ -289,7 +289,7 @@ int utoi(wchar_t *);
 int utob(wchar_t *);
 int uisdigit(wchar_t);
 wchar_t *ustrlow(wchar_t *s);
-wchar_t *ustrftime(wchar_t *fmt, struct tm *timespec);
+wchar_t *ustrftime(const wchar_t *wfmt, const struct tm *timespec);
 int cvt_ok(int charset, const wchar_t *s);
 
 /*
index 50c02d4..0e3bfee 100644 (file)
--- a/ustring.c
+++ b/ustring.c
@@ -331,19 +331,9 @@ int uisdigit(wchar_t c) {
 }
 
 #define USTRFTIME_DELTA 128
-wchar_t *ustrftime(wchar_t *wfmt, struct tm *timespec) {
-    void *blk = NULL;
-    wchar_t *wblk, *wp;
-    char *fmt, *text, *p;
-    size_t size = 0;
-    size_t len;
-
-    /*
-     * FIXME: really we ought to copy non-% parts of the format
-     * ourselves, and only resort to strftime for % parts. Also we
-     * should use wcsftime if it's present.
-     */
-
+static void ustrftime_internal(rdstring *rs, char formatchr,
+                              const struct tm *timespec)
+{
     /*
      * strftime has the entertaining property that it returns 0
      * _either_ on out-of-space _or_ on successful generation of
@@ -351,38 +341,73 @@ wchar_t *ustrftime(wchar_t *wfmt, struct tm *timespec) {
      * generate the empty string. Somebody throw a custard pie at
      * whoever was responsible for that. Please?
      */
-    if (wfmt) {
-       len = ustrlen(wfmt);
-       fmt = mknewa(char, 2+len);
-       ustrtoa(wfmt, fmt+1, len+1, CS_ASCII);   /* CS_FIXME? */
-       fmt[0] = ' ';
-    } else
-       fmt = " %c";
-
-    while (1) {
+
+#ifdef HAS_WCSFTIME
+    wchar_t *buf = NULL;
+    wchar_t fmt[4];
+    int size, ret;
+
+    fmt[0] = L' ';
+    fmt[1] = L'%';
+    /* Format chars are all ASCII, so conversion to Unicode is no problem */
+    fmt[2] = formatchr;
+    fmt[3] = L'\0';
+
+    size = 0;
+    do {
        size += USTRFTIME_DELTA;
-       blk = resize((char *)blk, size);
-       len = strftime((char *)blk, size-1, fmt, timespec);
-       if (len > 0)
-           break;
+       buf = resize(buf, size);
+       ret = (int) wcsftime(buf, size, fmt, timespec);
+    } while (ret == 0);
+
+    rdadds(rs, buf+1);
+    sfree(buf);
+#else
+    char *buf = NULL;
+    wchar_t *cvtbuf;
+    char fmt[4];
+    int size, ret;
+
+    fmt[0] = ' ';
+    fmt[1] = '%';
+    fmt[2] = formatchr;
+    fmt[3] = '\0';
+
+    size = 0;
+    do {
+       size += USTRFTIME_DELTA;
+       buf = resize(buf, size);
+       ret = (int) strftime(buf, size, fmt, timespec);
+    } while (ret == 0);
+
+    cvtbuf = ufroma_locale_dup(buf+1);
+    rdadds(rs, cvtbuf);
+    sfree(cvtbuf);
+    sfree(buf);
+#endif
+}
+
+wchar_t *ustrftime(const wchar_t *wfmt, const struct tm *timespec)
+{
+    rdstring rs = { 0, 0, NULL };
+
+    if (!wfmt)
+       wfmt = L"%c";
+
+    while (*wfmt) {
+       if (wfmt[0] == L'%' && wfmt[1] == L'%') {
+           rdadd(&rs, L'%');
+           wfmt += 2;
+       } else if (wfmt[0] == L'%' && wfmt[1]) {
+           ustrftime_internal(&rs, wfmt[1], timespec);
+           wfmt += 2;
+       } else {
+           rdadd(&rs, wfmt[0]);
+           wfmt++;
+       }
     }
 
-    /* Note: +1 for the terminating 0, -1 for the initial space in fmt */
-    wblk = resize((wchar_t *)blk, len);
-    text = mknewa(char, len);
-    strftime(text, len, fmt+1, timespec);
-    /*
-     * We operate in the C locale, so this all ought to be kosher
-     * ASCII. If we ever move outside ASCII machines, we may need
-     * to make this more portable...
-     */
-    for (wp = wblk, p = text; *p; p++, wp++)
-       *wp = *p;
-    *wp = 0;
-    if (wfmt)
-       sfree(fmt);
-    sfree(text);
-    return wblk;
+    return rdtrim(&rs);
 }
 
 /*