From 68ff8a0484b592a629ef2bbcb0537265ae36d1d0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 29 Aug 2014 12:09:04 +0200 Subject: Move compat/ and bstr/ directory contents somewhere else bstr.c doesn't really deserve its own directory, and compat had just a few files, most of which may as well be in osdep. There isn't really any justification for these extra directories, so get rid of them. The compat/libav.h was empty - just delete it. We changed our approach to API compatibility, and will likely not need it anymore. --- audio/chmap.h | 2 +- audio/decode/ad_lavc.c | 2 - audio/decode/dec_audio.c | 2 +- audio/filter/af_convertsignendian.c | 2 +- audio/format.h | 2 +- audio/out/ao.h | 2 +- audio/out/ao_lavc.c | 1 - audio/out/ao_wasapi.h | 2 +- audio/out/pull.c | 2 +- audio/out/push.c | 2 +- bstr/bstr.c | 437 ------------------------------------ bstr/bstr.h | 214 ------------------ common/codecs.c | 2 +- common/common.c | 2 +- common/common.h | 2 +- common/msg.c | 4 +- common/msg.h | 2 +- common/playlist.h | 2 +- common/tags.c | 2 +- common/tags.h | 2 +- compat/atomics.h | 77 ------- compat/compiler.h | 27 --- compat/libav.h | 24 -- compat/mpbswap.h | 32 --- demux/demux.h | 2 +- demux/demux_cue.c | 2 +- demux/demux_lavf.c | 3 +- demux/demux_mkv.c | 2 +- demux/ebml.c | 2 +- demux/ebml.h | 2 +- demux/ms_hdr.h | 2 +- input/cmd_parse.c | 2 +- input/event.h | 2 +- input/input.c | 2 +- input/input.h | 2 +- input/keycodes.c | 2 +- input/pipe.c | 2 +- misc/bstr.c | 437 ++++++++++++++++++++++++++++++++++++ misc/bstr.h | 214 ++++++++++++++++++ misc/charset_conv.h | 2 +- misc/ring.c | 2 +- old-makefile | 3 +- options/m_config.h | 2 +- options/m_option.h | 2 +- options/path.h | 2 +- osdep/atomics.h | 77 +++++++ osdep/compiler.h | 28 ++- osdep/mpbswap.h | 32 +++ osdep/terminal-unix.c | 2 +- player/lua.c | 2 +- player/screenshot.c | 2 +- player/scripting.c | 2 +- player/timeline/tl_cue.c | 2 +- player/timeline/tl_matroska.c | 2 +- player/timeline/tl_mpv_edl.c | 2 +- stream/stream.c | 4 +- stream/stream.h | 2 +- stream/stream_cdda.c | 2 +- stream/stream_lavf.c | 2 +- sub/osd_libass.c | 2 +- sub/sd_lavc_conv.c | 2 +- sub/sd_lavf_srt.c | 2 +- sub/sd_microdvd.c | 2 +- sub/sd_srt.c | 2 +- talloc.h | 2 +- video/decode/vd_lavc.c | 6 +- video/filter/vf_divtc.c | 2 +- video/filter/vf_scale.c | 1 - video/image_writer.c | 2 - video/img_format.c | 2 - video/img_format.h | 2 +- video/out/gl_common.h | 2 +- video/out/gl_lcms.c | 2 +- video/out/gl_video.c | 2 +- video/out/vo.c | 2 +- video/out/vo_image.c | 2 +- video/out/vo_lavc.c | 1 - video/out/vo_opengl.c | 2 +- video/out/wayland_common.c | 2 +- video/out/x11_common.c | 2 +- wscript_build.py | 4 +- 81 files changed, 854 insertions(+), 894 deletions(-) delete mode 100644 bstr/bstr.c delete mode 100644 bstr/bstr.h delete mode 100644 compat/atomics.h delete mode 100644 compat/compiler.h delete mode 100644 compat/libav.h delete mode 100644 compat/mpbswap.h create mode 100644 misc/bstr.c create mode 100644 misc/bstr.h create mode 100644 osdep/atomics.h create mode 100644 osdep/mpbswap.h diff --git a/audio/chmap.h b/audio/chmap.h index 37815a25b6..22cf6fb73b 100644 --- a/audio/chmap.h +++ b/audio/chmap.h @@ -20,7 +20,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #define MP_NUM_CHANNELS 8 diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index c4372ba4b3..afff84ef00 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -37,8 +37,6 @@ #include "ad.h" #include "audio/fmt-conversion.h" -#include "compat/libav.h" - struct priv { AVCodecContext *avctx; AVFrame *avframe; diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index c7580a23d8..0afcd8857e 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -28,7 +28,7 @@ #include "config.h" #include "common/codecs.h" #include "common/msg.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "stream/stream.h" #include "demux/demux.h" diff --git a/audio/filter/af_convertsignendian.c b/audio/filter/af_convertsignendian.c index 45b365efd8..a0b47b38a3 100644 --- a/audio/filter/af_convertsignendian.c +++ b/audio/filter/af_convertsignendian.c @@ -20,7 +20,7 @@ #include "af.h" #include "audio/format.h" -#include "compat/mpbswap.h" +#include "osdep/mpbswap.h" static bool test_conversion(int src_format, int dst_format) { diff --git a/audio/format.h b/audio/format.h index 788f4ed1c1..c4afe7a428 100644 --- a/audio/format.h +++ b/audio/format.h @@ -26,7 +26,7 @@ #include #include "osdep/endian.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #if BYTE_ORDER == BIG_ENDIAN #define AF_SELECT_LE_BE(LE, BE) BE diff --git a/audio/out/ao.h b/audio/out/ao.h index 59de0c08b1..3eb2925971 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -21,7 +21,7 @@ #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/common.h" #include "audio/chmap.h" #include "audio/chmap_sel.h" diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 34cf2c21ac..357c34763d 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -28,7 +28,6 @@ #include #include -#include "compat/libav.h" #include "config.h" #include "options/options.h" #include "common/common.h" diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index 52813b586d..36428b4aea 100755 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -28,7 +28,7 @@ #include #include -#include "compat/atomics.h" +#include "osdep/atomics.h" typedef struct wasapi_state { struct mp_log *log; diff --git a/audio/out/pull.c b/audio/out/pull.c index eb77be81a2..0613006f07 100644 --- a/audio/out/pull.c +++ b/audio/out/pull.c @@ -30,7 +30,7 @@ #include "osdep/timer.h" #include "osdep/threads.h" -#include "compat/atomics.h" +#include "osdep/atomics.h" #include "misc/ring.h" /* diff --git a/audio/out/push.c b/audio/out/push.c index f35c597100..91b4a67571 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -35,7 +35,7 @@ #include "osdep/threads.h" #include "osdep/timer.h" -#include "compat/atomics.h" +#include "osdep/atomics.h" #include "audio/audio.h" #include "audio/audio_buffer.h" diff --git a/bstr/bstr.c b/bstr/bstr.c deleted file mode 100644 index a6268b4d53..0000000000 --- a/bstr/bstr.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "talloc.h" - -#include "common/common.h" -#include "misc/ctype.h" -#include "bstr.h" - -int bstrcmp(struct bstr str1, struct bstr str2) -{ - int ret = memcmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); - - if (!ret) { - if (str1.len == str2.len) - return 0; - else if (str1.len > str2.len) - return 1; - else - return -1; - } - return ret; -} - -int bstrcasecmp(struct bstr str1, struct bstr str2) -{ - int ret = strncasecmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); - - if (!ret) { - if (str1.len == str2.len) - return 0; - else if (str1.len > str2.len) - return 1; - else - return -1; - } - return ret; -} - -int bstrchr(struct bstr str, int c) -{ - for (int i = 0; i < str.len; i++) - if (str.start[i] == c) - return i; - return -1; -} - -int bstrrchr(struct bstr str, int c) -{ - for (int i = str.len - 1; i >= 0; i--) - if (str.start[i] == c) - return i; - return -1; -} - -int bstrcspn(struct bstr str, const char *reject) -{ - int i; - for (i = 0; i < str.len; i++) - if (strchr(reject, str.start[i])) - break; - return i; -} - -int bstrspn(struct bstr str, const char *accept) -{ - int i; - for (i = 0; i < str.len; i++) - if (!strchr(accept, str.start[i])) - break; - return i; -} - -int bstr_find(struct bstr haystack, struct bstr needle) -{ - for (int i = 0; i < haystack.len; i++) - if (bstr_startswith(bstr_splice(haystack, i, haystack.len), needle)) - return i; - return -1; -} - -struct bstr bstr_lstrip(struct bstr str) -{ - while (str.len && mp_isspace(*str.start)) { - str.start++; - str.len--; - } - return str; -} - -struct bstr bstr_strip(struct bstr str) -{ - str = bstr_lstrip(str); - while (str.len && mp_isspace(str.start[str.len - 1])) - str.len--; - return str; -} - -struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest) -{ - int start; - for (start = 0; start < str.len; start++) - if (!strchr(sep, str.start[start])) - break; - str = bstr_cut(str, start); - int end = bstrcspn(str, sep); - if (rest) { - *rest = bstr_cut(str, end); - } - return bstr_splice(str, 0, end); -} - -// Unlike with bstr_split(), tok is a string, and not a set of char. -// If tok is in str, return true, and: concat(out_left, tok, out_right) == str -// Otherwise, return false, and set out_left==str, out_right=="" -bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right) -{ - bstr bsep = bstr0(tok); - int pos = bstr_find(str, bsep); - if (pos < 0) - pos = str.len; - *out_left = bstr_splice(str, 0, pos); - *out_right = bstr_cut(str, pos + bsep.len); - return pos != str.len; -} - -struct bstr bstr_splice(struct bstr str, int start, int end) -{ - if (start < 0) - start += str.len; - if (end < 0) - end += str.len; - end = FFMIN(end, str.len); - start = FFMAX(start, 0); - end = FFMAX(end, start); - str.start += start; - str.len = end - start; - return str; -} - -long long bstrtoll(struct bstr str, struct bstr *rest, int base) -{ - str = bstr_lstrip(str); - char buf[51]; - int len = FFMIN(str.len, 50); - memcpy(buf, str.start, len); - buf[len] = 0; - char *endptr; - long long r = strtoll(buf, &endptr, base); - if (rest) - *rest = bstr_cut(str, endptr - buf); - return r; -} - -double bstrtod(struct bstr str, struct bstr *rest) -{ - str = bstr_lstrip(str); - char buf[101]; - int len = FFMIN(str.len, 100); - memcpy(buf, str.start, len); - buf[len] = 0; - char *endptr; - double r = strtod(buf, &endptr); - if (rest) - *rest = bstr_cut(str, endptr - buf); - return r; -} - -struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str) -{ - if (str.len == 0) - return NULL; - int count = 0; - for (int i = 0; i < str.len; i++) - if (str.start[i] == '\n') - count++; - if (str.start[str.len - 1] != '\n') - count++; - struct bstr *r = talloc_array_ptrtype(talloc_ctx, r, count); - unsigned char *p = str.start; - for (int i = 0; i < count - 1; i++) { - r[i].start = p; - while (*p++ != '\n'); - r[i].len = p - r[i].start; - } - r[count - 1].start = p; - r[count - 1].len = str.start + str.len - p; - return r; -} - -struct bstr bstr_getline(struct bstr str, struct bstr *rest) -{ - int pos = bstrchr(str, '\n'); - if (pos < 0) - pos = str.len; - if (rest) - *rest = bstr_cut(str, pos + 1); - return bstr_splice(str, 0, pos + 1); -} - -struct bstr bstr_strip_linebreaks(struct bstr str) -{ - if (bstr_endswith0(str, "\r\n")) { - str = bstr_splice(str, 0, str.len - 2); - } else if (bstr_endswith0(str, "\n")) { - str = bstr_splice(str, 0, str.len - 1); - } - return str; -} - -bool bstr_eatstart(struct bstr *s, struct bstr prefix) -{ - if (!bstr_startswith(*s, prefix)) - return false; - *s = bstr_cut(*s, prefix.len); - return true; -} - -void bstr_lower(struct bstr str) -{ - for (int i = 0; i < str.len; i++) - str.start[i] = mp_tolower(str.start[i]); -} - -int bstr_sscanf(struct bstr str, const char *format, ...) -{ - char *ptr = bstrdup0(NULL, str); - va_list va; - va_start(va, format); - int ret = vsscanf(ptr, format, va); - va_end(va); - talloc_free(ptr); - return ret; -} - -int bstr_parse_utf8_code_length(unsigned char b) -{ - if (b < 128) - return 1; - int bytes = 7 - av_log2(b ^ 255); - return (bytes >= 2 && bytes <= 4) ? bytes : -1; -} - -int bstr_decode_utf8(struct bstr s, struct bstr *out_next) -{ - if (s.len == 0) - return -1; - unsigned int codepoint = s.start[0]; - s.start++; s.len--; - if (codepoint >= 128) { - int bytes = bstr_parse_utf8_code_length(codepoint); - if (bytes < 0 || s.len < bytes - 1) - return -1; - codepoint &= 127 >> bytes; - for (int n = 1; n < bytes; n++) { - int tmp = (unsigned char)s.start[0]; - if ((tmp & 0xC0) != 0x80) - return -1; - codepoint = (codepoint << 6) | (tmp & ~0xC0); - s.start++; s.len--; - } - if (codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) - return -1; - // Overlong sequences - check taken from libavcodec. - // (The only reason we even bother with this is to make libavcodec's - // retarded subtitle utf-8 check happy.) - unsigned int min = bytes == 2 ? 0x80 : 1 << (5 * bytes - 4); - if (codepoint < min) - return -1; - } - if (out_next) - *out_next = s; - return codepoint; -} - -struct bstr bstr_split_utf8(struct bstr str, struct bstr *out_next) -{ - bstr rest; - int code = bstr_decode_utf8(str, &rest); - if (code < 0) - return (bstr){0}; - if (out_next) - *out_next = rest; - return bstr_splice(str, 0, str.len - rest.len); -} - -int bstr_validate_utf8(struct bstr s) -{ - while (s.len) { - if (bstr_decode_utf8(s, &s) < 0) { - // Try to guess whether the sequence was just cut-off. - unsigned int codepoint = (unsigned char)s.start[0]; - int bytes = bstr_parse_utf8_code_length(codepoint); - if (bytes > 1 && s.len < 6) { - // Manually check validity of left bytes - for (int n = 1; n < bytes; n++) { - if (n >= s.len) { - // Everything valid until now - just cut off. - return -(bytes - s.len); - } - int tmp = (unsigned char)s.start[n]; - if ((tmp & 0xC0) != 0x80) - break; - } - } - return -8; - } - } - return 0; -} - -struct bstr bstr_sanitize_utf8_latin1(void *talloc_ctx, struct bstr s) -{ - bstr new = {0}; - bstr left = s; - unsigned char *first_ok = s.start; - while (left.len) { - int r = bstr_decode_utf8(left, &left); - if (r < 0) { - bstr_xappend(talloc_ctx, &new, (bstr){first_ok, left.start - first_ok}); - mp_append_utf8_bstr(talloc_ctx, &new, (unsigned char)left.start[0]); - left.start += 1; - left.len -= 1; - first_ok = left.start; - } - } - if (!new.start) - return s; - if (first_ok != left.start) - bstr_xappend(talloc_ctx, &new, (bstr){first_ok, left.start - first_ok}); - return new; -} - -static void resize_append(void *talloc_ctx, bstr *s, size_t append_min) -{ - size_t size = talloc_get_size(s->start); - assert(s->len <= size); - if (append_min > size - s->len) { - if (append_min < size) - append_min = size; // preallocate in power of 2s - if (size >= SIZE_MAX / 2 || append_min >= SIZE_MAX / 2) - abort(); // oom - s->start = talloc_realloc_size(talloc_ctx, s->start, size + append_min); - } -} - -// Append the string, so that *s = *s + append. s->start is expected to be -// a talloc allocation (which can be realloced) or NULL. -// This function will always implicitly append a \0 after the new string for -// convenience. -// talloc_ctx will be used as parent context, if s->start is NULL. -void bstr_xappend(void *talloc_ctx, bstr *s, bstr append) -{ - resize_append(talloc_ctx, s, append.len + 1); - memcpy(s->start + s->len, append.start, append.len); - s->len += append.len; - s->start[s->len] = '\0'; -} - -void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - bstr_xappend_vasprintf(talloc_ctx, s, fmt, ap); - va_end(ap); -} - -// Exactly as bstr_xappend(), but with a formatted string. -void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt, - va_list ap) -{ - int size; - va_list copy; - va_copy(copy, ap); - char c; - size = vsnprintf(&c, 1, fmt, copy); - va_end(copy); - - if (size < 0) - abort(); - - resize_append(talloc_ctx, s, size + 1); - vsnprintf(s->start + s->len, size + 1, fmt, ap); - s->len += size; -} - -bool bstr_case_startswith(struct bstr s, struct bstr prefix) -{ - struct bstr start = bstr_splice(s, 0, prefix.len); - return start.len == prefix.len && bstrcasecmp(start, prefix) == 0; -} - -bool bstr_case_endswith(struct bstr s, struct bstr suffix) -{ - struct bstr end = bstr_cut(s, -suffix.len); - return end.len == suffix.len && bstrcasecmp(end, suffix) == 0; -} - -struct bstr bstr_strip_ext(struct bstr str) -{ - int dotpos = bstrrchr(str, '.'); - if (dotpos < 0) - return str; - return (struct bstr){str.start, dotpos}; -} - -struct bstr bstr_get_ext(struct bstr s) -{ - int dotpos = bstrrchr(s, '.'); - if (dotpos < 0) - return (struct bstr){NULL, 0}; - return bstr_splice(s, dotpos + 1, s.len); -} diff --git a/bstr/bstr.h b/bstr/bstr.h deleted file mode 100644 index a1e99dd4a5..0000000000 --- a/bstr/bstr.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_BSTR_H -#define MPLAYER_BSTR_H - -#include -#include -#include -#include -#include - -#include "talloc.h" -#include "osdep/compiler.h" - -/* NOTE: 'len' is size_t, but most string-handling functions below assume - * that input size has been sanity checked and len fits in an int. - */ -typedef struct bstr { - unsigned char *start; - size_t len; -} bstr; - -// If str.start is NULL, return NULL. -static inline char *bstrdup0(void *talloc_ctx, struct bstr str) -{ - return talloc_strndup(talloc_ctx, (char *)str.start, str.len); -} - -// Like bstrdup0(), but always return a valid C-string. -static inline char *bstrto0(void *talloc_ctx, struct bstr str) -{ - return str.start ? bstrdup0(talloc_ctx, str) : talloc_strdup(talloc_ctx, ""); -} - -// Return start = NULL iff that is true for the original. -static inline struct bstr bstrdup(void *talloc_ctx, struct bstr str) -{ - struct bstr r = { NULL, str.len }; - if (str.start) - r.start = (unsigned char *)talloc_memdup(talloc_ctx, str.start, str.len); - return r; -} - -static inline struct bstr bstr0(const char *s) -{ - return (struct bstr){(unsigned char *)s, s ? strlen(s) : 0}; -} - -int bstrcmp(struct bstr str1, struct bstr str2); -int bstrcasecmp(struct bstr str1, struct bstr str2); -int bstrchr(struct bstr str, int c); -int bstrrchr(struct bstr str, int c); -int bstrspn(struct bstr str, const char *accept); -int bstrcspn(struct bstr str, const char *reject); - -int bstr_find(struct bstr haystack, struct bstr needle); -struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str); -struct bstr bstr_lstrip(struct bstr str); -struct bstr bstr_strip(struct bstr str); -struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest); -bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right); -struct bstr bstr_splice(struct bstr str, int start, int end); -long long bstrtoll(struct bstr str, struct bstr *rest, int base); -double bstrtod(struct bstr str, struct bstr *rest); -void bstr_lower(struct bstr str); -int bstr_sscanf(struct bstr str, const char *format, ...); - -// Decode the UTF-8 code point at the start of the string, and return the -// character. -// After calling this function, *out_next will point to the next character. -// out_next can be NULL. -// On error, -1 is returned, and *out_next is not modified. -int bstr_decode_utf8(struct bstr str, struct bstr *out_next); - -// Return the UTF-8 code point at the start of the string. -// After calling this function, *out_next will point to the next character. -// out_next can be NULL. -// On error, an empty string is returned, and *out_next is not modified. -struct bstr bstr_split_utf8(struct bstr str, struct bstr *out_next); - -// Return the length of the UTF-8 sequence that starts with the given byte. -// Given a string char *s, the next UTF-8 code point is to be expected at -// s + bstr_parse_utf8_code_length(s[0]) -// On error, -1 is returned. On success, it returns a value in the range [1, 4]. -int bstr_parse_utf8_code_length(unsigned char b); - -// Return >= 0 if the string is valid UTF-8, otherwise negative error code. -// Embedded \0 bytes are considered valid. -// This returns -N if the UTF-8 string was likely just cut-off in the middle of -// an UTF-8 sequence: -1 means 1 byte was missing, -5 5 bytes missing. -// If the string was likely not cut off, -8 is returned. -// Use (return_value > -8) to check whether the string is valid UTF-8 or valid -// but cut-off UTF-8. -int bstr_validate_utf8(struct bstr s); - -// Force the input string to valid UTF-8. If invalid UTF-8 encoding is -// encountered, the invalid bytes are interpreted as Latin-1. -// Embedded \0 bytes are considered valid. -// If replacement happens, a newly allocated string is returned (with a \0 -// byte added past its end for convenience). The string is allocated via -// talloc, with talloc_ctx as parent. -struct bstr bstr_sanitize_utf8_latin1(void *talloc_ctx, struct bstr s); - -// Return the text before the next line break, and return it. Change *rest to -// point to the text following this line break. (rest can be NULL.) -// Line break characters are not stripped. -struct bstr bstr_getline(struct bstr str, struct bstr *rest); - -// Strip one trailing line break. This is intended for use with bstr_getline, -// and will remove the trailing \n or \r\n sequence. -struct bstr bstr_strip_linebreaks(struct bstr str); - -void bstr_xappend(void *talloc_ctx, bstr *s, bstr append); -void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...) - PRINTF_ATTRIBUTE(3, 4); -void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt, va_list va) - PRINTF_ATTRIBUTE(3, 0); - -// If s starts with prefix, return true and return the rest of the string in s. -bool bstr_eatstart(struct bstr *s, struct bstr prefix); - -bool bstr_case_startswith(struct bstr s, struct bstr prefix); -bool bstr_case_endswith(struct bstr s, struct bstr suffix); -struct bstr bstr_strip_ext(struct bstr str); -struct bstr bstr_get_ext(struct bstr s); - -static inline struct bstr bstr_cut(struct bstr str, int n) -{ - if (n < 0) { - n += str.len; - if (n < 0) - n = 0; - } - if (((size_t)n) > str.len) - n = str.len; - return (struct bstr){str.start + n, str.len - n}; -} - -static inline bool bstr_startswith(struct bstr str, struct bstr prefix) -{ - if (str.len < prefix.len) - return false; - return !memcmp(str.start, prefix.start, prefix.len); -} - -static inline bool bstr_startswith0(struct bstr str, const char *prefix) -{ - return bstr_startswith(str, bstr0(prefix)); -} - -static inline bool bstr_endswith(struct bstr str, struct bstr suffix) -{ - if (str.len < suffix.len) - return false; - return !memcmp(str.start + str.len - suffix.len, suffix.start, suffix.len); -} - -static inline bool bstr_endswith0(struct bstr str, const char *suffix) -{ - return bstr_endswith(str, bstr0(suffix)); -} - -static inline int bstrcmp0(struct bstr str1, const char *str2) -{ - return bstrcmp(str1, bstr0(str2)); -} - -static inline bool bstr_equals(struct bstr str1, struct bstr str2) -{ - return bstrcmp(str1, str2) == 0; -} - -static inline bool bstr_equals0(struct bstr str1, const char *str2) -{ - return bstrcmp(str1, bstr0(str2)) == 0; -} - -static inline int bstrcasecmp0(struct bstr str1, const char *str2) -{ - return bstrcasecmp(str1, bstr0(str2)); -} - -static inline int bstr_find0(struct bstr haystack, const char *needle) -{ - return bstr_find(haystack, bstr0(needle)); -} - -static inline int bstr_eatstart0(struct bstr *s, const char *prefix) -{ - return bstr_eatstart(s, bstr0(prefix)); -} - -// create a pair (not single value!) for "%.*s" printf syntax -#define BSTR_P(bstr) (int)((bstr).len), (bstr).start - -#define WHITESPACE " \f\n\r\t\v" - -#endif /* MPLAYER_BSTR_H */ diff --git a/common/codecs.c b/common/codecs.c index 1cbab44969..f89ef0c318 100644 --- a/common/codecs.c +++ b/common/codecs.c @@ -17,7 +17,7 @@ #include #include "talloc.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/msg.h" #include "codecs.h" diff --git a/common/common.c b/common/common.c index afab994d72..a74205dd92 100644 --- a/common/common.c +++ b/common/common.c @@ -22,7 +22,7 @@ #include #include "talloc.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/common.h" #define appendf(ptr, ...) \ diff --git a/common/common.h b/common/common.h index 6c759e9258..b9c3e1e5ea 100644 --- a/common/common.h +++ b/common/common.h @@ -24,7 +24,7 @@ #include #include -#include "compat/compiler.h" +#include "osdep/compiler.h" #include "talloc.h" // double should be able to represent this exactly diff --git a/common/msg.c b/common/msg.c index 6bde6d481d..866cae5c9d 100644 --- a/common/msg.c +++ b/common/msg.c @@ -27,8 +27,8 @@ #include "talloc.h" -#include "bstr/bstr.h" -#include "compat/atomics.h" +#include "misc/bstr.h" +#include "osdep/atomics.h" #include "common/common.h" #include "common/global.h" #include "misc/ring.h" diff --git a/common/msg.h b/common/msg.h index 80aec2f5b3..5ca868d4bb 100644 --- a/common/msg.h +++ b/common/msg.h @@ -24,7 +24,7 @@ #include #include -#include "compat/compiler.h" +#include "osdep/compiler.h" struct mp_log; diff --git a/common/playlist.h b/common/playlist.h index 73227f071c..ea0e3698a2 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -19,7 +19,7 @@ #define MPLAYER_PLAYLIST_H #include -#include "bstr/bstr.h" +#include "misc/bstr.h" struct playlist_param { bstr name, value; diff --git a/common/tags.c b/common/tags.c index c722d5d89c..bc9d98ea2f 100644 --- a/common/tags.c +++ b/common/tags.c @@ -17,7 +17,7 @@ #include #include "tags.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" void mp_tags_set_str(struct mp_tags *tags, const char *key, const char *value) { diff --git a/common/tags.h b/common/tags.h index 375289695f..b6db5f3df2 100644 --- a/common/tags.h +++ b/common/tags.h @@ -1,7 +1,7 @@ #ifndef MP_TAGS_H #define MP_TAGS_H -#include "bstr/bstr.h" +#include "misc/bstr.h" struct mp_tags { char **keys; diff --git a/compat/atomics.h b/compat/atomics.h deleted file mode 100644 index e5fb717a78..0000000000 --- a/compat/atomics.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of mpv. - * Copyright (c) 2013 Stefano Pigozzi - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MP_ATOMICS_H -#define MP_ATOMICS_H - -#include -#include "config.h" - -#define HAVE_ATOMICS 1 - -#if HAVE_STDATOMIC -#include -#else - -// Emulate the parts of C11 stdatomic.h needed by mpv. -// Still relies on gcc/clang atomic builtins. - -typedef struct { volatile unsigned long v; } atomic_ulong; -typedef struct { volatile int v; } atomic_int; -typedef struct { volatile _Bool v; } atomic_bool; -typedef struct { volatile long long v; } atomic_llong; -typedef struct { volatile uint_least32_t v; } atomic_uint_least32_t; -typedef struct { volatile unsigned long long v; } atomic_ullong; - -#define ATOMIC_VAR_INIT(x) \ - {.v = (x)} - -#if HAVE_ATOMIC_BUILTINS - -#define atomic_load(p) \ - __atomic_load_n(&(p)->v, __ATOMIC_SEQ_CST) -#define atomic_store(p, val) \ - __atomic_store_n(&(p)->v, val, __ATOMIC_SEQ_CST) -#define atomic_fetch_add(a, b) \ - __atomic_fetch_add(&(a)->v, b, __ATOMIC_SEQ_CST) - -#elif HAVE_SYNC_BUILTINS - -#define atomic_load(p) \ - __sync_fetch_and_add(&(p)->v, 0) -#define atomic_store(p, val) \ - (__sync_synchronize(), (p)->v = (val), __sync_synchronize()) -#define atomic_fetch_add(a, b) \ - __sync_fetch_and_add(&(a)->v, b) - -#else - -// This is extremely wrong. The build system actually disables code that has -// a serious dependency on working atomics, so this is barely ok. -#define atomic_load(p) ((p)->v) -#define atomic_store(p, val) ((p)->v = (val)) -#define atomic_fetch_add(a, b) (((a)->v += (b)) - (b)) - -#undef HAVE_ATOMICS -#define HAVE_ATOMICS 0 - -#endif /* no atomics */ - -#endif /* else HAVE_STDATOMIC */ - -#endif diff --git a/compat/compiler.h b/compat/compiler.h deleted file mode 100644 index a507cd02c2..0000000000 --- a/compat/compiler.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MPV_COMPILER_H -#define MPV_COMPILER_H - -#define MP_EXPAND_ARGS(...) __VA_ARGS__ - -#ifdef __GNUC__ - -#define MP_NORETURN __attribute__((noreturn)) - -/** Use gcc attribute to check printf fns. a1 is the 1-based index of - * the parameter containing the format, and a2 the index of the first - * argument. **/ -#ifdef __MINGW32__ -// MinGW maps "printf" to the non-standard MSVCRT functions, even if -// __USE_MINGW_ANSI_STDIO is defined and set to 1. We need to use "gnu_printf", -// which isn't necessarily available on other GCC compatible compilers. -#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (gnu_printf, a1, a2))) -#else -#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (printf, a1, a2))) -#endif - -#else -#define PRINTF_ATTRIBUTE(a1, a2) -#define MP_NORETURN -#endif - -#endif diff --git a/compat/libav.h b/compat/libav.h deleted file mode 100644 index 608cedaa8b..0000000000 --- a/compat/libav.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPV_LIBAV_COMPAT_H -#define MPV_LIBAV_COMPAT_H - -// There's nothing here. But for how long? - -#endif /* MPV_LIBAV_COMPAT_H */ diff --git a/compat/mpbswap.h b/compat/mpbswap.h deleted file mode 100644 index f75c8b86c8..0000000000 --- a/compat/mpbswap.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MPBSWAP_H -#define MPLAYER_MPBSWAP_H - -#include - -#define bswap_16(x) av_bswap16(x) -#define bswap_32(x) av_bswap32(x) -#define be2me_16(x) av_be2ne16(x) -#define be2me_32(x) av_be2ne32(x) -#define le2me_16(x) av_le2ne16(x) -#define le2me_32(x) av_le2ne32(x) -#define le2me_64(x) av_le2ne64(x) - -#endif /* MPLAYER_MPBSWAP_H */ diff --git a/demux/demux.h b/demux/demux.h index 20e6b8a15e..b1c1e28128 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -25,7 +25,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/common.h" #include "common/tags.h" #include "packet.h" diff --git a/demux/demux_cue.c b/demux/demux_cue.c index bfca04dcad..2f2e6fca46 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -22,7 +22,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "demux.h" #include "stream/stream.h" diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 79565993a4..988c3da4e4 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -39,13 +39,12 @@ # include #endif #include -#include "compat/libav.h" #include "options/options.h" #include "common/msg.h" #include "common/tags.h" #include "common/av_common.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "stream/stream.h" #include "demux.h" diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index dff08ec894..5e2e0f904f 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -44,7 +44,7 @@ #include "talloc.h" #include "common/av_common.h" #include "options/options.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "stream/stream.h" #include "demux.h" #include "stheader.h" diff --git a/demux/ebml.c b/demux/ebml.c index 7e79ee04c8..fdebc4a8ed 100644 --- a/demux/ebml.c +++ b/demux/ebml.c @@ -34,7 +34,7 @@ #include "talloc.h" #include "ebml.h" #include "stream/stream.h" -#include "compat/mpbswap.h" +#include "osdep/mpbswap.h" #include "common/msg.h" // Whether the id is a known Matroska level 1 element (allowed as element on diff --git a/demux/ebml.h b/demux/ebml.h index a544ad41cf..9d7a0cc924 100644 --- a/demux/ebml.h +++ b/demux/ebml.h @@ -24,7 +24,7 @@ #include #include "stream/stream.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" struct mp_log; diff --git a/demux/ms_hdr.h b/demux/ms_hdr.h index e44f3589ad..795b070cef 100644 --- a/demux/ms_hdr.h +++ b/demux/ms_hdr.h @@ -19,7 +19,7 @@ #ifndef MPLAYER_MS_HDR_H #define MPLAYER_MS_HDR_H -#include "compat/mpbswap.h" +#include "osdep/mpbswap.h" #include "video/img_fourcc.h" // These structs must be binary-compatible to the native win32 types, diff --git a/input/cmd_parse.c b/input/cmd_parse.c index db44ccaf5e..05cd066dbf 100644 --- a/input/cmd_parse.c +++ b/input/cmd_parse.c @@ -18,7 +18,7 @@ #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/common.h" #include "common/msg.h" #include "options/m_option.h" diff --git a/input/event.h b/input/event.h index 820932d9da..a1cb542f8f 100644 --- a/input/event.h +++ b/input/event.h @@ -15,7 +15,7 @@ * with mpv. If not, see . */ -#include "bstr/bstr.h" +#include "misc/bstr.h" struct input_ctx; diff --git a/input/input.c b/input/input.c index e85d16ccd2..908d50d014 100644 --- a/input/input.c +++ b/input/input.c @@ -48,7 +48,7 @@ #include "options/path.h" #include "talloc.h" #include "options/options.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "stream/stream.h" #include "common/common.h" diff --git a/input/input.h b/input/input.h index a8341d7773..431519a47c 100644 --- a/input/input.h +++ b/input/input.h @@ -20,7 +20,7 @@ #define MPLAYER_INPUT_H #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "cmd_list.h" #include "cmd_parse.h" diff --git a/input/keycodes.c b/input/keycodes.c index 00f983e140..a92b6ed0c8 100644 --- a/input/keycodes.c +++ b/input/keycodes.c @@ -20,7 +20,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "common/common.h" #include "common/msg.h" diff --git a/input/pipe.c b/input/pipe.c index 59f6a64c2b..12922f590c 100644 --- a/input/pipe.c +++ b/input/pipe.c @@ -10,7 +10,7 @@ #endif #include "common/msg.h" -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "osdep/io.h" #include "input.h" #include "cmd_parse.h" diff --git a/misc/bstr.c b/misc/bstr.c new file mode 100644 index 0000000000..a6268b4d53 --- /dev/null +++ b/misc/bstr.c @@ -0,0 +1,437 @@ +/* + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "talloc.h" + +#include "common/common.h" +#include "misc/ctype.h" +#include "bstr.h" + +int bstrcmp(struct bstr str1, struct bstr str2) +{ + int ret = memcmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); + + if (!ret) { + if (str1.len == str2.len) + return 0; + else if (str1.len > str2.len) + return 1; + else + return -1; + } + return ret; +} + +int bstrcasecmp(struct bstr str1, struct bstr str2) +{ + int ret = strncasecmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); + + if (!ret) { + if (str1.len == str2.len) + return 0; + else if (str1.len > str2.len) + return 1; + else + return -1; + } + return ret; +} + +int bstrchr(struct bstr str, int c) +{ + for (int i = 0; i < str.len; i++) + if (str.start[i] == c) + return i; + return -1; +} + +int bstrrchr(struct bstr str, int c) +{ + for (int i = str.len - 1; i >= 0; i--) + if (str.start[i] == c) + return i; + return -1; +} + +int bstrcspn(struct bstr str, const char *reject) +{ + int i; + for (i = 0; i < str.len; i++) + if (strchr(reject, str.start[i])) + break; + return i; +} + +int bstrspn(struct bstr str, const char *accept) +{ + int i; + for (i = 0; i < str.len; i++) + if (!strchr(accept, str.start[i])) + break; + return i; +} + +int bstr_find(struct bstr haystack, struct bstr needle) +{ + for (int i = 0; i < haystack.len; i++) + if (bstr_startswith(bstr_splice(haystack, i, haystack.len), needle)) + return i; + return -1; +} + +struct bstr bstr_lstrip(struct bstr str) +{ + while (str.len && mp_isspace(*str.start)) { + str.start++; + str.len--; + } + return str; +} + +struct bstr bstr_strip(struct bstr str) +{ + str = bstr_lstrip(str); + while (str.len && mp_isspace(str.start[str.len - 1])) + str.len--; + return str; +} + +struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest) +{ + int start; + for (start = 0; start < str.len; start++) + if (!strchr(sep, str.start[start])) + break; + str = bstr_cut(str, start); + int end = bstrcspn(str, sep); + if (rest) { + *rest = bstr_cut(str, end); + } + return bstr_splice(str, 0, end); +} + +// Unlike with bstr_split(), tok is a string, and not a set of char. +// If tok is in str, return true, and: concat(out_left, tok, out_right) == str +// Otherwise, return false, and set out_left==str, out_right=="" +bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right) +{ + bstr bsep = bstr0(tok); + int pos = bstr_find(str, bsep); + if (pos < 0) + pos = str.len; + *out_left = bstr_splice(str, 0, pos); + *out_right = bstr_cut(str, pos + bsep.len); + return pos != str.len; +} + +struct bstr bstr_splice(struct bstr str, int start, int end) +{ + if (start < 0) + start += str.len; + if (end < 0) + end += str.len; + end = FFMIN(end, str.len); + start = FFMAX(start, 0); + end = FFMAX(end, start); + str.start += start; + str.len = end - start; + return str; +} + +long long bstrtoll(struct bstr str, struct bstr *rest, int base) +{ + str = bstr_lstrip(str); + char buf[51]; + int len = FFMIN(str.len, 50); + memcpy(buf, str.start, len); + buf[len] = 0; + char *endptr; + long long r = strtoll(buf, &endptr, base); + if (rest) + *rest = bstr_cut(str, endptr - buf); + return r; +} + +double bstrtod(struct bstr str, struct bstr *rest) +{ + str = bstr_lstrip(str); + char buf[101]; + int len = FFMIN(str.len, 100); + memcpy(buf, str.start, len); + buf[len] = 0; + char *endptr; + double r = strtod(buf, &endptr); + if (rest) + *rest = bstr_cut(str, endptr - buf); + return r; +} + +struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str) +{ + if (str.len == 0) + return NULL; + int count = 0; + for (int i = 0; i < str.len; i++) + if (str.start[i] == '\n') + count++; + if (str.start[str.len - 1] != '\n') + count++; + struct bstr *r = talloc_array_ptrtype(talloc_ctx, r, count); + unsigned char *p = str.start; + for (int i = 0; i < count - 1; i++) { + r[i].start = p; + while (*p++ != '\n'); + r[i].len = p - r[i].start; + } + r[count - 1].start = p; + r[count - 1].len = str.start + str.len - p; + return r; +} + +struct bstr bstr_getline(struct bstr str, struct bstr *rest) +{ + int pos = bstrchr(str, '\n'); + if (pos < 0) + pos = str.len; + if (rest) + *rest = bstr_cut(str, pos + 1); + return bstr_splice(str, 0, pos + 1); +} + +struct bstr bstr_strip_linebreaks(struct bstr str) +{ + if (bstr_endswith0(str, "\r\n")) { + str = bstr_splice(str, 0, str.len - 2); + } else if (bstr_endswith0(str, "\n")) { + str = bstr_splice(str, 0, str.len - 1); + } + return str; +} + +bool bstr_eatstart(struct bstr *s, struct bstr prefix) +{ + if (!bstr_startswith(*s, prefix)) + return false; + *s = bstr_cut(*s, prefix.len); + return true; +} + +void bstr_lower(struct bstr str) +{ + for (int i = 0; i < str.len; i++) + str.start[i] = mp_tolower(str.start[i]); +} + +int bstr_sscanf(struct bstr str, const char *format, ...) +{ + char *ptr = bstrdup0(NULL, str); + va_list va; + va_start(va, format); + int ret = vsscanf(ptr, format, va); + va_end(va); + talloc_free(ptr); + return ret; +} + +int bstr_parse_utf8_code_length(unsigned char b) +{ + if (b < 128) + return 1; + int bytes = 7 - av_log2(b ^ 255); + return (bytes >= 2 && bytes <= 4) ? bytes : -1; +} + +int bstr_decode_utf8(struct bstr s, struct bstr *out_next) +{ + if (s.len == 0) + return -1; + unsigned int codepoint = s.start[0]; + s.start++; s.len--; + if (codepoint >= 128) { + int bytes = bstr_parse_utf8_code_length(codepoint); + if (bytes < 0 || s.len < bytes - 1) + return -1; + codepoint &= 127 >> bytes; + for (int n = 1; n < bytes; n++) { + int tmp = (unsigned char)s.start[0]; + if ((tmp & 0xC0) != 0x80) + return -1; + codepoint = (codepoint << 6) | (tmp & ~0xC0); + s.start++; s.len--; + } + if (codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) + return -1; + // Overlong sequences - check taken from libavcodec. + // (The only reason we even bother with this is to make libavcodec's + // retarded subtitle utf-8 check happy.) + unsigned int min = bytes == 2 ? 0x80 : 1 << (5 * bytes - 4); + if (codepoint < min) + return -1; + } + if (out_next) + *out_next = s; + return codepoint; +} + +struct bstr bstr_split_utf8(struct bstr str, struct bstr *out_next) +{ + bstr rest; + int code = bstr_decode_utf8(str, &rest); + if (code < 0) + return (bstr){0}; + if (out_next) + *out_next = rest; + return bstr_splice(str, 0, str.len - rest.len); +} + +int bstr_validate_utf8(struct bstr s) +{ + while (s.len) { + if (bstr_decode_utf8(s, &s) < 0) { + // Try to guess whether the sequence was just cut-off. + unsigned int codepoint = (unsigned char)s.start[0]; + int bytes = bstr_parse_utf8_code_length(codepoint); + if (bytes > 1 && s.len < 6) { + // Manually check validity of left bytes + for (int n = 1; n < bytes; n++) { + if (n >= s.len) { + // Everything valid until now - just cut off. + return -(bytes - s.len); + } + int tmp = (unsigned char)s.start[n]; + if ((tmp & 0xC0) != 0x80) + break; + } + } + return -8; + } + } + return 0; +} + +struct bstr bstr_sanitize_utf8_latin1(void *talloc_ctx, struct bstr s) +{ + bstr new = {0}; + bstr left = s; + unsigned char *first_ok = s.start; + while (left.len) { + int r = bstr_decode_utf8(left, &left); + if (r < 0) { + bstr_xappend(talloc_ctx, &new, (bstr){first_ok, left.start - first_ok}); + mp_append_utf8_bstr(talloc_ctx, &new, (unsigned char)left.start[0]); + left.start += 1; + left.len -= 1; + first_ok = left.start; + } + } + if (!new.start) + return s; + if (first_ok != left.start) + bstr_xappend(talloc_ctx, &new, (bstr){first_ok, left.start - first_ok}); + return new; +} + +static void resize_append(void *talloc_ctx, bstr *s, size_t append_min) +{ + size_t size = talloc_get_size(s->start); + assert(s->len <= size); + if (append_min > size - s->len) { + if (append_min < size) + append_min = size; // preallocate in power of 2s + if (size >= SIZE_MAX / 2 || append_min >= SIZE_MAX / 2) + abort(); // oom + s->start = talloc_realloc_size(talloc_ctx, s->start, size + append_min); + } +} + +// Append the string, so that *s = *s + append. s->start is expected to be +// a talloc allocation (which can be realloced) or NULL. +// This function will always implicitly append a \0 after the new string for +// convenience. +// talloc_ctx will be used as parent context, if s->start is NULL. +void bstr_xappend(void *talloc_ctx, bstr *s, bstr append) +{ + resize_append(talloc_ctx, s, append.len + 1); + memcpy(s->start + s->len, append.start, append.len); + s->len += append.len; + s->start[s->len] = '\0'; +} + +void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + bstr_xappend_vasprintf(talloc_ctx, s, fmt, ap); + va_end(ap); +} + +// Exactly as bstr_xappend(), but with a formatted string. +void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt, + va_list ap) +{ + int size; + va_list copy; + va_copy(copy, ap); + char c; + size = vsnprintf(&c, 1, fmt, copy); + va_end(copy); + + if (size < 0) + abort(); + + resize_append(talloc_ctx, s, size + 1); + vsnprintf(s->start + s->len, size + 1, fmt, ap); + s->len += size; +} + +bool bstr_case_startswith(struct bstr s, struct bstr prefix) +{ + struct bstr start = bstr_splice(s, 0, prefix.len); + return start.len == prefix.len && bstrcasecmp(start, prefix) == 0; +} + +bool bstr_case_endswith(struct bstr s, struct bstr suffix) +{ + struct bstr end = bstr_cut(s, -suffix.len); + return end.len == suffix.len && bstrcasecmp(end, suffix) == 0; +} + +struct bstr bstr_strip_ext(struct bstr str) +{ + int dotpos = bstrrchr(str, '.'); + if (dotpos < 0) + return str; + return (struct bstr){str.start, dotpos}; +} + +struct bstr bstr_get_ext(struct bstr s) +{ + int dotpos = bstrrchr(s, '.'); + if (dotpos < 0) + return (struct bstr){NULL, 0}; + return bstr_splice(s, dotpos + 1, s.len); +} diff --git a/misc/bstr.h b/misc/bstr.h new file mode 100644 index 0000000000..a1e99dd4a5 --- /dev/null +++ b/misc/bstr.h @@ -0,0 +1,214 @@ +/* + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPLAYER_BSTR_H +#define MPLAYER_BSTR_H + +#include +#include +#include +#include +#include + +#include "talloc.h" +#include "osdep/compiler.h" + +/* NOTE: 'len' is size_t, but most string-handling functions below assume + * that input size has been sanity checked and len fits in an int. + */ +typedef struct bstr { + unsigned char *start; + size_t len; +} bstr; + +// If str.start is NULL, return NULL. +static inline char *bstrdup0(void *talloc_ctx, struct bstr str) +{ + return talloc_strndup(talloc_ctx, (char *)str.start, str.len); +} + +// Like bstrdup0(), but always return a valid C-string. +static inline char *bstrto0(void *talloc_ctx, struct bstr str) +{ + return str.start ? bstrdup0(talloc_ctx, str) : talloc_strdup(talloc_ctx, ""); +} + +// Return start = NULL iff that is true for the original. +static inline struct bstr bstrdup(void *talloc_ctx, struct bstr str) +{ + struct bstr r = { NULL, str.len }; + if (str.start) + r.start = (unsigned char *)talloc_memdup(talloc_ctx, str.start, str.len); + return r; +} + +static inline struct bstr bstr0(const char *s) +{ + return (struct bstr){(unsigned char *)s, s ? strlen(s) : 0}; +} + +int bstrcmp(struct bstr str1, struct bstr str2); +int bstrcasecmp(struct bstr str1, struct bstr str2); +int bstrchr(struct bstr str, int c); +int bstrrchr(struct bstr str, int c); +int bstrspn(struct bstr str, const char *accept); +int bstrcspn(struct bstr str, const char *reject); + +int bstr_find(struct bstr haystack, struct bstr needle); +struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str); +struct bstr bstr_lstrip(struct bstr str); +struct bstr bstr_strip(struct bstr str); +struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest); +bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right); +struct bstr bstr_splice(struct bstr str, int start, int end); +long long bstrtoll(struct bstr str, struct bstr *rest, int base); +double bstrtod(struct bstr str, struct bstr *rest); +void bstr_lower(struct bstr str); +int bstr_sscanf(struct bstr str, const char *format, ...); + +// Decode the UTF-8 code point at the start of the string, and return the +// character. +// After calling this function, *out_next will point to the next character. +// out_next can be NULL. +// On error, -1 is returned, and *out_next is not modified. +int bstr_decode_utf8(struct bstr str, struct bstr *out_next); + +// Return the UTF-8 code point at the start of the string. +// After calling this function, *out_next will point to the next character. +// out_next can be NULL. +// On error, an empty string is returned, and *out_next is not modified. +struct bstr bstr_split_utf8(struct bstr str, struct bstr *out_next); + +// Return the length of the UTF-8 sequence that starts with the given byte. +// Given a string char *s, the next UTF-8 code point is to be expected at +// s + bstr_parse_utf8_code_length(s[0]) +// On error, -1 is returned. On success, it returns a value in the range [1, 4]. +int bstr_parse_utf8_code_length(unsigned char b); + +// Return >= 0 if the string is valid UTF-8, otherwise negative error code. +// Embedded \0 bytes are considered valid. +// This returns -N if the UTF-8 string was likely just cut-off in the middle of +// an UTF-8 sequence: -1 means 1 byte was missing, -5 5 bytes missing. +// If the string was likely not cut off, -8 is returned. +// Use (return_value > -8) to check whether the string is valid UTF-8 or valid +// but cut-off UTF-8. +int bstr_validate_utf8(struct bstr s); + +// Force the input string to valid UTF-8. If invalid UTF-8 encoding is +// encountered, the invalid bytes are interpreted as Latin-1. +// Embedded \0 bytes are considered valid. +// If replacement happens, a newly allocated string is returned (with a \0 +// byte added past its end for convenience). The string is allocated via +// talloc, with talloc_ctx as parent. +struct bstr bstr_sanitize_utf8_latin1(void *talloc_ctx, struct bstr s); + +// Return the text before the next line break, and return it. Change *rest to +// point to the text following this line break. (rest can be NULL.) +// Line break characters are not stripped. +struct bstr bstr_getline(struct bstr str, struct bstr *rest); + +// Strip one trailing line break. This is intended for use with bstr_getline, +// and will remove the trailing \n or \r\n sequence. +struct bstr bstr_strip_linebreaks(struct bstr str); + +void bstr_xappend(void *talloc_ctx, bstr *s, bstr append); +void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...) + PRINTF_ATTRIBUTE(3, 4); +void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt, va_list va) + PRINTF_ATTRIBUTE(3, 0); + +// If s starts with prefix, return true and return the rest of the string in s. +bool bstr_eatstart(struct bstr *s, struct bstr prefix); + +bool bstr_case_startswith(struct bstr s, struct bstr prefix); +bool bstr_case_endswith(struct bstr s, struct bstr suffix); +struct bstr bstr_strip_ext(struct bstr str); +struct bstr bstr_get_ext(struct bstr s); + +static inline struct bstr bstr_cut(struct bstr str, int n) +{ + if (n < 0) { + n += str.len; + if (n < 0) + n = 0; + } + if (((size_t)n) > str.len) + n = str.len; + return (struct bstr){str.start + n, str.len - n}; +} + +static inline bool bstr_startswith(struct bstr str, struct bstr prefix) +{ + if (str.len < prefix.len) + return false; + return !memcmp(str.start, prefix.start, prefix.len); +} + +static inline bool bstr_startswith0(struct bstr str, const char *prefix) +{ + return bstr_startswith(str, bstr0(prefix)); +} + +static inline bool bstr_endswith(struct bstr str, struct bstr suffix) +{ + if (str.len < suffix.len) + return false; + return !memcmp(str.start + str.len - suffix.len, suffix.start, suffix.len); +} + +static inline bool bstr_endswith0(struct bstr str, const char *suffix) +{ + return bstr_endswith(str, bstr0(suffix)); +} + +static inline int bstrcmp0(struct bstr str1, const char *str2) +{ + return bstrcmp(str1, bstr0(str2)); +} + +static inline bool bstr_equals(struct bstr str1, struct bstr str2) +{ + return bstrcmp(str1, str2) == 0; +} + +static inline bool bstr_equals0(struct bstr str1, const char *str2) +{ + return bstrcmp(str1, bstr0(str2)) == 0; +} + +static inline int bstrcasecmp0(struct bstr str1, const char *str2) +{ + return bstrcasecmp(str1, bstr0(str2)); +} + +static inline int bstr_find0(struct bstr haystack, const char *needle) +{ + return bstr_find(haystack, bstr0(needle)); +} + +static inline int bstr_eatstart0(struct bstr *s, const char *prefix) +{ + return bstr_eatstart(s, bstr0(prefix)); +} + +// create a pair (not single value!) for "%.*s" printf syntax +#define BSTR_P(bstr) (int)((bstr).len), (bstr).start + +#define WHITESPACE " \f\n\r\t\v" + +#endif /* MPLAYER_BSTR_H */ diff --git a/misc/charset_conv.h b/misc/charset_conv.h index e9efa48444..93bd91cffe 100644 --- a/misc/charset_conv.h +++ b/misc/charset_conv.h @@ -2,7 +2,7 @@ #define MP_CHARSET_CONV_H #include -#include "bstr/bstr.h" +#include "misc/bstr.h" struct mp_log; diff --git a/misc/ring.c b/misc/ring.c index 804e6330b0..41c9c6a99e 100644 --- a/misc/ring.c +++ b/misc/ring.c @@ -21,7 +21,7 @@ #include #include #include "talloc.h" -#include "compat/atomics.h" +#include "osdep/atomics.h" #include "ring.h" struct mp_ring { diff --git a/old-makefile b/old-makefile index d0568c0722..2c3c623eb8 100644 --- a/old-makefile +++ b/old-makefile @@ -146,7 +146,6 @@ SOURCES = audio/audio.c \ audio/out/ao_pcm.c \ audio/out/pull.c \ audio/out/push.c \ - bstr/bstr.c \ common/av_common.c \ common/av_log.c \ common/codecs.c \ @@ -175,6 +174,7 @@ SOURCES = audio/audio.c \ input/input.c \ input/keycodes.c \ input/pipe.c \ + misc/bstr.c \ misc/charset_conv.c \ misc/dispatch.c \ misc/rendezvous.c \ @@ -303,7 +303,6 @@ DIRS = . \ audio/decode \ audio/filter \ audio/out \ - bstr \ common \ compat \ input \ diff --git a/options/m_config.h b/options/m_config.h index 958dc3d5e4..eb255428e0 100644 --- a/options/m_config.h +++ b/options/m_config.h @@ -22,7 +22,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" // m_config provides an API to manipulate the config variables in MPlayer. // It makes use of the Options API to provide a context stack that diff --git a/options/m_option.h b/options/m_option.h index 13afea22df..d0ca211aa1 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -23,7 +23,7 @@ #include #include -#include "bstr/bstr.h" +#include "misc/bstr.h" #include "audio/chmap.h" // m_option allows to parse, print and copy data of various types. diff --git a/options/path.h b/options/path.h index 30ca34d205..6e64cd1d3c 100644 --- a/options/path.h +++ b/options/path.h @@ -22,7 +22,7 @@ #define MPLAYER_PATH_H #include -#include "bstr/bstr.h" +#include "misc/bstr.h" struct mpv_global; diff --git a/osdep/atomics.h b/osdep/atomics.h new file mode 100644 index 0000000000..e5fb717a78 --- /dev/null +++ b/osdep/atomics.h @@ -0,0 +1,77 @@ +/* + * This file is part of mpv. + * Copyright (c) 2013 Stefano Pigozzi + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see . + */ + +#ifndef MP_ATOMICS_H +#define MP_ATOMICS_H + +#include +#include "config.h" + +#define HAVE_ATOMICS 1 + +#if HAVE_STDATOMIC +#include +#else + +// Emulate the parts of C11 stdatomic.h needed by mpv. +// Still relies on gcc/clang atomic builtins. + +typedef struct { volatile unsigned long v; } atomic_ulong; +typedef struct { volatile int v; } atomic_int; +typedef struct { volatile _Bool v; } atomic_bool; +typedef struct { volatile long long v; } atomic_llong; +typedef struct { volatile uint_least32_t v; } atomic_uint_least32_t; +typedef struct { volatile unsigned long long v; } atomic_ullong; + +#define ATOMIC_VAR_INIT(x) \ + {.v = (x)} + +#if HAVE_ATOMIC_BUILTINS + +#define atomic_load(p) \ + __atomic_load_n(&(p)->v, __ATOMIC_SEQ_CST) +#define atomic_store(p, val) \ + __atomic_store_n(&(p)->v, val, __ATOMIC_SEQ_CST) +#define atomic_fetch_add(a, b) \ + __atomic_fetch_add(&(a)->v, b, __ATOMIC_SEQ_CST) + +#elif HAVE_SYNC_BUILTINS + +#define atomic_load(p) \ + __sync_fetch_and_add(&(p)->v, 0) +#define atomic_store(p, val) \ + (__sync_synchronize(), (p)->v = (val), __sync_s