OpenTTD/src/misc/str.hpp

152 lines
3.5 KiB
C++

/* $Id$ */
/*
* This file is part of OpenTTD.
* OpenTTD 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, version 2.
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file str.hpp String formatting? */
#ifndef STR_HPP
#define STR_HPP
#include <errno.h>
#include <stdarg.h>
#include "blob.hpp"
#include "../core/math_func.hpp"
#include "../string_func.h"
/** Blob based case sensitive ANSI/UTF-8 string */
struct CStrA : public CBlobT<char>
{
typedef CBlobT<char> base; ///< base class
/** Create an empty CStrT */
inline CStrA()
{
}
/** Copy constructor */
inline CStrA(const CStrA &src) : base(src)
{
base::FixTail();
}
/** Take over ownership constructor */
inline CStrA(const OnTransfer &ot)
: base(ot)
{
}
/** Grow the actual buffer and fix the trailing zero at the end. */
inline char *GrowSizeNC(uint count)
{
char *ret = base::GrowSizeNC(count);
base::FixTail();
return ret;
}
/** Append zero-ended C string. */
inline void AppendStr(const char *str)
{
if (!StrEmpty(str)) {
base::AppendRaw(str, strlen(str));
base::FixTail();
}
}
/** Append another CStrA. */
inline void Append(const CStrA &src)
{
if (src.Length() > 0) {
base::AppendRaw(src);
base::FixTail();
}
}
/** Assignment from C string. */
inline CStrA &operator=(const char *src)
{
base::Clear();
AppendStr(src);
return *this;
}
/** Assignment from another CStrA. */
inline CStrA &operator=(const CStrA &src)
{
if (&src != this) {
base::Clear();
base::AppendRaw(src.Data(), src.Size());
base::FixTail();
}
return *this;
}
/** Lower-than operator (to support stl collections) */
inline bool operator<(const CStrA &other) const
{
return strcmp(base::Data(), other.Data()) < 0;
}
/** Add formatted string (like vsprintf) at the end of existing contents. */
int AddFormatL(const char *format, va_list args)
{
size_t addSize = max<size_t>(strlen(format), 16);
addSize += addSize / 2;
int ret;
int err = 0;
for (;;) {
char *buf = MakeFreeSpace(addSize);
ret = vseprintf(buf, buf + base::GetReserve() - 1, format, args);
if (ret >= (int)base::GetReserve()) {
/* Greater return than given count means needed buffer size. */
addSize = ret + 1;
continue;
}
if (ret >= 0) {
/* success */
break;
}
err = errno;
if (err != ERANGE && err != ENOENT && err != 0) {
/* some strange failure */
break;
}
/* small buffer (M$ implementation) */
addSize *= 2;
}
if (ret > 0) {
GrowSizeNC(ret);
} else {
base::FixTail();
}
return ret;
}
/** Add formatted string (like sprintf) at the end of existing contents. */
int CDECL WARN_FORMAT(2, 3) AddFormat(const char *format, ...)
{
va_list args;
va_start(args, format);
int ret = AddFormatL(format, args);
va_end(args);
return ret;
}
/** Assign formatted string (like sprintf). */
int CDECL WARN_FORMAT(2, 3) Format(const char *format, ...)
{
base::Free();
va_list args;
va_start(args, format);
int ret = AddFormatL(format, args);
va_end(args);
return ret;
}
};
#endif /* STR_HPP */