]> granicus.if.org Git - libass/commitdiff
NIH: add locale-independent string functions
authorGrigori Goronzy <greg@chown.ath.cx>
Mon, 7 Sep 2015 21:44:41 +0000 (23:44 +0200)
committerGrigori Goronzy <greg@chown.ath.cx>
Thu, 10 Sep 2015 23:12:47 +0000 (01:12 +0200)
OS or platform-specific locale independent functions are painful to
use and/or not available, so roll our own. Not great but the least
painful and least intrusive.

v2: fix indexing, use static inline

libass/Makefile.am
libass/ass.c
libass/ass_font.c
libass/ass_fontselect.c
libass/ass_library.c
libass/ass_string.c [new file with mode: 0644]
libass/ass_string.h [new file with mode: 0644]
libass/ass_strtod.c
libass/ass_utils.c

index 2cf63545dc3c34ba5a0126da3bbef4d25e2a1dc0..cef1291a19665c1118228ee85312e4ae29fa3db3 100644 (file)
@@ -29,7 +29,8 @@ libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c ass_render.c \
                     ass_library.h ass_types.h ass_utils.h ass_drawing.c \
                     ass_drawing.h ass_cache_template.h ass_render.h \
                     ass_parse.c ass_parse.h ass_render_api.c ass_shaper.c \
-                    ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.h
+                    ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.h \
+                    ass_string.h ass_string.c
 
 libass_la_LDFLAGS = -no-undefined -version-info $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE)
 libass_la_LDFLAGS += -export-symbols $(srcdir)/libass.sym
index b51cf2e1c34c7a52d0acdbb7e67536adddd53ce8..a0a6d473c4e6f2c037cc2a2c16dad7a6522163ce 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 #include <assert.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <inttypes.h>
-#include <ctype.h>
 
 #ifdef CONFIG_ICONV
 #include <iconv.h>
@@ -37,6 +35,7 @@
 #include "ass.h"
 #include "ass_utils.h"
 #include "ass_library.h"
+#include "ass_string.h"
 
 #define ass_atof(STR) (ass_strtod((STR),NULL))
 
@@ -212,7 +211,7 @@ static int numpad2align(int val)
 
 
 #define ALIAS(alias,name) \
