blob: 7b38e8037a8844763baeebbc358c427e5ccb5d9f [file]
//
// snprintf functions for libppd.
//
// Copyright © 2007-2019 by Apple Inc.
// Copyright © 1997-2007 by Easy Software Products.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
//
// Include necessary headers...
//
#include "string-private.h"
#ifndef HAVE_VSNPRINTF
//
// '_ppd_vsnprintf()' - Format a string into a fixed size buffer.
//
int // O - Number of bytes formatted
_ppd_vsnprintf(char *buffer, // O - Output buffer
size_t bufsize, // O - Size of output buffer
const char *format, // I - printf-style format string
va_list ap) // I - Pointer to additional arguments
{
char *bufptr, // Pointer to position in buffer
*bufend, // Pointer to end of buffer
sign, // Sign of format width
type; // Format type character
int width, // Width of field
prec; // Number of characters of precision
char tformat[100], // Temporary format string for sprintf()
*tptr, // Pointer into temporary format
temp[1024]; // Buffer for formatted numbers
size_t templen; // Length of "temp"
char *s; // Pointer to string
int slen; // Length of string
int bytes; // Total number of bytes needed
//
// Loop through the format string, formatting as needed...
//
bufptr = buffer;
bufend = buffer + bufsize - 1;
bytes = 0;
while (*format)
{
if (*format == '%')
{
tptr = tformat;
*tptr++ = *format++;
if (*format == '%')
{
if (bufptr && bufptr < bufend) *bufptr++ = *format;
bytes ++;
format ++;
continue;
}
else if (strchr(" -+#\'", *format))
{
*tptr++ = *format;
sign = *format++;
}
else
sign = 0;
if (*format == '*')
{
//
// Get width from argument...
//
format ++;
width = va_arg(ap, int);
// Note: Can't use snprintf here since we are implementing this
// function...
sprintf(tptr, "%d", width);
tptr += strlen(tptr);
}
else
{
width = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
width = width * 10 + *format++ - '0';
}
}
if (*format == '.')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
format ++;
if (*format == '*')
{
//
// Get precision from argument...
//
format ++;
prec = va_arg(ap, int);
// Note: Can't use snprintf here since we are implementing this
// function...
sprintf(tptr, "%d", prec);
tptr += strlen(tptr);
}
else
{
prec = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
prec = prec * 10 + *format++ - '0';
}
}
}
else
prec = -1;
if (*format == 'l' && format[1] == 'l')
{
if (tptr < (tformat + sizeof(tformat) - 2))
{
*tptr++ = 'l';
*tptr++ = 'l';
}
format += 2;
}
else if (*format == 'h' || *format == 'l' || *format == 'L')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
}
if (!*format)
break;
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
type = *format++;
*tptr = '\0';
switch (type)
{
case 'E' : // Floating point formats
case 'G' :
case 'e' :
case 'f' :
case 'g' :
if ((width + 2) > sizeof(temp))
break;
// Note: Can't use snprintf here since we are implementing this
// function...
sprintf(temp, tformat, va_arg(ap, double));
templen = strlen(temp);
bytes += (int)templen;
if (bufptr)
{
if ((bufptr + templen) > bufend)
{
strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
memcpy(bufptr, temp, templen + 1);
bufptr += templen;
}
}
break;
case 'B' : // Integer formats
case 'X' :
case 'b' :
case 'd' :
case 'i' :
case 'o' :
case 'u' :
case 'x' :
if ((width + 2) > sizeof(temp))
break;
// Note: Can't use snprintf here since we are implementing this
// function...
sprintf(temp, tformat, va_arg(ap, int));
templen = strlen(temp);
bytes += (int)templen;
if (bufptr)
{
if ((bufptr + templen) > bufend)
{
strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
memcpy(bufptr, temp, templen + 1);
bufptr += templen;
}
}
break;
case 'p' : // Pointer value
if ((width + 2) > sizeof(temp))
break;
// Note: Can't use snprintf here since we are implementing this
// function...
sprintf(temp, tformat, va_arg(ap, void *));
templen = strlen(temp);
bytes += (int)templen;
if (bufptr)
{
if ((bufptr + templen) > bufend)
{
strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
memcpy(bufptr, temp, templen + 1);
bufptr += templen;
}
}
break;
case 'c' : // Character or character array
bytes += width;
if (bufptr)
{
if (width <= 1)
*bufptr++ = va_arg(ap, int);
else
{
if ((bufptr + width) > bufend)
width = (int)(bufend - bufptr);
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
bufptr += width;
}
}
break;
case 's' : // String
if ((s = va_arg(ap, char *)) == NULL)
s = "(null)";
slen = (int)strlen(s);
if (slen > width && prec != width)
width = slen;
bytes += width;
if (bufptr)
{
if ((bufptr + width) > bufend)
width = (int)(bufend - bufptr);
if (slen > width)
slen = width;
if (sign == '-')
{
memcpy(bufptr, s, (size_t)slen);
memset(bufptr + slen, ' ', (size_t)(width - slen));
}
else
{
memset(bufptr, ' ', (size_t)(width - slen));
memcpy(bufptr + width - slen, s, (size_t)slen);
}
bufptr += width;
}
break;
case 'n' : // Output number of chars so far
*(va_arg(ap, int *)) = bytes;
break;
}
}
else
{
bytes ++;
if (bufptr && bufptr < bufend)
*bufptr++ = *format;
format ++;
}
}
//
// Nul-terminate the string and return the number of characters needed.
//
if (bufptr && bufptr < bufend)
*bufptr = '\0';
return (bytes);
}
#endif // !HAVE_VSNPRINT
#ifndef HAVE_SNPRINTF
//
// '_ppd_snprintf()' - Format a string into a fixed size buffer.
//
int // O - Number of bytes formatted
_ppd_snprintf(char *buffer, // O - Output buffer
size_t bufsize, // O - Size of output buffer
const char *format, // I - printf-style format string
...) // I - Additional arguments as needed
{
int bytes; // Number of bytes formatted
va_list ap; // Pointer to additional arguments
va_start(ap, format);
bytes = vsnprintf(buffer, bufsize, format, ap);
va_end(ap);
return (bytes);
}
#endif // !HAVE_SNPRINTF