lavu/bprint: implement av_bprint_strftime().
authorNicolas George <nicolas.george@normalesup.org>
Sat, 10 Nov 2012 15:05:53 +0000 (16:05 +0100)
committerNicolas George <nicolas.george@normalesup.org>
Sat, 17 Nov 2012 18:47:56 +0000 (19:47 +0100)
doc/APIchanges
libavutil/bprint.c
libavutil/bprint.h
libavutil/version.h
tests/ref/fate/bprint

index 1d10af5..57be6ba 100644 (file)
@@ -15,6 +15,9 @@ libavutil:     2012-10-22
 
 API changes, most recent first:
 
+2012-11-17 - xxxxxxx - lavu 52.8.100 - bprint.h
+  Add av_bprint_strftime().
+
 2012-11-15 - xxxxxxx - lavu 52.7.100 - opt.h
   Add av_opt_get_key_value().
 
index 9d8e7c1..4684ab4 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 #include "avassert.h"
 #include "bprint.h"
 #include "common.h"
@@ -129,6 +130,48 @@ void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
     av_bprint_grow(buf, n);
 }
 
+void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
+{
+    unsigned room;
+    size_t l;
+
+    if (!*fmt)
+        return;
+    while (1) {
+        room = av_bprint_room(buf);
+        if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
+            break;
+        /* strftime does not tell us how much room it would need: let us
+           retry with twice as much until the buffer is large enough */
+        room = !room ? strlen(fmt) + 1 :
+               room <= INT_MAX / 2 ? room * 2 : INT_MAX;
+        if (av_bprint_alloc(buf, room)) {
+            /* impossible to grow, try to manage something useful anyway */
+            room = av_bprint_room(buf);
+            if (room < 1024) {
+                /* if strftime fails because the buffer has (almost) reached
+                   its maximum size, let us try in a local buffer; 1k should
+                   be enough to format any real date+time string */
+                char buf2[1024];
+                if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
+                    av_bprintf(buf, "%s", buf2);
+                    return;
+                }
+            }
+            if (room) {
+                /* if anything else failed and the buffer is not already
+                   truncated, let us add a stock string and force truncation */
+                static const char txt[] = "[truncated strftime output]";
+                memset(buf->str + buf->len, '!', room);
+                memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
+                av_bprint_grow(buf, room); /* force truncation */
+            }
+            return;
+        }
+    }
+    av_bprint_grow(buf, l);
+}
+
 void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
                           unsigned char **mem, unsigned *actual_size)
 {
@@ -201,6 +244,7 @@ int main(void)
 {
     AVBPrint b;
     char buf[256];
+    struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 };
 
     av_bprint_init(&b, 0, -1);
     bprint_pascal(&b, 5);
@@ -235,6 +279,15 @@ int main(void)
     bprint_pascal(&b, 25);
     printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len);
 
+    av_bprint_init(&b, 0, -1);
+    av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
+    printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
+    av_bprint_finalize(&b, NULL);
+
+    av_bprint_init(&b, 0, 8);
+    av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
+    printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
+
     return 0;
 }
 
index c09b61f..f3915fe 100644 (file)
@@ -116,7 +116,7 @@ void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
 void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size);
 
 /**
- * Append a formated string to a print buffer.
+ * Append a formatted string to a print buffer.
  */
 void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
 
@@ -125,6 +125,20 @@ void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
  */
 void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
 
+struct tm;
+/**
+ * Append a formatted date and time to a print buffer.
+ *
+ * param buf  bprint buffer to use
+ * param fmt  date and time format string, see strftime()
+ * param tm   broken-down time structure to translate
+ *
+ * @note due to poor design of the standard strftime function, it may
+ * produce poor results if the format string expands to a very long text and
+ * the bprint buffer is near the limit stated by the size_max option.
+ */
+void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm);
+
 /**
  * Allocate bytes in the buffer for external use.
  *
index 3f82a97..16771ad 100644 (file)
@@ -75,7 +75,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  52
-#define LIBAVUTIL_VERSION_MINOR   7
+#define LIBAVUTIL_VERSION_MINOR   8
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
index e027fa1..b33c1ae 100644 (file)
@@ -12,3 +12,5 @@ Short text in automatic buffer: 174/174
 Long text in automatic buffer: 1000/2834
 Long text count only buffer: 0/2834
 Long text count only buffer: 255/2834
+strftime full: 255/10 "2000-12-20"
+strftime truncated: 255/10 "2000-12"