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

0001 /*****************************************************************************
0002  *   Copyright 2013 - 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 #define __QTC_UTILS_STRS_INTERNAL__
0023 
0024 #include "strs.h"
0025 #include "number.h"
0026 
0027 namespace QtCurve {
0028 namespace Str {
0029 
0030 template<bool allocated>
0031 char*
0032 vformat(char *buff, size_t *_size, const char *fmt, va_list ap)
0033 {
0034     if (!buff || !_size || !*_size) {
0035         char *res = nullptr;
0036         vasprintf(&res, fmt, ap);
0037         return res;
0038     }
0039     va_list _ap;
0040     va_copy(_ap, ap);
0041     size_t size = *_size;
0042     size_t new_size = vsnprintf(buff, size, fmt, ap) + 1;
0043     if (new_size > size) {
0044         new_size = alignTo(new_size, 1024);
0045         if (allocated) {
0046             buff = (char*)realloc(buff, new_size);
0047         } else {
0048             buff = (char*)malloc(new_size);
0049         }
0050         *_size = new_size;
0051         new_size = vsnprintf(buff, new_size, fmt, _ap);
0052     }
0053     return buff;
0054 }
0055 
0056 template QTC_EXPORT char *vformat<true>(char *buff, size_t *size,
0057                                         const char *fmt, va_list ap);
0058 template QTC_EXPORT char *vformat<false>(char *buff, size_t *size,
0059                                          const char *fmt, va_list ap);
0060 
0061 template<>
0062 QTC_EXPORT double
0063 convert<double>(const char *str, const double &def, bool *is_def)
0064 {
0065     if (!str) {
0066         qtcAssign(is_def, true);
0067         return def;
0068     }
0069     str += strspn(str, " \t\b\n\f\v");
0070     char *end = nullptr;
0071     double res = strtod(str, &end);
0072     if (end == str) {
0073         qtcAssign(is_def, true);
0074         res = def;
0075     } else {
0076         qtcAssign(is_def, false);
0077     }
0078     return res;
0079 }
0080 template double convert<double>(const char*, const double&, bool *is_def);
0081 
0082 template<>
0083 QTC_EXPORT long
0084 convert<long>(const char *str, const long &def, bool *is_def)
0085 {
0086     if (!str) {
0087         qtcAssign(is_def, true);
0088         return def;
0089     }
0090     str += strspn(str, " \t\b\n\f\v");
0091     char *end = nullptr;
0092     long res = strtol(str, &end, 0);
0093     if (end == str) {
0094         qtcAssign(is_def, true);
0095         res = def;
0096     } else {
0097         qtcAssign(is_def, false);
0098     }
0099     return res;
0100 }
0101 template long convert<long>(const char*, const long&, bool *is_def);
0102 
0103 template<>
0104 QTC_EXPORT bool
0105 convert<bool>(const char *str, const bool &def, bool *is_def)
0106 {
0107     qtcAssign(is_def, false);
0108     if (str && *str) {
0109         if (def) {
0110             return noneOf<CaseCmp>(str, "0", "f", "false", "off");
0111         } else {
0112             return oneOf<CaseCmp>(str, "1", "t", "true", "on");
0113         }
0114     }
0115     return def;
0116 }
0117 template bool convert<bool>(const char*, const bool&, bool *is_def);
0118 
0119 }
0120 
0121 namespace StrList {
0122 
0123 QTC_EXPORT void
0124 _forEach(const char *str, char delim, char escape,
0125          const std::function<bool(const char*, size_t)> &func)
0126 {
0127     QTC_RET_IF_FAIL(str);
0128     Str::Buff<1024> buff;
0129     if (qtcUnlikely(escape == delim)) {
0130         escape = '\0';
0131     }
0132     const char key[] = {delim, escape, '\0'};
0133     const char *p = str;
0134     while (true) {
0135         size_t len = 0;
0136         while (true) {
0137             size_t sub_len = strcspn(p, key);
0138             buff.resize(len + sub_len + 2);
0139             memcpy(buff.get() + len, p, sub_len);
0140             len += sub_len;
0141             p += sub_len;
0142             if (escape && *p == escape) {
0143                 buff[len] = p[1];
0144                 if (qtcUnlikely(!p[1])) {
0145                     p++;
0146                     break;
0147                 }
0148                 len++;
0149                 p += 2;
0150             } else {
0151                 buff[len] = '\0';
0152                 break;
0153             }
0154         }
0155         if (!func(buff.get(), len) || !*p) {
0156             break;
0157         }
0158         p++;
0159     }
0160 }
0161 }
0162 
0163 }
0164 
0165 QTC_EXPORT void*
0166 qtcStrLoadList(const char *str, char delim, char escape, size_t size,
0167                size_t *_nele, void *buff, size_t max_len,
0168                QtcListEleLoader loader, void *data)
0169 {
0170     QTC_RET_IF_FAIL(_nele && size && loader && str, nullptr);
0171     size_t nele = *_nele;
0172     size_t offset = 0;
0173     if (!(buff && nele)) {
0174         nele = 16;
0175         buff = malloc(16 * size);
0176     }
0177     QtCurve::StrList::forEach(
0178         str, delim, escape, [&] (const char *str, size_t len) {
0179             if (nele <= offset) {
0180                 nele += 8;
0181                 buff = (char*)realloc(buff, nele * size);
0182             }
0183             if (loader((char*)buff + offset * size, str, len, data)) {
0184                 offset++;
0185                 if (max_len && offset >= max_len) {
0186                     return false;
0187                 }
0188             }
0189             return true;
0190         });
0191     *_nele = offset;
0192     if (!*_nele) {
0193         free(buff);
0194         return nullptr;
0195     }
0196     return buff;
0197 }
0198 
0199 static bool
0200 qtcStrListStrLoader(void *ele, const char *str, size_t len, void *data)
0201 {
0202     const char *def = (const char*)data;
0203     if (def && !str[0]) {
0204         *(char**)ele = strdup(def);
0205     } else {
0206         *(char**)ele = QtCurve::Str::dup(nullptr, str, len);
0207     }
0208     return true;
0209 }
0210 
0211 QTC_EXPORT char**
0212 qtcStrLoadStrList(const char *str, char delim, char escape, size_t *nele,
0213                   char **buff, size_t max_len, const char *def)
0214 {
0215     return (char**)qtcStrLoadList(str, delim, escape, sizeof(char*), nele, buff,
0216                                   max_len, qtcStrListStrLoader, (void*)def);
0217 }
0218 
0219 static bool
0220 qtcStrListIntLoader(void *ele, const char *str, size_t, void *data)
0221 {
0222     *(long*)ele = QtCurve::Str::convert(str, (long)(intptr_t)data);
0223     return true;
0224 }
0225 
0226 QTC_EXPORT long*
0227 qtcStrLoadIntList(const char *str, char delim, char escape, size_t *nele,
0228                   long *buff, size_t max_len, long def)
0229 {
0230     return (long*)qtcStrLoadList(str, delim, escape, sizeof(long), nele, buff,
0231                                  max_len, qtcStrListIntLoader,
0232                                  (void*)(intptr_t)def);
0233 }
0234 
0235 static bool
0236 qtcStrListFloatLoader(void *ele, const char *str, size_t, void *data)
0237 {
0238     *(double*)ele = QtCurve::Str::convert(str, *(double*)data);
0239     return true;
0240 }
0241 
0242 QTC_EXPORT double*
0243 qtcStrLoadFloatList(const char *str, char delim, char escape, size_t *nele,
0244                     double *buff, size_t max_len, double def)
0245 {
0246     return (double*)qtcStrLoadList(str, delim, escape, sizeof(double), nele,
0247                                    buff, max_len, qtcStrListFloatLoader, &def);
0248 }