- Refactored lang yet again, `fennec/lang` is now C++ language. `fennec/string` `fennec/filesystem` and `fennec/format` are now independent.
141 lines
3.4 KiB
C++
141 lines
3.4 KiB
C++
// =====================================================================================================================
|
|
// fennec, a free and open source game engine
|
|
// Copyright © 2025 Medusa Slockbower
|
|
//
|
|
// This program 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 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
// =====================================================================================================================
|
|
|
|
///
|
|
/// \file format.h
|
|
/// \brief
|
|
///
|
|
///
|
|
/// \details
|
|
/// \author Medusa Slockbower
|
|
///
|
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
|
///
|
|
///
|
|
|
|
#ifndef FENNEC_LANG_STRINGS_FORMAT_H
|
|
#define FENNEC_LANG_STRINGS_FORMAT_H
|
|
|
|
#include <fennec/string/string.h>
|
|
|
|
#include <fennec/format/detail/_format.h>
|
|
#include <fennec/format/formatter.h>
|
|
|
|
namespace fennec
|
|
{
|
|
|
|
template<typename...ArgsT>
|
|
string format(const cstring& str, ArgsT&&...args) {
|
|
static constexpr size_t argc = sizeof...(ArgsT);
|
|
static constexpr format_arg default_fmt = {
|
|
.fill { // default no fill
|
|
.c = '\0',
|
|
.n = 0,
|
|
},
|
|
.align = '\0', // default to locale
|
|
.sign = '-', // default to sign only for negative numbers
|
|
.alt = false, // default no prefix
|
|
.width = 0,
|
|
.precision = 0,
|
|
.type = '\0',
|
|
};
|
|
|
|
// empty case
|
|
if constexpr(argc == 0) {
|
|
return str;
|
|
}
|
|
|
|
detail::_format_argarray<argc> argarray = { fennec::forward<ArgsT>(args)... };
|
|
string res;
|
|
size_t i = 0;
|
|
size_t a = -1;
|
|
|
|
while (i <= str.length()) {
|
|
size_t b = str.find('{', i);
|
|
size_t e = str.find('}', i);
|
|
format_arg fmt = default_fmt;
|
|
|
|
// check for '}}'
|
|
if (e < b) {
|
|
if (str[e + 1] == '}') {
|
|
res += string(str.data() + i, e - i);
|
|
i = e + 2;
|
|
continue;
|
|
}
|
|
assertf(false, "fennec::format syntax error, encountered unexpected '{'")
|
|
}
|
|
|
|
// append string
|
|
if (b >= str.length()) { // handle end case
|
|
res += string(str.data() + i, str.length() - i);
|
|
break;
|
|
}
|
|
res += string(str.data() + i, b - i);
|
|
|
|
// next brace, validate escape
|
|
size_t nb = str.find('{', b + 1);
|
|
if (b + 1 == nb) {
|
|
res += '{';
|
|
i = nb + 1;
|
|
continue;
|
|
}
|
|
|
|
// find contained colon
|
|
size_t c = str.find(':', b);
|
|
|
|
// validate colon and brace location
|
|
assertf(c < nb or e < nb, "fennec::format syntax error, mismatched '{}'");
|
|
|
|
// parse index if present
|
|
size_t id = min(c, e) - 1;
|
|
if (id > b) {
|
|
a = 0;
|
|
} else {
|
|
++a;
|
|
}
|
|
for (size_t j = id, k = 1; j > b; --j, k *= 10) {
|
|
size_t u = (str[j] - '0');
|
|
assertf(u < 10, "fennec::format syntax error, invalid argument index");
|
|
a += k * u;
|
|
}
|
|
|
|
// validate index
|
|
assertf(a < argc, "fennec::format syntax error, invalid argument index");
|
|
|
|
// early return case for no colon
|
|
if (c > e) {
|
|
res += argarray.format(a, fmt);
|
|
i = e + 1;
|
|
continue;
|
|
}
|
|
|
|
// parse format specifiers
|
|
|
|
|
|
|
|
// add formatted argument
|
|
res += argarray.format(a, fmt);
|
|
i = e + 1;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
}
|
|
|
|
#endif // FENNEC_LANG_STRINGS_FORMAT_H
|