17db96d56Sopenharmony_ci#include "Python.h"
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci/* snprintf() and vsnprintf() wrappers.
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci   If the platform has vsnprintf, we use it, else we
67db96d56Sopenharmony_ci   emulate it in a half-hearted way.  Even if the platform has it, we wrap
77db96d56Sopenharmony_ci   it because platforms differ in what vsnprintf does in case the buffer
87db96d56Sopenharmony_ci   is too small:  C99 behavior is to return the number of characters that
97db96d56Sopenharmony_ci   would have been written had the buffer not been too small, and to set
107db96d56Sopenharmony_ci   the last byte of the buffer to \0.  At least MS _vsnprintf returns a
117db96d56Sopenharmony_ci   negative value instead, and fills the entire buffer with non-\0 data.
127db96d56Sopenharmony_ci   Unlike C99, our wrappers do not support passing a null buffer.
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci   The wrappers ensure that str[size-1] is always \0 upon return.
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci   PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
177db96d56Sopenharmony_ci   (including the trailing '\0') into str.
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci   Return value (rv):
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci    When 0 <= rv < size, the output conversion was unexceptional, and
227db96d56Sopenharmony_ci    rv characters were written to str (excluding a trailing \0 byte at
237db96d56Sopenharmony_ci    str[rv]).
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci    When rv >= size, output conversion was truncated, and a buffer of
267db96d56Sopenharmony_ci    size rv+1 would have been needed to avoid truncation.  str[size-1]
277db96d56Sopenharmony_ci    is \0 in this case.
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    When rv < 0, "something bad happened".  str[size-1] is \0 in this
307db96d56Sopenharmony_ci    case too, but the rest of str is unreliable.  It could be that
317db96d56Sopenharmony_ci    an error in format codes was detected by libc, or on platforms
327db96d56Sopenharmony_ci    with a non-C99 vsnprintf simply that the buffer wasn't big enough
337db96d56Sopenharmony_ci    to avoid truncation, or on platforms without any vsnprintf that
347db96d56Sopenharmony_ci    PyMem_Malloc couldn't obtain space for a temp buffer.
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci   CAUTION:  Unlike C99, str != NULL and size > 0 are required.
377db96d56Sopenharmony_ci   Also, size must be smaller than INT_MAX.
387db96d56Sopenharmony_ci*/
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ciint
417db96d56Sopenharmony_ciPyOS_snprintf(char *str, size_t size, const  char  *format, ...)
427db96d56Sopenharmony_ci{
437db96d56Sopenharmony_ci    int rc;
447db96d56Sopenharmony_ci    va_list va;
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci    va_start(va, format);
477db96d56Sopenharmony_ci    rc = PyOS_vsnprintf(str, size, format, va);
487db96d56Sopenharmony_ci    va_end(va);
497db96d56Sopenharmony_ci    return rc;
507db96d56Sopenharmony_ci}
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ciint
537db96d56Sopenharmony_ciPyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
547db96d56Sopenharmony_ci{
557db96d56Sopenharmony_ci    assert(str != NULL);
567db96d56Sopenharmony_ci    assert(size > 0);
577db96d56Sopenharmony_ci    assert(size <= (INT_MAX - 1));
587db96d56Sopenharmony_ci    assert(format != NULL);
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci    int len;  /* # bytes written, excluding \0 */
617db96d56Sopenharmony_ci    /* We take a size_t as input but return an int.  Sanity check
627db96d56Sopenharmony_ci     * our input so that it won't cause an overflow in the
637db96d56Sopenharmony_ci     * vsnprintf return value.  */
647db96d56Sopenharmony_ci    if (size > INT_MAX - 1) {
657db96d56Sopenharmony_ci        len = -666;
667db96d56Sopenharmony_ci        goto Done;
677db96d56Sopenharmony_ci    }
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci#if defined(_MSC_VER)
707db96d56Sopenharmony_ci    len = _vsnprintf(str, size, format, va);
717db96d56Sopenharmony_ci#else
727db96d56Sopenharmony_ci    len = vsnprintf(str, size, format, va);
737db96d56Sopenharmony_ci#endif
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ciDone:
767db96d56Sopenharmony_ci    if (size > 0) {
777db96d56Sopenharmony_ci        str[size-1] = '\0';
787db96d56Sopenharmony_ci    }
797db96d56Sopenharmony_ci    return len;
807db96d56Sopenharmony_ci}
81