mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 19:29:09 +00:00
Add framework for plFormat
This commit is contained in:
@ -51,6 +51,7 @@ set(CoreLib_SOURCES
|
||||
hsWide.cpp
|
||||
pcSmallRect.cpp
|
||||
plFileSystem.cpp
|
||||
plFormat.cpp
|
||||
plGeneric.cpp
|
||||
plLoadMask.cpp
|
||||
plProduct.cpp
|
||||
@ -96,6 +97,7 @@ set(CoreLib_HEADERS
|
||||
hsWindows.h
|
||||
pcSmallRect.h
|
||||
plFileSystem.h
|
||||
plFormat.h
|
||||
plGeneric.h
|
||||
plLoadMask.h
|
||||
plProduct.h
|
||||
|
187
Sources/Plasma/CoreLib/plFormat.cpp
Normal file
187
Sources/Plasma/CoreLib/plFormat.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "plFormat.h"
|
||||
|
||||
#include "HeadSpin.h"
|
||||
|
||||
namespace plFormat_Private
|
||||
{
|
||||
static const char *_scanNextFormat(IFormatDataObject &data)
|
||||
{
|
||||
hsAssert(data.fFormatStr, "Passed a null format string!");
|
||||
|
||||
const char *ptr = data.fFormatStr;
|
||||
while (*ptr) {
|
||||
if (*ptr == '{')
|
||||
return ptr;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void _fetchPrefixChunk(IFormatDataObject &data)
|
||||
{
|
||||
do {
|
||||
const char *next = _scanNextFormat(data);
|
||||
if (*next && *(next + 1) == '{') {
|
||||
// Escaped '{'
|
||||
data.fOutput.push_back(plStringBuffer<char>(data.fFormatStr, 1 + next - data.fFormatStr));
|
||||
data.fFormatStr = next + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next != data.fFormatStr)
|
||||
data.fOutput.push_back(plStringBuffer<char>(data.fFormatStr, next - data.fFormatStr));
|
||||
data.fFormatStr = next;
|
||||
} while (0);
|
||||
}
|
||||
|
||||
FormatSpec FetchNextFormat(IFormatDataObject &data)
|
||||
{
|
||||
_fetchPrefixChunk(data);
|
||||
hsAssert(*data.fFormatStr == '{', "Too many actual parameters for format string");
|
||||
|
||||
FormatSpec spec;
|
||||
const char *ptr = data.fFormatStr;
|
||||
for ( ;; ) {
|
||||
++ptr;
|
||||
|
||||
switch (*ptr) {
|
||||
case 0:
|
||||
hsAssert(0, "Unterminated format specifier.");
|
||||
abort();
|
||||
case '}':
|
||||
// Done with format spec
|
||||
data.fFormatStr = ptr + 1;
|
||||
return spec;
|
||||
break;
|
||||
|
||||
case '<':
|
||||
spec.fAlignment = kAlignLeft;
|
||||
break;
|
||||
case '>':
|
||||
spec.fAlignment = kAlignRight;
|
||||
break;
|
||||
case '_':
|
||||
spec.fPadChar = *(ptr + 1);
|
||||
hsAssert(spec.fPadChar, "Unterminated format specifier");
|
||||
++ptr;
|
||||
break;
|
||||
case 'x':
|
||||
spec.fDigitClass = kDigitHex;
|
||||
break;
|
||||
case 'X':
|
||||
spec.fDigitClass = kDigitHexUpper;
|
||||
break;
|
||||
case 'd':
|
||||
spec.fDigitClass = kDigitDec;
|
||||
break;
|
||||
case 'o':
|
||||
spec.fDigitClass = kDigitOct;
|
||||
break;
|
||||
case 'b':
|
||||
spec.fDigitClass = kDigitBin;
|
||||
break;
|
||||
case 'c':
|
||||
spec.fDigitClass = kDigitChar;
|
||||
break;
|
||||
case 'f':
|
||||
spec.fFloatClass = kFloatF;
|
||||
break;
|
||||
case 'g':
|
||||
spec.fFloatClass = kFloatG;
|
||||
break;
|
||||
case 'e':
|
||||
spec.fFloatClass = kFloatE;
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
{
|
||||
char *end = nullptr;
|
||||
spec.fPrecisionLeft = strtol(ptr, &end, 10);
|
||||
ptr = end - 1;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
{
|
||||
hsAssert(*(ptr + 1), "Unterminated format specifier");
|
||||
char *end = nullptr;
|
||||
spec.fPrecisionRight = strtol(ptr + 1, &end, 10);
|
||||
ptr = end - 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hsAssert(0, "Unexpected character in format string");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plString _IFormat(plFormat_Private::IFormatDataObject &data)
|
||||
{
|
||||
_fetchPrefixChunk(data);
|
||||
hsAssert(*data.fFormatStr == 0, "Not enough actual parameters for format string");
|
||||
|
||||
size_t outsize = 0;
|
||||
for (const plStringBuffer<char> &buf : data.fOutput)
|
||||
outsize += buf.GetSize();
|
||||
|
||||
plStringBuffer<char> outbuf;
|
||||
char *out_ptr = outbuf.CreateWritableBuffer(outsize);
|
||||
for (const plStringBuffer<char> &buf : data.fOutput) {
|
||||
memcpy(out_ptr, buf.GetData(), buf.GetSize());
|
||||
out_ptr += buf.GetSize();
|
||||
}
|
||||
*out_ptr = 0;
|
||||
|
||||
return outbuf;
|
||||
}
|
||||
}
|
||||
|
||||
PL_FORMAT_IMPL(int)
|
||||
{
|
||||
char buffer[32];
|
||||
int size = snprintf(buffer, 32, "%d", value);
|
||||
return plStringBuffer<char>(buffer, size);
|
||||
}
|
176
Sources/Plasma/CoreLib/plFormat.h
Normal file
176
Sources/Plasma/CoreLib/plFormat.h
Normal file
@ -0,0 +1,176 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plFormat_Defined
|
||||
#define plFormat_Defined
|
||||
|
||||
#include "plString.h"
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
/* (TODO: Make this table doxygen-friendly)
|
||||
*
|
||||
* FORMAT SPECIFICATION
|
||||
*
|
||||
* {} - format a value (defaults)
|
||||
* {{ - Escape for a single '{' char
|
||||
* {options} - Format a value, with the specified options (see below)
|
||||
*
|
||||
* Options:
|
||||
* < - Align left
|
||||
* > - Align right
|
||||
* NNN - Pad to NNN characters (minimum - can be more)
|
||||
* _C - Use C as the pad character (only '\001'..'\177' supported for now)
|
||||
* x - Hex (lower-case)
|
||||
* X - Hex (upper-case)
|
||||
* o - Octal
|
||||
* b - Binary
|
||||
* d - Decimal (default) -- when used with char types, outputs a
|
||||
* number instead of the UTF representation of the char
|
||||
* c - UTF character (default for character types)
|
||||
* FFF.EEE - Use FFF.EEE floating point precision
|
||||
* f - Use 'f' format for floating point numbers
|
||||
* g - Use 'g' format for floating point numbers
|
||||
* e - Use 'e' format for floating point numbers
|
||||
*/
|
||||
|
||||
// For internal use by plFormat and its helper function
|
||||
namespace plFormat_Private
|
||||
{
|
||||
enum Alignment : unsigned char
|
||||
{
|
||||
kAlignDefault, kAlignLeft, kAlignRight
|
||||
};
|
||||
|
||||
enum DigitClass : unsigned char
|
||||
{
|
||||
kDigitDefault, kDigitDec, kDigitHex, kDigitHexUpper,
|
||||
kDigitOct, kDigitBin, kDigitChar
|
||||
};
|
||||
|
||||
enum FloatClass : unsigned char
|
||||
{
|
||||
kFloatDefault, kFloatE, kFloatF, kFloatG
|
||||
};
|
||||
|
||||
struct FormatSpec
|
||||
{
|
||||
const char *fEnd;
|
||||
|
||||
int fPrecisionLeft = 0;
|
||||
int fPrecisionRight = 0;
|
||||
|
||||
char fPadChar = 0;
|
||||
Alignment fAlignment = kAlignDefault;
|
||||
DigitClass fDigitClass = kDigitDefault;
|
||||
FloatClass fFloatClass = kFloatDefault;
|
||||
};
|
||||
|
||||
struct IFormatDataObject
|
||||
{
|
||||
const char *fFormatStr;
|
||||
std::list<plStringBuffer<char>> fOutput;
|
||||
};
|
||||
|
||||
extern FormatSpec FetchNextFormat(IFormatDataObject &data);
|
||||
}
|
||||
|
||||
// Fun fact: You can add your own formatters by declaring
|
||||
// PL_FORMAT_TYPE(mytype) in a header, and
|
||||
// PL_FORMAT_IMPL(mytype) { ... } in a source file
|
||||
|
||||
#define PL_FORMAT_TYPE(_type) \
|
||||
extern plStringBuffer<char> _impl_plFormat_DataHandler( \
|
||||
plFormat_Private::FormatSpec &format, _type value); \
|
||||
namespace plFormat_Private \
|
||||
{ \
|
||||
template <typename... _Args> \
|
||||
plString _IFormat(IFormatDataObject &data, _type value, _Args... args) \
|
||||
{ \
|
||||
plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat(data); \
|
||||
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \
|
||||
return _IFormat(data, args...); \
|
||||
} \
|
||||
} \
|
||||
template <typename... _Args> \
|
||||
plString plFormat(const char *fmt_str, _type value, _Args... args) \
|
||||
{ \
|
||||
plFormat_Private::IFormatDataObject data; \
|
||||
data.fFormatStr = fmt_str; \
|
||||
plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat(data); \
|
||||
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \
|
||||
return plFormat_Private::_IFormat(data, args...); \
|
||||
}
|
||||
|
||||
#define PL_FORMAT_IMPL(_type) \
|
||||
plStringBuffer<char> _impl_plFormat_DataHandler( \
|
||||
plFormat_Private::FormatSpec &format, _type value)
|
||||
|
||||
PL_FORMAT_TYPE(char)
|
||||
PL_FORMAT_TYPE(wchar_t)
|
||||
PL_FORMAT_TYPE(signed char)
|
||||
PL_FORMAT_TYPE(unsigned char)
|
||||
PL_FORMAT_TYPE(short)
|
||||
PL_FORMAT_TYPE(unsigned short)
|
||||
PL_FORMAT_TYPE(int)
|
||||
PL_FORMAT_TYPE(unsigned)
|
||||
PL_FORMAT_TYPE(long)
|
||||
PL_FORMAT_TYPE(unsigned long)
|
||||
PL_FORMAT_TYPE(int64_t)
|
||||
PL_FORMAT_TYPE(uint64_t)
|
||||
PL_FORMAT_TYPE(float)
|
||||
PL_FORMAT_TYPE(double)
|
||||
PL_FORMAT_TYPE(const char *)
|
||||
PL_FORMAT_TYPE(const wchar_t *)
|
||||
PL_FORMAT_TYPE(const plString &)
|
||||
|
||||
// TODO: Remove these when they're no longer needed
|
||||
PL_FORMAT_TYPE(const std::string &)
|
||||
PL_FORMAT_TYPE(const std::wstring &)
|
||||
|
||||
// End of the chain -- emits the last piece (if any) and builds the final string
|
||||
namespace plFormat_Private
|
||||
{
|
||||
plString _IFormat(IFormatDataObject &data);
|
||||
}
|
||||
|
||||
#endif // plFormat_Defined
|
Reference in New Issue
Block a user