diff --git a/bstr.c b/bstr.c index 3cc3928086..d86b488912 100644 --- a/bstr.c +++ b/bstr.c @@ -18,6 +18,10 @@ #include #include +#include + +#include "talloc.h" + #include "bstr.h" int bstrcmp(struct bstr str1, struct bstr str2) @@ -49,3 +53,90 @@ int bstrcasecmp(struct bstr str1, struct bstr str2) } 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; +} + +struct bstr bstr_strip(struct bstr str) +{ + while (str.len && isspace(*str.start)) { + str.start++; + str.len--; + } + while (str.len && isspace(str.start[str.len - 1])) + str.len--; + return str; +} + +struct bstr bstr_split(struct bstr str, char *sep, struct bstr *rest) +{ + int start, end; + for (start = 0; start < str.len; start++) + if (!strchr(sep, str.start[start])) + break; + for (end = start; end < str.len; end++) + if (strchr(sep, str.start[end])) + break; + if (rest) { + *rest = bstr_cut(str, end); + } + str.start += start; + str.len = end - start; + return str; +} + + +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); + if (start >= end) + return (struct bstr){NULL, 0}; + str.start += start; + str.len = end - start; + return str; +} + +long long bstrtoll(struct bstr str, struct bstr *rest, int base) +{ + 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; +} + +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; +} diff --git a/bstr.h b/bstr.h index 459bf70bef..33a47c0abc 100644 --- a/bstr.h +++ b/bstr.h @@ -22,18 +22,50 @@ #include #include #include +#include +#include "talloc.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. + */ struct bstr { - const uint8_t *start; + unsigned char *start; size_t len; }; int bstrcmp(struct bstr str1, struct bstr str2); int bstrcasecmp(struct bstr str1, struct bstr str2); +int bstrchr(struct bstr str, int c); +struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str); +struct bstr bstr_strip(struct bstr str); +struct bstr bstr_split(struct bstr str, char *sep, struct bstr *rest); +struct bstr bstr_splice(struct bstr str, int start, int end); +long long bstrtoll(struct bstr str, struct bstr *rest, int base); + +static inline struct bstr bstr_cut(struct bstr str, int n) +{ + 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 char *bstrdup0(void *talloc_ctx, struct bstr str) +{ + // cast is live555 C++ compilation workaround + return talloc_strndup(talloc_ctx, (char *)str.start, str.len); +} // Create bstr compound literal from null-terminated string -#define BSTR(s) (struct bstr){(s), (s) ? strlen(s) : 0} +#define BSTR(s) (struct bstr){(char *)(s), (s) ? strlen(s) : 0} // 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/osdep/findfiles.c b/osdep/findfiles.c index 879f6d5c98..e35174dfd4 100644 --- a/osdep/findfiles.c +++ b/osdep/findfiles.c @@ -22,38 +22,18 @@ #include #include "talloc.h" - -#if defined(__MINGW32__) || defined(__CYGWIN__) -static const char dir_separators[] = "/\\:"; -#else -static const char dir_separators[] = "/"; -#endif +#include "path.h" +#include "bstr.h" char **find_files(const char *original_file, const char *suffix, int *num_results_ptr) { void *tmpmem = talloc_new(NULL); - char *fname = talloc_strdup(tmpmem, original_file); - char *basename = NULL; - char *next = fname; - while (1) { - next = strpbrk(next, dir_separators); - if (!next) - break; - basename = next++; - } - char *directory; - if (basename) { - directory = fname; - *basename++ = 0; - } else { - directory = "."; - basename = fname; - } - - + char *basename = mp_basename(original_file); + struct bstr directory = mp_dirname(original_file); char **results = talloc_size(NULL, 0); - DIR *dp = opendir(directory); + char *dir_zero = bstrdup0(tmpmem, directory); + DIR *dp = opendir(dir_zero); struct dirent *ep; char ***names_by_matchlen = talloc_array(tmpmem, char **, strlen(basename) + 1); @@ -68,7 +48,7 @@ char **find_files(const char *original_file, const char *suffix, if (!strcmp(ep->d_name, basename)) continue; - char *name = talloc_asprintf(results, "%s/%s", directory, ep->d_name); + char *name = mp_path_join(results, directory, BSTR(ep->d_name)); char *s1 = ep->d_name; char *s2 = basename; int matchlen = 0; diff --git a/path.c b/path.c index 7f4ce88f17..f97e8a6c3a 100644 --- a/path.c +++ b/path.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "config.h" #include "mp_msg.h" #include "path.h" @@ -42,6 +43,8 @@ #include #endif +#include "talloc.h" + #include "osdep/osdep.h" char *get_path(const char *filename){ @@ -194,7 +197,7 @@ void set_codec_path(const char *path) needs_free = 1; } -const char *mp_basename(const char *path) +char *mp_basename(const char *path) { char *s; @@ -207,5 +210,41 @@ const char *mp_basename(const char *path) path = s + 1; #endif s = strrchr(path, '/'); - return s ? s + 1 : path; + return s ? s + 1 : (char *)path; +} + +struct bstr mp_dirname(const char *path) +{ + struct bstr ret = {(uint8_t *)path, mp_basename(path) - path}; + if (ret.len == 0) + return BSTR("."); + return ret; +} + +char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2) +{ + if (p1.len == 0) + return bstrdup0(talloc_ctx, p2); + if (p2.len == 0) + return bstrdup0(talloc_ctx, p1); + +#if HAVE_DOS_PATHS + if (p2.len >= 2 && p2.start[1] == ':' + || p2.start[0] == '\\' || p2.start[0] == '/') +#else + if (p2.start[0] == '/') +#endif + return bstrdup0(talloc_ctx, p2); // absolute path + + bool have_separator; + int endchar1 = p1.start[p1.len - 1]; +#if HAVE_DOS_PATHS + have_separator = endchar1 == '/' || endchar1 == '\\' + || p1.len == 2 && endchar1 == ':'; // "X:" only +#else + have_separator = endchar1 == '/'; +#endif + + return talloc_asprintf(talloc_ctx, "%.*s%s%.*s", BSTR_P(p1), + have_separator ? "" : "/", BSTR_P(p2)); } diff --git a/path.h b/path.h index 349f55e3cc..ffa052d680 100644 --- a/path.h +++ b/path.h @@ -21,11 +21,27 @@ #ifndef MPLAYER_PATH_H #define MPLAYER_PATH_H +#include "bstr.h" + extern char *codec_path; char *get_path(const char *filename); void set_path_env(void); void set_codec_path(const char *path); -const char *mp_basename(const char *path); + +// Return pointer to filename part of path + +char *mp_basename(const char *path); + +/* Return struct bstr referencing directory part of path, or if that + * would be empty, ".". + */ +struct bstr mp_dirname(const char *path); + +/* Join two path components and return a newly allocated string + * for the result. '/' is inserted between the components if needed. + * If p2 is an absolute path then the value of p1 is ignored. + */ +char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2); #endif /* MPLAYER_PATH_H */