-        if (strcasecmp(tname, #alias) == 0) {tname = #name;}
+        if (ass_strcasecmp(tname, #alias) == 0) {tname = #name;}
 
 /* One section started with PARSE_START and PARSE_END parses a single token
  * (contained in the variable named token) for the header indicated by the
@@ -228,16 +227,16 @@ static int numpad2align(int val)
 #define PARSE_END   }
 
 #define ANYVAL(name,func) \
-       } else if (strcasecmp(tname, #name) == 0) { \
+       } else if (ass_strcasecmp(tname, #name) == 0) { \
                target->name = func(token);
 
 #define STRVAL(name) \
-       } else if (strcasecmp(tname, #name) == 0) { \
+       } else if (ass_strcasecmp(tname, #name) == 0) { \
                if (target->name != NULL) free(target->name); \
                target->name = strdup(token);
 
 #define STARREDSTRVAL(name) \
-    } else if (strcasecmp(tname, #name) == 0) { \
+    } else if (ass_strcasecmp(tname, #name) == 0) { \
         if (target->name != NULL) free(target->name); \
         while (*token == '*') ++token; \
         target->name = strdup(token);
@@ -246,11 +245,11 @@ static int numpad2align(int val)
 #define INTVAL(name) ANYVAL(name,atoi)
 #define FPVAL(name) ANYVAL(name,ass_atof)
 #define TIMEVAL(name) \
-       } else if (strcasecmp(tname, #name) == 0) { \
+       } else if (ass_strcasecmp(tname, #name) == 0) { \
                target->name = string2timecode(track->library, token);
 
 #define STYLEVAL(name) \
-       } else if (strcasecmp(tname, #name) == 0) { \
+       } else if (ass_strcasecmp(tname, #name) == 0) { \
                target->name = lookup_style(track, token);
 
 static char *next_token(char **str)
@@ -309,7 +308,7 @@ static int process_event_tail(ASS_Track *track, ASS_Event *event,
 
     while (1) {
         NEXT(q, tname);
-        if (strcasecmp(tname, "Text") == 0) {
+        if (ass_strcasecmp(tname, "Text") == 0) {
             char *last;
             event->Text = strdup(p);
             if (*event->Text != 0) {
@@ -362,19 +361,19 @@ void ass_process_force_style(ASS_Track *track)
         *eq = '\0';
         token = eq + 1;
 
-        if (!strcasecmp(*fs, "PlayResX"))
+        if (!ass_strcasecmp(*fs, "PlayResX"))
             track->PlayResX = atoi(token);
-        else if (!strcasecmp(*fs, "PlayResY"))
+        else if (!ass_strcasecmp(*fs, "PlayResY"))
             track->PlayResY = atoi(token);
-        else if (!strcasecmp(*fs, "Timer"))
+        else if (!ass_strcasecmp(*fs, "Timer"))
             track->Timer = ass_atof(token);
-        else if (!strcasecmp(*fs, "WrapStyle"))
+        else if (!ass_strcasecmp(*fs, "WrapStyle"))
             track->WrapStyle = atoi(token);
-        else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
+        else if (!ass_strcasecmp(*fs, "ScaledBorderAndShadow"))
             track->ScaledBorderAndShadow = parse_bool(token);
-        else if (!strcasecmp(*fs, "Kerning"))
+        else if (!ass_strcasecmp(*fs, "Kerning"))
             track->Kerning = parse_bool(token);
-        else if (!strcasecmp(*fs, "YCbCr Matrix"))
+        else if (!ass_strcasecmp(*fs, "YCbCr Matrix"))
             track->YCbCrMatrix = parse_ycbcr_matrix(token);
 
         dt = strrchr(*fs, '.');
@@ -388,7 +387,7 @@ void ass_process_force_style(ASS_Track *track)
         }
         for (sid = 0; sid < track->n_styles; ++sid) {
             if (style == NULL
-                || strcasecmp(track->styles[sid].Name, style) == 0) {
+                || ass_strcasecmp(track->styles[sid].Name, style) == 0) {
                 target = track->styles + sid;
                 PARSE_START
                     STRVAL(FontName)
@@ -575,7 +574,7 @@ static int process_info_line(ASS_Track *track, char *str)
         track->YCbCrMatrix = parse_ycbcr_matrix(str + 13);
     } else if (!strncmp(str, "Language:", 9)) {
         char *p = str + 9;
-        while (*p && isspace(*p)) p++;
+        while (*p && ass_isspace(*p)) p++;
         track->Language = strndup(p, 2);
     }
     return 0;
@@ -743,17 +742,17 @@ static int process_fonts_line(ASS_Track *track, char *str)
 */
 static int process_line(ASS_Track *track, char *str)
 {
-    if (!strncasecmp(str, "[Script Info]", 13)) {
+    if (!ass_strncasecmp(str, "[Script Info]", 13)) {
         track->parser_priv->state = PST_INFO;
-    } else if (!strncasecmp(str, "[V4 Styles]", 11)) {
+    } else if (!ass_strncasecmp(str, "[V4 Styles]", 11)) {
         track->parser_priv->state = PST_STYLES;
         track->track_type = TRACK_TYPE_SSA;
-    } else if (!strncasecmp(str, "[V4+ Styles]", 12)) {
+    } else if (!ass_strncasecmp(str, "[V4+ Styles]", 12)) {
         track->parser_priv->state = PST_STYLES;
         track->track_type = TRACK_TYPE_ASS;
-    } else if (!strncasecmp(str, "[Events]", 8)) {
+    } else if (!ass_strncasecmp(str, "[Events]", 8)) {
         track->parser_priv->state = PST_EVENTS;
-    } else if (!strncasecmp(str, "[Fonts]", 7)) {
+    } else if (!ass_strncasecmp(str, "[Fonts]", 7)) {
         track->parser_priv->state = PST_FONTS;
     } else {
         switch (track->parser_priv->state) {
index 5b0131f471b23803f878da193f55cc66d73f020f..67f8eec4102447d8ad11db3b98ac7e353939976e 100644 (file)
@@ -25,7 +25,6 @@
 #include FT_GLYPH_H
 #include FT_TRUETYPE_TABLES_H
 #include FT_OUTLINE_H
-#include <strings.h>
 #include <limits.h>
 
 #include "ass.h"
index 19ae6d4bdd1efae5f055299272e8ba3547760df7..2a2ec51bbbd204466b73bbf6d5fc4a4e292b0b33 100644 (file)
@@ -24,7 +24,6 @@
 #include <limits.h>
 #include <assert.h>
 #include <string.h>
-#include <strings.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <inttypes.h>
@@ -45,6 +44,7 @@
 #include "ass_coretext.h"
 #include "ass_directwrite.h"
 #include "ass_font.h"
+#include "ass_string.h"
 
 #define ABS(x) ((x) < 0 ? -(x) : (x))
 #define MAX_FULLNAME 100
@@ -408,7 +408,7 @@ void ass_font_provider_free(ASS_FontProvider *provider)
 static bool matches_family_name(ASS_FontInfo *f, const char *family)
 {
     for (int i = 0; i < f->n_family; i++) {
-        if (strcasecmp(f->families[i], family) == 0)
+        if (ass_strcasecmp(f->families[i], family) == 0)
             return true;
     }
     return false;
@@ -420,7 +420,7 @@ static bool matches_family_name(ASS_FontInfo *f, const char *family)
 static bool matches_fullname(ASS_FontInfo *f, const char *fullname)
 {
     for (int i = 0; i < f->n_fullname; i++) {
-        if (strcasecmp(f->fullnames[i], fullname) == 0)
+        if (ass_strcasecmp(f->fullnames[i], fullname) == 0)
             return true;
     }
     return false;
@@ -1054,7 +1054,7 @@ void ass_map_font(const ASS_FontMapping *map, int len, const char *name,
                   ASS_FontProviderMetaData *meta)
 {
     for (int i = 0; i < len; i++) {
-        if (strcasecmp(map[i].from, name) == 0) {
+        if (ass_strcasecmp(map[i].from, name) == 0) {
             meta->fullnames = calloc(1, sizeof(char *));
             if (meta->fullnames) {
                 meta->fullnames[0] = strdup(map[i].to);
index 5b7a5c9e2010e240eddb428a38942e923b8022ee..a2945d86619c158982dd810ca5865708dc73467d 100644 (file)
@@ -27,6 +27,7 @@
 #include "ass.h"
 #include "ass_library.h"
 #include "ass_utils.h"
+#include "ass_string.h"
 
 static void ass_msg_handler(int level, const char *fmt, va_list va, void *data)
 {
diff --git a/libass/ass_string.c b/libass/ass_string.c
new file mode 100644 (file)
index 0000000..bb755a6
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 Grigori Goronzy <greg@kinoho.net>
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ass_string.h"
+
+static const char lowertab[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+    0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+    0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+    0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+    0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61,
+    0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+    0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+    0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
+    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+    0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+    0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+    0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+    0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+    0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+    0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+    0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+    0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+    0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+    0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
+    0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
+    0xfd, 0xfe, 0xff
+};
+
+int ass_strcasecmp(const char *s1, const char *s2)
+{
+    unsigned char a, b;
+
+    do {
+        a = lowertab[(unsigned char)*s1++];
+        b = lowertab[(unsigned char)*s2++];
+    } while (a && a == b);
+
+    return a - b;
+}
+
+int ass_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+    unsigned char a, b;
+    const char *last = s1 + n;
+
+    do {
+        a = lowertab[(unsigned char)*s1++];
+        b = lowertab[(unsigned char)*s2++];
+    } while (s1 < last && a && a == b);
+
+    return a - b;
+}
+
diff --git a/libass/ass_string.h b/libass/ass_string.h
new file mode 100644 (file)
index 0000000..8944804
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Grigori Goronzy <greg@kinoho.net>
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#ifndef ASS_STRING_H
+#define ASS_STRING_H
+
+int ass_strcasecmp(const char *s1, const char *s2);
+int ass_strncasecmp(const char *s1, const char *s2, size_t n);
+
+static inline int ass_isspace(int c)
+{
+    return c == ' ' || c == '\t' || c == '\n' || c == '\v' ||
+           c == '\f' || c == '\r';
+}
+
+static inline int ass_isdigit(int c)
+{
+    return c >= '0' && c <= '9';
+}
+
+#endif
index 4e964049eb3984c8fbea1d6e1ee3871974774d56..566f6e4abd020b9865185abbbae9e9823a7e4dea 100644 (file)
@@ -13,8 +13,8 @@
  */
 
 #include <stdlib.h>
-#include <ctype.h>
 #include <errno.h>
+#include "ass_string.h"
 
 static
 const int maxExponent = 511;    /* Largest possible base 10 exponent.  Any
@@ -100,7 +100,7 @@ ass_strtod(
      */
 
     p = string;
-    while (isspace(*p)) {
+    while (ass_isspace(*p)) {
         p += 1;
     }
     if (*p == '-') {
@@ -122,7 +122,7 @@ ass_strtod(
     for (mantSize = 0; ; mantSize += 1)
     {
         c = *p;
-        if (!isdigit(c)) {
+        if (!ass_isdigit(c)) {
             if ((c != '.') || (decPt >= 0)) {
                 break;
             }
@@ -198,7 +198,7 @@ ass_strtod(
             }
             expSign = 0;
         }
-        while (isdigit(*p)) {
+        while (ass_isdigit(*p)) {
             exp = exp * 10 + (*p - '0');
             p += 1;
         }
index 1c0ebdd0bee9711683f67e14f12212f7a2739482..9c9155b6e99ebdcc3bd3dfb469d7d6321acd073e 100644 (file)
 #include <stdio.h>
 #include <stdint.h>
 #include <inttypes.h>
-#include <strings.h>
-#include <ctype.h>
 
 #include "ass_library.h"
 #include "ass.h"
 #include "ass_utils.h"
+#include "ass_string.h"
 
 #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
 
@@ -232,7 +231,7 @@ static int mystrtou32_modulo(char **p, int base, uint32_t *res)
     else if (**p == '-')
         sign = -1, ++*p;
 
-    if (base == 16 && !strncasecmp(*p, "0x", 2))
+    if (base == 16 && !ass_strncasecmp(*p, "0x", 2))
         *p += 2;
 
     if (read_digits(p, base, res)) {
@@ -271,7 +270,7 @@ uint32_t parse_color_header(char *str)
     uint32_t color = 0;
     int base;
 
-    if (!strncasecmp(str, "&h", 2) || !strncasecmp(str, "0x", 2)) {
+    if (!ass_strncasecmp(str, "&h", 2) || !ass_strncasecmp(str, "0x", 2)) {
         str += 2;
         base = 16;
     } else
@@ -285,7 +284,7 @@ uint32_t parse_color_header(char *str)
 char parse_bool(char *str)
 {
     skip_spaces(&str);
-    return !strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0;
+    return !ass_strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0;
 }
 
 int parse_ycbcr_matrix(char *str)
@@ -305,23 +304,23 @@ int parse_ycbcr_matrix(char *str)
     memcpy(buffer, str, n);
     buffer[n] = '\0';
 
-    if (!strcasecmp(buffer, "none"))
+    if (!ass_strcasecmp(buffer, "none"))
         return YCBCR_NONE;
-    if (!strcasecmp(buffer, "tv.601"))
+    if (!ass_strcasecmp(buffer, "tv.601"))
         return YCBCR_BT601_TV;
-    if (!strcasecmp(buffer, "pc.601"))
+    if (!ass_strcasecmp(buffer, "pc.601"))
         return YCBCR_BT601_PC;
-    if (!strcasecmp(buffer, "tv.709"))
+    if (!ass_strcasecmp(buffer, "tv.709"))
         return YCBCR_BT709_TV;
-    if (!strcasecmp(buffer, "pc.709"))
+    if (!ass_strcasecmp(buffer, "pc.709"))
         return YCBCR_BT709_PC;
-    if (!strcasecmp(buffer, "tv.240m"))
+    if (!ass_strcasecmp(buffer, "tv.240m"))
         return YCBCR_SMPTE240M_TV;
-    if (!strcasecmp(buffer, "pc.240m"))
+    if (!ass_strcasecmp(buffer, "pc.240m"))
         return YCBCR_SMPTE240M_PC;
-    if (!strcasecmp(buffer, "tv.fcc"))
+    if (!ass_strcasecmp(buffer, "tv.fcc"))
         return YCBCR_FCC_TV;
-    if (!strcasecmp(buffer, "pc.fcc"))
+    if (!ass_strcasecmp(buffer, "pc.fcc"))
         return YCBCR_FCC_PC;
     return YCBCR_UNKNOWN;
 }
@@ -345,8 +344,8 @@ char *strdup_trimmed(const char *str)
     int right = strlen(str) - 1;
     char *out = NULL;
 
-    while (isspace(str[left])) left++;
-    while (right > left && isspace(str[right])) right--;
+    while (ass_isspace(str[left])) left++;
+    while (right > left && ass_isspace(str[right])) right--;
 
     out = calloc(1, right-left+2);
 
@@ -435,7 +434,7 @@ int lookup_style(ASS_Track *track, char *name)
         ++name;
     // VSFilter then normalizes the case of "Default"
     // (only in contexts where this function is called)
-    if (strcasecmp(name, "Default") == 0)
+    if (ass_strcasecmp(name, "Default") == 0)
         name = "Default";
     for (i = track->n_styles - 1; i >= 0; --i) {
         if (strcmp(track->styles[i].Name, name) == 0)
@@ -491,7 +490,7 @@ void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
     for (i = 0; i < langcnt; i++) {
         const char *tmp;
 
-        if (strcasecmp(languages[i], preferred_language) != 0)
+        if (ass_strcasecmp(languages[i], preferred_language) != 0)
             continue;
         analyser = enca_analyser_alloc(languages[i]);
         encoding = enca_analyse_const(analyser, buffer, buflen);