Improve str.h and str.c

Move alloca_tohex() from serval.h into str.h so it can be used stand-alone.

Rename str_to_ll_scaled() to str_to_int64_scaled().  Add str_to_uint64_scaled()
and scale_factor().

Add a few more URI parsing functions.  Move some functions out of str.c and
into str.h as inline functions.
This commit is contained in:
Andrew Bettison 2012-11-22 18:15:40 +10:30
parent 1fbf7001d1
commit 494a766b9e
5 changed files with 87 additions and 43 deletions

View File

@ -86,7 +86,7 @@ static int overlay_interface_type(char *s)
if (!strcasecmp(s,"wifi")) return OVERLAY_INTERFACE_WIFI;
if (!strcasecmp(s,"other")) return OVERLAY_INTERFACE_UNKNOWN;
if (!strcasecmp(s,"catear")) return OVERLAY_INTERFACE_PACKETRADIO;
return WHY("Invalid interface type -- consider using 'wifi','ethernet' or 'other'");
return -1;
}
int overlay_interface_arg(char *arg)
@ -1290,7 +1290,7 @@ parse_quantity(char *q)
if (strlen(q) >= 80)
return WHY("quantity string >=80 characters");
long long result;
if (str_to_ll_scaled(q, 10, &result, NULL))
if (str_to_int64_scaled(q, 10, &result, NULL))
return result;
return WHYF("Illegal quantity: %s", alloca_str_toprint(q));
}

View File

@ -466,7 +466,6 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f);
int overlay_frame_resolve_addresses(struct overlay_frame *f);
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
#define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE)
#define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE)

75
str.c
View File

