First
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html; charset=ISO-8859-1">
|
||||
<title>EASprintf</title>
|
||||
<link type="text/css" rel="stylesheet"
|
||||
href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body style="background-color: rgb(255, 255, 255);">
|
||||
<h1>EASprintf</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>EAStdC provides a portable
|
||||
version of the C printf family of functions which improves on
|
||||
the C family in the following ways:</p>
|
||||
<ul>
|
||||
<li>Behaves identically on all
|
||||
platforms</li>
|
||||
<li>Provides the full gamut of
|
||||
printf functions, including vsnprintf</li>
|
||||
<li>Is more efficient; executes 20-80% faster. </li>
|
||||
<li>Never allocates memory</li>
|
||||
<li>Provides both 8 and 16 bit
|
||||
versions for all platforms</li>
|
||||
<li>Provides useful
|
||||
extended functionality</li>
|
||||
<li>Complies with the C99
|
||||
standard (except for the %a format, as of this writing)</li>
|
||||
<li>Is readable enough to be
|
||||
traced/debugged by non-experts</li>
|
||||
<li>Is savvy to UTF8 Unicode</li>
|
||||
</ul>
|
||||
<p>The primary disadvantages of
|
||||
EAStdC's printf are:</p>
|
||||
<ul>
|
||||
<li>It doesn't use
|
||||
locale-specific formatting</li>
|
||||
<li>It isn't part of the C/C++
|
||||
standard library</li>
|
||||
</ul>
|
||||
<p>EAStdC doesn't attempt to
|
||||
solve the locale formatting problem because users really are better off
|
||||
using serious locale libraries for such things rather than using the
|
||||
meager support provided by the C standard library. The EALocale library
|
||||
attempts to provide such functionality.</p>
|
||||
<p>EAStdC provides the
|
||||
following functions in 8, 16, and 32 bit versions:
|
||||
</p>
|
||||
<pre><span class="code-example">int Cprintf(WriteFunction8 pWriteFunction, void* pContext, const char8_t* pFormat, ...);
|
||||
int Fprintf(FILE* pFile, const char8_t* pFormat, ...);
|
||||
int Printf(const char8_t* pFormat, ...);
|
||||
int Sprintf(char8_t* pDestination, const char8_t* pFormat, ...);
|
||||
int Snprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, ...);
|
||||
|
||||
int Vcprintf(WriteFunction8 pWriteFunction8, void* pContext, const char8_t* pFormat, va_list arguments);
|
||||
int Vfprintf(FILE* pFile, const char8_t* pFormat, va_list arguments);
|
||||
int Vprintf(const char8_t* pFormat, va_list arguments);
|
||||
int Vsprintf(char8_t* pDestination, const char8_t* pFormat, va_list arguments);
|
||||
int Vsnprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments);<br>int Vscprintf(const char8_t* EA_RESTRICT pFormat, va_list arguments);</span></pre>
|
||||
<p>Also there are:</p>
|
||||
<pre class="code-example">template <typename String>
|
||||
int StringPrintf(String& s, const typename String::value_type* EA_RESTRICT pFormat, ...);</pre>
|
||||
<pre class="code-example">template <typename String>
|
||||
int StringVcprintf(String& s, const typename String::value_type* EA_RESTRICT pFormat, va_list arguments);</pre>
|
||||
<blockquote></blockquote>
|
||||
<h2>Snprintf uses C99 behavior</h2>
|
||||
<p> The EASprintf 'n' functions (Snprintf and Vsnprintf) follow the C99 standard
|
||||
for return value, which is different from some C standard library implementations
|
||||
such as VC++. These functions return the number of characters that would have
|
||||
been written had n been sufficiently large, not counting the terminating null
|
||||
character, or a negative value if an encoding error occurred. Thus, the null-terminated
|
||||
output has been completely written if and only if the returned value is nonnegative
|
||||
and less than n. Another way of saying it is that the return value equal to
|
||||
the strlen of the intended output. See the examples below.</p>
|
||||
<h2>Watch out for common mistakes and security problems</h2>
|
||||
<p> The sprintf family of functions are very convenient but offer numerous opportunities
|
||||
for incorrect usage and security problems. Here is a list of some of the most
|
||||
common issues.</p>
|
||||
<ul>
|
||||
<li>Don't use sprintf unless you are absolutely certain the result will fit
|
||||
into the output buffer. Instead use snprintf.</li>
|
||||
<li>When printing a string, always use <font face="Courier New, Courier, mono" size="-1">printf("%s",
|
||||
pStr)</font> and never <font face="Courier New, Courier, mono" size="-1">printf(pStr)</font>,
|
||||
as the latter may have formatting characters in it.</li>
|
||||
<li>Watch out for platform differences between format types. For example, %u
|
||||
means unsigned int, and you can't use a size_t argument with it on 64 bit
|
||||
platforms. Instead, explicitly cast your arguments to the expected type or
|
||||
use the EASprintf extended format types (see below).</li>
|
||||
<li>Similarly, watch out when passing int8_t and int16_t arguments to EAPrintf
|
||||
(and regular printf), as the compiler will promote them to int and they might
|
||||
not print as you expected, depending on your output format.</li>
|
||||
<li>Watch out for EASprintf's C99 behaviour. C99 behaviour is standard C and
|
||||
is superior to previous C library behaviour, but the previous behaviour exists
|
||||
in the C library today with compilers such as VC++. This behaviour affects
|
||||
the return value of Snprintf/Vsnprintf, and affects the way some format specifiers
|
||||
are rendered.</li>
|
||||
</ul>
|
||||
<h2>Extended Functionality</h2>
|
||||
<p> Printf provides extended
|
||||
format functionality not found in the C99 standard but which is useful
|
||||
nevertheless:</p>
|
||||
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
|
||||
cellspacing="2">
|
||||
<tbody>
|
||||
<tr style="font-weight: bold;">
|
||||
<td>Format/modifier</td>
|
||||
<td>Description</td>
|
||||
<td>Example</td>
|
||||
<td>Example output</td>
|
||||
</tr>
|
||||
<tr style="font-weight: bold;">
|
||||
<td><span style="font-weight: normal;">b</span></td>
|
||||
<td style="font-weight: normal;">Binary
|
||||
output field type (joins d, i, x, o, etc.).</td>
|
||||
<td><span class="code-example-span">printf("0b%b", 255);<br>
|
||||
printf<span style="font-weight: normal;">("%<span style="font-weight: normal;"><span style="font-weight: normal;">#</span></span>b", 255);</span></span> <span class="code-example-span"><br>
|
||||
<span style="font-weight: normal;">printf<span style="font-weight: normal;">("%<span style="font-weight: normal;"><span style="font-weight: normal;">#</span></span>B", 255);</span> </span></span> </td>
|
||||
<td><span class="code-example-span">0b11111111<br>
|
||||
<span style="font-weight: normal;">0b11111111</span></span> <span class="code-example-span"><br>
|
||||
<span style="font-weight: normal;"><span style="font-weight: normal;">0B11111111</span> </span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I8</td>
|
||||
<td>8 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I8d", 0xff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I16</td>
|
||||
<td>16 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I16u", 0xffff);</td>
|
||||
<td class="code-example-span">65535</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I32</td>
|
||||
<td>32 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I32d",
|
||||
0xffffffff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I64</td>
|
||||
<td>64 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I64u",
|
||||
0xffffffffffffffff);</td>
|
||||
<td class="code-example-span">18446744073709551615</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I128</td>
|
||||
<td>128 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I128d",
|
||||
0xffffffffffffffffffffffffffffffff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>'</td>
|
||||
<td>Display a thousands separator.</td>
|
||||
<td class="code-example-span">printf("%'I16u", 0xffff);</td>
|
||||
<td class="code-example-span">65,535</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>SprintfOrdered</h2>
|
||||
<p>EAStdC also provides an ordered sprintf</p>
|
||||
<p>Ordered printf is like printf except it works on "ordered" printf specifiers. This means that instead of using "%4d %f" we give an order to the arguments via an index and colon, as with "%1:4d %2:f". The point, however, is that you can reorder the indexes, as with "%2:f %1:4d". This is particularly useful for formatted string localization, as different locales use subjects and verbs in different orders.<br>
|
||||
<br>
|
||||
User indexes can start at either 0 or 1. Oprintf detects which is in use as it goes. So the following have identical effect:</p>
|
||||
<pre class="code-example">OPrintf("%1:s" %0:f", 3.0, "hello");
|
||||
OPrintf("%2:s" %1:f", 3.0, "hello");</pre>
|
||||
<p> // User indexes must be contiguous and the behaviour of Oprintf is undefined<br>
|
||||
// if the ordering is non-contiguous. There are debug checks to validate <br>
|
||||
// contiguity, so debug tests should catch mistakes. The following is an <br>
|
||||
// example of non-contiguous ordering, as it is missing a "3:" format:<br>
|
||||
// OPrintf("%1:d" %0:d %3:d", 17, 18, 19, 20);<br>
|
||||
</p>
|
||||
<p>Example usage:</p>
|
||||
<pre><span class="code-example">char16_t buffer[80];</span></pre>
|
||||
<p>// The module provides ordered versions of the printf family of functions:<br>
|
||||
// int OCprintf(WriteFunction pFunction, void* pContext, const char_t* pFormat, ...);<br>
|
||||
// int OFprintf(FILE* pFile, const char_t* pFormat, ...);<br>
|
||||
// int OPrintf(cconst char_t* pFormat, ...);<br>
|
||||
// int OSprintf(char_t* pDestination, const char_t* pFormat, ...);<br>
|
||||
// int OSnprintf(char_t* pDestination, size_t n, const char_t* pFormat, ...);<br>
|
||||
//<br>
|
||||
// int OVcprintf(WriteFunction pFunction, void* pContext, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVfprintf(FILE* pFile, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVprintf(const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVsprintf(char_t* pDestination, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVsnprintf(char_t* pDestination, size_t n, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVscprintf(const char* pFormat, va_list arguments);<br>
|
||||
//<br>
|
||||
// Ordered printf is like printf except it works on "ordered" printf specifiers.<br>
|
||||
// This means that instead of using "%4d %f" we give an order to the arguments via <br>
|
||||
// an index and colon, as with "%1:4d %2:f". The point, however, is that you can <br>
|
||||
// reorder the indexes, as with "%2:f %1:4d". This is particularly useful for <br>
|
||||
// formatted string localization, as different locales use subjects and verbs<br>
|
||||
// in different orders.<br>
|
||||
//<br>
|
||||
// User indexes can start at either 0 or 1. Oprintf detects which is in use as <br>
|
||||
// it goes. So the following have identical effect:<br>
|
||||
// OPrintf("%1:s" %0:f", 3.0, "hello");<br>
|
||||
// OPrintf("%2:s" %1:f", 3.0, "hello");<br>
|
||||
//<br>
|
||||
// User indexes must be contiguous and the behaviour of Oprintf is undefined<br>
|
||||
// if the ordering is non-contiguous. There are debug checks to validate <br>
|
||||
// contiguity, so debug tests should catch mistakes. The following is an <br>
|
||||
// example of non-contiguous ordering, as it is missing a "3:" format:<br>
|
||||
// OPrintf("%1:d" %0:d %3:d", 17, 18, 19, 20);<br>
|
||||
/////////////////////////////////////////////////////////////////////////////<br>
|
||||
</p>
|
||||
<h2>Example usage</h2>
|
||||
<p>All examples presume the #include of EASprintf.h.</p>
|
||||
<p>Snprintf usage:</p>
|
||||
<pre><span class="code-example">char16_t buffer[80];
|
||||
int nStrlen = Snprintf16(buffer, 80, "Columbus arrived in %d.", 1492);
|
||||
|
||||
if((unsigned)nStrlen < 80) // Cast to unsigned in order to make any negative values be positive and > 80.
|
||||
puts("success");</span></pre>
|
||||
<p>How to write a function that takes variable arguments (e.g. ...) and passes
|
||||
them to EASprintf:</p>
|
||||
<pre><span class="code-example">#include <stdarg.h>
|
||||
|
||||
void CustomFormattedOutput(const char* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
Vprintf8(pFormat, arguments);
|
||||
va_end(arguments);
|
||||
}</span></pre>
|
||||
<p>How to write a function that does custom formatted output to a buffer that
|
||||
is resized as needed for it. This is useful for the implementation of fail-safe
|
||||
utility functions and for debug tracing systems, among other things.</p>
|
||||
<pre><span class="code-example">#include <stdarg.h>
|
||||
#include <string>
|
||||
|
||||
<span class="code-example-comment">// This is a generic function for doing a sprintf into a C++ std::string object.
|
||||
// If the string object lacks enough space for the output, then the string will
|
||||
// be resized to exactly fit the output.
|
||||
</span>size_t StringSprintf(std::string& s, const char* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
|
||||
if(s.size() < s.capacity())
|
||||
s.resize(s.capacity());
|
||||
|
||||
const int nStrlen = Vsnprintf8(const_cast<char*>(s.data()), s.capacity() + 1, pFormat, arguments);
|
||||
|
||||
va_end(arguments);
|
||||
|
||||
if(nStrlen > (int)s.size())
|
||||
{
|
||||
s.resize(nStrlen);
|
||||
Vsnprintf8(const_cast<char*>(s.data()), s.capacity() + 1, pFormat, arguments);
|
||||
|
||||
return (size_t)nStrlen;
|
||||
}</span></pre>
|
||||
<p>Write to the C stderr stream:</p>
|
||||
<pre><span class="code-example">#include <stdio.h>
|
||||
|
||||
Fprintf8(stderr, "Columbus arrived in %d.", 1492);</span></pre>
|
||||
<p>Vsscanf usage. A complete discussion of the ins and outs of vsscanf are currently
|
||||
beyond the scope of this document. The scanf found in EAPrintf acts the same
|
||||
as with the C++ standard, so you can read about that elsewhere for the time
|
||||
being.</p>
|
||||
<pre><span class="code-example">char16_t buffer[64] = EAText16("Columbus arrived in 1492");
|
||||
int year;
|
||||
|
||||
Vsscanf16(buffer, "Columbus arrived in %d.", &year);</span></pre>
|
||||
<h2>Interface</h2>
|
||||
<p>Printf family</p>
|
||||
<pre><span class="code-example">int Fprintf8(FILE* pFile, const char8_t* pFormat, ...);<br>int Printf8(const char8_t* pFormat, ...);<br>int Sprintf8(char8_t* pDestination, const char8_t* pFormat, ...);<br>int Snprintf8(char8_t* pDestination, size_t n, const char8_t* pFormat, ...);<br><br>int Fprintf16(FILE* pFile, const char16_t* pFormat, ...);<br>int Printf16(const char16_t* pFormat, ...);<br>int Sprintf16(char16_t* pDestination, const char16_t* pFormat, ...);<br>int Snprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, ...);<br></span></pre>
|
||||
<p>Vprintf family</p>
|
||||
<pre><span class="code-example"><span class="code-example-comment">/// Note that vsnprintf was not added to the C standard until C99.<br>/// Here we follow the C99 standard and have the return value of vsnprintf <br>/// return the number of required characters to complete the formatted string.<br>/// This is more useful than the way some libraries implement vsnprintf by <br>/// returning -1 if there isn't enough space. The return value is -1 if there <br>/// was an "encoding error" or the implementation was unable to return a <br>/// value > n upon lack of sufficient space as per the C99 standard.<br>///<br>/// Specification:<br>/// The vsnprintf function is equivalent to snprintf, with the variable <br>/// argument list replaced by arguments, which shall have been initialized <br>/// by the va_start macro (and possibly subsequent va_arg calls). <br>/// The vsnprintf function does not invoke the va_end macro. If copying <br>/// takes place between objects that overlap, the behavior is undefined.<br>///<br>/// The vsnprintf function returns the number of characters that would <br>/// have been written had n been sufficiently large, not counting the <br>/// terminating null character, or a neg ative value if an encoding error <br>/// occurred. Thus, the null-terminated output has been completely written <br>/// if and only if the returned value is nonnegative and less than n.<br>///<br></span>int Vfprintf8(FILE* pFile, const char8_t* pFormat, va_list arguments);<br>int Vprintf8(const char8_t* pFormat, va_list arguments);<br>int Vsprintf8(char8_t* pDestination, const char8_t* pFormat, va_list arguments);<br>int Vsnprintf8(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments);<br><br>int Vfprintf16(FILE* pFile, const char16_t* pFormat, va_list arguments);<br>int Vprintf16(const char16_t* pFormat, va_list arguments);<br>int Vsprintf16(char16_t* pDestination, const char16_t* pFormat, va_list arguments);<br>int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments);<br></span><br>
|
||||
</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user