| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- <!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>
|