ossp-pkg/var/expand-named-characters.c
#include "internal.h"
/* Internal parsing code for octal. */
static int isoct(char c)
{
if (c >= '0' && c <= '7')
return 1;
else
return 0;
}
static var_rc_t expand_octal(const char** src, char** dst, const char* end)
{
unsigned char c;
if (end - *src < 3)
return VAR_INCOMPLETE_OCTAL;
if (!isoct(**src) || !isoct((*src)[1]) || !isoct((*src)[2]))
return VAR_INVALID_OCTAL;
c = **src - '0';
if (c > 3)
return VAR_OCTAL_TOO_LARGE;
c *= 8;
++(*src);
c += **src - '0';
c *= 8;
++(*src);
c += **src - '0';
**dst = (char)c;
++(*dst);
return VAR_OK;
}
static int ishex(char c)
{
if ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'))
return 1;
else
return 0;
}
/* Internal parsing code for hex. */
static var_rc_t expand_simple_hex(const char** src, char** dst, const char* end)
{
unsigned char c = 0;
if (end - *src < 2)
return VAR_INCOMPLETE_HEX;
if (!ishex(**src) || !ishex((*src)[1]))
return VAR_INVALID_HEX;
if (**src >= '0' && **src <= '9')
c = **src - '0';
else if (c >= 'a' && c <= 'f')
c = **src - 'a' + 10;
else if (c >= 'A' && c <= 'F')
c = **src - 'A' + 10;
c = c << 4;
++(*src);
if (**src >= '0' && **src <= '9')
c += **src - '0';
else if (**src >= 'a' && **src <= 'f')
c += **src - 'a' + 10;
else if (**src >= 'A' && **src <= 'F')
c += **src - 'A' + 10;
**dst = (char)c;
++(*dst);
return VAR_OK;
}
static var_rc_t expand_grouped_hex(const char** src, char** dst, const char* end)
{
var_rc_t rc;
while (*src < end && **src != '}')
{
if ((rc = expand_simple_hex(src, dst, end)) != 0)
return rc;
++(*src);
}
if (*src == end)
return VAR_INCOMPLETE_GROUPED_HEX;
return VAR_OK;
}
static var_rc_t expand_hex(const char** src, char** dst, const char* end)
{
if (*src == end)
return VAR_INCOMPLETE_HEX;
if (**src == '{')
{
++(*src);
return expand_grouped_hex(src, dst, end);
}
else
return expand_simple_hex(src, dst, end);
}
/*
Expand the following named characters in the buffer:
\t tab
\n newline
\r return
\033 octal char
\x1B hex char
\x{263a} wide hex char
Any other character quoted by a backslash is copied verbatim.
*/
var_rc_t expand_named_characters(const char* src, size_t len, char* dst)
{
const char* end = src + len;
var_rc_t rc;
assert(src != NULL);
assert(dst != NULL);
while (src < end)
{
if (*src == '\\')
{
if (++src == end)
return VAR_INCOMPLETE_NAMED_CHARACTER;
switch (*src)
{
case 'n':
*dst++ = '\n';
break;
case 't':
*dst++ = '\t';
break;
case 'r':
*dst++ = '\r';
break;
case 'x':
++src;
if ((rc = expand_hex(&src, &dst, end)) != 0)
return rc;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if ((rc = expand_octal(&src, &dst, end)) != 0)
return rc;
break;
default:
*dst++ = *src;
}
++src;
}
else
*dst++ = *src++;
}
*dst = '\0';
return VAR_OK;
}