]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/parseutils.c
configure: Prefix libc-related variables with "libc_"
[ffmpeg] / libavutil / parseutils.c
index 09eebcf56f25ea09d3def39231785f29e839042c..0e3fd9eab5b3f8cf2735e5fee49e954bb873e85d 100644 (file)
@@ -1,18 +1,18 @@
 /*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
  *
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * FFmpeg is distributed in the hope that it will be useful,
+ * Libav is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
+ * License along with Libav; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
  * misc parsing utilities
  */
 
-#include <strings.h>
+#include <time.h>
+
+#include "avstring.h"
+#include "avutil.h"
+#include "common.h"
+#include "eval.h"
+#include "log.h"
+#include "random_seed.h"
 #include "parseutils.h"
-#include "libavutil/avutil.h"
-#include "libavutil/eval.h"
-#include "libavutil/avstring.h"
-#include "libavutil/random_seed.h"
 
 typedef struct {
     const char *abbr;
@@ -104,8 +107,7 @@ int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
         }
     }
     if (i == n) {
-        p = str;
-        width = strtol(p, &p, 10);
+        width = strtol(str, &p, 10);
         if (*p)
             p++;
         height = strtol(p, &p, 10);
@@ -290,7 +292,7 @@ static ColorEntry color_table[] = {
 
 static int color_table_compare(const void *lhs, const void *rhs)
 {
-    return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
+    return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
 }
 
 #define ALPHA_SEP '@'
@@ -316,7 +318,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
     len = strlen(color_string2);
     rgba_color[3] = 255;
 
-    if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
+    if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) {
         int rgba = av_get_random_seed();
         rgba_color[0] = rgba >> 24;
         rgba_color[1] = rgba >> 16;
@@ -352,7 +354,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
     }
 
     if (tail) {
-        unsigned long int alpha;
+        double alpha;
         const char *alpha_string = tail;
         if (!strncmp(alpha_string, "0x", 2)) {
             alpha = strtoul(alpha_string, &tail, 16);
@@ -360,7 +362,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
             alpha = 255 * strtod(alpha_string, &tail);
         }
 
-        if (tail == alpha_string || *tail || alpha > 255) {
+        if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) {
             av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
                    alpha_string, color_string);
             return AVERROR(EINVAL);
@@ -371,16 +373,281 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
     return 0;
 }
 
-#ifdef TEST
+/* get a positive number between n_min and n_max, for a maximum length
+   of len_max. Return -1 if error. */
+static int date_get_num(const char **pp,
+                        int n_min, int n_max, int len_max)
+{
+    int i, val, c;
+    const char *p;
+
+    p = *pp;
+    val = 0;
+    for(i = 0; i < len_max; i++) {
+        c = *p;
+        if (!av_isdigit(c))
+            break;
+        val = (val * 10) + c - '0';
+        p++;
+    }
+    /* no number read ? */
+    if (p == *pp)
+        return -1;
+    if (val < n_min || val > n_max)
+        return -1;
+    *pp = p;
+    return val;
+}
 
-#undef printf
+static const char *small_strptime(const char *p, const char *fmt, struct tm *dt)
+{
+    int c, val;
+
+    for(;;) {
+        c = *fmt++;
+        if (c == '\0') {
+            return p;
+        } else if (c == '%') {
+            c = *fmt++;
+            switch(c) {
+            case 'H':
+                val = date_get_num(&p, 0, 23, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_hour = val;
+                break;
+            case 'M':
+                val = date_get_num(&p, 0, 59, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_min = val;
+                break;
+            case 'S':
+                val = date_get_num(&p, 0, 59, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_sec = val;
+                break;
+            case 'Y':
+                val = date_get_num(&p, 0, 9999, 4);
+                if (val == -1)
+                    return NULL;
+                dt->tm_year = val - 1900;
+                break;
+            case 'm':
+                val = date_get_num(&p, 1, 12, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_mon = val - 1;
+                break;
+            case 'd':
+                val = date_get_num(&p, 1, 31, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_mday = val;
+                break;
+            case '%':
+                goto match;
+            default:
+                return NULL;
+            }
+        } else {
+        match:
+            if (c != *p)
+                return NULL;
+            p++;
+        }
+    }
+}
+
+time_t av_timegm(struct tm *tm)
+{
+    time_t t;
+
+    int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
+
+    if (m < 3) {
+        m += 12;
+        y--;
+    }
+
+    t = 86400 *
+        (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
+
+    t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
+
+    return t;
+}
+
+int av_parse_time(int64_t *timeval, const char *timestr, int duration)
+{
+    const char *p;
+    int64_t t;
+    struct tm dt = { 0 };
+    int i;
+    static const char * const date_fmt[] = {
+        "%Y-%m-%d",
+        "%Y%m%d",
+    };
+    static const char * const time_fmt[] = {
+        "%H:%M:%S",
+        "%H%M%S",
+    };
+    const char *q;
+    int is_utc, len;
+    char lastch;
+    int negative = 0;
+
+    time_t now = time(0);
+
+    len = strlen(timestr);
+    if (len > 0)
+        lastch = timestr[len - 1];
+    else
+        lastch = '\0';
+    is_utc = (lastch == 'z' || lastch == 'Z');
+
+    p = timestr;
+    q = NULL;
+    if (!duration) {
+        if (!av_strncasecmp(timestr, "now", len)) {
+            *timeval = (int64_t) now * 1000000;
+            return 0;
+        }
+
+        /* parse the year-month-day part */
+        for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
+            q = small_strptime(p, date_fmt[i], &dt);
+            if (q) {
+                break;
+            }
+        }
+
+        /* if the year-month-day part is missing, then take the
+         * current year-month-day time */
+        if (!q) {
+            if (is_utc) {
+                dt = *gmtime(&now);
+            } else {
+                dt = *localtime(&now);
+            }
+            dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
+        } else {
+            p = q;
+        }
+
+        if (*p == 'T' || *p == 't' || *p == ' ')
+            p++;
+
+        /* parse the hour-minute-second part */
+        for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
+            q = small_strptime(p, time_fmt[i], &dt);
+            if (q) {
+                break;
+            }
+        }
+    } else {
+        /* parse timestr as a duration */
+        if (p[0] == '-') {
+            negative = 1;
+            ++p;
+        }
+        /* parse timestr as HH:MM:SS */
+        q = small_strptime(p, time_fmt[0], &dt);
+        if (!q) {
+            /* parse timestr as S+ */
+            dt.tm_sec = strtol(p, (char **)&q, 10);
+            if (q == p) {
+                /* the parsing didn't succeed */
+                *timeval = INT64_MIN;
+                return AVERROR(EINVAL);
+            }
+            dt.tm_min = 0;
+            dt.tm_hour = 0;
+        }
+    }
+
+    /* Now we have all the fields that we can get */
+    if (!q) {
+        *timeval = INT64_MIN;
+        return AVERROR(EINVAL);
+    }
+
+    if (duration) {
+        t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
+    } else {
+        dt.tm_isdst = -1;       /* unknown */
+        if (is_utc) {
+            t = av_timegm(&dt);
+        } else {
+            t = mktime(&dt);
+        }
+    }
+
+    t *= 1000000;
+
+    /* parse the .m... part */
+    if (*q == '.') {
+        int val, n;
+        q++;
+        for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
+            if (!av_isdigit(*q))
+                break;
+            val += n * (*q - '0');
+        }
+        t += val;
+    }
+    *timeval = negative ? -t : t;
+    return 0;
+}
+
+int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
+{
+    const char *p;
+    char tag[128], *q;
+
+    p = info;
+    if (*p == '?')
+        p++;
+    for(;;) {
+        q = tag;
+        while (*p != '\0' && *p != '=' && *p != '&') {
+            if ((q - tag) < sizeof(tag) - 1)
+                *q++ = *p;
+            p++;
+        }
+        *q = '\0';
+        q = arg;
+        if (*p == '=') {
+            p++;
+            while (*p != '&' && *p != '\0') {
+                if ((q - arg) < arg_size - 1) {
+                    if (*p == '+')
+                        *q++ = ' ';
+                    else
+                        *q++ = *p;
+                }
+                p++;
+            }
+        }
+        *q = '\0';
+        if (!strcmp(tag, tag1))
+            return 1;
+        if (*p != '&')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+#ifdef TEST
 
 int main(void)
 {
     printf("Testing av_parse_video_rate()\n");
     {
         int i;
-        const char *rates[] = {
+        static const char *const rates[] = {
             "-inf",
             "inf",
             "nan",
@@ -410,10 +677,10 @@ int main(void)
 
         for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
             int ret;
-            AVRational q = (AVRational){0, 0};
-            ret = av_parse_video_rate(&q, rates[i]),
-            printf("'%s' -> %d/%d ret:%d\n",
-                   rates[i], q.num, q.den, ret);
+            AVRational q = { 0, 0 };
+            ret = av_parse_video_rate(&q, rates[i]);
+            printf("'%s' -> %d/%d %s\n",
+                   rates[i], q.num, q.den, ret ? "ERROR" : "OK");
         }
     }
 
@@ -421,9 +688,7 @@ int main(void)
     {
         int i;
         uint8_t rgba[4];
-        const char *color_names[] = {
-            "bikeshed",
-            "RaNdOm",
+        static const char *const color_names[] = {
             "foo",
             "red",
             "Red ",
@@ -464,7 +729,8 @@ int main(void)
 
         for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
             if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
-                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
+                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
+                       color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
         }
     }