blob: deb71d21428dbcf1868797ced06360d3a8c86ca7 [file] [log] [blame]
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "Config.h"
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <ctype.h>
#include <regex.h>
#include <limits.h>
#include "NumberFormatException.h"
#include "system/System.h"
#include "Str.h"
/**
* Implementation of the Str interface
*
* @see http://www.mmonit.com/
* @file
*/
/* -------------------------------------------------------- Public Methods */
char *Str_chomp(char *s) {
if (STR_DEF(s)) {
for (char *p = s; *p; p++)
if (*p == '\r' || *p == '\n') {
*p = 0; break;
}
}
return s;
}
char *Str_trim(char *s) {
return (Str_ltrim(Str_rtrim(s)));
}
char *Str_ltrim(char *s) {
if (STR_DEF(s) && isspace(*s)) {
int i, j;
for (j = 0; s[j]; j++) ;
for (i = 0; isspace(s[i]); i++) ;
memmove(s, s + i, j - i);
s[j-i] = 0;
}
return s;
}
char *Str_rtrim(char *s) {
if (STR_DEF(s)) {
int j;
for (j = 0; s[j]; j++) ;
for (j = j - 1; isspace(s[j]); j--) s[j] = 0;
}
return s;
}
char *Str_unquote(char *s) {
if (STR_DEF(s)) {
char *t = s;
// Left unquote
while (*t == 34 || *t == 39 || isspace(*t)) t++;
if (t != s) {
char *u = s;
for (; *t; t++, u++)
*u = *t;
t = u;
} else
while (*t) t++;
// Right unquote
do
*(t--) = 0;
while (t > s && (*t == 34 || *t == 39 || isspace(*t)));
}
return s;
}
char *Str_toLower(char *s) {
if (s)
for (int i = 0; s[i]; i++)
s[i] = tolower(s[i]);
return s;
}
char *Str_toUpper(char *s) {
if (s)
for (int i = 0; s[i]; i++)
s[i] = toupper(s[i]);
return s;
}
char *Str_ton(long n, char s[43]) {
assert(s);
s[42] = 0;
char *t = s + 42;
unsigned long m;
if (n == LONG_MIN)
m = LONG_MAX + 1UL;
else if (n < 0)
m = -n;
else
m = n;
do
*--t = m % 10 + '0';
while ((m /= 10) > 0);
if (n < 0)
*--t = '-';
return t;
}
int Str_parseInt(const char *s) {
int i;
char *e;
if (STR_UNDEF(s))
THROW(NumberFormatException, "For input string null");
errno = 0;
i = (int)strtol(s, &e, 10);
if (errno || (e == s))
THROW(NumberFormatException, "For input string %s -- %s", s, System_getError(errno));
return i;
}
long long int Str_parseLLong(const char *s) {
char *e;
long long l;
if (STR_UNDEF(s))
THROW(NumberFormatException, "For input string null");
errno = 0;
l = strtoll(s, &e, 10);
if (errno || (e == s))
THROW(NumberFormatException, "For input string %s -- %s", s, System_getError(errno));
return l;
}
double Str_parseDouble(const char *s) {
char *e;
double d;
if (STR_UNDEF(s))
THROW(NumberFormatException, "For input string null");
errno = 0;
d = strtod(s, &e);
if (errno || (e == s))
THROW(NumberFormatException, "For input string %s -- %s", s, System_getError(errno));
return d;
}
char *Str_replaceChar(char *s, char o, char n) {
if (s) {
for (char *t = s; *t; t++)
if (*t == o)
*t = n;
}
return s;
}
int Str_startsWith(const char *a, const char *b) {
if (a && b) {
do
if (*a++ != *b++) return false;
while (*b);
return true;
}
return false;
}
int Str_endsWith(const char *a, const char *b) {
if (a && b) {
register int i = 0, j = 0;
while (a[i]) i++;
while (b[j]) j++;
for(; (i && j); i--, j--)
if(toupper(a[i]) != toupper(b[j])) return false;
return (i >= j);
}
return false;
}
char *Str_sub(const char *a, const char *b) {
if (a && STR_DEF(b)) {
const char *ap, *bp;
while (*a) {
if (toupper(*a) == toupper(*b)) {
ap = a;
bp = b;
do
if (! *bp)
return (char*)a;
while (toupper(*ap++) == toupper(*bp++));
}
a++;
}
}
return NULL;
}
int Str_has(const char *charset, const char *s) {
if (charset && s) {
for (int x = 0; s[x]; x++) {
for (int y = 0; charset[y]; y++) {
if (s[x] == charset[y])
return true;
}
}
}
return false;
}
int Str_isEqual(const char *a, const char *b) {
if (a && b) {
while (*a && *b)
if (toupper(*a++) != toupper(*b++)) return false;
return (*a == *b);
}
return false;
}
int Str_isByteEqual(const char *a, const char *b) {
if (a && b) {
while (*a && *b)
if (*a++ != *b++) return false;
return (*a == *b);
}
return false;
}
char *Str_copy(char *dest, const char *src, int n) {
if (src && dest && (n > 0)) {
char *t = dest;
while (*src && n--)
*t++ = *src++;
*t = 0;
} else if (dest)
*dest = 0;
return dest;
}
// We don't use strdup so we can report MemoryException on OOM
char *Str_dup(const char *s) {
char *t = NULL;
if (s) {
size_t n = strlen(s);
t = ALLOC(n + 1);
memcpy(t, s, n);
t[n] = 0;
}
return t;
}
char *Str_ndup(const char *s, long n) {
char *t = NULL;
assert(n >= 0);
if (s) {
size_t l = strlen(s);
n = l < n ? l : n; // Use the actual length of s if shorter than n
t = ALLOC(n + 1);
memcpy(t, s, n);
t[n] = 0;
}
return t;
}
char *_Str_join(char *dest, int n, ...) {
char *p, *q;
va_list ap;
assert(dest);
va_start(ap, n);
for (q = dest, p = va_arg(ap, char *); (p && (n > 0)); p = va_arg(ap, char *))
while (*p && n--) *q++ = *p++;
va_end(ap);
*q = 0;
return dest;
}
char *Str_cat(const char *s, ...) {
char *t = NULL;
if (s) {
va_list ap;
va_start(ap, s);
t = Str_vcat(s, ap);
va_end(ap);
}
return t;
}
char *Str_vcat(const char *s, va_list ap) {
char *t = NULL;
if (s) {
int n = 0;
va_list ap_copy;
int size = STRLEN;
t = ALLOC(size);
while (true) {
va_copy(ap_copy, ap);
n = vsnprintf(t, size, s, ap_copy);
va_end(ap_copy);
if (n < size)
break;
size = n + 1;
RESIZE(t, size);
}
}
return t;
}
char *Str_trunc(char *s, int n) {
assert(n >= 0);
if (s) {
size_t sl = strlen(s);
if (sl > (n + 4)) {
int e = n+3;
for (; n < e; n++)
s[n] = '.';
s[n] = 0;
}
}
return s;
}
char *Str_curtail(char *s, char *t) {
if (s) {
char *x = Str_sub(s, t);
if (x) *x = 0;
}
return s;
}
int Str_lim(const char *s, int limit) {
assert(limit>=0);
if (s)
for (; *s; s++) limit--;
return (limit <= 0);
}
int Str_match(const char *pattern, const char *subject) {
assert(pattern);
if (STR_DEF(subject)) {
regex_t regex = {0};
int error = regcomp(&regex, pattern, REG_NOSUB|REG_EXTENDED);
if (error) {
char e[STRLEN];
regerror(error, &regex, e, STRLEN);
regfree(&regex);
THROW(AssertException, "regular expression error -- %s", e);
} else {
error = regexec(&regex, subject, 0, NULL, 0);
regfree(&regex);
return (error == 0);
}
}
return false;
}
unsigned int Str_hash(const void *x) {
const char *s = x;
unsigned long h = 0, g;
assert(x);
while (*s) {
h = (h << 4) + *s++;
if ((g = h & 0xF0000000))
h ^= g >> 24;
h &= ~g;
}
return (int)h;
}
int Str_cmp(const void *x, const void *y) {
return strcmp((const char *)x, (const char *)y);
}