2008-04-01 16:52:26 +00:00
|
|
|
/*
|
|
|
|
* ircd-ratbox: A slightly useful ircd.
|
|
|
|
* tools.c: Various functions needed here and there.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1996-2002 Hybrid Development Team
|
|
|
|
* Copyright (C) 2002-2005 ircd-ratbox development team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
|
|
* USA
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Here is the original header:
|
|
|
|
*
|
|
|
|
* Useful stuff, ripped from places ..
|
|
|
|
* adrian chadd <adrian@creative.net.au>
|
|
|
|
*
|
|
|
|
* The TOOLS_C define builds versions of the functions in tools.h
|
|
|
|
* so that they end up in the resulting object files. If its not
|
|
|
|
* defined, tools.h will build inlined versions of the functions
|
|
|
|
* on supported compilers
|
|
|
|
*/
|
2016-03-24 00:10:44 +00:00
|
|
|
|
2008-04-01 16:52:26 +00:00
|
|
|
#define _GNU_SOURCE 1
|
2016-03-06 09:49:27 +00:00
|
|
|
#include <librb_config.h>
|
|
|
|
#include <rb_lib.h>
|
2008-04-01 16:52:26 +00:00
|
|
|
#include <rb_tools.h>
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* init_rb_dlink_nodes
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static rb_bh *dnode_heap;
|
|
|
|
void
|
|
|
|
rb_init_rb_dlink_nodes(size_t dh_size)
|
|
|
|
{
|
|
|
|
|
|
|
|
dnode_heap = rb_bh_create(sizeof(rb_dlink_node), dh_size, "librb_dnode_heap");
|
|
|
|
if(dnode_heap == NULL)
|
|
|
|
rb_outofmemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_rb_dlink_node
|
|
|
|
*
|
|
|
|
* inputs - NONE
|
|
|
|
* output - pointer to new rb_dlink_node
|
|
|
|
* side effects - NONE
|
|
|
|
*/
|
|
|
|
rb_dlink_node *
|
|
|
|
rb_make_rb_dlink_node(void)
|
|
|
|
{
|
2008-12-02 23:49:39 +00:00
|
|
|
return (rb_bh_alloc(dnode_heap));
|
2008-04-01 16:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* free_rb_dlink_node
|
|
|
|
*
|
|
|
|
* inputs - pointer to rb_dlink_node
|
|
|
|
* output - NONE
|
2014-03-03 04:25:47 +00:00
|
|
|
* side effects - free given rb_dlink_node
|
2008-04-01 16:52:26 +00:00
|
|
|
*/
|
|
|
|
void
|
2008-12-02 23:49:39 +00:00
|
|
|
rb_free_rb_dlink_node(rb_dlink_node *ptr)
|
2008-04-01 16:52:26 +00:00
|
|
|
{
|
|
|
|
assert(ptr != NULL);
|
|
|
|
rb_bh_free(dnode_heap, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* rb_string_to_array()
|
|
|
|
* Changes a given buffer into an array of parameters.
|
|
|
|
* Taken from ircd-ratbox.
|
|
|
|
*
|
2017-07-28 20:50:16 +00:00
|
|
|
* inputs - string to parse, array to put in (size >= maxpara)
|
2008-04-01 16:52:26 +00:00
|
|
|
* outputs - number of parameters
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rb_string_to_array(char *string, char **parv, int maxpara)
|
|
|
|
{
|
|
|
|
char *p, *xbuf = string;
|
|
|
|
int x = 0;
|
|
|
|
|
|
|
|
if(string == NULL || string[0] == '\0')
|
|
|
|
return x;
|
|
|
|
|
2008-12-02 23:49:39 +00:00
|
|
|
while(*xbuf == ' ') /* skip leading spaces */
|
2008-04-01 16:52:26 +00:00
|
|
|
xbuf++;
|
|
|
|
if(*xbuf == '\0') /* ignore all-space args */
|
|
|
|
return x;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if(*xbuf == ':') /* Last parameter */
|
|
|
|
{
|
|
|
|
xbuf++;
|
|
|
|
parv[x++] = xbuf;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parv[x++] = xbuf;
|
|
|
|
if((p = strchr(xbuf, ' ')) != NULL)
|
|
|
|
{
|
|
|
|
*p++ = '\0';
|
|
|
|
xbuf = p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
2008-12-02 23:49:39 +00:00
|
|
|
while(*xbuf == ' ')
|
2008-04-01 16:52:26 +00:00
|
|
|
xbuf++;
|
|
|
|
if(*xbuf == '\0')
|
|
|
|
return x;
|
|
|
|
}
|
2008-12-02 23:49:39 +00:00
|
|
|
while(x < maxpara - 1);
|
2008-04-01 16:52:26 +00:00
|
|
|
|
|
|
|
if(*p == ':')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
parv[x++] = p;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-04-05 10:33:43 +00:00
|
|
|
int
|
|
|
|
rb_strcasecmp(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
return strcasecmp(s1, s2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_strncasecmp(const char *s1, const char *s2, size_t n)
|
|
|
|
{
|
|
|
|
return strncasecmp(s1, s2, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef HAVE_STRCASESTR
|
2016-04-10 22:25:32 +00:00
|
|
|
/* Fallback taken from FreeBSD. --Elizafox */
|
2016-04-05 10:33:43 +00:00
|
|
|
char *
|
2016-04-10 22:26:09 +00:00
|
|
|
rb_strcasestr(const char *s, const char *find)
|
2016-04-05 10:33:43 +00:00
|
|
|
{
|
2016-04-10 22:25:32 +00:00
|
|
|
char c, sc;
|
|
|
|
size_t len;
|
2016-04-05 10:33:43 +00:00
|
|
|
|
2016-04-10 22:25:32 +00:00
|
|
|
if ((c = *find++) != 0) {
|
|
|
|
c = tolower((unsigned char)c);
|
|
|
|
len = strlen(find);
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
if ((sc = *s++) == 0)
|
|
|
|
return (NULL);
|
|
|
|
} while ((char)tolower((unsigned char)sc) != c);
|
|
|
|
} while (rb_strncasecmp(s, find, len) != 0);
|
|
|
|
s--;
|
2016-04-05 10:33:43 +00:00
|
|
|
}
|
2016-04-10 22:25:32 +00:00
|
|
|
return ((char *)s);
|
2016-04-05 10:33:43 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
char *
|
|
|
|
rb_strcasestr(const char *s, const char *find)
|
|
|
|
{
|
|
|
|
return strcasestr(s, find);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-04-01 16:52:26 +00:00
|
|
|
#ifndef HAVE_STRLCAT
|
2008-12-02 23:49:39 +00:00
|
|
|
size_t
|
2008-04-01 16:52:26 +00:00
|
|
|
rb_strlcat(char *dest, const char *src, size_t count)
|
|
|
|
{
|
2008-12-02 23:49:39 +00:00
|
|
|
size_t dsize = strlen(dest);
|
|
|
|
size_t len = strlen(src);
|
|
|
|
size_t res = dsize + len;
|
|
|
|
|
|
|
|
dest += dsize;
|
|
|
|
count -= dsize;
|
|
|
|
if(len >= count)
|
|
|
|
len = count - 1;
|
|
|
|
memcpy(dest, src, len);
|
|
|
|
dest[len] = 0;
|
|
|
|
return res;
|
2008-04-01 16:52:26 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
size_t
|
|
|
|
rb_strlcat(char *dest, const char *src, size_t count)
|
|
|
|
{
|
|
|
|
return strlcat(dest, src, count);
|
|
|
|
}
|
|
|
|
#endif
|
2008-12-02 23:49:39 +00:00
|
|
|
|
2008-04-01 16:52:26 +00:00
|
|
|
#ifndef HAVE_STRLCPY
|
2008-12-02 23:49:39 +00:00
|
|
|
size_t
|
2008-04-01 16:52:26 +00:00
|
|
|
rb_strlcpy(char *dest, const char *src, size_t size)
|
|
|
|
{
|
2008-12-02 23:49:39 +00:00
|
|
|
size_t ret = strlen(src);
|
|
|
|
|
|
|
|
if(size)
|
|
|
|
{
|
|
|
|
size_t len = (ret >= size) ? size - 1 : ret;
|
|
|
|
memcpy(dest, src, len);
|
|
|
|
dest[len] = '\0';
|
|
|
|
}
|
|
|
|
return ret;
|
2008-04-01 16:52:26 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
size_t
|
|
|
|
rb_strlcpy(char *dest, const char *src, size_t size)
|
|
|
|
{
|
|
|
|
return strlcpy(dest, src, size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
rb_strnlen(const char *s, size_t count)
|
|
|
|
{
|
|
|
|
return strnlen(s, count);
|
|
|
|
}
|
|
|
|
|
2016-02-10 01:25:32 +00:00
|
|
|
/*
|
|
|
|
* rb_snprintf_append()
|
|
|
|
* appends snprintf formatted string to the end of the buffer but not
|
|
|
|
* exceeding len
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rb_snprintf_append(char *str, size_t len, const char *format, ...)
|
|
|
|
{
|
|
|
|
if(len == 0)
|
2017-07-30 16:03:30 +00:00
|
|
|
return -1;
|
2016-02-10 01:25:32 +00:00
|
|
|
|
2017-07-30 16:03:30 +00:00
|
|
|
int orig_len = strlen(str);
|
2016-02-10 01:25:32 +00:00
|
|
|
|
2017-07-30 16:03:30 +00:00
|
|
|
if((int)len < orig_len)
|
2016-02-10 01:25:32 +00:00
|
|
|
{
|
|
|
|
str[len - 1] = '\0';
|
2017-07-30 16:03:30 +00:00
|
|
|
return len - 1;
|
2016-02-10 01:25:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
2017-07-30 16:03:30 +00:00
|
|
|
int append_len = vsnprintf(str + orig_len, len - orig_len, format, ap);
|
2016-02-10 01:25:32 +00:00
|
|
|
va_end(ap);
|
|
|
|
|
2017-07-30 16:03:30 +00:00
|
|
|
if (append_len < 0)
|
|
|
|
return append_len;
|
|
|
|
|
|
|
|
return (orig_len + append_len);
|
2016-02-10 01:25:32 +00:00
|
|
|
}
|
|
|
|
|
2017-07-30 16:04:06 +00:00
|
|
|
/*
|
|
|
|
* rb_snprintf_try_append()
|
|
|
|
* appends snprintf formatted string to the end of the buffer but not
|
|
|
|
* exceeding len
|
|
|
|
* returns -1 if there isn't enough space for the whole string to fit
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rb_snprintf_try_append(char *str, size_t len, const char *format, ...)
|
|
|
|
{
|
|
|
|
if(len == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int orig_len = strlen(str);
|
|
|
|
|
|
|
|
if((int)len < orig_len) {
|
|
|
|
str[len - 1] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
int append_len = vsnprintf(str + orig_len, len - orig_len, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (append_len < 0)
|
|
|
|
return append_len;
|
|
|
|
|
|
|
|
if (orig_len + append_len > (int)(len - 1)) {
|
|
|
|
str[orig_len] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (orig_len + append_len);
|
|
|
|
}
|
|
|
|
|
2008-12-02 23:49:39 +00:00
|
|
|
/* rb_basename
|
|
|
|
*
|
|
|
|
* input -
|
|
|
|
* output -
|
2014-03-03 04:25:47 +00:00
|
|
|
* side effects -
|
2008-12-02 23:49:39 +00:00
|
|
|
*/
|
|
|
|
char *
|
|
|
|
rb_basename(const char *path)
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
if(!(s = strrchr(path, '/')))
|
|
|
|
s = path;
|
|
|
|
else
|
|
|
|
s++;
|
|
|
|
return rb_strdup(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rb_dirname
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *
|
|
|
|
rb_dirname (const char *path)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
s = strrchr(path, '/');
|
|
|
|
if(s == NULL)
|
|
|
|
{
|
|
|
|
return rb_strdup(".");
|
2014-03-03 04:25:47 +00:00
|
|
|
}
|
2008-12-02 23:49:39 +00:00
|
|
|
|
|
|
|
/* remove extra slashes */
|
|
|
|
while(s > path && *s == '/')
|
|
|
|
--s;
|
|
|
|
|
2014-03-03 04:25:47 +00:00
|
|
|
return rb_strndup(path, ((uintptr_t)s - (uintptr_t)path) + 2);
|
2008-12-02 23:49:39 +00:00
|
|
|
}
|
2015-12-11 21:56:33 +00:00
|
|
|
|
2017-08-06 11:05:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
int rb_fsnprint(char *buf, size_t len, const rb_strf_t *strings)
|
|
|
|
{
|
|
|
|
size_t used = 0;
|
|
|
|
size_t remaining = len;
|
|
|
|
|
|
|
|
while (strings != NULL) {
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (strings->length != 0) {
|
|
|
|
remaining = strings->length;
|
|
|
|
if (remaining > len - used)
|
|
|
|
remaining = len - used;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remaining == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (strings->format != NULL) {
|
|
|
|
if (strings->format_args != NULL) {
|
|
|
|
ret = vsnprintf(buf + used, remaining,
|
|
|
|
strings->format, *strings->format_args);
|
|
|
|
} else {
|
|
|
|
ret = rb_strlcpy(buf + used,
|
|
|
|
strings->format, remaining);
|
|
|
|
}
|
|
|
|
} else if (strings->func != NULL) {
|
|
|
|
ret = strings->func(buf + used, remaining,
|
|
|
|
strings->func_args);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
} else if ((size_t)ret > remaining - 1) {
|
|
|
|
used += remaining - 1;
|
|
|
|
} else {
|
|
|
|
used += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (used >= len - 1) {
|
|
|
|
used = len - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
remaining -= ret;
|
|
|
|
strings = strings->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return used;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rb_fsnprintf(char *buf, size_t len, const rb_strf_t *strings, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
rb_strf_t prepend_string = { .format = format, .format_args = &args, .next = strings };
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
ret = rb_fsnprint(buf, len, &prepend_string);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|