]> jfr.im git - solanum.git/blob - librb/src/tools.c
ircd: send tags on every message
[solanum.git] / librb / src / tools.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * tools.c: Various functions needed here and there.
4 *
5 * Copyright (C) 1996-2002 Hybrid Development Team
6 * Copyright (C) 2002-2005 ircd-ratbox development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
23 *
24 * Here is the original header:
25 *
26 * Useful stuff, ripped from places ..
27 * adrian chadd <adrian@creative.net.au>
28 *
29 * The TOOLS_C define builds versions of the functions in tools.h
30 * so that they end up in the resulting object files. If its not
31 * defined, tools.h will build inlined versions of the functions
32 * on supported compilers
33 */
34
35 #define _GNU_SOURCE 1
36 #include <librb_config.h>
37 #include <rb_lib.h>
38 #include <rb_tools.h>
39
40
41 /*
42 * init_rb_dlink_nodes
43 *
44 */
45 static rb_bh *dnode_heap;
46 void
47 rb_init_rb_dlink_nodes(size_t dh_size)
48 {
49
50 dnode_heap = rb_bh_create(sizeof(rb_dlink_node), dh_size, "librb_dnode_heap");
51 if(dnode_heap == NULL)
52 rb_outofmemory();
53 }
54
55 /*
56 * make_rb_dlink_node
57 *
58 * inputs - NONE
59 * output - pointer to new rb_dlink_node
60 * side effects - NONE
61 */
62 rb_dlink_node *
63 rb_make_rb_dlink_node(void)
64 {
65 return (rb_bh_alloc(dnode_heap));
66 }
67
68 /*
69 * free_rb_dlink_node
70 *
71 * inputs - pointer to rb_dlink_node
72 * output - NONE
73 * side effects - free given rb_dlink_node
74 */
75 void
76 rb_free_rb_dlink_node(rb_dlink_node *ptr)
77 {
78 assert(ptr != NULL);
79 rb_bh_free(dnode_heap, ptr);
80 }
81
82 /* rb_string_to_array()
83 * Changes a given buffer into an array of parameters.
84 * Taken from ircd-ratbox.
85 *
86 * inputs - string to parse, array to put in (size >= maxpara)
87 * outputs - number of parameters
88 */
89 int
90 rb_string_to_array(char *string, char **parv, int maxpara)
91 {
92 char *p, *xbuf = string;
93 int x = 0;
94
95 if(string == NULL || string[0] == '\0')
96 return x;
97
98 while(*xbuf == ' ') /* skip leading spaces */
99 xbuf++;
100 if(*xbuf == '\0') /* ignore all-space args */
101 return x;
102
103 do
104 {
105 if(*xbuf == ':') /* Last parameter */
106 {
107 xbuf++;
108 parv[x++] = xbuf;
109 return x;
110 }
111 else
112 {
113 parv[x++] = xbuf;
114 if((p = strchr(xbuf, ' ')) != NULL)
115 {
116 *p++ = '\0';
117 xbuf = p;
118 }
119 else
120 return x;
121 }
122 while(*xbuf == ' ')
123 xbuf++;
124 if(*xbuf == '\0')
125 return x;
126 }
127 while(x < maxpara - 1);
128
129 if(*p == ':')
130 p++;
131
132 parv[x++] = p;
133 return x;
134 }
135
136 #ifndef HAVE_STRCASECMP
137 #ifndef _WIN32
138 /* Fallback taken from FreeBSD. --Elizafox */
139 int
140 rb_strcasecmp(const char *s1, const char *s2)
141 {
142 const unsigned char *us1 = (const unsigned char *)s1;
143 const unsigned char *us2 = (const unsigned char *)s2;
144
145 while (tolower(*us1) == tolower(*us2++))
146 {
147 if (*us1++ == '\0')
148 return 0;
149 }
150
151 return (tolower(*us1) - tolower(*--us2));
152 }
153 #else /* _WIN32 */
154 int
155 rb_strcasecmp(const char *s1, const char *s2)
156 {
157 return stricmp(s1, s2);
158 }
159 #endif /* _WIN32 */
160 #else /* HAVE_STRCASECMP */
161 int
162 rb_strcasecmp(const char *s1, const char *s2)
163 {
164 return strcasecmp(s1, s2);
165 }
166 #endif
167
168 #ifndef HAVE_STRNCASECMP
169 #ifndef _WIN32
170 /* Fallback taken from FreeBSD. --Elizafox */
171 int
172 rb_strncasecmp(const char *s1, const char *s2, size_t n)
173 {
174 if (n != 0)
175 {
176 const unsigned char *us1 = (const unsigned char *)s1;
177 const unsigned char *us2 = (const unsigned char *)s2;
178
179 do
180 {
181 if (tolower(*us1) != tolower(*us2++))
182 return (tolower(*us1) - tolower(*--us2));
183 if (*us1++ == '\0')
184 break;
185 } while (--n != 0);
186 }
187 return 0;
188 }
189 #else /* _WIN32 */
190 int
191 rb_strncasecmp(const char *s1, const char *s2, size_t n)
192 {
193 return strnicmp(s1, s2, n);
194 }
195 #endif /* _WIN32 */
196 #else /* HAVE_STRNCASECMP */
197 int
198 rb_strncasecmp(const char *s1, const char *s2, size_t n)
199 {
200 return strncasecmp(s1, s2, n);
201 }
202 #endif
203
204 #ifndef HAVE_STRCASESTR
205 /* Fallback taken from FreeBSD. --Elizafox */
206 char *
207 rb_strcasestr(const char *s, const char *find)
208 {
209 char c, sc;
210 size_t len;
211
212 if ((c = *find++) != 0) {
213 c = tolower((unsigned char)c);
214 len = strlen(find);
215 do {
216 do {
217 if ((sc = *s++) == 0)
218 return (NULL);
219 } while ((char)tolower((unsigned char)sc) != c);
220 } while (rb_strncasecmp(s, find, len) != 0);
221 s--;
222 }
223 return ((char *)s);
224 }
225 #else
226 char *
227 rb_strcasestr(const char *s, const char *find)
228 {
229 return strcasestr(s, find);
230 }
231 #endif
232
233 #ifndef HAVE_STRLCAT
234 size_t
235 rb_strlcat(char *dest, const char *src, size_t count)
236 {
237 size_t dsize = strlen(dest);
238 size_t len = strlen(src);
239 size_t res = dsize + len;
240
241 dest += dsize;
242 count -= dsize;
243 if(len >= count)
244 len = count - 1;
245 memcpy(dest, src, len);
246 dest[len] = 0;
247 return res;
248 }
249 #else
250 size_t
251 rb_strlcat(char *dest, const char *src, size_t count)
252 {
253 return strlcat(dest, src, count);
254 }
255 #endif
256
257 #ifndef HAVE_STRLCPY
258 size_t
259 rb_strlcpy(char *dest, const char *src, size_t size)
260 {
261 size_t ret = strlen(src);
262
263 if(size)
264 {
265 size_t len = (ret >= size) ? size - 1 : ret;
266 memcpy(dest, src, len);
267 dest[len] = '\0';
268 }
269 return ret;
270 }
271 #else
272 size_t
273 rb_strlcpy(char *dest, const char *src, size_t size)
274 {
275 return strlcpy(dest, src, size);
276 }
277 #endif
278
279
280 #ifndef HAVE_STRNLEN
281 size_t
282 rb_strnlen(const char *s, size_t count)
283 {
284 const char *sc;
285 for(sc = s; count-- && *sc != '\0'; ++sc)
286 ;
287 return sc - s;
288 }
289 #else
290 size_t
291 rb_strnlen(const char *s, size_t count)
292 {
293 return strnlen(s, count);
294 }
295 #endif
296
297 /*
298 * rb_snprintf_append()
299 * appends snprintf formatted string to the end of the buffer but not
300 * exceeding len
301 */
302 int
303 rb_snprintf_append(char *str, size_t len, const char *format, ...)
304 {
305 if(len == 0)
306 return -1;
307
308 int orig_len = strlen(str);
309
310 if((int)len < orig_len)
311 {
312 str[len - 1] = '\0';
313 return len - 1;
314 }
315
316 va_list ap;
317 va_start(ap, format);
318 int append_len = vsnprintf(str + orig_len, len - orig_len, format, ap);
319 va_end(ap);
320
321 if (append_len < 0)
322 return append_len;
323
324 return (orig_len + append_len);
325 }
326
327 /*
328 * rb_snprintf_try_append()
329 * appends snprintf formatted string to the end of the buffer but not
330 * exceeding len
331 * returns -1 if there isn't enough space for the whole string to fit
332 */
333 int
334 rb_snprintf_try_append(char *str, size_t len, const char *format, ...)
335 {
336 if(len == 0)
337 return -1;
338
339 int orig_len = strlen(str);
340
341 if((int)len < orig_len) {
342 str[len - 1] = '\0';
343 return -1;
344 }
345
346 va_list ap;
347 va_start(ap, format);
348 int append_len = vsnprintf(str + orig_len, len - orig_len, format, ap);
349 va_end(ap);
350
351 if (append_len < 0)
352 return append_len;
353
354 if (orig_len + append_len > (int)(len - 1)) {
355 str[orig_len] = '\0';
356 return -1;
357 }
358
359 return (orig_len + append_len);
360 }
361
362 /* rb_basename
363 *
364 * input -
365 * output -
366 * side effects -
367 */
368 char *
369 rb_basename(const char *path)
370 {
371 const char *s;
372
373 if(!(s = strrchr(path, '/')))
374 s = path;
375 else
376 s++;
377 return rb_strdup(s);
378 }
379
380 /*
381 * rb_dirname
382 */
383
384 char *
385 rb_dirname (const char *path)
386 {
387 char *s;
388
389 s = strrchr(path, '/');
390 if(s == NULL)
391 {
392 return rb_strdup(".");
393 }
394
395 /* remove extra slashes */
396 while(s > path && *s == '/')
397 --s;
398
399 return rb_strndup(path, ((uintptr_t)s - (uintptr_t)path) + 2);
400 }
401
402 size_t rb_zstring_serialized(rb_zstring_t *zs, void **buf, size_t *buflen)
403 {
404 uint8_t *p;
405 size_t alloclen = sizeof(uint16_t) + zs->len;
406
407 p = rb_malloc(sizeof(alloclen));
408 memcpy(p, &zs->len, sizeof(uint16_t));
409 p += sizeof(uint16_t);
410 memcpy(p, zs->data, zs->len);
411 return alloclen;
412 }
413
414 size_t rb_zstring_deserialize(rb_zstring_t *zs, void *buf)
415 {
416 uint8_t *p = (uint8_t *)buf;
417
418 memcpy(&zs->len, p, sizeof(uint16_t));
419 p += sizeof(uint16_t);
420 if(zs->len == 0)
421 {
422 zs->data = NULL;
423 return sizeof(uint16_t);
424 }
425 zs->data = rb_malloc(zs->len);
426 memcpy(zs->data, p, zs->len);
427 return zs->len + sizeof(uint16_t);
428 }
429
430 void rb_zstring_free(rb_zstring_t *zs)
431 {
432 rb_free(zs->data);
433 rb_free(zs);
434
435 }
436
437 rb_zstring_t *rb_zstring_alloc(void)
438 {
439 rb_zstring_t *zs = rb_malloc(sizeof(rb_zstring_t));
440 return zs;
441 }
442
443 rb_zstring_t *rb_zstring_from_c_len(const char *buf, size_t len)
444 {
445 rb_zstring_t *zs;
446
447 if(len > UINT16_MAX-1)
448 return NULL;
449
450 zs = rb_zstring_alloc();
451 zs->alloclen = zs->len = (uint16_t)len;
452 zs->alloclen = (uint16_t)len;
453 if(zs->alloclen < 128)
454 zs->alloclen = 128;
455 zs->data = rb_malloc(zs->alloclen);
456 memcpy(zs->data, buf, zs->len);
457 return(zs);
458 }
459
460 rb_zstring_t *rb_zstring_from_c(const char *buf)
461 {
462 return rb_zstring_from_c_len(buf, strlen(buf));
463 }
464
465 size_t rb_zstring_len(rb_zstring_t *zs)
466 {
467 return zs->len;
468 }
469
470 void rb_zstring_append_from_zstring(rb_zstring_t *dst_zs, rb_zstring_t *src_zs)
471 {
472 void *ep;
473 size_t nlen = dst_zs->len + src_zs->len;
474
475 if(nlen > dst_zs->alloclen)
476 {
477 dst_zs->alloclen += src_zs->len + 64;
478 dst_zs->data = rb_realloc(dst_zs->data, dst_zs->alloclen);
479 }
480
481 ep = dst_zs->data + dst_zs->len;
482 memcpy(ep, src_zs->data, src_zs->len);
483 }
484
485 void rb_zstring_append_from_c(rb_zstring_t *zs, const char *buf, size_t len)
486 {
487 void *ep;
488 size_t nlen = zs->len + len;
489
490 if(nlen > zs->alloclen)
491 {
492 zs->alloclen += len + 64;
493 zs->data = rb_realloc(zs->data, zs->alloclen);
494 }
495 ep = zs->data + zs->len;
496 zs->len += len;
497 memcpy(ep, buf, len);
498 }
499
500 char *rb_zstring_to_c(rb_zstring_t *zs, char *buf, size_t len)
501 {
502 size_t cpylen;
503 if(len < zs->len)
504 cpylen = len - 1;
505 else
506 cpylen = zs->len;
507 buf[cpylen] = '\0';
508 memcpy(buf, zs->data, cpylen);
509 return buf;
510 }
511
512
513 char *rb_zstring_to_c_alloc(rb_zstring_t *zs)
514 {
515 char *p;
516 p = rb_malloc(zs->len+1);
517 memcpy(p, zs->data, zs->len);
518 return p;
519 }
520
521 size_t rb_zstring_to_ptr(rb_zstring_t *zs, void **ptr)
522 {
523 *ptr = (void *)zs->data;
524 return zs->len;
525 }
526
527
528
529 int rb_fsnprint(char *buf, size_t len, const rb_strf_t *strings)
530 {
531 size_t used = 0;
532 size_t remaining = len;
533
534 while (strings != NULL) {
535 int ret = 0;
536
537 if (strings->length != 0) {
538 remaining = strings->length;
539 if (remaining > len - used)
540 remaining = len - used;
541 }
542
543 if (remaining == 0)
544 break;
545
546 if (strings->format != NULL) {
547 if (strings->format_args != NULL) {
548 ret = vsnprintf(buf + used, remaining,
549 strings->format, *strings->format_args);
550 } else {
551 ret = rb_strlcpy(buf + used,
552 strings->format, remaining);
553 }
554 } else if (strings->func != NULL) {
555 ret = strings->func(buf + used, remaining,
556 strings->func_args);
557 }
558
559 if (ret < 0) {
560 return ret;
561 } else if ((size_t)ret > remaining - 1) {
562 used += remaining - 1;
563 } else {
564 used += ret;
565 }
566
567 if (used >= len - 1) {
568 used = len - 1;
569 break;
570 }
571
572 remaining -= ret;
573 strings = strings->next;
574 }
575
576 return used;
577 }
578
579 int rb_fsnprintf(char *buf, size_t len, const rb_strf_t *strings, const char *format, ...)
580 {
581 va_list args;
582 rb_strf_t prepend_string = { .format = format, .format_args = &args, .next = strings };
583 int ret;
584
585 va_start(args, format);
586 ret = rb_fsnprint(buf, len, &prepend_string);
587 va_end(args);
588
589 return ret;
590 }
591