/* Miscellaneous routines.
*
* (C) 2003-2010 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id$
*
*/
#include "services.h"
#include "language.h"
#include "hashcomp.h" // If this gets added to services.h or someplace else later, remove it from here -- CyberBotX
/* Cheaper than isspace() or isblank() */
#define issp(c) ((c) == 32)
struct arc4_stream {
uint8 i;
uint8 j;
uint8 s[256];
} rs;
/*************************************************************************/
/**
* toupper: Like the ANSI functions, but make sure we return an
* int instead of a (signed) char.
* @param c Char
* @return int
*/
int toupper(char c)
{
if (islower(c)) {
return static_cast<int>(c) - ('a' - 'A');
} else {
return static_cast<int>(c);
}
}
/*************************************************************************/
/**
* tolower: Like the ANSI functions, but make sure we return an
* int instead of a (signed) char.
* @param c Char
* @return int
*/
int tolower(char c)
{
if (isupper(c)) {
return static_cast<int>(c) + ('a' - 'A');
} else {
return static_cast<int>(c);
}
}
/*************************************************************************/
/**
* Simple function to convert binary data to hex.
* Taken from hybrid-ircd ( http://ircd-hybrid.com/ )
*/
void binary_to_hex(unsigned char *bin, char *hex, int length)
{
static const char trans[] = "0123456789ABCDEF";
int i;
for (i = 0; i < length; i++) {
hex[i << 1] = trans[bin[i] >> 4];
hex[(i << 1) + 1] = trans[bin[i] & 0xf];
}
hex[i << 1] = '\0';
}
/*************************************************************************/
/**
* strscpy: Copy at most len-1 characters from a string to a buffer, and
* add a null terminator after the last character copied.
* @param d Buffer to copy into
* @param s Data to copy int
* @param len Length of data
* @return updated buffer
*/
char *strscpy(char *d, const char *s, size_t len)
{
char *d_orig = d;
if (!len) {
return d;
}
while (--len && (*d++ = *s++));
*d = '\0';
return d_orig;
}
/*************************************************************************/
/**
* stristr: Search case-insensitively for string s2 within string s1,
* returning the first occurrence of s2 or NULL if s2 was not
* found.
* @param s1 String 1
* @param s2 String 2
* @return first occurrence of s2
*/
const char *stristr(const char *s1, const char *s2)
{
register const char *s = s1, *d = s2;
while (*s1) {
if (tolower(*s1) == tolower(*d)) {
s1++;
d++;
if (*d == 0)
return s;
} else {
s = ++s1;
d = s2;
}
}
return NULL;
}
/*************************************************************************/
/**
* strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
* replacing if a replacement would cause the string to exceed
* `size' bytes (including the null terminator). Return the
* string.
* @param s String
* @param size size of s
* @param old character to replace
* @param newstr character to replace with
* @return updated s
*/
char *strnrepl(char *s, int32 size, const char *old, const char *newstr)
{
char *ptr = s;
int32 left = strlen(s);
int32 avail = size - (left + 1);
int32 oldlen = strlen(old);
int32 newlen = strlen(newstr);
int32 diff = newlen - oldlen;
while (left >= oldlen) {
if (strncmp(ptr, old, oldlen) != 0) {
left--;
ptr++;
continue;
}
if (diff > avail)
break;
if (diff != 0)
memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
strncpy(ptr, newstr, newlen);
ptr += newlen;
left -= oldlen;
}
return s;
}
/*************************************************************************/
/**
* merge_args: Take an argument count and argument vector and merge them
* into a single string in which each argument is separated by
* a space.
* @param int Number of Args
* @param argv Array
* @return string of the merged array
*/
const char *merge_args(int argc, const char **argv)
{
int i;
static char s[4096];
char *t;
t = s;
for (i = 0; i < argc; i++)
t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
(i < argc - 1) ? " " : "");
return s;
}
/*
* XXX: temporary "safe" version to avoid casting, it's still ugly.
*/
const char *merge_args(int argc, char **argv)
{
int i;
static char s[4096];
char *t;
t = s;
for (i = 0; i < argc; i++)
t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
(i < argc - 1) ? " " : "");
return s;
}
/*************************************************************************/
/**
* Process a string containing a number/range list in the form
* "n1[-n2][,n3[-n4]]...", calling a caller-specified routine for each
* number in the list. If the callback returns -1, stop immediately.
* Returns the sum of all nonnegative return values from the callback.
* If `count' is non-NULL, it will be set to the total number of times the
* callback was called.
*
* The callback should be of type range_callback_t, which is defined as:
* int (*range_callback_t)(User *u, int num, va_list args)
* @param numstr
* @param count_ret
* @param callback Call back function
* @param u User Struct
* @param ... various args
* @return int
*/
int process_numlist(const char *numstr, int *count_ret,
range_callback_t callback, User * u, ...)
{
int n1, n2, i;
int res = 0, retval = 0, count = 0;
va_list args, preserve;
if (!numstr || !*numstr) {
return -1;
}
va_start(args, u);
/*
* This algorithm ignores invalid characters, ignores a dash
* when it precedes a comma, and ignores everything from the
* end of a valid number or range to the next comma or null.
*/
for (;;) {
n1 = n2 = strtol(numstr, const_cast<char **>(&numstr), 10);
numstr += strcspn(numstr, "0123456789,-");
if (*numstr == '-') {
numstr++;
numstr += strcspn(numstr, "0123456789,");
if (isdigit(*numstr)) {
n2 = strtol(numstr, const_cast<char **>(&numstr), 10);
numstr += strcspn(numstr, "0123456789,-");
}
}
for (i = n1; i <= n2 && i >= 0; i++) {
VA_COPY(preserve, args);
res = callback(u, i, preserve);
va_end(preserve);
count++;
if (res < 0)
break;
retval += res;
if (count >= 32767) {
if (count_ret)
*count_ret = count;
return retval;
}
}
if (res < -1)
break;
numstr += strcspn(numstr, ",");
if (*numstr)
numstr++;
else
break;
}
if (count_ret)
*count_ret = count;
va_end(args);
return retval;
}
/*************************************************************************/
/**
* dotime: Return the number of seconds corresponding to the given time
* string. If the given string does not represent a valid time,
* return -1.
*
* A time string is either a plain integer (representing a number
* of seconds), or an integer followed by one of these characters:
* "s" (seconds), "m" (minutes), "h" (hours), or "d" (days).
* @param s String to convert
* @return time_t
*/
time_t dotime(const char *s)
{
int amount;
if (!s || !*s) {
return -1;
}
amount = strtol(s, const_cast<char **>(&s), 10);
if (*s) {
switch (*s) {
case 's':
return amount;
case 'm':
return amount * 60;
case 'h':
return amount * 3600;
case 'd':
return amount * 86400;
case 'w':
return amount * 86400 * 7;
case 'y':
return amount * 86400 * 365;
default:
return -1;
}
} else {
return amount;
}
}
/*************************************************************************/
/**
* Expresses in a string the period of time represented by a given amount
* of seconds (with days/hours/minutes).
* @param na Nick Alias
* @param buf buffer to store result into
* @param bufsize Size of the buffer
* @param seconds time in seconds
* @return buffer
*/
const char *duration(NickCore *nc, char *buf, int bufsize, time_t seconds)
{
int days = 0, hours = 0, minutes = 0;
int need_comma = 0;
char buf2[64], *end;
const char *comma = getstring(nc, COMMA_SPACE);
/* We first calculate everything */
days
|