Мне показалось, что мой предыдущий ответ был обманом, потому что функция, которая записывает в буфер, гораздо полезнее, чем функция, которая просто записывает в stdout
, поэтому вот альтернативное решение, которое определяет, сколько памяти нужно, если dst
NULL
, а также останавливается на dstLen
согласно требованию.
Вероятно, это немного неэффективно со всей проверкой if(dst)
.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
size_t str_escape(char *dst, const char *src, size_t dstLen)
{
const char complexCharMap[] = "abtnvfr";
size_t i;
size_t srcLen = strlen(src);
size_t dstIdx = 0;
// If caller wants to determine required length (supplying NULL for dst)
// then we set dstLen to SIZE_MAX and pretend the buffer is the largest
// possible, but we never write to it. Caller can also provide dstLen
// as 0 if no limit is wanted.
if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX;
for (i = 0; i < srcLen && dstIdx < dstLen; i++)
{
size_t complexIdx = 0;
switch (src[i])
{
case '\'':
case '\"':
case '\\':
if (dst && dstIdx <= dstLen - 2)
{
dst[dstIdx++] = '\\';
dst[dstIdx++] = src[i];
}
else dstIdx += 2;
break;
case '\r': complexIdx++;
case '\f': complexIdx++;
case '\v': complexIdx++;
case '\n': complexIdx++;
case '\t': complexIdx++;
case '\b': complexIdx++;
case '\a':
if (dst && dstIdx <= dstLen - 2)
{
dst[dstIdx++] = '\\';
dst[dstIdx++] = complexCharMap[complexIdx];
}
else dstIdx += 2;
break;
default:
if (isprint(src[i]))
{
// simply copy the character
if (dst)
dst[dstIdx++] = src[i];
else
dstIdx++;
}
else
{
// produce octal escape sequence
if (dst && dstIdx <= dstLen - 4)
{
dst[dstIdx++] = '\\';
dst[dstIdx++] = ((src[i] & 0300) >> 6) + '0';
dst[dstIdx++] = ((src[i] & 0070) >> 3) + '0';
dst[dstIdx++] = ((src[i] & 0007) >> 0) + '0';
}
else
{
dstIdx += 4;
}
}
}
}
if (dst && dstIdx <= dstLen)
dst[dstIdx] = '\0';
return dstIdx;
}