in PAL/HAPBase+String.c [21:182]
HAPError HAPStringWithFormatAndArguments(char* bytes, size_t maxBytes, const char* format, va_list arguments) {
HAPPrecondition(bytes);
HAPPrecondition(format);
char c = format[0];
size_t i = 1;
size_t n = 0;
while (c) {
if (c == '%') {
// insert value
c = format[i++]; // format defaults:
char prefix = ' '; // fill with space
char sign = 0; // do not us a positive sign
uint32_t length = 0; // no long type
uint32_t width = 0; // minimum width
// flags field
while (c == '0' || c == '+' || c == ' ') {
if (c == '0') {
prefix = '0';
} else {
sign = c;
}
c = format[i++];
}
// width field
while (c >= '0' && c <= '9') {
width = width * 10 + (uint32_t)(c - '0');
c = format[i++];
}
// length field
if (c == 'l') {
length = 1;
c = format[i++];
if (c == 'l') {
length = 2;
c = format[i++];
}
} else if (c == 'z') {
length = 3;
c = format[i++];
}
// type field
char buffer[32]; // temporary string buffer
char* string = NULL;
size_t strLen = 0;
int64_t sValue = 0;
uint64_t uValue = 0;
switch (c) {
case '%': {
string = "%";
} break;
case 'd':
case 'i': {
if (length == 0) {
sValue = (int64_t) va_arg(arguments, int);
} else if (length == 1) { // 'l'
sValue = (int64_t) va_arg(arguments, long);
} else if (length == 2) { // 'll'
sValue = (int64_t) va_arg(arguments, long long);
} else { // 'z'
sValue = (int64_t) va_arg(arguments, size_t);
}
} break;
case 'x':
case 'X':
case 'u': {
if (length == 0) {
uValue = (uint64_t) va_arg(arguments, unsigned int);
} else if (length == 1) { // 'l'
uValue = (uint64_t) va_arg(arguments, unsigned long);
} else if (length == 2) { // 'll'
uValue = (uint64_t) va_arg(arguments, long long);
} else { // 'z'
uValue = (uint64_t) va_arg(arguments, size_t);
}
} break;
case 'p': {
uValue = (uint64_t)(uintptr_t) va_arg(arguments, void*);
} break;
case 's': {
string = va_arg(arguments, char*);
if (string == NULL) {
string = "(null)";
}
} break;
case 'c': {
buffer[0] = (char) va_arg(arguments, int);
buffer[1] = 0;
string = buffer;
strLen = 1;
} break;
case 'g': {
double d = (double) va_arg(arguments, double);
HAPError res = HAPFloatGetDescription(buffer, sizeof buffer, (float) d);
if (res != kHAPError_None) {
return res;
}
string = buffer;
} break;
default: {
HAPLogError(&kHAPLog_Default, "Unsupported format string type specifier: %%%c", c);
HAPPreconditionFailure();
}
}
if (!string) { // convert integer to string
HAPError res;
if (c == 'i' || c == 'd') { // signed
if (sValue < 0) {
sValue = -sValue;
sign = '-';
}
uValue = (uint64_t) sValue;
}
if (c == 'x') {
res = HAPUInt64GetHexDescription(uValue, buffer, sizeof buffer, kHAPLetterCase_Lowercase);
} else if (c == 'X') {
res = HAPUInt64GetHexDescription(uValue, buffer, sizeof buffer, kHAPLetterCase_Uppercase);
} else if (c == 'p') {
buffer[0] = '0';
buffer[1] = 'x';
res = HAPUInt64GetHexDescription(uValue, buffer + 2, sizeof buffer - 2, kHAPLetterCase_Lowercase);
} else {
res = HAPUInt64GetDescription(uValue, buffer, sizeof buffer);
}
if (res != kHAPError_None) {
return res;
}
string = buffer;
}
if (strLen == 0) {
strLen = HAPStringGetNumBytes(string);
}
size_t totLen = strLen;
if (sign)
totLen++;
if (n + totLen >= maxBytes || n + width >= maxBytes) {
return kHAPError_OutOfResources;
}
if (sign && prefix == '0') {
bytes[n++] = sign; // write sign before zeros
}
while (totLen < width) {
bytes[n++] = prefix;
totLen++;
}
if (sign && prefix == ' ') {
bytes[n++] = sign; // write sign after spaces
}
HAPRawBufferCopyBytes(&bytes[n], string, strLen);
n += strLen;
} else {
// copy char to output
if (n + 1 >= maxBytes) {
return kHAPError_OutOfResources;
}
bytes[n++] = c;
}
c = format[i++];
}
bytes[n] = 0;
return kHAPError_None;
}