// SensibleFormat.h
//
// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
// The purpose of this file is to define a generic format command that works reasonably even when there's no heap free
// Because it uses a stack buffer in this case, it is very difficult to make this a generic function without macroing
// Because I needed a 16-bit variant as well, and even templating would generate the same amount of code, I've done it
// as a #includable code snippet
// Note: If you do define SF_WIDE, Collapse() will be called on the result of the format before being passed to SF_ACTION
// If you want to pass in a VA_LIST, then #define SF_LIST aArgList
// If you want to pass in a bunch of arguments, #define SF_ARGLIST arg1,arg2,arg3
#if !defined(SF_FORMAT) || !defined(SF_BUF) || !defined(SF_ACTION)
#error "you must define all of SF_FORMAT, SF_BUF and SF_ACTION before including this file"
#endif
#if !((defined(SF_LIST) && !defined(SF_ARGLIST)) || (!defined(SF_LIST) && defined(SF_ARGLIST)))
#error "you must define exactly one of SF_LIST and SF_ARGLIST before including this file"
#endif
#ifndef COMMON_H
#error "you need to include common.h somewhere before including this file"
#endif
#ifdef SF_WIDE
#define TOverflowX TOverflow16
#define TBufX TBuf16<256>
#else
#define TOverflowX TOverflow8
#define TBufX TBuf8<256>
#endif
#ifdef SF_ARGLIST
#define SFAppend() AppendFormat(SF_FORMAT, &overflow, SF_ARGLIST)
#else
#define SFAppend() AppendFormatList(SF_FORMAT, SF_LIST, &overflow)
#endif
// Think of this as Format(RBuf8& SF_BUF, FunctionPointer SF_ACTION, const TDesCX& SF_FORMAT, TBool SF_STACKONLY, VA_LIST SF_LIST)
// where SF_ACTION(SF_BUF) is called passing in the fully formatted string
{
const TInt minBufSize = Max(SF_BUF.MaxSize(), 512);
const TInt KMaxBufSize = 8192;
TInt err = KErrNone;
#ifdef SF_STACKONLY
if (SF_STACKONLY)
{
err = KErrNoMemory;
}
else
#endif
{
if (SF_BUF.MaxSize() == 0)
{
err = SF_BUF.Create(256);
}
else
{
SF_BUF.Zero();
}
}
TOverflowX overflow;
if (err == KErrNone)
{
// Do clever things to try and ensure that the format string won't be truncated, while at the same time not allocating an insanely big buffer
for (TInt bufSize = minBufSize; bufSize <= KMaxBufSize; bufSize*=2)
{
#ifdef SF_WIDE
TPtr16 widePtr((TUint16*)SF_BUF.Ptr(), SF_BUF.MaxSize()/2);
widePtr.SFAppend();
#else
SF_BUF.SFAppend();
#endif
if (!overflow.iOverflow)
{
// Then the format went ok
#ifdef SF_WIDE
TPtr8 collapsed = widePtr.Collapse();
SF_ACTION(collapsed);
#else
SF_ACTION(SF_BUF);
#endif
break;
}
else
{
// Overflowed
if (bufSize == KMaxBufSize)
{
// We've grown up to our (self-imposed) max buf size, so just live with the truncation
#ifdef SF_WIDE
TPtr8 collapsed = widePtr.Collapse();
SF_ACTION(collapsed);
#else
SF_ACTION(SF_BUF);
#endif
break;
}
// Try and grow
SF_BUF.Close();
err = SF_BUF.Create(bufSize*2);
if (err) break;
else continue;
}
}
}
if (err)
{
// Last resort, use 256 char buf on the stack
TBufX stackBuf;
stackBuf.SFAppend(); // Silently truncate if overflow happens now
#ifdef SF_WIDE
TPtr8 collapsed = stackBuf.Collapse();
SF_ACTION(collapsed);
#else
SF_ACTION(stackBuf);
#endif
}
}
#undef SF_WIDE
#undef SF_FORMAT
#undef SF_LIST
#undef SF_ARGLIST
#undef SF_BUF
#undef SF_ACTION
#undef TBufX
#undef TOverflowX
#undef SFAppend
#undef SF_STACKONLY