1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
/* source: utils.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* useful additions to C library */
#include "config.h"
#include "sysincludes.h"
#include "compat.h" /* socklen_t */
#include "mytypes.h"
#include "sycls.h"
#include "utils.h"
#if !HAVE_PROTOTYPE_LIB_memrchr
/* GNU extension, available since glibc 2.1.91 */
void *memrchr(const void *s, int c, size_t n) {
const unsigned char *t = ((unsigned char *)s)+n;
while (--t >= (unsigned char *)s) {
if (*t == c) break;
}
if (t < (unsigned char *)s)
return NULL;
return (void *)t;
}
#endif /* !HAVE_PROTOTYPE_LIB_memrchr */
void *memdup(const void *src, size_t n) {
void *dest;
if ((dest = Malloc(n)) == NULL) {
return NULL;
}
memcpy(dest, src, n);
return dest;
}
#if !HAVE_PROTOTYPE_LIB_strndup
char *strndup(
const char *s,
size_t n)
{
char *m;
m = malloc(n+1);
if (m == NULL) {
return m;
}
strncpy(m, s, n);
m[n] = '\0';
return m;
}
#endif /* !HAVE_PROTOTYPE_LIB_strndup */
/* search the keyword-table for a match of the leading part of name. */
/* returns the pointer to the matching field of the keyword or NULL if no
keyword was found. */
const struct wordent *keyw(const struct wordent *keywds, const char *name, unsigned int nkeys) {
unsigned int lower, upper, mid;
int r;
lower = 0;
upper = nkeys;
while (upper - lower > 1)
{
mid = (upper + lower) >> 1;
if (!(r = strcasecmp(keywds[mid].name, name)))
{
return &keywds[mid];
}
if (r < 0)
lower = mid;
else
upper = mid;
}
if (nkeys > 0 && !(strcasecmp(keywds[lower].name, name)))
{
return &keywds[lower];
}
return NULL;
}
/* Linux: setenv(), AIX (4.3?): putenv() */
#if !HAVE_SETENV
int setenv(const char *name, const char *value, int overwrite) {
int result;
char *env;
if (!overwrite) {
if (getenv(name)) return 0; /* already exists */
}
if ((env = Malloc(strlen(name)+strlen(value)+2)) == NULL) {
return -1;
}
sprintf(env, "%s=%s", name, value);
if ((result = putenv(env)) != 0) { /* AIX docu says "... nonzero ..." */
free(env);
result = -1;
}
/* linux "man putenv" says: ...this string becomes part of the environment*/
return result;
}
#endif /* !HAVE_SETENV */
/* sanitizes an "untrusted" character. output buffer must provide at least 4
characters space.
Does not append \0. returns length of output (currently: max 4) */
static size_t sanitize_char(char c, char *o, int style) {
int hn; /* high nibble */
int ln; /* low nibble */
int n; /* written chars */
if (isprint((unsigned char)c)) {
*o = c;
return 1;
}
*o++ = '\\';
n = 2;
switch (c) {
case '\0': *o++ = '0'; break;
case '\a': *o++ = 'a'; break;
case '\b': *o++ = 'b'; break;
case '\t': *o++ = 't'; break;
case '\n': *o++ = 'n'; break;
case '\v': *o++ = 'v'; break;
case '\f': *o++ = 'f'; break;
case '\r': *o++ = 'r'; break;
case '\'': *o++ = '\''; break;
case '\"': *o++ = '"'; break;
case '\\': *o++ = '\\'; break;
default:
*o++ = 'x';
hn = (c>>4)&0x0f;
ln = c&0x0f;
*o++ = (hn>=10 ? (('A'-1)+(hn-10)) : ('0'+hn));
*o++ = (ln>=10 ? (('A'-1)+(ln-10)) : ('0'+ln));
n = 4;
}
return n;
}
/* sanitizes "untrusted" text, replacing special control characters with the C
string version (eg."\n"), and replacing unprintable chars with hex
representation ("\xAB").
text can grow to four times of input, so keep output buffer long enough!
returns a pointer to the first untouched byte of the output buffer.
Output is not \0 terminated.
*/
char *sanitize_string(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded, /* output buffer, must be long enough */
int style
) {
int c;
while (bytes > 0) {
c = *(unsigned char *)data++;
coded += sanitize_char(c, coded, style);
--bytes;
}
return coded;
}
/* copies a substring out of a given buff
returns scratch, \0 terminated; scratch must provide len+1 bytes
*/
char *xiosubstr(char *scratch, const char *str, size_t from, size_t len) {
char *scratch0 = scratch;
str += from;
while (len--) {
*scratch++ = *str++;
}
*scratch = '\0';
return scratch0;
}
/* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
can handle the old glibc case with -1 return on truncation.
Do not rely on exact return value in case of truncation
*/
int xio_snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
int result;
va_start(ap, format);
result = vsnprintf(str, size, format, ap);
#if ! HAVE_C99_SNPRINTF
if (result < 0) {
result = size+63; /* indicate truncation with just some guess */
}
#endif /* !HAVE_C99_SNPRINTF */
va_end(ap);
return result;
}
|