Отрыл любопытнейший исходник, если коротко, то относительно просто можно ввести форматирование строки как в старом добром C (аля printf):
cout << c_format("test: %d", 100) << endl;
Вначале моя "all-in-one" сборка в одном cpp файле и в конце - оригинал из XORP.
c_format.cpp#include <iostream>
#include <vector>
#include <cstdarg>
using namespace std;
#ifndef HOST_OS_WINDOWS
#define HAVE_C99_SNPRINTF // [v]snprintf() conforms to ISO C99 spec
#endif
#define FORMAT_BUFSIZE 4096
#define c_format(format, args...) \
(c_format_validate(format, arg_count(args)), do_c_format(format, ## args))
inline int arg_count() { return 0; }
template <class A>
inline int arg_count(A) { return 1; }
template <class A, class B>
inline int arg_count(A,B) { return 2; }
template <class A, class B, class C>
inline int arg_count(A,B,C) { return 3; }
template <class A, class B, class C, class D>
inline int arg_count(A,B,C,D) { return 4; }
template <class A, class B, class C, class D, class E>
inline int arg_count(A,B,C,D,E) { return 5; }
template <class A, class B, class C,class D, class E, class F>
inline int arg_count(A,B,C,D,E,F) { return 6; }
template <class A, class B, class C, class D, class E, class F, class G>
inline int arg_count(A,B,C,D,E,F,G) { return 7; }
template <class A, class B, class C, class D, class E, class F, class G,
class H>
inline int arg_count(A,B,C,D,E,F,G,H) { return 8; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I>
inline int arg_count(A,B,C,D,E,F,G,H,I) { return 9; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J>
inline int arg_count(A,B,C,D,E,F,G,H,I,J) { return 10; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K) { return 11; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L) { return 12; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L, class M>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M) { return 13; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L, class M, class N>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M,N) { return 14; }
void c_format_validate(const char* fmt, int n);
#if defined(__printflike)
string do_c_format(const char* fmt, ...) __printflike(1,2);
#elif (defined(__GNUC__))
string do_c_format(const char* fmt, ...)
__attribute__((__format__(printf, 1, 2)));
#else
string do_c_format(const char* fmt, ...);
#endif
void
c_format_validate(const char* fmt, int exp_count)
{
const char *p = fmt;
int state = 0;
int count = 0;
while(*p != 0) {
if (state == 0) {
if (*p == '%') {
count++;
state = 1;
}
} else {
switch (*p) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'D':
case 'O':
case 'U':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
case 'c':
case 's':
case 'p':
//parameter type specifiers
state = 0;
break;
case '%':
//escaped percent
state = 0;
count--;
break;
case 'n':
//we don't permit %n
fprintf(stderr, "%%n detected in c_format()\n");
abort();
case '*':
//field width or precision also needs a parameter
count++;
break;
}
}
p++;
}
if (exp_count != count) {
abort();
}
}
string
do_c_format(const char* fmt, ...)
{
size_t buf_size = FORMAT_BUFSIZE; // Default buffer size
vector<char> b(buf_size);
va_list ap;
do {
va_start(ap, fmt);
int ret = vsnprintf(&b[0], buf_size, fmt, ap);
#ifndef HAVE_C99_SNPRINTF
// We have an evil vsnprintf() implementation (MSVC)
if (ret != -1 && ((size_t)ret < buf_size)) {
string r = string(&b[0]); // Buffer size is OK
va_end(ap);
return r;
}
buf_size += FORMAT_BUFSIZE;
#else // HAVE_C99_SNPRINTF
// We have a C99 compliant implementation
if ((size_t)ret < buf_size) {
string r = string(&b[0]); // Buffer size is OK
va_end(ap);
return r;
}
buf_size = ret + 1; // Add space for the extra '\0'
#endif // HAVE_C99_SNPRINTF
b.resize(buf_size);
} while (true);
// XLOG_UNREACHABLE();
}
int main()
{
cout << c_format("test: %d", 100) << endl;
return 0;
}
Исходник из проекта
XORP:
c_format.hh // -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
// $XORP: xorp/libxorp/c_format.hh,v 1.10 2007/02/16 22:46:15 pavlin Exp $
#ifndef __LIBXORP_C_FORMAT_HH__
#define __LIBXORP_C_FORMAT_HH__
#include "libxorp/xorp.h"
//
// c_format is a macro that creates a string from a c-style format
// string. It takes the same arguments as printf, but %n is illegal and
// will cause abort to be called.
//
// Pseudo prototype:
// string c_format(const char* format, ...);
//
// In practice c_format is a nasty macro, but by doing this we can check
// the compile time arguments are sane and the run time arguments.
//
#define c_format(format, args...) \
(c_format_validate(format, arg_count(args)), do_c_format(format, ## args))
//
// Template magic to allow us to count the number of varargs passed to
// the macro c_format. We could also count the size of the var args data
// for extra protection if we were doing the formatting ourselves...
//
// Comment this out to find unnecessary calls to c_format()
inline int arg_count() { return 0; }
template <class A>
inline int arg_count(A) { return 1; }
template <class A, class B>
inline int arg_count(A,B) { return 2; }
template <class A, class B, class C>
inline int arg_count(A,B,C) { return 3; }
template <class A, class B, class C, class D>
inline int arg_count(A,B,C,D) { return 4; }
template <class A, class B, class C, class D, class E>
inline int arg_count(A,B,C,D,E) { return 5; }
template <class A, class B, class C,class D, class E, class F>
inline int arg_count(A,B,C,D,E,F) { return 6; }
template <class A, class B, class C, class D, class E, class F, class G>
inline int arg_count(A,B,C,D,E,F,G) { return 7; }
template <class A, class B, class C, class D, class E, class F, class G,
class H>
inline int arg_count(A,B,C,D,E,F,G,H) { return 8; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I>
inline int arg_count(A,B,C,D,E,F,G,H,I) { return 9; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J>
inline int arg_count(A,B,C,D,E,F,G,H,I,J) { return 10; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K) { return 11; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L) { return 12; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L, class M>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M) { return 13; }
template <class A, class B, class C, class D, class E, class F, class G,
class H, class I, class J, class K, class L, class M, class N>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M,N) { return 14; }
void c_format_validate(const char* fmt, int n);
#if defined(__printflike)
string do_c_format(const char* fmt, ...) __printflike(1,2);
#elif (defined(__GNUC__))
string do_c_format(const char* fmt, ...)
__attribute__((__format__(printf, 1, 2)));
#else
string do_c_format(const char* fmt, ...);
#endif
#endif // __LIBXORP_C_FORMAT_HH__
c_format.cc// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
#ident "$XORP: xorp/libxorp/c_format.cc,v 1.12 2007/02/16 22:46:15 pavlin Exp $"
#include "libxorp_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include <vector>
#include "c_format.hh"
#ifndef HOST_OS_WINDOWS
#define HAVE_C99_SNPRINTF // [v]snprintf() conforms to ISO C99 spec
#endif
#define FORMAT_BUFSIZE 4096
void
c_format_validate(const char* fmt, int exp_count)
{
const char *p = fmt;
int state = 0;
int count = 0;
while(*p != 0) {
if (state == 0) {
if (*p == '%') {
count++;
state = 1;
}
} else {
switch (*p) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'D':
case 'O':
case 'U':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
case 'c':
case 's':
case 'p':
//parameter type specifiers
state = 0;
break;
case '%':
//escaped percent
state = 0;
count--;
break;
case 'n':
//we don't permit %n
fprintf(stderr, "%%n detected in c_format()\n");
abort();
case '*':
//field width or precision also needs a parameter
count++;
break;
}
}
p++;
}
if (exp_count != count) {
abort();
}
}
string
do_c_format(const char* fmt, ...)
{
size_t buf_size = FORMAT_BUFSIZE; // Default buffer size
vector<char> b(buf_size);
va_list ap;
do {
va_start(ap, fmt);
int ret = vsnprintf(&b[0], buf_size, fmt, ap);
#ifndef HAVE_C99_SNPRINTF
// We have an evil vsnprintf() implementation (MSVC)
if (ret != -1 && ((size_t)ret < buf_size)) {
string r = string(&b[0]); // Buffer size is OK
va_end(ap);
return r;
}
buf_size += FORMAT_BUFSIZE;
#else // HAVE_C99_SNPRINTF
// We have a C99 compliant implementation
if ((size_t)ret < buf_size) {
string r = string(&b[0]); // Buffer size is OK
va_end(ap);
return r;
}
buf_size = ret + 1; // Add space for the extra '\0'
#endif // HAVE_C99_SNPRINTF
b.resize(buf_size);
} while (true);
XLOG_UNREACHABLE();
}
#ifdef TESTING_C_FORMAT_123
int main(int, char**)
{
c_format("%d", 3);
printf("%s", c_format("hello%%\n").c_str());
printf("%s", c_format("hello %d\n", 27).c_str());
printf("%s", c_format("hello %3d %%%s\n", 27, "xyz").c_str());
printf("%s", c_format("hello %*d %%%s\n", 5, 27, "xyz").c_str());
printf("%s", c_format("hello %%%*n\n").c_str());
}
#endif // TESTING_C_FORMAT_123
Сообщение отредактировал Andrew Selivanov - 22.4.2008, 17:34