File indexing completed on 2024-04-28 05:46:51

0001 /*****************************************************************************
0002  *   Copyright 2012 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0003  *                                                                           *
0004  *   This program is free software; you can redistribute it and/or modify    *
0005  *   it under the terms of the GNU Lesser General Public License as          *
0006  *   published by the Free Software Foundation; either version 2.1 of the    *
0007  *   License, or (at your option) version 3, or any later version accepted   *
0008  *   by the membership of KDE e.V. (or its successor approved by the         *
0009  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0010  *   Section 6 of version 3 of the license.                                  *
0011  *                                                                           *
0012  *   This program is distributed in the hope that it will be useful,         *
0013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0015  *   Lesser General Public License for more details.                         *
0016  *                                                                           *
0017  *   You should have received a copy of the GNU Lesser General Public        *
0018  *   License along with this library. If not,                                *
0019  *   see <http://www.gnu.org/licenses/>.                                     *
0020  *****************************************************************************/
0021 
0022 #ifndef _QTC_UTILS_STRS_H_
0023 #define _QTC_UTILS_STRS_H_
0024 
0025 #include "utils.h"
0026 #include <stdarg.h>
0027 
0028 #include <array>
0029 #include <numeric>
0030 #include <functional>
0031 #include <string>
0032 
0033 namespace QtCurve {
0034 
0035 class uniqueStr : public uniqueCPtr<char> {
0036 public:
0037     // TODO add back when when we drop gcc 4.7 support.
0038     // using uniqueCPtr<char>::uniqueCPtr;
0039     uniqueStr(char *p)
0040         : uniqueCPtr<char>(p)
0041     {
0042     }
0043     template<typename T,
0044              typename std::enable_if<
0045                  std::is_convertible<decltype(std::declval<T>()()),
0046                                      char*>::value>::type* = nullptr>
0047     uniqueStr(T &&f)
0048         : uniqueStr((char*)f())
0049     {
0050     }
0051 };
0052 
0053 namespace Str {
0054 
0055 QTC_ALWAYS_INLINE static inline bool
0056 startsWith(const char *str, const char *head)
0057 {
0058     return strncmp(str, head, strlen(head)) == 0;
0059 }
0060 
0061 QTC_ALWAYS_INLINE static inline bool
0062 endsWith(const char *str, const char *tail)
0063 {
0064     size_t len1 = strlen(str);
0065     size_t len2 = strlen(tail);
0066     if (len2 > len1) {
0067         return false;
0068     }
0069     return memcmp(str + len1 - len2, tail, len2) == 0;
0070 }
0071 
0072 QTC_ALWAYS_INLINE static inline char*
0073 dup(char *dest, const char *src, size_t len)
0074 {
0075     dest = (char*)realloc(dest, len + 1);
0076     memcpy(dest, src, len);
0077     dest[len] = '\0';
0078     return dest;
0079 }
0080 QTC_ALWAYS_INLINE static inline char*
0081 dup(char *dest, const char *src)
0082 {
0083     return dup(dest, src, strlen(src));
0084 }
0085 QTC_ALWAYS_INLINE static inline char*
0086 dup(const char *src)
0087 {
0088     return strdup(src);
0089 }
0090 
0091 template<bool allocated=true> __attribute__((format(printf, 3, 0)))
0092 char *vformat(char *buff, size_t *size, const char *fmt, va_list ap);
0093 
0094 #ifndef __QTC_UTILS_STRS_INTERNAL__
0095 extern template __attribute__((format(printf, 3, 0)))
0096 char *vformat<true>(char *buff, size_t *size, const char *fmt, va_list ap);
0097 extern template __attribute__((format(printf, 3, 0)))
0098 char *vformat<false>(char *buff, size_t *size, const char *fmt, va_list ap);
0099 #endif
0100 
0101 template<bool allocated=true>
0102 __attribute__((format(printf, 3, 4)))
0103 static inline char*
0104 format(char *buff, size_t *size, const char *fmt, ...)
0105 {
0106     va_list ap;
0107     va_start(ap, fmt);
0108     char *res = vformat<allocated>(buff, size, fmt, ap);
0109     va_end(ap);
0110     return res;
0111 }
0112 
0113 template <typename... ArgTypes>
0114 QTC_ALWAYS_INLINE static inline char*
0115 fill(char *buff, ArgTypes&&...strs)
0116 {
0117     const std::array<const char*, sizeof...(strs)> strs_l{{strs...}};
0118     const std::array<size_t, sizeof...(strs)> str_lens{{strlen(strs)...}};
0119     const size_t total_len = std::accumulate(str_lens.begin(),
0120                                              str_lens.end(), 0);
0121     char *res = (buff ? (char*)realloc(buff, total_len + 1) :
0122                  (char*)malloc(total_len + 1));
0123     char *p = res;
0124     for (size_t i = 0;i < sizeof...(strs);i++) {
0125         memcpy(p, strs_l[i], str_lens[i]);
0126         p += str_lens[i];
0127     }
0128     res[total_len] = 0;
0129     return res;
0130 }
0131 
0132 template <typename... ArgTypes>
0133 QTC_ALWAYS_INLINE static inline char*
0134 cat(ArgTypes&&... strs)
0135 {
0136     return fill(nullptr, std::forward<ArgTypes>(strs)...);
0137 }
0138 
0139 template<size_t N>
0140 class Buff : public LocalBuff<char, N> {
0141 public:
0142     Buff(size_t size=N, const char *ary=nullptr)
0143         : LocalBuff<char, N>(size, ary)
0144     {}
0145     Buff(const char *str)
0146         : Buff(str ? strlen(str) + 1 : 0, str)
0147     {}
0148     operator char*() const
0149     {
0150         return this->get();
0151     }
0152     __attribute__((format(printf, 2, 3)))
0153     char*
0154     printf(const char *fmt, ...)
0155     {
0156         va_list ap;
0157         va_start(ap, fmt);
0158         if (this->is_static()) {
0159             size_t new_size = N;
0160             char *res = vformat<false>(this->m_ptr, &new_size, fmt, ap);
0161             if (res != this->m_ptr) {
0162                 this->m_ptr = res;
0163                 this->m_size = new_size;
0164             }
0165         } else {
0166             this->m_ptr = vformat(this->m_ptr, &this->m_size, fmt, ap);
0167         }
0168         va_end(ap);
0169         return this->m_ptr;
0170     }
0171     template <typename... ArgTypes>
0172     inline char*
0173     cat(ArgTypes&&... strs)
0174     {
0175         return this->append_from(0, std::forward<ArgTypes>(strs)...);
0176     }
0177     template <typename... ArgTypes>
0178     inline char*
0179     append(ArgTypes&&... strs)
0180     {
0181         return this->append_from(strlen(this->m_ptr),
0182                                  std::forward<ArgTypes>(strs)...);
0183     }
0184     template <typename... ArgTypes>
0185     inline char*
0186     append_from(size_t orig_len, ArgTypes&&... strs)
0187     {
0188         const std::array<const char*, sizeof...(strs)> strs_l{{strs...}};
0189         const std::array<size_t, sizeof...(strs)> str_lens{{strlen(strs)...}};
0190         const size_t total_len = std::accumulate(str_lens.begin(),
0191                                                  str_lens.end(), 0) + orig_len;
0192         this->resize(total_len);
0193         char *p = this->m_ptr + orig_len;
0194         for (size_t i = 0;i < sizeof...(strs);i++) {
0195             memcpy(p, strs_l[i], str_lens[i]);
0196             p += str_lens[i];
0197         }
0198         this->m_ptr[total_len] = 0;
0199         return this->m_ptr;
0200     }
0201 };
0202 
0203 template<typename T>
0204 T convert(const char*, const T &def=T(), bool *is_def=nullptr);
0205 
0206 #ifndef __QTC_UTILS_STRS_INTERNAL__
0207 extern template double convert<double>(const char*, const double& =0,
0208                                        bool* =nullptr);
0209 extern template long convert<long>(const char*, const long& =0, bool* =nullptr);
0210 extern template bool convert<bool>(const char*, const bool& =false,
0211                                    bool* =nullptr);
0212 #endif
0213 
0214 template<>
0215 inline std::string
0216 convert<std::string>(const char *str, const std::string&, bool *is_def)
0217 {
0218     qtcAssign(is_def, false);
0219     return std::string(str);
0220 }
0221 
0222 template<>
0223 inline char*
0224 convert<char*>(const char *str, char *const&, bool *is_def)
0225 {
0226     qtcAssign(is_def, false);
0227     return strdup(str);
0228 }
0229 
0230 }
0231 
0232 namespace StrList {
0233 
0234 void _forEach(const char *str, char delim, char escape,
0235               const std::function<bool(const char*, size_t)> &func);
0236 
0237 template<typename Func, typename... Args>
0238 static inline auto
0239 _forEachCaller(const char *str, size_t len, Func &func, Args&... args)
0240     -> typename std::enable_if<std::is_same<decltype(func(str, len, args...)),
0241                                             bool>::value, bool>::type
0242 {
0243     return func(str, len, args...);
0244 }
0245 
0246 template<typename Func, typename... Args>
0247 static inline auto
0248 _forEachCaller(const char *str, size_t, Func &func, Args&... args)
0249     -> typename std::enable_if<std::is_same<decltype(func(str, args...)),
0250                                             bool>::value, bool>::type
0251 {
0252     return func(str, args...);
0253 }
0254 
0255 template<typename Func, typename... Args>
0256 static inline void
0257 forEach(const char *str, char delim, char escape, Func &&func, Args&&... args)
0258 {
0259     using namespace std::placeholders;
0260     _forEach(str, delim, escape,
0261              std::bind(_forEachCaller<typename std::decay<Func>::type,
0262                        typename std::decay<Args>::type...>, _1, _2,
0263                        std::forward<Func>(func), std::forward<Args>(args)...));
0264 }
0265 template<typename Func, typename... Args>
0266 static inline typename std::enable_if<!_isChar<Func>::value>::type
0267 forEach(const char *str, char delim, Func &&func, Args&&... args)
0268 {
0269     forEach(str, delim, '\\', std::forward<Func>(func),
0270             std::forward<Args>(args)...);
0271 }
0272 template<typename Func, typename... Args>
0273 static inline typename std::enable_if<!_isChar<Func>::value>::type
0274 forEach(const char *str, Func &&func, Args&&... args)
0275 {
0276     forEach(str, ',', std::forward<Func>(func), std::forward<Args>(args)...);
0277 }
0278 
0279 }
0280 }
0281 
0282 typedef bool (*QtcListEleLoader)(void *ele, const char *str,
0283                                  size_t len, void *data);
0284 
0285 void *qtcStrLoadList(const char *str, char delim, char escape,
0286                      size_t size, size_t *nele, void *buff, size_t max_len,
0287                      QtcListEleLoader loader, void *data=nullptr);
0288 #define qtcStrLoadList(str, delim, escape, size, nele,                  \
0289                        buff, max_len, loader, data...)                  \
0290     qtcStrLoadList(str, QTC_DEFAULT(delim, ','), QTC_DEFAULT(escape, '\\'), \
0291                    size, nele, QTC_DEFAULT(buff, nullptr),              \
0292                    QTC_DEFAULT(max_len, 0), loader, ##data)
0293 
0294 char **qtcStrLoadStrList(const char *str, char delim, char escape, size_t *nele,
0295                          char **buff, size_t max_len, const char *def);
0296 #define qtcStrLoadStrList(str, delim, escape, nele, buff, max_len, def) \
0297     qtcStrLoadStrList(str, QTC_DEFAULT(delim, ','),                     \
0298                       QTC_DEFAULT(escape, '\\'), nele,                  \
0299                       QTC_DEFAULT(buff, nullptr), QTC_DEFAULT(max_len, 0), \
0300                       QTC_DEFAULT(def, nullptr))
0301 
0302 long *qtcStrLoadIntList(const char *str, char delim, char escape,
0303                         size_t *nele, long *buff=nullptr,
0304                         size_t max_len=0, long def=0);
0305 #define qtcStrLoadIntList(str, delim, escape, nele, extra...)   \
0306     qtcStrLoadIntList(str, QTC_DEFAULT(delim, ','),             \
0307                       QTC_DEFAULT(escape, '\\'), nele, ##extra)
0308 
0309 double *qtcStrLoadFloatList(const char *str, char delim, char escape,
0310                             size_t *nele, double *buff=nullptr,
0311                             size_t max_len=0, double def=0);
0312 #define qtcStrLoadFloatList(str, delim, escape, nele, extra...)         \
0313     qtcStrLoadFloatList(str, QTC_DEFAULT(delim, ','),                   \
0314                         QTC_DEFAULT(escape, '\\'), nele, ##extra)
0315 
0316 #endif