@ -28,7 +28,7 @@
#include <assert.h>
#include <limits.h>
char hexdigit[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
const char hexdigit[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes)
{
@ -163,24 +163,50 @@ char *str_str(char *haystack, const char *needle, int haystack_len)
return NULL;
}
int str_to_ll_scaled(const char *str, int base, long long *result, const char **afterp)
uint64_t scale_factor(const char *str, const char **afterp)
{
uint64_t factor = 1;
switch (str[0]) {
case 'k': ++str; factor = 1000LL; break;
case 'K': ++str; factor = 1024LL; break;
case 'm': ++str; factor = 1000LL * 1000LL; break;
case 'M': ++str; factor = 1024LL * 1024LL; break;
case 'g': ++str; factor = 1000LL * 1000LL * 1000LL; break;
case 'G': ++str; factor = 1024LL * 1024LL * 1024LL; break;
}
if (afterp)
*afterp = str;
else if (*str)
factor = 0;
return factor;
}
int str_to_int64_scaled(const char *str, int base, int64_t *result, const char **afterp)
{
if (!(isdigit(*str) || *str == '-' || *str == '+'))
return 0;
char *end;
long long value = strtoll(str, &end, base);
const char *end = str;
long long value = strtoll(str, (char**)&end, base);
if (end == str)
return 0;
switch (*end) {
case '\0': break;
case 'k': value *= 1000LL; ++end; break;
case 'K': value *= 1024LL; ++end; break;
case 'm': value *= 1000LL * 1000LL; ++end; break;
case 'M': value *= 1024LL * 1024LL; ++end; break;
case 'g': value *= 1000LL * 1000LL * 1000LL; ++end; break;
case 'G': value *= 1024LL * 1024LL * 1024LL; ++end; break;
default: return 0;
}
value *= scale_factor(end, &end);
if (afterp)
*afterp = end;
else if (*end)
return 0;
*result = value;
return 1;
}
int str_to_uint64_scaled(const char *str, int base, uint64_t *result, const char **afterp)
{
if (!isdigit(*str))
return 0;
const char *end = str;
unsigned long long value = strtoull(str, (char**)&end, base);
if (end == str)
return 0;
value *= scale_factor(end, &end);
if (afterp)
*afterp = end;
else if (*end)
@ -265,27 +291,6 @@ size_t str_fromprint(unsigned char *dst, const char *src)
return dst - odst;
}
int is_uri_char_scheme(char c)
{
return isalpha(c) || isdigit(c) || c == '+' || c == '-' || c == '.';
}
int is_uri_char_unreserved(char c)
{
return isalpha(c) || isdigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
}
int is_uri_char_reserved(char c)
{
switch (c) {
case ':': case '/': case '?': case '#': case '[': case ']': case '@':
case '!': case '$': case '&': case '\'': case '(': case ')':
case '*': case '+': case ',': case ';': case '=':
return 1;
}
return 0;
}
/* Return true if the string resembles a URI.
* Based on RFC-3986 generic syntax, assuming nothing about the hierarchical part.
*

44
str.h
View File

@ -21,6 +21,7 @@
#define __STR_H__
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <ctype.h>
@ -58,13 +59,15 @@ __STR_INLINE int is_xstring(const char *text, int len)
return *text == '\0';
}
extern char hexdigit[16];
extern const char hexdigit[16];
char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes);
size_t fromhex(unsigned char *dstBinary, const char *srcHex, size_t nbinary);
int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t nbinary);
int is_all_matching(const unsigned char *ptr, size_t len, unsigned char value);
char *str_toupper_inplace(char *s);
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
__STR_INLINE int hexvalue(char c)
{
if (c >= '0' && c <= '9') return c - '0';
@ -136,7 +139,9 @@ char *str_str(char *haystack, const char *needle, int haystack_len);
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int str_to_ll_scaled(const char *str, int base, long long *result, const char **afterp);
int str_to_int64_scaled(const char *str, int base, int64_t *result, const char **afterp);
int str_to_uint64_scaled(const char *str, int base, uint64_t *result, const char **afterp);
uint64_t scale_factor(const char *str, const char **afterp);
/* Return true if the string resembles a nul-terminated URI.
* Based on RFC-3986 generic syntax, assuming nothing about the hierarchical part.
@ -147,6 +152,41 @@ int str_to_ll_scaled(const char *str, int base, long long *result, const char **
*/
int str_is_uri(const char *uri);
__STR_INLINE int is_uri_char_scheme(char c)
{
return isalpha(c) || isdigit(c) || c == '+' || c == '-' || c == '.';
}
__STR_INLINE int is_uri_char_unreserved(char c)
{
return isalpha(c) || isdigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
}
__STR_INLINE int is_uri_char_reserved(char c)
{
switch (c) {
case ':': case '/': case '?': case '#': case '[': case ']': case '@':
case '!': case '$': case '&': case '\'': case '(': case ')':
case '*': case '+': case ',': case ';': case '=':
return 1;
}
return 0;
}
/* Return true if the string resembles a URI scheme without the terminating colon.
* Based on RFC-3986 generic syntax.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
__STR_INLINE int str_is_uri_scheme(const char *scheme)
{
if (!isalpha(*scheme++))
return 0;
while (is_uri_char_scheme(*scheme))
++scheme;
return *scheme == '\0';
}
/* Pick apart a URI into its basic parts.
*
* uri := scheme ":" hierarchical [ "?" query ] [ "#" fragment ]

View File

@ -49,13 +49,13 @@ static inline char stripe(int i)
int main(int argc, char **argv)
{
argv0 = argv[0];
long long size = 0;
uint64_t size = 0;
const char *label = "";
int i;
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (str_startswith(arg, "--size=", &arg)) {
if (!str_to_ll_scaled(arg, 10, &size, NULL) || size < 0)
if (!str_to_uint64_scaled(arg, 10, &size, NULL) || size < 0)
fatal("illegal --size= argument: %s", arg);
}
else if (str_startswith(arg, "--label=", &arg))
@ -63,7 +63,7 @@ int main(int argc, char **argv)
else
fatal("unrecognised argument: %s", arg);
}
long long offset = 0;
uint64_t offset = 0;
char buf[127];
for (i = 0; i != sizeof buf; ++i)
buf[i] = stripe(i);