summaryrefslogtreecommitdiff
path: root/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc.c')
-rw-r--r--misc.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/misc.c b/misc.c
new file mode 100644
index 000000000..02ab31aba
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,642 @@
+/* Miscellaneous routines.
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ * $Id: misc.c,v 1.14 2004/01/31 18:57:18 dane Exp $
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+
+/* Cheaper than isspace() or isblank() */
+#define issp(c) ((c) == 32)
+
+/*************************************************************************/
+
+/* toupper/tolower: Like the ANSI functions, but make sure we return an
+ * int instead of a (signed) char.
+ */
+
+int toupper(char c)
+{
+ if (islower(c))
+ return (unsigned char) c - ('a' - 'A');
+ else
+ return (unsigned char) c;
+}
+
+int tolower(char c)
+{
+ if (isupper(c))
+ return (unsigned char) c + ('a' - 'A');
+ else
+ return (unsigned char) c;
+}
+
+/*************************************************************************/
+
+/* strscpy: Copy at most len-1 characters from a string to a buffer, and
+ * add a null terminator after the last character copied.
+ */
+
+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.
+ */
+
+char *stristr(char *s1, char *s2)
+{
+ register 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.
+ */
+
+char *strnrepl(char *s, int32 size, const char *old, const char *new)
+{
+ char *ptr = s;
+ int32 left = strlen(s);
+ int32 avail = size - (left + 1);
+ int32 oldlen = strlen(old);
+ int32 newlen = strlen(new);
+ 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);
+ strncpy(ptr, new, 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.
+ */
+
+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;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* match_wild: Attempt to match a string to a pattern which might contain
+ * '*' or '?' wildcards. Return 1 if the string matches the
+ * pattern, 0 if not.
+ */
+
+static int do_match_wild(const char *pattern, const char *str, int docase)
+{
+ char c;
+ const char *s;
+
+ /* This WILL eventually terminate: either by *pattern == 0, or by a
+ * trailing '*'. */
+
+ for (;;) {
+ switch (c = *pattern++) {
+ case 0:
+ if (!*str)
+ return 1;
+ return 0;
+ case '?':
+ if (!*str)
+ return 0;
+ str++;
+ break;
+ case '*':
+ if (!*pattern)
+ return 1; /* trailing '*' matches everything else */
+ s = str;
+ while (*s) {
+ if ((docase ? (*s == *pattern)
+ : (tolower(*s) == tolower(*pattern)))
+ && do_match_wild(pattern, s, docase))
+ return 1;
+ s++;
+ }
+ break;
+ default:
+ if (docase ? (*str++ != c) : (tolower(*str++) != tolower(c)))
+ return 0;
+ break;
+ } /* switch */
+ }
+}
+
+
+int match_wild(const char *pattern, const char *str)
+{
+ return do_match_wild(pattern, str, 1);
+}
+
+int match_wild_nocase(const char *pattern, const char *str)
+{
+ return do_match_wild(pattern, str, 0);
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* 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)
+ */
+
+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;
+
+ 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, (char **) &numstr, 10);
+ numstr += strcspn(numstr, "0123456789,-");
+ if (*numstr == '-') {
+ numstr++;
+ numstr += strcspn(numstr, "0123456789,");
+ if (isdigit(*numstr)) {
+ n2 = strtol(numstr, (char **) &numstr, 10);
+ numstr += strcspn(numstr, "0123456789,-");
+ }
+ }
+ for (i = n1; i <= n2 && i >= 0; i++) {
+ int res = callback(u, i, args);
+ 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;
+ 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).
+ */
+
+int dotime(const char *s)
+{
+ int amount;
+
+ amount = strtol(s, (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;
+ 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). */
+
+char *duration(NickAlias * na, char *buf, int bufsize, time_t seconds)
+{
+ int days = 0, hours = 0, minutes = 0;
+ int need_comma = 0;
+
+ char buf2[64], *end;
+ char *comma = getstring(na, COMMA_SPACE);
+
+ /* We first calculate everything */
+ days = seconds / 86400;
+ seconds -= (days * 86400);
+ hours = seconds / 3600;
+ seconds -= (hours * 3600);
+ minutes = seconds / 60;
+
+ if (!days && !hours && !minutes) {
+ snprintf(buf, bufsize,
+ getstring(na,
+ (seconds <=
+ 1 ? DURATION_SECOND : DURATION_SECONDS)),
+ seconds);
+ } else {
+ end = buf;
+ if (days) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (days == 1 ? DURATION_DAY : DURATION_DAYS)),
+ days);
+ end += snprintf(end, bufsize - (end - buf), "%s", buf2);
+ need_comma = 1;
+ }
+ if (hours) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (hours ==
+ 1 ? DURATION_HOUR : DURATION_HOURS)),
+ hours);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ if (minutes) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (minutes ==
+ 1 ? DURATION_MINUTE : DURATION_MINUTES)),
+ minutes);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ }
+
+ return buf;
+}
+
+/*************************************************************************/
+
+/* Generates a human readable string of type "expires in ..." */
+
+char *expire_left(NickAlias * na, char *buf, int len, time_t expires)
+{
+ time_t now = time(NULL);
+
+ if (!expires) {
+ strncpy(buf, getstring(na, NO_EXPIRE), len);
+ } else if (expires <= now) {
+ strncpy(buf, getstring(na, EXPIRES_SOON), len);
+ } else {
+ time_t diff = expires - now + 59;
+
+ if (diff >= 86400) {
+ int days = diff / 86400;
+ snprintf(buf, len,
+ getstring(na, (days == 1) ? EXPIRES_1D : EXPIRES_D),
+ days);
+ } else {
+ if (diff <= 3600) {
+ int minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(na,
+ (minutes ==
+ 1) ? EXPIRES_1M : EXPIRES_M), minutes);
+ } else {
+ int hours = diff / 3600, minutes;
+ diff -= (hours * 3600);
+ minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(na,
+ ((hours == 1
+ && minutes ==
+ 1) ? EXPIRES_1H1M : ((hours == 1
+ && minutes !=
+ 1) ? EXPIRES_1HM
+ : ((hours != 1
+ && minutes ==
+ 1) ?
+ EXPIRES_H1M :
+ EXPIRES_HM)))),
+ hours, minutes);
+ }
+ }
+ }
+
+ return buf;
+}
+
+/**
+ * Return 1 if a host is valid, 0 if it isnt.
+ * host = string to check
+ * type = format, 1 = ip4addr, 2 = hostname
+ *
+ * shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
+ * hostname = shortname *( "." shortname )
+ * ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
+ *
+ **/
+
+int doValidHost(const char *host, int type)
+{
+ int idx = 0;
+ int len = 0;
+ int sec_len = 0;
+ int dots = 1;
+ if (type != 1 && type != 2) {
+ return 0;
+ }
+ if (!host) {
+ return 0;
+ }
+
+ len = strlen(host);
+
+ if (len > HOSTMAX) {
+ return 0;
+ }
+
+ switch (type) {
+ case 1:
+ for (idx = 0; idx < len; idx++) {
+ if (isdigit(host[idx])) {
+ if (sec_len < 3) {
+ sec_len++;
+ } else {
+ return 0;
+ }
+ } else {
+ if (idx == 0) {
+ return 0;
+ } /* cant start with a non-digit */
+ if (host[idx] != '.') {
+ return 0;
+ } /* only . is a valid non-digit */
+ if (sec_len > 3) {
+ return 0;
+ } /* sections cant be more than 3 digits */
+ sec_len = 0;
+ dots++;
+ }
+ }
+ if (dots != 4) {
+ return 0;
+ }
+ break;
+ case 2:
+ dots = 0;
+ for (idx = 0; idx < len; idx++) {
+ if (!isalnum(host[idx])) {
+ if (idx == 0) {
+ return 0;
+ }
+ if ((host[idx] != '.') && (host[idx] != '-')) {
+ return 0;
+ }
+ if (host[idx] == '.') {
+ dots++;
+ }
+ }
+ }
+ if (host[len - 1] == '.') {
+ return 0;
+ }
+ /**
+ * Ultimate3 dosnt like a non-dotted hosts at all, nor does unreal,
+ * so just dont allow them.
+ **/
+ if (dots == 0) {
+ return 0;
+ }
+
+ break;
+ }
+ return 1;
+}
+
+/**
+ * Return 1 if a host is valid, 0 if it isnt.
+ * host = string to check
+ * type = format, 1 = ip4addr, 2 = hostname, 3 = either
+ *
+ * shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
+ * hostname = shortname *( "." shortname )
+ * ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
+ *
+ **/
+int isValidHost(const char *host, int type)
+{
+ int status = 0;
+ if (type == 3) {
+ if (!(status = doValidHost(host, 1))) {
+ status = doValidHost(host, 2);
+ }
+ } else {
+ status = doValidHost(host, type);
+ }
+ return status;
+}
+
+int isvalidchar(const char c)
+{
+ if (((c >= 'A') && (c <= 'Z')) ||
+ ((c >= 'a') && (c <= 'z')) ||
+ ((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
+ return 1;
+ else
+ return 0;
+}
+
+char *myStrGetToken(const char *str, const char dilim, int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+char *myStrGetOnlyToken(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if (str[idx] == dilim) {
+ if (counter == token_number) {
+ if (str[idx] == '\r')
+ substring = myStrSubString(str, start_pos, idx - 1);
+ else
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+char *myStrGetTokenRemainder(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, len);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+char *myStrSubString(const char *src, int start, int end)
+{
+ char *substring = NULL;
+ int len, idx;
+ if (!src) {
+ return NULL;
+ }
+ len = strlen(src);
+ if (((start >= 0) && (end <= len)) && (end > start)) {
+ substring = (char *) malloc(sizeof(char) * ((end - start) + 1));
+ for (idx = 0; idx <= end - start; idx++) {
+ substring[idx] = src[start + idx];
+ }
+ substring[end - start] = '\0';
+ }
+ return substring;
+}
+
+void doCleanBuffer(char *str)
+{
+ char *in = str;
+ char *out = str;
+ char ch;
+
+ while (issp(ch = *in++));
+ if (ch != '\0')
+ for (;;) {
+ *out++ = ch;
+ ch = *in++;
+ if (ch == '\0')
+ break;
+ if (!issp(ch))
+ continue;
+ while (issp(ch = *in++));
+ if (ch == '\0')
+ break;
+ *out++ = ' ';
+ }
+ *out = ch; // == '\0'
+}