/* * 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 * * 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 */ #define _GNU_SOURCE 1 #include /* * 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) { return (rb_bh_alloc(dnode_heap)); } /* * free_rb_dlink_node * * inputs - pointer to rb_dlink_node * output - NONE * side effects - free given rb_dlink_node */ void rb_free_rb_dlink_node(rb_dlink_node *ptr) { 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. * * inputs - string to parse, array to put in * outputs - number of parameters */ int rb_string_to_array(char *string, char **parv, int maxpara) { char *p, *xbuf = string; int x = 0; parv[x] = NULL; if(string == NULL || string[0] == '\0') return x; while(*xbuf == ' ') /* skip leading spaces */ xbuf++; if(*xbuf == '\0') /* ignore all-space args */ return x; do { if(*xbuf == ':') /* Last parameter */ { xbuf++; parv[x++] = xbuf; parv[x] = NULL; return x; } else { parv[x++] = xbuf; parv[x] = NULL; if((p = strchr(xbuf, ' ')) != NULL) { *p++ = '\0'; xbuf = p; } else return x; } while(*xbuf == ' ') xbuf++; if(*xbuf == '\0') return x; } while(x < maxpara - 1); if(*p == ':') p++; parv[x++] = p; parv[x] = NULL; return x; } /* rb_array_to_string() * Inverse of rb_string_to_array() * - space for delim * - ':' prefixed at last parameter */ size_t rb_array_to_string(int parc, const char **parv, char *buf, size_t max) { size_t ret = 0; if(rb_unlikely(!max)) return ret; buf[0] = '\0'; for(int i = 0; i < parc - 1; ++i) { ret = rb_strlcat(buf, parv[i], max); ret = rb_strlcat(buf, " ", max); } if(parc) { ret = rb_strlcat(buf, ":", max); ret = rb_strlcat(buf, parv[parc - 1], max); } return ret; } #ifndef HAVE_STRCASECMP #ifndef _WIN32 /* Fallback taken from FreeBSD. --Elizafox */ int rb_strcasecmp(const char *s1, const char *s2) { const unsigned char *us1 = (const unsigned char *)s1; const unsigned char *us2 = (const unsigned char *)s2; while (tolower(*us1) == tolower(*us2++)) { if (*us1++ == '\0') return 0; } return (tolower(*us1) - tolower(*--us2)); } #else /* _WIN32 */ int rb_strcasecmp(const char *s1, const char *s2) { return stricmp(s1, s2); } #endif /* _WIN32 */ #else /* HAVE_STRCASECMP */ int rb_strcasecmp(const char *s1, const char *s2) { return strcasecmp(s1, s2); } #endif #ifndef HAVE_STRNCASECMP #ifndef _WIN32 /* Fallback taken from FreeBSD. --Elizafox */ int rb_strncasecmp(const char *s1, const char *s2, size_t n) { if (n != 0) { const unsigned char *us1 = (const unsigned char *)s1; const unsigned char *us2 = (const unsigned char *)s2; do { if (tolower(*us1) != tolower(*us2++)) return (tolower(*us1) - tolower(*--us2)); if (*us1++ == '\0') break; } while (--n != 0); } return 0; } #else /* _WIN32 */ int rb_strncasecmp(const char *s1, const char *s2, size_t n) { return strnicmp(s1, s2, n); } #endif /* _WIN32 */ #else /* HAVE_STRNCASECMP */ int rb_strncasecmp(const char *s1, const char *s2, size_t n) { return strncasecmp(s1, s2, n); } #endif #ifndef HAVE_STRCASESTR /* Fallback taken from FreeBSD. --Elizafox */ char * rb_strcasestr(const char *s, const char *find) { char c, sc; size_t len; 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--; } return ((char *)s); } #else char * rb_strcasestr(const char *s, const char *find) { return strcasestr(s, find); } #endif #ifndef HAVE_STRLCAT size_t rb_strlcat(char *dest, const char *src, size_t count) { 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; } #else size_t rb_strlcat(char *dest, const char *src, size_t count) { return strlcat(dest, src, count); } #endif #ifndef HAVE_STRLCPY size_t rb_strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); if(size) { size_t len = (ret >= size) ? size - 1 : ret; memcpy(dest, src, len); dest[len] = '\0'; } return ret; } #else size_t rb_strlcpy(char *dest, const char *src, size_t size) { return strlcpy(dest, src, size); } #endif #ifndef HAVE_STRNLEN size_t rb_strnlen(const char *s, size_t count) { const char *sc; for(sc = s; count-- && *sc != '\0'; ++sc) ; return sc - s; } #else size_t rb_strnlen(const char *s, size_t count) { return strnlen(s, count); } #endif /* * 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) return 0; size_t x = strlen(str); if(len < x) { str[len - 1] = '\0'; return (int)len - 1; } va_list ap; va_start(ap, format); int y = (vsnprintf(str + x, len - x, format, ap) + (int)x); va_end(ap); return (y); } /* rb_basename * * input - * output - * side effects - */ 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("."); } /* remove extra slashes */ while(s > path && *s == '/') --s; return rb_strndup(path, ((uintptr_t)s - (uintptr_t)path) + 2); } size_t rb_zstring_serialized(rb_zstring_t *zs, void **buf, size_t *buflen) { uint8_t *p; size_t alloclen = sizeof(uint16_t) + zs->len; p = rb_malloc(sizeof(alloclen)); memcpy(p, &zs->len, sizeof(uint16_t)); p += sizeof(uint16_t); memcpy(p, zs->data, zs->len); return alloclen; } size_t rb_zstring_deserialize(rb_zstring_t *zs, void *buf) { uint8_t *p = (uint8_t *)buf; memcpy(&zs->len, p, sizeof(uint16_t)); p += sizeof(uint16_t); if(zs->len == 0) { zs->data = NULL; return sizeof(uint16_t); } zs->data = rb_malloc(zs->len); memcpy(zs->data, p, zs->len); return zs->len + sizeof(uint16_t); } void rb_zstring_free(rb_zstring_t *zs) { rb_free(zs->data); rb_free(zs); } rb_zstring_t *rb_zstring_alloc(void) { rb_zstring_t *zs = rb_malloc(sizeof(rb_zstring_t)); return zs; } rb_zstring_t *rb_zstring_from_c_len(const char *buf, size_t len) { rb_zstring_t *zs; if(len > UINT16_MAX-1) return NULL; zs = rb_zstring_alloc(); zs->alloclen = zs->len = (uint16_t)len; zs->alloclen = (uint16_t)len; if(zs->alloclen < 128) zs->alloclen = 128; zs->data = rb_malloc(zs->alloclen); memcpy(zs->data, buf, zs->len); return(zs); } rb_zstring_t *rb_zstring_from_c(const char *buf) { return rb_zstring_from_c_len(buf, strlen(buf)); } size_t rb_zstring_len(rb_zstring_t *zs) { return zs->len; } void rb_zstring_append_from_zstring(rb_zstring_t *dst_zs, rb_zstring_t *src_zs) { void *ep; size_t nlen = dst_zs->len + src_zs->len; if(nlen > dst_zs->alloclen) { dst_zs->alloclen += src_zs->len + 64; dst_zs->data = rb_realloc(dst_zs->data, dst_zs->alloclen); } ep = dst_zs->data + dst_zs->len; memcpy(ep, src_zs->data, src_zs->len); } void rb_zstring_append_from_c(rb_zstring_t *zs, const char *buf, size_t len) { void *ep; size_t nlen = zs->len + len; if(nlen > zs->alloclen) { zs->alloclen += len + 64; zs->data = rb_realloc(zs->data, zs->alloclen); } ep = zs->data + zs->len; zs->len += len; memcpy(ep, buf, len); } char *rb_zstring_to_c(rb_zstring_t *zs, char *buf, size_t len) { size_t cpylen; if(len < zs->len) cpylen = len - 1; else cpylen = zs->len; buf[cpylen] = '\0'; memcpy(buf, zs->data, cpylen); return buf; } char *rb_zstring_to_c_alloc(rb_zstring_t *zs) { char *p; p = rb_malloc(zs->len+1); memcpy(p, zs->data, zs->len); return p; } size_t rb_zstring_to_ptr(rb_zstring_t *zs, void **ptr) { *ptr = (void *)zs->data; return zs->len; }