A
A. Farber
Hello,
I'm programming a web application and for that I'm trying
to extend the standard C string functions, so that they can
handle the application/x-www-form-urlencoded format
(which encodes non-alphanumeric characters as %XY).
I've written my own xstrlen(), xstrlcat(), xstrlcpy and xstrdup()
(please see the source code on the bottom of this post).
But I can't figure out how to extend the last function I need -
the snprintf(). Namely I'd like to add an %a to its format
and for each corresponding string I'd call the xstrdup()
thus converting it application/x-www-form-urlencoded
and finally I'd replaced the %a itself by the normal %s
and call the normal (v)snprintf (and free()d the strings):
int
xsnprintf(char *dst, size_t size, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
/* HERE:
loop through fmt,
replace %a by %s,
xstrdup(va_arg(ap, char*))
*/
vsnprintf(dst, size, fmt, ap);
va_end(ap);
/* HERE:
free() the strings xstrdup()ed above */
}
However I can't figure out how to put my xstrdup()ed
strings into the va_list ap, before I call vsnprintf().
Does anybody please have an idea here?
Regards
Alex
static const char hex[] = "0123456789ABCDEF";
size_t
xstrlen(const char *str)
{
size_t len;
for (len = 0; *str; ++str)
/* [a-zA-Z0-9._-] or space require 1 byte */
if (isalnum(*str) ||
'.' == *str ||
'_' == *str ||
'-' == *str ||
' ' == *str)
len += 1;
/* all other chars will be converted to %XX */
else
len += 3;
return len;
}
size_t
xstrlcpy(char *dst, const unsigned char *src, size_t size)
{
size_t len;
if (0 == size)
return xstrlen(src);
/* copy at most (size - 1) chars from src to dst */
for (len = 0; *src && len < size - 1; ++src)
/* just copy [a-zA-Z0-9._-] */
if (isalnum(*src) ||
'.' == *src ||
'_' == *src ||
'-' == *src)
dst[len++] = *src;
/* convert spaces to pluses */
else if (' ' == *src)
dst[len++] = '+';
/* convert other chars to %XX */
else {
if (len >= size - 3)
break;
dst[len++] = '%';
dst[len++] = hex[*src >> 4];
dst[len++] = hex[*src & 0xF];
}
dst[len] = 0;
if (0 == *src)
return len;
else
return len + xstrlen(src);
}
size_t
xstrlcat(char *dst, const char *src, size_t size)
{
size_t len = strlen(dst);
if (size <= len)
return size + xstrlen(src);
return xstrlcpy(&dst[len], src, size - len);
}
char*
xstrdup(const char *src)
{
char *copy;
size_t size = xstrlen(src) + 1;
if ((copy = malloc(size)) == NULL)
return NULL;
memmove(copy, src, size);
return copy;
}
I'm programming a web application and for that I'm trying
to extend the standard C string functions, so that they can
handle the application/x-www-form-urlencoded format
(which encodes non-alphanumeric characters as %XY).
I've written my own xstrlen(), xstrlcat(), xstrlcpy and xstrdup()
(please see the source code on the bottom of this post).
But I can't figure out how to extend the last function I need -
the snprintf(). Namely I'd like to add an %a to its format
and for each corresponding string I'd call the xstrdup()
thus converting it application/x-www-form-urlencoded
and finally I'd replaced the %a itself by the normal %s
and call the normal (v)snprintf (and free()d the strings):
int
xsnprintf(char *dst, size_t size, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
/* HERE:
loop through fmt,
replace %a by %s,
xstrdup(va_arg(ap, char*))
*/
vsnprintf(dst, size, fmt, ap);
va_end(ap);
/* HERE:
free() the strings xstrdup()ed above */
}
However I can't figure out how to put my xstrdup()ed
strings into the va_list ap, before I call vsnprintf().
Does anybody please have an idea here?
Regards
Alex
static const char hex[] = "0123456789ABCDEF";
size_t
xstrlen(const char *str)
{
size_t len;
for (len = 0; *str; ++str)
/* [a-zA-Z0-9._-] or space require 1 byte */
if (isalnum(*str) ||
'.' == *str ||
'_' == *str ||
'-' == *str ||
' ' == *str)
len += 1;
/* all other chars will be converted to %XX */
else
len += 3;
return len;
}
size_t
xstrlcpy(char *dst, const unsigned char *src, size_t size)
{
size_t len;
if (0 == size)
return xstrlen(src);
/* copy at most (size - 1) chars from src to dst */
for (len = 0; *src && len < size - 1; ++src)
/* just copy [a-zA-Z0-9._-] */
if (isalnum(*src) ||
'.' == *src ||
'_' == *src ||
'-' == *src)
dst[len++] = *src;
/* convert spaces to pluses */
else if (' ' == *src)
dst[len++] = '+';
/* convert other chars to %XX */
else {
if (len >= size - 3)
break;
dst[len++] = '%';
dst[len++] = hex[*src >> 4];
dst[len++] = hex[*src & 0xF];
}
dst[len] = 0;
if (0 == *src)
return len;
else
return len + xstrlen(src);
}
size_t
xstrlcat(char *dst, const char *src, size_t size)
{
size_t len = strlen(dst);
if (size <= len)
return size + xstrlen(src);
return xstrlcpy(&dst[len], src, size - len);
}
char*
xstrdup(const char *src)
{
char *copy;
size_t size = xstrlen(src) + 1;
if ((copy = malloc(size)) == NULL)
return NULL;
memmove(copy, src, size);
return copy;
}