bitchx/source/ircaux.c

3227 lines
62 KiB
C

/*
* ircaux.c: some extra routines... not specific to irc... that I needed
*
* Written By Michael Sandrof
*
* Copyright(c) 1990, 1991
*
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
*/
#include "irc.h"
static char cvsrevision[] = "$Id$";
CVS_REVISION(ircaux_c)
#include "struct.h"
#include "alias.h"
#include "log.h"
#include "misc.h"
#include "vars.h"
#include "screen.h"
#include <pwd.h>
#include <sys/stat.h>
#include "ircaux.h"
#include "output.h"
#include "ircterm.h"
#define MAIN_SOURCE
#include "modval.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN PATHLEN
#endif
/*
* These are used by the malloc routines. We actually ask for an int-size
* more of memory, and in that extra int we store the malloc size. Very
* handy for debugging and other hackeries.
*/
/*#define MEM_DEBUG 1*/
#ifdef MEM_DEBUG
#include <dmalloc.h>
#endif
#define alloc_start(ptr) ((ptr) - sizeof(void *))
#define alloc_size(ptr) (*(int *)( alloc_start((ptr)) ))
#define FREE_DEBUG 1
#define FREED_VAL -3
#define ALLOC_MAGIC 0xafbdce70
char compress_buffer[10000];
void start_memdebug(void)
{
#ifdef MEM_DEBUG
dmalloc_debug(/*0x2202*/0x14f41d83);
#endif
}
/*
* really_new_malloc is the general interface to the malloc(3) call.
* It is only called by way of the ``new_malloc'' #define.
* It wont ever return NULL.
*/
/*
* Malloc allocator with size caching.
*/
void * n_malloc (size_t size, const char *module, const char *file, const int line)
{
char *ptr;
#ifdef MEM_DEBUG
if (!(ptr = (char *)_calloc_leap(file, line, 1, size+sizeof(void *))))
#else
if (!(ptr = (char *)calloc(1, size+sizeof(void *)+sizeof(void *))))
#endif
{
yell("Malloc() failed, giving up!");
putlog(LOG_ALL, "*", "*** failed calloc %s %s (%d)", module?module:empty_string, file, line);
term_reset();
exit(1);
}
/* Store the size of the allocation in the buffer. */
ptr += sizeof(void *);
alloc_size(ptr) = size;
return ptr;
}
/*
* new_free: Why do this? Why not? Saves me a bit of trouble here and there
*/
void * n_free(void **ptr, const char *module, const char *file, const int line)
{
if (*ptr)
{
#ifdef FREE_DEBUG
/* Check to make sure its not been freed before */
if (alloc_size(*ptr) == FREED_VAL)
{
yell("free()ing a already free'd pointer, giving up!");
putlog(LOG_ALL, "*", "*** failed free %s %s (%d)", module?module:empty_string, file, line);
term_reset();
exit(1);
}
#endif
alloc_size(*ptr) = FREED_VAL;
#ifdef MEM_DEBUG
_free_leap(file, line, (void *)alloc_start(*ptr));
#else
free((void *)alloc_start(*ptr));
#endif
*ptr = NULL;
}
return (*ptr);
}
void * n_realloc (void **ptr, size_t size, const char *module, const char *file, const int line)
{
char *ptr2 = NULL;
if (*ptr)
{
if (size)
{
size_t msize = alloc_size(*ptr);
if (msize >= size)
return *ptr;
ptr2 = n_malloc(size, module, file, line);
memmove(ptr2, *ptr, msize);
n_free(ptr, module, file, line);
return ((*ptr = ptr2));
}
n_free(ptr, module, file, line);
return NULL;
}
else if (size)
ptr2 = n_malloc(size, module, file, line);
return ((*ptr = ptr2));
}
/*
* malloc_strcpy: Mallocs enough space for src to be copied in to where
* ptr points to.
*
* Never call this with ptr pointinng to an uninitialised string, as the
* call to new_free() might crash the client... - phone, jan, 1993.
*/
char * n_malloc_strcpy (char **ptr, const char *src, const char *module, const char *file, const int line)
{
if (!src)
return n_free((void **)ptr, module, file, line);
if (ptr && *ptr)
{
if (*ptr == src)
return *ptr;
if (alloc_size(*ptr) > strlen(src))
return strcpy(*ptr, src);
n_free((void **)ptr, module, file, line);
}
*ptr = n_malloc(strlen(src) + 1, module, file, line);
return strcpy(*ptr, src);
return *ptr;
}
/* malloc_strcat: Yeah, right */
char * n_malloc_strcat (char **ptr, const char *src, const char *module, const char *file, const int line)
{
size_t msize;
if (*ptr)
{
if (!src)
return *ptr;
msize = strlen(*ptr) + strlen(src) + 1;
n_realloc((void **)ptr, sizeof(char)*msize, module, file, line);
return strcat(*ptr, src);
}
return (*ptr = n_m_strdup(src, module, file, line));
}
char *BX_malloc_str2cpy(char **ptr, const char *src1, const char *src2)
{
if (!src1 && !src2)
return new_free(ptr);
if (*ptr)
{
if (alloc_size(*ptr) > strlen(src1) + strlen(src2))
return strcat(strcpy(*ptr, src1), src2);
new_free(ptr);
}
*ptr = new_malloc(strlen(src1) + strlen(src2) + 1);
return strcat(strcpy(*ptr, src1), src2);
}
char *BX_m_3dup (const char *str1, const char *str2, const char *str3)
{
size_t msize = strlen(str1) + strlen(str2) + strlen(str3) + 1;
return strcat(strcat(strcpy((char *)new_malloc(msize), str1), str2), str3);
}
char *BX_m_opendup (const char *str1, ...)
{
va_list args;
int size;
char *this_arg = NULL;
char *retval = NULL;
size = strlen(str1);
va_start(args, str1);
while ((this_arg = va_arg(args, char *)))
size += strlen(this_arg);
retval = (char *)new_malloc(size + 1);
strcpy(retval, str1);
va_start(args, str1);
while ((this_arg = va_arg(args, char *)))
strcat(retval, this_arg);
va_end(args);
return retval;
}
char *n_m_strdup (const char *str, const char *module, const char *file, const int line)
{
char *ptr;
if (!str)
str = empty_string;
ptr = (char *)n_malloc(strlen(str) + 1, module, file, line);
return strcpy(ptr, str);
}
char *BX_m_s3cat (char **one, const char *maybe, const char *definitely)
{
if (*one && **one)
return m_3cat(one, maybe, definitely);
return malloc_strcpy(one, definitely);
}
char *BX_m_s3cat_s (char **one, const char *maybe, const char *ifthere)
{
if (ifthere && *ifthere)
return m_3cat(one, maybe, ifthere);
return *one;
}
char *BX_m_3cat(char **one, const char *two, const char *three)
{
int len = 0;
char *str;
if (*one)
len = strlen(*one);
if (two)
len += strlen(two);
if (three)
len += strlen(three);
len += 1;
str = (char *)new_malloc(len);
if (*one)
strcpy(str, *one);
if (two)
strcat(str, two);
if (three)
strcat(str, three);
new_free(one);
return ((*one = str));
}
char *BX_upper (char *str)
{
register char *ptr = NULL;
if (str)
{
ptr = str;
for (; *str; str++)
{
if (islower((unsigned char)*str))
*str = toupper(*str);
}
}
return (ptr);
}
char *BX_lower (char *str)
{
register char *ptr = NULL;
if (str)
{
ptr = str;
for (; *str; str++)
{
if (isupper((unsigned char)*str))
*str = tolower(*str);
}
}
return (ptr);
}
char *BX_malloc_sprintf (char **to, const char *pattern, ...)
{
char booya[BIG_BUFFER_SIZE*3+1];
*booya = 0;
if (pattern)
{
va_list args;
va_start (args, pattern);
vsnprintf(booya, BIG_BUFFER_SIZE * 3, pattern, args);
va_end(args);
}
malloc_strcpy(to, booya);
return *to;
}
/* same thing, different variation */
char *BX_m_sprintf (const char *pattern, ...)
{
char booya[BIG_BUFFER_SIZE * 3 + 1];
*booya = 0;
if (pattern)
{
va_list args;
va_start (args, pattern);
vsnprintf(booya, BIG_BUFFER_SIZE * 3, pattern, args);
va_end(args);
}
return m_strdup(booya);
}
/* case insensitive string searching */
char *BX_stristr (const char *source, const char *search)
{
int x = 0;
if (!source || !*source || !search || !*search || strlen(source) < strlen(search))
return NULL;
while (*source)
{
if (source[x] && toupper(source[x]) == toupper(search[x]))
x++;
else if (search[x])
source++, x = 0;
else
return (char *)source;
}
return NULL;
}
/* case insensitive string searching from the end */
char *BX_rstristr (char *source, char *search)
{
char *ptr;
int x = 0;
if (!source || !*source || !search || !*search || strlen(source) < strlen(search))
return NULL;
ptr = source + strlen(source) - strlen(search);
while (ptr >= source)
{
if (!search[x])
return ptr;
if (toupper(ptr[x]) == toupper(search[x]))
x++;
else
ptr--, x = 0;
}
return NULL;
}
/*
* word_count: Efficient way to find out how many words are in
* a given string. Relies on isspace() not being broken.
*/
int BX_word_count (char *str)
{
int cocs = 0;
int isv = 1;
register char *foo = str;
if (!foo)
return 0;
while (*foo)
{
if (*foo == '"' && isv)
{
while (*(foo+1) && *++foo != '"')
;
isv = 0;
cocs++;
}
if (!my_isspace(*foo) != !isv)
{
isv = my_isspace(*foo);
cocs++;
}
foo++;
}
return (cocs + 1) / 2;
}
#if 0
extern int word_scount (char *str)
{
int cocs = 0;
char *foo = str;
int isv = 1;
if (!foo)
return 0;
while (*foo)
{
if (my_isspace(*foo) != !isv)
{
isv = my_isspace(*foo);
cocs++;
}
foo++;
}
return (cocs + 1) / 2;
}
#endif
char *BX_next_arg (char *str, char **new_ptr)
{
char *ptr;
/* added by Sheik (kilau@prairie.nodak.edu) -- sanity */
if (!str || !*str)
return NULL;
if ((ptr = sindex(str, "^ ")) != NULL)
{
if ((str = sindex(ptr, space)) != NULL)
*str++ = (char) 0;
else
str = empty_string;
}
else
str = empty_string;
if (new_ptr)
*new_ptr = str;
return ptr;
}
extern char *BX_remove_trailing_spaces (char *foo)
{
char *end;
if (!*foo)
return foo;
end = foo + strlen(foo) - 1;
while (end > foo && my_isspace(*end))
end--;
end[1] = 0;
return foo;
}
/*
* yanks off the last word from 'src'
* kinda the opposite of next_arg
*/
char *BX_last_arg (char **src)
{
char *ptr;
if (!src || !*src)
return NULL;
remove_trailing_spaces(*src);
ptr = *src + strlen(*src) - 1;
if (*ptr == '"')
{
for (ptr--;;ptr--)
{
if (*ptr == '"')
{
if (ptr == *src)
break;
if (ptr[-1] == ' ')
{
ptr--;
break;
}
}
if (ptr == *src)
break;
}
}
else
{
for (;;ptr--)
{
if (*ptr == ' ')
break;
if (ptr == *src)
break;
}
}
if (ptr == *src)
{
ptr = *src;
*src = empty_string;
}
else
{
*ptr++ = 0;
remove_trailing_spaces(*src);
}
return ptr;
}
#define risspace(c) (c == ' ')
char *BX_new_next_arg (char *str, char **new_ptr)
{
char *ptr,
*start;
if (!str || !*str)
return NULL;
ptr = str;
while (*ptr && risspace(*ptr))
ptr++;
if (*ptr == '"')
{
start = ++ptr;
for (str = start; *str; str++)
{
if (*str == '\\' && str[1])
str++;
else if (*str == '"')
{
*(str++) = 0;
if (risspace(*str))
str++;
break;
}
}
}
else if (*ptr)
{
str = ptr;
while (*str && !risspace(*str))
str++;
if (*str)
*str++ = 0;
}
if (!*str || !*ptr)
str = empty_string;
if (new_ptr)
*new_ptr = str;
return ptr;
}
/*
* This function is "safe" because it doesnt ever return NULL.
* XXXX - this is an ugly kludge that needs to go away
*/
char *safe_new_next_arg (char *str, char **new_ptr)
{
char *ptr,
*start;
if (!str || !*str)
return empty_string;
if ((ptr = sindex(str, "^ \t")) != NULL)
{
if (*ptr == '"')
{
start = ++ptr;
while ((str = sindex(ptr, "\"\\")) != NULL)
{
switch (*str)
{
case '"':
*str++ = '\0';
if (*str == ' ')
str++;
if (new_ptr)
*new_ptr = str;
return (start);
case '\\':
if (*(str + 1) == '"')
ov_strcpy(str, str + 1);
ptr = str + 1;
}
}
str = empty_string;
}
else
{
if ((str = sindex(ptr, " \t")) != NULL)
*str++ = '\0';
else
str = empty_string;
}
}
else
str = empty_string;
if (new_ptr)
*new_ptr = str;
if (!ptr)
return empty_string;
return ptr;
}
char *BX_new_new_next_arg (char *str, char **new_ptr, char *type)
{
char *ptr,
*start;
if (!str || !*str)
return NULL;
if ((ptr = sindex(str, "^ \t")) != NULL)
{
if ((*ptr == '"') || (*ptr == '\''))
{
char blah[3];
blah[0] = *ptr;
blah[1] = '\\';
blah[2] = '\0';
*type = *ptr;
start = ++ptr;
while ((str = sindex(ptr, blah)) != NULL)
{
switch (*str)
{
case '\'':
case '"':
*str++ = '\0';
if (*str == ' ')
str++;
if (new_ptr)
*new_ptr = str;
return (start);
case '\\':
if (str[1] == *type)
ov_strcpy(str, str + 1);
ptr = str + 1;
}
}
str = empty_string;
}
else
{
*type = '\"';
if ((str = sindex(ptr, " \t")) != NULL)
*str++ = 0;
else
str = empty_string;
}
}
else
str = empty_string;
if (new_ptr)
*new_ptr = str;
return ptr;
}
unsigned char stricmp_table [] =
{
0, 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, 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, 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, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255
};
/* my_stricmp: case insensitive version of strcmp */
int BX_my_stricmp (register const unsigned char *str1, register const unsigned char *str2)
{
while (*str1 && *str2 && (stricmp_table[(unsigned short)*str1] == stricmp_table[(unsigned short)*str2]))
str1++, str2++;
return (stricmp_table[(unsigned short)*str1] -
stricmp_table[(unsigned short)*str2]);
}
/* my_strnicmp: case insensitive version of strncmp */
int BX_my_strnicmp (register const unsigned char *str1, register const unsigned char *str2, register size_t n)
{
while (n && *str1 && *str2 && (stricmp_table[(unsigned short)*str1] == stricmp_table[(unsigned short)*str2]))
str1++, str2++, n--;
return (n ?
(stricmp_table[(unsigned short)*str1] -
stricmp_table[(unsigned short)*str2]) : 0);
}
/* my_strnstr: case insensitive version of strstr */
int BX_my_strnstr (register const unsigned char *str1, register const unsigned char *str2, register size_t n)
{
char *p = (char *)str1;
if (!p) return 0;
for (; *p; p++)
if (!strncasecmp(p, str2, strlen(str2)))
return 1;
return 0;
}
/* chop -- chops off the last character. capiche? */
char *BX_chop (char *stuff, int nchar)
{
size_t sl = strlen(stuff);
if (nchar > 0 && sl > 0 && nchar <= sl)
stuff[sl - nchar] = 0;
else if (nchar > sl)
stuff[0] = 0;
return stuff;
}
/*
* strext: Makes a copy of the string delmited by two char pointers and
* returns it in malloced memory. Useful when you dont want to munge up
* the original string with a null. end must be one place beyond where
* you want to copy, ie, its the first character you dont want to copy.
*/
char *strext(char *start, char *end)
{
char *ptr, *retval;
ptr = retval = (char *)new_malloc(end-start+1);
while (start < end)
*ptr++ = *start++;
*ptr = 0;
return retval;
}
/*
* strmcpy: Well, it's like this, strncpy doesn't append a trailing null if
* strlen(str) == maxlen. strmcpy always makes sure there is a trailing null
*/
char * BX_strmcpy (char *dest, const char *src, int maxlen)
{
strlcpy(dest, src, maxlen + 1);
return dest;
}
/*
* strmcat: like strcat, but truncs the dest string to maxlen (thus the dest
* should be able to handle maxlen+1 (for the null))
*/
char * BX_strmcat(char *dest, const char *src, int maxlen)
{
strlcat(dest, src, maxlen + 1);
return dest;
}
#ifdef INCLUDE_DEADCODE
/*
* strmcat_ue: like strcat, but truncs the dest string to maxlen (thus the dest
* should be able to handle maxlen + 1 (for the null)). Also unescapes
* backslashes.
*/
char * strmcat_ue(char *dest, const char *src, int maxlen)
{
int dstlen;
dstlen = strlen(dest);
dest += dstlen;
maxlen -= dstlen;
while (*src && maxlen > 0)
{
if (*src == '\\')
{
if (strchr("npr0", src[1]))
*dest++ = '\020';
else if (*(src + 1))
*dest++ = *++src;
else
*dest++ = '\\';
}
else
*dest++ = *src;
src++;
}
*dest = '\0';
return dest;
}
#endif
/*
* m_strcat_ues: Given two strings, concatenate the 2nd string to
* the end of the first one, but if the "unescape" argument is 1, do
* unescaping (like in strmcat_ue).
* (Malloc_STRCAT_UnEscape Special, in case you were wondering. ;-))
*
* This uses a cheating, "not-as-efficient-as-possible" algorithm,
* but it works with negligible cpu lossage.
*/
char * n_m_strcat_ues(char **dest, char *src, int unescape, const char *module, const char *file, const int line)
{
int total_length;
char *ptr, *ptr2;
int z;
if (!unescape)
{
n_malloc_strcat(dest, src, module, file, line);
return *dest;
}
z = total_length = (*dest) ? strlen(*dest) : 0;
total_length += strlen(src);
/* RESIZE(*dest, char, total_length + 2);*/
n_realloc((void **)dest, sizeof(char) * (total_length + 2), module, file, line);
if (z == 0)
**dest = 0;
ptr2 = *dest + z;
for (ptr = src; *ptr; ptr++)
{
if (*ptr == '\\')
{
switch (*++ptr)
{
case 'n': case 'p': case 'r': case '0':
*ptr2++ = '\020';
break;
case (char) 0:
*ptr2++ = '\\';
goto end_strcat_ues;
break;
default:
*ptr2++ = *ptr;
}
}
else
*ptr2++ = *ptr;
}
end_strcat_ues:
*ptr2 = '\0';
return *dest;
}
/*
* scanstr: looks for an occurrence of str in source. If not found, returns
* 0. If it is found, returns the position in source (1 being the first
* position). Not the best way to handle this, but what the hell
*/
extern int BX_scanstr (char *str, char *source)
{
int i,
max,
len;
len = strlen(str);
max = strlen(source) - len;
for (i = 0; i <= max; i++, source++)
{
if (!my_strnicmp(source, str, len))
return (i + 1);
}
return (0);
}
#if defined(WINNT) || defined(__EMX__)
char *convert_dos(char *str)
{
register char *p;
for (p = str; *p; p++)
if (*p == '/')
*p = '\\';
return str;
}
char *convert_unix(char *arg)
{
register char *x = arg;
while (*x)
{
if (*x == '\\')
*x = '/';
x++;
}
return arg;
}
int is_dos(char *filename)
{
if (strlen(filename) > 3 && ( (*(filename+1) == ':') && (*(filename+2) == '/' || *(filename+2) == '\\')) )
return 1;
else
return 0;
}
#endif
/* expand_twiddle: expands ~ in pathnames. */
char *BX_expand_twiddle (char *str)
{
char buffer[BIG_BUFFER_SIZE/4 + 1];
char *str2;
#ifdef WINNT
convert_unix(str);
#endif
if (*str == '~')
{
str++;
#if defined(WINNT) || defined(__EMX__)
if (*str == '\\' || *str == '/')
#else
if (*str == '/')
#endif
{
strmcpy(buffer, my_path, BIG_BUFFER_SIZE/4);
strmcat(buffer, str, BIG_BUFFER_SIZE/4);
}
else
{
char *rest;
struct passwd *entry;
char *p = NULL;
if ((rest = strchr(str, '/')) != NULL)
*rest++ = '\0';
#if defined(WINNT) || defined(__EMX__)
if (((entry = getpwnam(str)) != NULL) || (p = getenv("HOME")))
{
if (p)
strmcpy(buffer, p, BIG_BUFFER_SIZE/4);
else
strmcpy(buffer, entry->pw_dir, BIG_BUFFER_SIZE/4);
#else
if ((entry = getpwnam(str)) != NULL || (p = getenv("HOME")))
{
if (p)
strmcpy(buffer, p, BIG_BUFFER_SIZE/4);
else
strmcpy(buffer, entry->pw_dir, BIG_BUFFER_SIZE/4);
#endif
if (rest)
{
strmcat(buffer, "/", BIG_BUFFER_SIZE/4);
strmcat(buffer, rest, BIG_BUFFER_SIZE/4);
}
}
else
return (char *) NULL;
}
}
else
strmcpy(buffer, str, BIG_BUFFER_SIZE/4);
/* This isnt legal! */
str2 = NULL;
malloc_strcpy(&str2, buffer);
#ifdef __EMX__
convert_unix(str2);
#endif
return str2;
}
/* islegal: true if c is a legal nickname char anywhere but first char */
#define islegal(c) ((((c) >= 'A') && ((c) <= '}')) || \
(((c) >= '0') && ((c) <= '9')) || \
((c) == '-') || ((c) == '_'))
/*
* check_nickname: checks is a nickname is legal. If the first character is
* bad new, null is returned. If the first character is bad, the string is
* truncd down to only legal characters and returned
*
* rewritten, with help from do_nick_name() from the server code (2.8.5),
* phone, april 1993.
*/
char *BX_check_nickname (char *nick)
{
char *s;
int len = 0;
if (!nick || *nick == '-' || isdigit((unsigned char)*nick) ||
!islegal(*nick))
return NULL;
for (s = nick; *s && (s - nick) < NICKNAME_LEN ; s++, len++)
if (!islegal(*s) || my_isspace(*s))
break;
*s = '\0';
return *nick ? nick : NULL;
}
/*
* sindex: much like index(), but it looks for a match of any character in
* the group, and returns that position. If the first character is a ^, then
* this will match the first occurence not in that group.
*/
char *BX_sindex (register char *string, char *group)
{
char *ptr;
if (!string || !group)
return (char *) NULL;
if (*group == '^')
{
group++;
for (; *string; string++)
{
for (ptr = group; *ptr; ptr++)
{
if (*ptr == *string)
break;
}
if (*ptr == '\0')
return string;
}
}
else
{
for (; *string; string++)
{
for (ptr = group; *ptr; ptr++)
{
if (*ptr == *string)
return string;
}
}
}
return (char *) NULL;
}
/*
* rsindex: much like rindex(), but it looks for a match of any character in
* the group, and returns that position. If the first character is a ^, then
* this will match the first occurence not in that group.
*/
char *BX_rsindex (register char *string, char *start, char *group, int howmany)
{
register char *ptr;
if (howmany && string && start && group && start <= string)
{
if (*group == '^')
{
group++;
for (ptr = string; (ptr >= start) && howmany; ptr--)
{
if (!strchr(group, *ptr))
{
if (--howmany == 0)
return ptr;
}
}
}
else
{
for (ptr = string; (ptr >= start) && howmany; ptr--)
{
if (strchr(group, *ptr))
{
if (--howmany == 0)
return ptr;
}
}
}
}
return NULL;
}
/* is_number: returns true if the given string is a number, false otherwise */
int BX_is_number (const char *str)
{
if (!str || !*str)
return 0;
while (*str == ' ')
str++;
if (*str == '-' || *str == '+')
str++;
if (*str)
{
for (; *str; str++)
{
if (!isdigit((unsigned char)(*str)))
return (0);
}
return 1;
}
else
return 0;
}
/* rfgets: exactly like fgets, cept it works backwards through a file! */
char *BX_rfgets (char *buffer, int size, FILE *file)
{
char *ptr;
off_t pos;
if (fseek(file, -2L, SEEK_CUR))
return NULL;
do
{
switch (fgetc(file))
{
case EOF:
return NULL;
case '\n':
pos = ftell(file);
ptr = fgets(buffer, size, file);
fseek(file, pos, 0);
return ptr;
}
}
while (fseek(file, -2L, SEEK_CUR) == 0);
rewind(file);
pos = 0L;
ptr = fgets(buffer, size, file);
fseek(file, pos, 0);
return ptr;
}
/*
* path_search: given a file called name, this will search each element of
* the given path to locate the file. If found in an element of path, the
* full path name of the file is returned in a static string. If not, null
* is returned. Path is a colon separated list of directories
*/
char *BX_path_search (char *name, char *path)
{
static char buffer[BIG_BUFFER_SIZE/2 + 1];
char *ptr,
*free_path = NULL;
/* A "relative" path is valid if the file exists */
/* A "relative" path is searched in the path if the
filename doesnt really exist from where we are */
if (strchr(name, '/'))
if (!access(name, F_OK))
return name;
/* an absolute path is always checked, never searched */
#if defined(WINNT) || defined(__EMX__)
if (name[0] == '/' || name[0] == '\\')
#else
if (name[0] == '/')
#endif
return (access(name, F_OK) ? NULL : name);
if (!path)
return NULL;
/* This is cheating. >;-) */
free_path = LOCAL_COPY(path);
path = free_path;
#ifdef __EMX__
convert_unix(path);
#endif
while (path)
{
#if defined(WINNT) || defined(__EMX__)
if (((ptr = strchr(path, ';')) != NULL) || ((ptr = strchr(path, ':')) != NULL))
#else
if ((ptr = strchr(path, ':')) != NULL)
#endif
*ptr++ = '\0';
*buffer = 0;
if (path[0] == '~')
{
strmcat(buffer, my_path, BIG_BUFFER_SIZE/4);
path++;
}
strmcat(buffer, path, BIG_BUFFER_SIZE/4);
strmcat(buffer, "/", BIG_BUFFER_SIZE/4);
strmcat(buffer, name, BIG_BUFFER_SIZE/4);
if (access(buffer, F_OK) == 0)
break;
path = ptr;
}
return (path != NULL) ? buffer : NULL;
}
/*
* double_quote: Given a str of text, this will quote any character in the
* set stuff with the QUOTE_CHAR. It returns a malloced quoted, null
* terminated string
*/
char *BX_double_quote (const char *str, const char *stuff, char *buffer)
{
register char c;
register int pos;
*buffer = 0;
if (!stuff)
return buffer;
for (pos = 0; (c = *str); str++)
{
if (strchr(stuff, c))
{
if (c == '$')
buffer[pos++] = '$';
else
buffer[pos++] = '\\';
}
buffer[pos++] = c;
}
buffer[pos] = '\0';
return buffer;
}
char *quote_it (const char *str, const char *stuff, char *buffer)
{
register char c;
register int pos;
*buffer = 0;
for (pos = 0; (c = *str); str++)
{
if (stuff && strchr(stuff, c))
{
if (c == '%')
buffer[pos++] = '%';
else
buffer[pos++] = '\\';
}
else if (c == '%')
buffer[pos++] = '%';
buffer[pos++] = c;
}
buffer[pos] = '\0';
return buffer;
}
void BX_ircpanic (char *format, ...)
{
char buffer[3 * BIG_BUFFER_SIZE + 1];
extern char cx_function[];
static int recursion = 0;
if (recursion || x_debug & DEBUG_CRASH)
abort();
recursion++;
if (format)
{
va_list arglist;
va_start(arglist, format);
vsnprintf(buffer, BIG_BUFFER_SIZE, format, arglist);
va_end(arglist);
}
yell("An unrecoverable logic error has occured.");
yell("Please email %s giving me the following message", "edwards@bitchx.dimension6.com" );
yell("Panic: [%s:%s %s]", irc_version, buffer, cx_function?cx_function:empty_string);
dump_call_stack();
irc_exit(1, "BitchX panic... Could it possibly be a bug? Nahhhh...", NULL);
}
/* Not very complicated, but very handy function to have */
int BX_end_strcmp (const char *one, const char *two, int bytes)
{
if (bytes < strlen(one))
return (strcmp(one + strlen (one) - (size_t) bytes, two));
else
return -1;
}
/* beep_em: Not hard to figure this one out */
void BX_beep_em (int beeps)
{
int cnt,
i;
for (cnt = beeps, i = 0; i < cnt; i++)
term_beep();
}
FILE *open_compression (char *executable, char *filename, int hook)
{
FILE *file_pointer = NULL;
int pipes[2];
pipes[0] = -1;
pipes[1] = -1;
if (pipe (pipes) == -1)
{
if (hook)
yell("Cannot start decompression: %s\n", strerror(errno));
if (pipes[0] != -1)
{
close (pipes[0]);
close (pipes[1]);
}
return NULL;
}
switch (fork ())
{
case -1:
{
if (hook)
yell("Cannot start decompression: %s\n", strerror(errno));
return NULL;
}
case 0:
{
int i;
#if !defined(WINNT) && !defined(__EMX__)
setsid();
#endif
setuid (getuid ());
setgid (getgid ());
dup2 (pipes[1], 1);
close (pipes[0]);
for (i = 2; i < 256; i++)
close(i);
#ifdef ZARGS
execl (executable, executable, "-c", ZARGS, filename, NULL);
#else
execl (executable, executable, "-c", filename, NULL);
#endif
_exit (0);
}
default :
{
close (pipes[1]);
if ((file_pointer = fdopen(pipes[0], "r")) == NULL)
{
if (hook)
yell("Cannot start decompression: %s\n", strerror(errno));
return NULL;
}
#if 0
setlinebuf(file_pointer);
setvbuf(file_pointer, NULL, _IONBF, 0);
#endif
break;
}
}
return file_pointer;
}
/* Front end to fopen() that will open ANY file, compressed or not, and
* is relatively smart about looking for the possibilities, and even
* searches a path for you! ;-)
*/
FILE *BX_uzfopen (char **filename, char *path, int hook)
{
static int setup = 0;
int ok_to_decompress = 0;
char * filename_path;
char *filename_trying;
char *filename_blah;
static char *path_to_gunzip = NULL;
static char *path_to_uncompress = NULL;
static char *path_to_bunzip2 = NULL;
FILE * doh = NULL;
filename_trying = alloca(MAXPATHLEN+1);
if (!setup)
{
char *gzip = path_search("gunzip", getenv("PATH"));
char *compress = NULL;
char *bzip = NULL;
if (!gzip)
gzip = empty_string;
path_to_gunzip = m_strdup(gzip);
if (!(compress = path_search("uncompress", getenv("PATH"))))
compress = empty_string;
path_to_uncompress = m_strdup(compress);
if (!(bzip = path_search("bunzip2", getenv("PATH"))))
bzip = empty_string;
path_to_bunzip2 = m_strdup(bzip);
setup = 1;
}
/* It is allowed to pass to this function either a true filename
with the compression extention, or to pass it the base name of
the filename, and this will look to see if there is a compressed
file that matches the base name */
/* Start with what we were given as an initial guess */
if (**filename == '~')
{
filename_blah = expand_twiddle(*filename);
strlcpy(filename_trying, filename_blah, MAXPATHLEN);
new_free(&filename_blah);
}
else
strlcpy(filename_trying, *filename, MAXPATHLEN);
/* Look to see if the passed filename is a full compressed filename */
if ((! end_strcmp (filename_trying, ".gz", 3)) ||
(! end_strcmp (filename_trying, ".z", 2)))
{
if (path_to_gunzip)
{
ok_to_decompress = 1;
filename_path = path_search (filename_trying, path);
}
else
{
if (hook)
yell("Cannot open file %s because gunzip was not found", filename_trying);
new_free(filename);
return NULL;
}
}
else if (! end_strcmp (filename_trying, ".Z", 2))
{
if (path_to_gunzip || path_to_uncompress)
{
ok_to_decompress = 1;
filename_path = path_search (filename_trying, path);
}
else
{
if (hook)
yell("Cannot open file %s because uncompress was not found", filename_trying);
new_free(filename);
return NULL;
}
}
else if (!end_strcmp(filename_trying, ".bz2", 4))
{
if (*path_to_bunzip2)
{
ok_to_decompress = 3;
filename_path = path_search(filename_trying, path);
}
else
{
if (hook)
yell("Cannot open file %s because bunzip2 was not found", filename_trying);
new_free(filename);
return NULL;
}
}
/* Right now it doesnt look like the file is a full compressed fn */
else
{
struct stat file_info;
/* Trivially, see if the file we were passed exists */
filename_path = path_search (filename_trying, path);
/* Nope. it doesnt exist. */
if (!filename_path)
{
/* Is there a "filename.gz"? */
strlcpy (filename_trying, *filename, MAXPATHLEN);
strlcat (filename_trying, ".gz", MAXPATHLEN);
filename_path = path_search (filename_trying, path);
/* Nope. no "filename.gz" */
if (!filename_path)
{
/* Is there a "filename.Z"? */
strlcpy (filename_trying, *filename, MAXPATHLEN);
strlcat (filename_trying, ".Z", MAXPATHLEN);
filename_path = path_search (filename_trying, path);
/* Nope. no "filename.Z" */
if (!filename_path)
{
/* Is there a "filename.z"? */
strlcpy (filename_trying, *filename, MAXPATHLEN);
strlcat (filename_trying, ".z", MAXPATHLEN);
filename_path = path_search (filename_trying, path);
if (!filename_path)
{
strlcpy(filename_trying, *filename, MAXPATHLEN);
strlcat(filename_trying, ".bz2", MAXPATHLEN);
filename_path = path_search(filename_trying, path);
if (!filename_path)
{
if (hook)
yell("File not found: %s", *filename);
new_free(filename);
return NULL;
}
else
/* found a bz2 */
ok_to_decompress = 3;
}
/* Yep. there's a "filename.z" */
else
ok_to_decompress = 2;
}
/* Yep. there's a "filename.Z" */
else
ok_to_decompress = 1;
}
/* Yep. There's a "filename.gz" */
else
ok_to_decompress = 2;
}
/* Imagine that! the file exists as-is (no decompression) */
else
ok_to_decompress = 0;
stat (filename_path, &file_info);
if (file_info.st_mode & S_IFDIR)
{
if (hook)
yell("%s is a directory", filename_trying);
new_free(filename);
return NULL;
}
#ifndef WINNT
if (file_info.st_mode & 0111)
{
char *p;
if ((p = strrchr(filename_path, '.')))
{
p++;
if (!strcmp(p, "so"))
{
malloc_strcpy(filename, filename_path);
return NULL;
}
}
if (hook)
yell("Cannot open %s -- executable file", filename_trying);
new_free(filename);
return NULL;
}
#endif
}
malloc_strcpy (filename, filename_path);
/* at this point, we should have a filename in the variable
filename_trying, and it should exist. If ok_to_decompress
is one, then we can gunzip the file if guzip is available,
else we uncompress the file */
if (ok_to_decompress)
{
if (ok_to_decompress <= 2 && *path_to_gunzip)
return open_compression (path_to_gunzip, filename_path, hook);
else if ((ok_to_decompress == 1) && *path_to_uncompress)
return open_compression (path_to_uncompress, filename_path, hook);
else if ((ok_to_decompress == 3) && *path_to_bunzip2)
return open_compression(path_to_bunzip2, filename_path, hook);
if (hook)
yell("Cannot open compressed file %s because no uncompressor was found", filename_trying);
new_free(filename);
return NULL;
}
/* Its not a compressed file... Try to open it regular-like. */
if ((doh = fopen(filename_path, "r")) != NULL)
return doh;
/* nope.. we just cant seem to open this file... */
if (hook)
yell("Cannot open file %s: %s", filename_path, strerror(errno));
new_free(filename);
return NULL;
}
#ifdef INCLUDE_DEADCODE
/* some more string manips by hop (june, 1995) */
extern int fw_strcmp(comp_len_func *compar, char *one, char *two)
{
int len = 0;
char *pos = one;
while (!my_isspace(*pos))
pos++, len++;
return compar(one, two, len);
}
/*
* Compares the last word in 'one' to the string 'two'. You must provide
* the compar function. my_stricmp is a good default.
*/
extern int lw_strcmp(comp_func *compar, char *one, char *two)
{
char *pos = one + strlen(one) - 1;
if (pos > one) /* cant do pos[-1] if pos == one */
while (!my_isspace(pos[-1]) && (pos > one))
pos--;
else
pos = one;
if (compar)
return compar(pos, two);
else
return my_stricmp(pos, two);
}
/*
* you give it a filename, some flags, and a position, and it gives you an
* fd with the file pointed at the 'position'th byte.
*/
extern int opento(char *filename, int flags, off_t position)
{
int file;
file = open(filename, flags, 777);
lseek(file, position, SEEK_SET);
return file;
}
#endif
/* swift and easy -- returns the size of the file */
off_t file_size (char *filename)
{
struct stat statbuf;
if (!stat(filename, &statbuf))
return (off_t)(statbuf.st_size);
else
return -1;
}
/* Gets the time in second/usecond if you can, second/0 if you cant. */
struct timeval BX_get_time(struct timeval *timer)
{
static struct timeval timer2;
#ifdef HAVE_GETTIMEOFDAY
if (timer)
{
gettimeofday(timer, NULL);
return *timer;
}
gettimeofday(&timer2, NULL);
return timer2;
#else
time_t time2 = time(NULL);
if (timer)
{
timer->tv_sec = time2;
timer->tv_usec = 0;
return *timer;
}
timer2.tv_sec = time2;
timer2.tv_usec = 0;
return timer2;
#endif
}
/*
* calculates the time elapsed between 'one' and 'two' where they were
* gotten probably with a call to get_time. 'one' should be the older
* timer and 'two' should be the most recent timer.
*/
double BX_time_diff (struct timeval one, struct timeval two)
{
struct timeval td;
td.tv_sec = two.tv_sec - one.tv_sec;
td.tv_usec = two.tv_usec - one.tv_usec;
return (double)td.tv_sec + ((double)td.tv_usec / 1000000.0);
}
int BX_time_to_next_minute (void)
{
time_t now = time(NULL);
static int which = 0;
if (which == 1)
return 60 - now % 60;
else
{
struct tm *now_tm = gmtime(&now);
if (!which)
{
if (now_tm->tm_sec == now % 60)
which = 1;
else
which = 2;
}
return 60-now_tm->tm_sec;
}
}
char *BX_plural (int number)
{
return (number != 1) ? "s" : empty_string;
}
char *BX_my_ctime (time_t when)
{
return chop(ctime(&when), 1);
}
char *BX_my_ltoa (long foo)
{
static char buffer[BIG_BUFFER_SIZE/8+1];
char *pos = buffer + BIG_BUFFER_SIZE/8-1;
unsigned long my_absv;
int negative;
my_absv = (foo < 0) ? (unsigned long)-foo : (unsigned long)foo;
negative = (foo < 0) ? 1 : 0;
buffer[BIG_BUFFER_SIZE/8] = 0;
for (; my_absv > 9; my_absv /= 10)
*pos-- = (my_absv % 10) + '0';
*pos = (my_absv) + '0';
if (negative)
*--pos = '-';
return pos;
}
/*
* Formats "src" into "dest" using the given length. If "length" is
* negative, then the string is right-justified. If "length" is
* zero, nothing happens. Sure, i cheat, but its cheaper then doing
* two sprintf's.
*/
char *BX_strformat (char *dest, const char *src, int length, char pad_char)
{
char *ptr1 = dest,
*ptr2 = (char *)src;
int tmplen = length;
int abslen;
char padc;
abslen = (length >= 0 ? length : -length);
if (!(padc = pad_char))
padc = ' ';
/* Cheat by spacing out 'dest' */
for (tmplen = abslen - 1; tmplen >= 0; tmplen--)
dest[tmplen] = padc;
dest[abslen] = 0;
/* Then cheat further by deciding where the string should go. */
if (length > 0) /* left justified */
{
while ((length-- > 0) && *ptr2)
*ptr1++ = *ptr2++;
}
else if (length < 0) /* right justified */
{
length = -length;
ptr1 = dest;
ptr2 = (char *)src;
if (strlen(src) < length)
ptr1 += length - strlen(src);
while ((length-- > 0) && *ptr2)
*ptr1++ = *ptr2++;
}
return dest;
}
/* MatchingBracket returns the next unescaped bracket of the given type */
char *BX_MatchingBracket(register char *string, register char left, register char right)
{
int bracket_count = 1;
if (left == '(')
{
for (; *string; string++)
{
switch (*string)
{
case '(':
bracket_count++;
break;
case ')':
bracket_count--;
if (bracket_count == 0)
return string;
break;
case '\\':
if (string[1])
string++;
break;
}
}
}
else if (left == '[')
{
for (; *string; string++)
{
switch (*string)
{
case '[':
bracket_count++;
break;
case ']':
bracket_count--;
if (bracket_count == 0)
return string;
break;
case '\\':
if (string[1])
string++;
break;
}
}
}
else /* Fallback for everyone else */
{
while (*string && bracket_count)
{
if (*string == '\\' && string[1])
string++;
else if (*string == left)
bracket_count++;
else if (*string == right)
{
if (--bracket_count == 0)
return string;
}
string++;
}
}
return NULL;
}
/*
* parse_number: returns the next number found in a string and moves the
* string pointer beyond that point in the string. Here's some examples:
*
* "123harhar" returns 123 and str as "harhar"
*
* while:
*
* "hoohar" returns -1 and str as "hoohar"
*/
extern int BX_parse_number(char **str)
{
long ret;
char *ptr = *str; /* sigh */
ret = strtol(ptr, str, 10);
if (*str == ptr)
ret = -1;
return (int)ret;
}
#if 0
extern char *chop_word(char *str)
{
char *end = str + strlen(str) - 1;
while (my_isspace(*end) && (end > str))
end--;
while (!my_isspace(*end) && (end > str))
end--;
if (end >= str)
*end = 0;
return str;
}
#endif
extern int BX_splitw (char *str, char ***to)
{
int numwords = word_count(str);
int counter;
if (numwords)
{
*to = (char **)new_malloc(sizeof(char *) * numwords);
for (counter = 0; counter < numwords; counter++)
(*to)[counter] = new_next_arg(str, &str);
}
else
*to = NULL;
return numwords;
}
char * BX_unsplitw (char ***container, int howmany)
{
char *retval = NULL;
char **str = *container;
while (howmany)
{
m_s3cat(&retval, space, *str);
str++, howmany--;
}
new_free((char **)container);
return retval;
}
char *BX_m_2dup (const char *str1, const char *str2)
{
size_t msize = strlen(str1) + strlen(str2) + 1;
return strcat(strcpy((char *)new_malloc(msize), str1), str2);
}
char *BX_m_e3cat (char **one, const char *yes1, const char *yes2)
{
if (*one && **one)
return m_3cat(one, yes1, yes2);
else
*one = m_2dup(yes1, yes2);
return *one;
}
double strtod();
extern int BX_check_val (char *sub)
{
long sval;
char *endptr;
if (!sub || !*sub)
return 0;
#ifdef __EMX__
if(strlen(sub) > 4 && strnicmp(sub, "infin", 5) == 0)
return 0;
#endif
/* get the numeric value (if any). */
sval = strtod(sub, &endptr);
/* Its OK if:
* 1) the f-val is not zero.
* 2) the first illegal character was not a null.
* 3) there were no valid f-chars.
*/
if (sval || *endptr || (sub == endptr))
return 1;
return 0;
}
char *BX_on_off(int var)
{
if (var)
return ("On");
return ("Off");
}
/*
* Appends 'num' copies of 'app' to the end of 'str'.
*/
extern char *BX_strextend(char *str, char app, int num)
{
char *ptr = str + strlen(str);
for (;num;num--)
*ptr++ = app;
*ptr = (char) 0;
return str;
}
const char *BX_strfill(char c, int num)
{
static char buffer[BIG_BUFFER_SIZE/4+1];
int i = 0;
if (num > BIG_BUFFER_SIZE/4)
num = BIG_BUFFER_SIZE/4;
for (i = 0; i < num; i++)
buffer[i] = c;
buffer[num] = 0;
return buffer;
}
#ifdef INCLUDE_DEADCODE
/*
* Appends the given character to the string
*/
char *strmccat(char *str, char c, int howmany)
{
int x = strlen(str);
if (x < howmany)
str[x] = c;
str[x+1] = 0;
return str;
}
/*
* Pull a substring out of a larger string
* If the ending delimiter doesnt occur, then we dont pass
* anything (by definition). This is because we dont want
* to introduce a back door into CTCP handlers.
*/
extern char *BX_pullstr (char *source_string, char *dest_string)
{
char delim = *source_string;
char *end;
end = strchr(source_string + 1, delim);
/* If there is no closing delim, then we punt. */
if (!end)
return NULL;
*end = 0;
end++;
strcpy(dest_string, source_string + 1);
strcpy(source_string, end);
return dest_string;
}
#endif
extern int BX_empty (const char *str)
{
while (str && *str && *str == ' ')
str++;
if (str && *str)
return 0;
return 1;
}
/* makes foo[one][two] look like tmp.one.two -- got it? */
char *BX_remove_brackets (const char *name, const char *args, int *arg_flag)
{
char *ptr, *right, *result1, *rptr, *retval = NULL;
/* XXXX - ugh. */
rptr = m_strdup(name);
while ((ptr = strchr(rptr, '[')))
{
*ptr++ = 0;
right = ptr;
if ((ptr = MatchingBracket(right, '[', ']')))
*ptr++ = 0;
if (args)
result1 = expand_alias(right, args, arg_flag, NULL);
else
result1 = right;
retval = m_3dup(rptr, ".", result1);
if (ptr)
malloc_strcat(&retval, ptr);
if (args)
new_free(&result1);
if (rptr)
new_free(&rptr);
rptr = retval;
}
return upper(rptr);
}
long BX_my_atol (const char *str)
{
if (str)
return (long) strtol(str, NULL, 0);
else
return 0L;
}
#if 0
u_long hashpjw (char *text, u_long prime)
{
char *p;
u_long h = 0, g;
for (p = text; *p; p++)
{
h <<= 4;
h += *p;
if ((g = h & 0xf0000000))
{
h ^= (g >> 24);
h ^= g;
}
}
return h % prime;
}
#endif
char *BX_m_dupchar(int i)
{
char c = (char) i; /* blah */
char *ret = (char *)new_malloc(2);
ret[0] = c;
ret[1] = 0;
return ret;
}
#ifdef INCLUDE_DEADCODE
/*
* This checks to see if ``root'' is a proper subname for ``var''.
*/
int is_root (char *root, char *var, int descend)
{
int rootl, varl;
/* ``root'' must end in a dot */
rootl = strlen(root);
if (root[rootl] != '.')
return 0;
/* ``root'' must be shorter than ``var'' */
varl = strlen(var);
if (varl <= rootl)
return 0;
/* ``var'' must contain ``root'' as a leading subset */
if (my_strnicmp(root, var, rootl))
return 0;
/*
* ``var'' must not contain any additional dots
* if we are checking for the current level only
*/
if (!descend && strchr(var + rootl, '.'))
return 0;
/* Looks like its ok */
return 1;
}
#endif
/* Returns the number of characters they are equal at. */
size_t BX_streq (const char *one, const char *two)
{
size_t cnt = 0;
while (*one && *two && (*one == *two))
cnt++, one++, two++;
return cnt;
}
/* Returns the number of characters they are equal at. */
size_t BX_strieq (const char *one, const char *two)
{
size_t cnt = 0;
while (*one && *two && (toupper(*one) == toupper(*two)))
cnt++, one++, two++;
return cnt;
}
char *n_m_strndup (const char *str, size_t len, const char *module, const char *file, const int line)
{
char *retval = (char *)n_malloc(len + 1, module, file, line);
return strmcpy(retval, (char *)str, len);
}
#if 0
char *remove_nl (char *str)
{
char *ptr;
if ((ptr = strrchr(str, '\n')))
*ptr = 0;
return str;
}
char *spanstr (const char *str, const char *tar)
{
int cnt = 1;
const char *p;
for ( ; *str; str++, cnt++)
{
for (p = tar; *p; p++)
{
if (*p == *str)
return (char *)p;
}
}
return 0;
}
char *s_next_arg (char **from)
{
char *next = strchr(*from, ' ');
char *keep = *from;
*from = next;
return keep;
}
#endif
char *BX_strmopencat (char *dest, int maxlen, ...)
{
va_list args;
int size;
char *this_arg = NULL;
int this_len;
size = strlen(dest);
va_start(args, maxlen);
while (size < maxlen)
{
if (!(this_arg = va_arg(args, char *)))
break;
if (size + ((this_len = strlen(this_arg))) > maxlen)
strncat(dest, this_arg, maxlen - size);
else
strcat(dest, this_arg);
size += this_len;
}
va_end(args);
return dest;
}
/*
* An strcpy that is guaranteed to be safe for overlaps.
*/
char *BX_ov_strcpy (char *one, const char *two)
{
if (two > one)
{
while (two && *two)
*one++ = *two++;
*one = 0;
}
return one;
}
char *BX_next_in_comma_list (char *str, char **after)
{
*after = str;
while (*after && **after && **after != ',')
(*after)++;
if (*after && **after == ',')
{
**after = 0;
(*after)++;
}
return str;
}
#ifdef INCLUDE_DEADCODE
/*
* Checks if ansi string only sets colors/attributes
* ^[[m won't work anymore !!!!
*/
void FixColorAnsi(unsigned char *str)
{
#if !defined(WINNT) && !defined(__EMX__)
register unsigned char *tmpstr;
register unsigned char *tmpstr1=NULL;
int what=0;
int numbers=0;
int val = 0;
tmpstr=str;
while (*tmpstr)
{
if ((*tmpstr>='0' && *tmpstr<='9'))
{
numbers = 1;
val = val * 10 + (*tmpstr - '0');
}
else if (*tmpstr==';')
numbers = 1, val = 0;
else if (!(*tmpstr=='m' || *tmpstr=='C'))
numbers = val = 0;
if (*tmpstr==0x1B)
{
if (what && tmpstr1)
*tmpstr1+=64;
what=1;
tmpstr1=tmpstr;
}
else if (*tmpstr==0x18 || *tmpstr==0x0E)
*tmpstr+=64;
if (what && numbers && (val > 130))
{
what = numbers = val = 0;
*tmpstr1+=64;
}
if (what && *tmpstr=='m')
{
if (!numbers || (val == 12))
{
*tmpstr1+=64;
tmpstr1=tmpstr;
}
what=0;
numbers = val = 0;
}
else if (what && *tmpstr=='C')
{
if (!numbers)
{
*tmpstr1+=64;
tmpstr1=tmpstr;
}
what=0;
numbers = val = 0;
}
else if (what && *tmpstr=='J')
{
val = numbers = 0;
*tmpstr1 +=64;
tmpstr1=tmpstr;
what = 0;
}
else if (what && *tmpstr=='(')
what=2;
else if (what == 2 && (*tmpstr == '0'))
*tmpstr1 += 64;
else if (what == 2 && (*tmpstr=='U' || *tmpstr=='B'))
what=0;
tmpstr++;
}
if (what && tmpstr1 && *tmpstr1)
*tmpstr1+=64;
#endif
}
#endif
/* Dest should be big enough to hold "src" */
void BX_strip_control (const char *src, char *dest)
{
for (; *src; src++)
{
if (isgraph((unsigned char)*src) || isspace((unsigned char)*src))
*dest++ = *src;
}
*dest++ = 0;
}
/*
* figure_out_address
*/
int BX_figure_out_address (char *nuh, char **nick, char **user, char **host, char **domain, int *ip)
{
static char *mystuff = NULL;
char *firstback, *secondback, *thirdback, *fourthback;
char *bang, *at, *myhost = star, *endstring;
int number;
/* Dont bother with channels, theyre ok. */
if (*nuh == '#' || *nuh == '&')
return -1;
malloc_strcpy(&mystuff, nuh);
*nick = *user = *host = *domain = star;
*ip = 0;
bang = strchr(mystuff, '!');
at = strchr(mystuff, '@');
if (!bang && !at)
{
if (strchr(mystuff, '.') || strchr(mystuff, ':'))
myhost = mystuff;
else
{
*nick = mystuff;
return 0;
}
}
if (bang == mystuff)
*user = bang + 1;
else if (bang)
{
*nick = mystuff;
*bang = 0;
*user = bang + 1;
}
else
*user = mystuff;
if (at)
{
if (*user == star)
*user = mystuff;
*at = 0;
myhost = at + 1;
}
/*
* At this point, 'myhost' points what what we think the hostname
* is. We chop it up into discrete parts and see what we end up with.
*/
endstring = myhost + strlen(myhost);
firstback = strnrchr(myhost, '.', 1);
secondback = strnrchr(myhost, '.', 2);
thirdback = strnrchr(myhost, '.', 3);
fourthback = strnrchr(myhost, '.', 4);
/* Track foo@bar or some such thing. */
if (!firstback)
{
*host = myhost;
return 0;
}
/*
* IP address (A.B.C.D)
*/
if (my_atol(firstback + 1))
{
*ip = 1;
*domain = myhost;
number = my_atol(myhost);
if (number < 128)
*host = thirdback;
else if (number < 192)
*host = secondback;
else
*host = firstback;
**host = 0;
(*host)++;
}
/*
* (*).(*.???)
* Handles *.com, *.net, *.edu, etc
*/
else if (secondback && (endstring - firstback == 4))
{
*host = myhost;
*domain = secondback;
**domain = 0;
(*domain)++;
}
/*
* (*).(*.k12.??.us)
* Handles host.school.k12.state.us
*/
else if (fourthback &&
(firstback - secondback == 3) &&
!strncmp(thirdback, ".k12.", 5) &&
!strncmp(firstback, ".us", 3))
{
*host = myhost;
*domain = fourthback;
**domain = 0;
(*domain)++;
}
/*
* ()(*.k12.??.us)
* Handles school.k12.state.us
*/
else if (thirdback && !fourthback &&
(firstback - secondback == 3) &&
!strncmp(thirdback, ".k12.", 5) &&
!strncmp(firstback, ".us", 3))
{
*host = empty_string;
*domain = myhost;
}
/*
* (*).(*.???.??)
* Handles host.domain.com.au
*/
else if (thirdback &&
(endstring - firstback == 3) &&
(firstback - secondback == 4))
{
*host = myhost;
*domain = thirdback;
**domain = 0;
(*domain)++;
}
/*
* ()(*.???.??)
* Handles domain.com.au
*/
else if (secondback && !thirdback &&
(endstring - firstback == 3) &&
(firstback - secondback == 4))
{
*host = empty_string;
*domain = myhost;
}
/*
* (*).(*.??.??)
* Handles host.domain.co.uk
*/
else if (thirdback &&
(endstring - firstback == 3) &&
(firstback - secondback == 3))
{
*host = myhost;
*domain = thirdback;
**domain = 0;
(*domain)++;
}
/*
* ()(*.??.??)
* Handles domain.co.uk
*/
else if (secondback && !thirdback &&
(endstring - firstback == 3) &&
(firstback - secondback == 3))
{
*host = empty_string;
*domain = myhost;
}
/*
* (*).(*.??)
* Handles domain.de
*/
else if (secondback && (endstring - firstback == 3))
{
*host = myhost;
*domain = secondback;
**domain = 0;
(*domain)++;
}
/*
* Everything else...
*/
else
{
*host = empty_string;
*domain = myhost;
}
return 0;
}
#ifdef INCLUDE_DEADCODE
int count_char (const unsigned char *src, const unsigned char look)
{
const unsigned char *t;
int cnt = 0;
while ((t = strchr(src, look)))
cnt++, src = t + 1;
return cnt;
}
#endif
char *BX_strnrchr(char *start, char which, int howmany)
{
char *ends = start + strlen(start);
while (ends > start && howmany)
{
if (*--ends == which)
howmany--;
}
if (ends == start)
return NULL;
else
return ends;
}
/*
* This replaces some number of numbers (1 or more) with a single asterisk.
* We know that the final strcpy() is safe, since we never make a string that
* is longer than the source string, always less than or equal in size.
*/
void BX_mask_digits (char **hostname)
{
char *src_ptr;
char *retval, *retval_ptr;
retval = retval_ptr = alloca(strlen(*hostname) + 1);
src_ptr = *hostname;
while (*src_ptr)
{
if (isdigit((unsigned char)*src_ptr))
{
while (*src_ptr && isdigit((unsigned char)*src_ptr))
src_ptr++;
*retval_ptr++ = '*';
}
else
*retval_ptr++ = *src_ptr++;
}
*retval_ptr = 0;
strcpy(*hostname, retval);
return;
}
/*
* Its like strcspn, except the seconD arg is NOT a string.
*/
size_t BX_ccspan (const char *string, int s)
{
size_t count = 0;
char c = (char) s;
while (string && *string && *string != c)
string++, count++;
return count;
}
#ifdef INCLUDE_DEADCODE
int last_char (const char *string)
{
while (string && string[0] && string[1])
string++;
return (int)*string;
}
#endif
int BX_charcount (const char *string, char what)
{
int x = 0;
const char *place = string;
while (*place)
if (*place++ == what)
x++;
return x;
}
char * encode(const char *str, int len)
{
char *retval;
char *ptr;
if (len == -1)
len = strlen(str);
ptr = retval = new_malloc(len * 2 + 1);
while (len)
{
*ptr++ = (*str >> 4) + 0x41;
*ptr++ = (*str & 0x0f) + 0x41;
str++;
len--;
}
*ptr = 0;
return retval;
}
char * decode(const char *str)
{
char *retval;
char *ptr;
int len = strlen(str);
ptr = retval = new_malloc(len / 2 + 1);
while (len >= 2)
{
*ptr++ = ((str[0] - 0x41) << 4) | (str[1] - 0x41);
str += 2;
len -= 2;
}
*ptr = 0;
return retval;
}
char * chomp (char *s)
{
char *e = s + strlen(s);
if (e == s)
return s;
while (*--e == '\n')
{
*e = 0;
if (e == s)
break;
}
return s;
}
char *BX_strpcat (char *source, const char *format, ...)
{
va_list args;
char buffer[BIG_BUFFER_SIZE + 1];
va_start(args, format);
vsnprintf(buffer, BIG_BUFFER_SIZE, format, args);
va_end(args);
strcat(source, buffer);
return source;
}
char * BX_strmpcat (char *source, size_t siz, const char *format, ...)
{
va_list args;
char buffer[BIG_BUFFER_SIZE + 1];
va_start(args, format);
vsnprintf(buffer, BIG_BUFFER_SIZE, format, args);
va_end(args);
strmcat(source, buffer, siz);
return source;
}
u_char *BX_strcpy_nocolorcodes (u_char *dest, const u_char *source)
{
u_char *save = dest;
do
{
while (*source == 3)
source = skip_ctl_c_seq(source, NULL, NULL, 0);
*dest++ = *source;
}
while (*source++);
return save;
}
char *crypt();
char *BX_cryptit(const char *string)
{
static char saltChars[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHJIKLMNOPQRSTUVWXYZ./";
char *cpass = (char *)string;
char salt[3];
salt[0] = saltChars[random_number(0) % 64];
salt[1] = saltChars[random_number(0) % 64];
salt[2] = 0;
#if !defined(WINNT)
cpass = crypt(string, salt);
#endif
return cpass;
}
int checkpass(const char *password, const char *old)
{
char seed[3], *p;
seed[0] = old[0];
seed[1] = old[1];
seed[2] = 0;
#if !defined(WINNT)
p = crypt(password, seed);
#else
p = password;
#endif
return strcmp(p, old);
}
char *BX_stripdev(char *ttynam)
{
if (ttynam == NULL)
return NULL;
#ifdef SVR4
/* unixware has /dev/pts012 as synonym for /dev/pts/12 */
if (!strncmp(ttynam, "/dev/pts", 8) && ttynam[8] >= '0' && ttynam[8] <= '9')
{
static char b[13];
sprintf(b, "pts/%d", atoi(ttynam + 8));
return b;
}
#endif /* SVR4 */
if (!strncmp(ttynam, "/dev/", 5))
return ttynam + 5;
return ttynam;
}
void init_socketpath(void)
{
#if !defined(__EMX__) && !defined(WINNT)
struct stat st;
extern char socket_path[], attach_ttyname[];
sprintf(socket_path, "%s/.BitchX/screens", my_path);
if (access(socket_path, F_OK))
{
if (mkdir(socket_path, 0700) != -1)
(void) chown(socket_path, getuid(), getgid());
else
return;
}
if (stat(socket_path, &st) != -1)
{
char host[BIG_BUFFER_SIZE+1];
char *ap;
if (!S_ISDIR(st.st_mode))
return;
gethostname(host, BIG_BUFFER_SIZE);
if ((ap = strchr(host, '.')))
*ap = 0;
ap = &socket_path[strlen(socket_path)];
sprintf(ap, "/%%d.%s.%s", stripdev(attach_ttyname), host);
ap++;
for ( ; *ap; ap++)
if (*ap == '/')
*ap = '-';
}
#endif
}
/*
* This mangles up 'incoming' corresponding to the current values of
* /set mangle_inbound or /set mangle_outbound.
* 'incoming' needs to be at _least_ thrice as big as neccesary
* (ie, sizeof(incoming) >= strlen(incoming) * 3 + 1)
*/
size_t BX_mangle_line (char *incoming, int how, size_t how_much)
{
int stuff;
char *buffer;
int i;
char *s;
stuff = how;
buffer = alloca(how_much + 1); /* Absurdly large */
#if notyet
if (stuff & STRIP_CTCP2)
{
char *output;
output = strip_ctcp2(incoming);
strlcpy(incoming, output, how_much);
new_free(&output);
}
else if (stuff & MANGLE_INBOUND_CTCP2)
{
char *output;
output = ctcp2_to_ircII(incoming);
strlcpy(incoming, output, how_much);
new_free(&output);
}
else if (stuff & MANGLE_OUTBOUND_CTCP2)
{
char *output;
output = ircII_to_ctcp2(incoming);
strlcpy(incoming, output, how_much);
new_free(&output);
}
#endif
if (stuff & MANGLE_ESCAPES)
{
for (i = 0; incoming[i]; i++)
{
if (incoming[i] == 0x1b)
incoming[i] = 0x5b;
}
}
if (stuff & MANGLE_ANSI_CODES)
{
/* strip_ansi can expand up to three times */
char *output;
strip_ansi_never_xlate = 1; /* XXXXX */
output = strip_ansi(incoming);
strip_ansi_never_xlate = 0; /* XXXXX */
if (strlcpy(incoming, output, how_much) > how_much)
say("Mangle_line truncating results. #1 -- "
"Email jnelson@acronet.net [%d] [%d]",
strlen(buffer), how_much);
new_free(&output);
}
/*
* Now we mangle the individual codes
*/
for (i = 0, s = incoming; *s; s++)
{
switch (*s)
{
case 003: /* color codes */
{
int lhs = 0,
rhs = 0;
char *end;
end = (char *)skip_ctl_c_seq(s, &lhs, &rhs, 0);
if (!(stuff & STRIP_COLOR))
{
while (s < end)
buffer[i++] = *s++;
}
s = end - 1;
break;
}
case REV_TOG: /* Reverse */
{
if (!(stuff & STRIP_REVERSE))
buffer[i++] = REV_TOG;
break;
}
case UND_TOG: /* Underline */
{
if (!(stuff & STRIP_UNDERLINE))
buffer[i++] = UND_TOG;
break;
}
case BOLD_TOG: /* Bold */
{
if (!(stuff & STRIP_BOLD))
buffer[i++] = BOLD_TOG;
break;
}
case BLINK_TOG: /* Flashing */
{
if (!(stuff & STRIP_BLINK))
buffer[i++] = BLINK_TOG;
break;
}
case ROM_CHAR: /* Special rom-chars */
{
if (!(stuff & STRIP_ROM_CHAR))
buffer[i++] = ROM_CHAR;
break;
}
case ND_SPACE: /* Nondestructive spaces */
{
if (!(stuff & STRIP_ND_SPACE))
buffer[i++] = ND_SPACE;
break;
}
case ALT_TOG: /* Alternate character set */
{
if (!(stuff & STRIP_ALT_CHAR))
buffer[i++] = ALT_TOG;
break;
}
case ALL_OFF: /* ALL OFF attribute */
{
if (!(stuff & STRIP_ALL_OFF))
buffer[i++] = ALL_OFF;
break;
}
default:
buffer[i++] = *s;
}
}
buffer[i] = 0;
return strlcpy(incoming, buffer, how_much);
}
void strip_chars(char *buffer, char *strip, char replace)
{
char *p;
if (!buffer || !*buffer || !strip || !*strip || !replace)
return;
while (*strip)
{
while ((p = strchr(buffer, *strip)))
*p = replace;
strip++;
}
}
char *longcomma(long val)
{
char buffer[40];
static char buff[40];
char *s = buff;
int i = 0, j = 0, len;
sprintf(buffer, "%ld", val);
len = strlen(buffer);
for (i = len % 3; i > 0; i--)
*s++ = buffer[j++];
if (len > 3 && len % 3)
*s++ = ',';
len -= (len % 3);
while (len --)
{
*s++ = buffer[j++];
if (!(len % 3) && len)
*s++ = ',';
}
*s = 0;
return buff;
}
char *ulongcomma(unsigned long val)
{
char buffer[40];
static char buff[40];
char *s = buff;
int i = 0, j = 0, len;
sprintf(buffer, "%lu", val);
len = strlen(buffer);
for (i = len % 3; i > 0; i--)
*s++ = buffer[j++];
if (len > 3 && len % 3)
*s++ = ',';
len -= (len % 3);
while (len --)
{
*s++ = buffer[j++];
if (!(len % 3) && len)
*s++ = ',';
}
*s = 0;
return buff;
}
/* XXXX this doesnt belong here. im not sure where it goes, though. */
char * get_userhost (void)
{
strmcpy(userhost, username, NAME_LEN);
strmcat(userhost, "@", NAME_LEN);
strmcat(userhost, hostname, NAME_LEN);
return userhost;
}
/* RANDOM NUMBERS */
/*
* Random number generator #1 -- psuedo-random sequence
* If you do not have /dev/random and do not want to use gettimeofday(), then
* you can use the psuedo-random number generator. Its performance varies
* from weak to moderate. It is a predictable mathematical sequence that
* varies depending on the seed, and it provides very little repetition,
* but with 4 or 5 samples, it should be trivial for an outside person to
* find the next numbers in your sequence.
*
* If 'l' is not zero, then it is considered a "seed" value. You want
* to call it once to set the seed. Subsequent calls should use 'l'
* as 0, and it will return a value.
*/
static unsigned long randm (unsigned long l)
{
/* patch from Sarayan to make $rand() better */
static const long RAND_A = 16807L;
static const long RAND_M = 2147483647L;
static const long RAND_Q = 127773L;
static const int RAND_R = 2836L;
static u_long z = 0;
long t;
if (z == 0)
z = (u_long) getuid();
if (l == 0)
{
t = RAND_A * (z % RAND_Q) - RAND_R * (z / RAND_Q);
if (t > 0)
z = t;
else
z = t + RAND_M;
return (z >> 8) | ((z & 255) << 23);
}
else
{
if (l < 0)
z = (u_long) getuid();
else
z = l;
return 0;
}
}
/*
* Random number generator #2 -- gettimeofday().
* If you have gettimeofday(), then we could use it. Its performance varies
* from weak to moderate. At best, it is a source of modest entropy, with
* distinct linear qualities. At worst, it is a linear sequence. If you do
* not have gettimeofday(), then it uses randm() instead.
*/
static unsigned long randt_2 (void)
{
struct timeval tp1;
get_time(&tp1);
return (unsigned long) tp1.tv_usec;
}
static unsigned long randt (unsigned long l)
{
#ifdef HAVE_GETTIMEOFDAY
unsigned long t1, t2, t;
if (l != 0)
return 0;
t1 = randt_2();
t2 = randt_2();
t = (t1 & 65535) * 65536 + (t2 & 65535);
return t;
#else
return randm(0);
#endif
}
/*
* Random number generator #3 -- /dev/urandom.
* If you have the /dev/urandom device, then we will use it. Its performance
* varies from moderate to very strong. At best, it is a source of pretty
* substantial unpredictable numbers. At worst, it is mathematical psuedo-
* random sequence (which randm() is).
*/
static unsigned long randd (unsigned long l)
{
unsigned long value;
static int random_fd = -1;
if (l != 0)
return 0; /* No seeding appropriate */
if (random_fd == -2)
return randm(0);
else if (random_fd == -1)
{
if ((random_fd = open("/dev/urandom", O_RDONLY)) == -1)
{
random_fd = -2;
return randm(0); /* Fall back to randm */
}
}
read(random_fd, (void *)&value, sizeof(value));
return value;
}
unsigned long BX_random_number (unsigned long l)
{
switch (get_int_var(RANDOM_SOURCE_VAR))
{
case 0:
default:
return randd(l);
case 1:
return randm(l);
case 2:
return randt(l);
}
}