1 /* $EPIC: ircaux.c,v 1.111 2008/03/17 03:42:46 jnelson Exp $ */
2 /*
3 * ircaux.c: some extra routines... not specific to irc... that I needed
4 *
5 * Copyright (c) 1990 Michael Sandroff.
6 * Copyright (c) 1991, 1992 Troy Rollo.
7 * Copyright (c) 1992-1996 Matthew Green.
8 * Copyright � 1994 Jake Khuon.
9 * Copyright � 1993, 2003 EPIC Software Labs.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notices, the above paragraph (the one permitting redistribution),
19 * this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. The names of the author(s) may not be used to endorse or promote
22 * products derived from this software without specific prior written
23 * permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include "irc.h"
39 #include "screen.h"
40 #include <pwd.h>
41 #include <sys/wait.h>
42 #include <math.h>
43 #include "ircaux.h"
44 #include "output.h"
45 #include "termx.h"
46 #include "vars.h"
47 #include "alias.h"
48 #include "if.h"
49 #include "words.h"
50 #include "ctcp.h"
51
52 /*
53 * This is the basic overhead for every malloc allocation (8 bytes).
54 * The size of the allocation and a "magic" sequence are retained here.
55 * This is in addition to any overhead the underlying malloc package
56 * may impose -- this may mean that malloc()s may be actually up to
57 * 20 to 30 bytes larger than you request.
58 */
59 typedef struct _mo_money
60 {
61 unsigned magic;
62 int size;
63 #ifdef ALLOC_DEBUG
64 unsigned entry;
65 char* fn;
66 int line;
67 #endif
68 } MO;
69
70 #ifdef ALLOC_DEBUG
71 struct {
72 int size;
73 void** entries;
74 } alloc_table = { 0, NULL };
75 #endif
76
77 #define mo_ptr(ptr) ((MO *)( (char *)(ptr) - sizeof(MO) ))
78 #define alloc_size(ptr) ((mo_ptr(ptr))->size)
79 #define magic(ptr) ((mo_ptr(ptr))->magic)
80
81 #define FREED_VAL -3
82 #define ALLOC_MAGIC (unsigned long)0x7fbdce70
83
84 /*
85 * This was all imported by pre3 for no reason other than to track down
86 * that blasted bug that splitfire is tickling.
87 */
88 #define NO_ERROR 0
89 #define ALLOC_MAGIC_FAILED 1
90 #define ALREADY_FREED 2
91
malloc_check(void * ptr)92 static int malloc_check (void *ptr)
93 {
94 if (!ptr)
95 return ALLOC_MAGIC_FAILED;
96 if (magic(ptr) != ALLOC_MAGIC)
97 return ALLOC_MAGIC_FAILED;
98 if (alloc_size(ptr) == FREED_VAL)
99 return ALREADY_FREED;
100 #ifdef ALLOC_DEBUG
101 if (ptr != alloc_table.entries[mo_ptr(ptr)->entry])
102 return ALREADY_FREED;
103 #endif
104 return NO_ERROR;
105 }
106
fatal_malloc_check(void * ptr,const char * special,const char * fn,int line)107 void fatal_malloc_check (void *ptr, const char *special, const char *fn, int line)
108 {
109 static int recursion = 0;
110
111 switch (malloc_check(ptr))
112 {
113 case ALLOC_MAGIC_FAILED:
114 {
115 if (recursion)
116 abort();
117
118 recursion++;
119 privileged_yell("IMPORTANT! MAKE SURE TO INCLUDE ALL OF THIS INFORMATION"
120 " IN YOUR BUG REPORT!");
121 privileged_yell("MAGIC CHECK OF MALLOCED MEMORY FAILED!");
122 if (special)
123 privileged_yell("Because of: [%s]", special);
124
125 if (ptr)
126 {
127 privileged_yell("Address: [%p] Size: [%d] Magic: [%x] "
128 "(should be [%lx])",
129 ptr, alloc_size(ptr), magic(ptr), ALLOC_MAGIC);
130 privileged_yell("Dump: [%s]", prntdump(ptr, alloc_size(ptr)));
131 }
132 else
133 privileged_yell("Address: [NULL]");
134
135 privileged_yell("IMPORTANT! MAKE SURE TO INCLUDE ALL OF THIS INFORMATION"
136 " IN YOUR BUG REPORT!");
137 panic("BE SURE TO INCLUDE THE ABOVE IMPORTANT INFORMATION! "
138 "-- new_free()'s magic check failed from [%s/%d].",
139 fn, line);
140 }
141
142 case ALREADY_FREED:
143 {
144 if (recursion)
145 abort();
146
147 recursion++;
148 panic("free()d the same address twice from [%s/%d].",
149 fn, line);
150 }
151
152 case NO_ERROR:
153 return;
154 }
155 }
156
157 /*
158 * really_new_malloc is the general interface to the malloc(3) call.
159 * It is only called by way of the ``new_malloc'' #define.
160 * It wont ever return NULL.
161 */
really_new_malloc(size_t size,const char * fn,int line)162 void * really_new_malloc (size_t size, const char *fn, int line)
163 {
164 char *ptr;
165
166 if (!(ptr = (char *)malloc(size + sizeof(MO))))
167 panic("Malloc() failed from [%s/%d], giving up!", fn, line);
168
169 /* Store the size of the allocation in the buffer. */
170 ptr += sizeof(MO);
171 magic(ptr) = ALLOC_MAGIC;
172 alloc_size(ptr) = size;
173 #ifdef ALLOC_DEBUG
174 mo_ptr(ptr)->entry = alloc_table.size;
175 mo_ptr(ptr)->fn = fn;
176 mo_ptr(ptr)->line = line;
177 alloc_table.size++;
178 alloc_table.entries = realloc(alloc_table.entries, (alloc_table.size) * sizeof(void**));
179 alloc_table.entries[alloc_table.size-1] = ptr;
180 #endif
181 return ptr;
182 }
183
184 #ifdef DELAYED_FREES
185 /*
186 * Instead of calling free() directly in really_new_free(), we instead
187 * delay that until the stack has been unwound completely. This masks the
188 * many bugs in epic where we hold a pointer to some object (such as a DCC
189 * item) and then invoke a sequence point. When that sequence point returns
190 * we cannot assume that pointer is still valid. But regretably we assume
191 * that so often that we can't just sweep this problem away. The rules
192 * regarding double and invalid frees stays because that is all done at a
193 * higher level. The only thing this changes is that we do not release
194 * memory until it is impossible that we could be holding a pointer to it.
195 * This does not fix those bugs, only mitigates their damaging effect.
196 */
197 int need_delayed_free = 0;
198 static void ** delayed_free_table;
199 static int delayed_free_table_size = 0;
200 static int delayed_frees = 0;
201
do_delayed_frees(void)202 void do_delayed_frees (void)
203 {
204 int i;
205
206 for (i = 0; i < delayed_frees; i++)
207 {
208 free((void *)delayed_free_table[i]);
209 delayed_free_table[i] = NULL;
210 }
211 delayed_frees = 0;
212 need_delayed_free = 0;
213 }
214
delay_free(void * ptr)215 static void delay_free (void *ptr)
216 {
217 need_delayed_free = 1;
218 if (delayed_frees >= delayed_free_table_size - 2)
219 {
220 int i = delayed_free_table_size;
221
222 if (delayed_free_table_size)
223 delayed_free_table_size *= 2;
224 else
225 delayed_free_table_size = 128;
226 RESIZE(delayed_free_table, void *, delayed_free_table_size);
227 for (; i < delayed_free_table_size; i++)
228 delayed_free_table[i] = NULL;
229 }
230 delayed_free_table[delayed_frees++] = ptr;
231 }
232 #endif
233
234 /*
235 * really_new_free is the general interface to the free(3) call.
236 * It is only called by way of the ``new_free'' #define.
237 * You must always use new_free to free anything youve allocated
238 * with new_malloc, or all heck will break loose.
239 */
really_new_free(void ** ptr,const char * fn,int line)240 void * really_new_free (void **ptr, const char *fn, int line)
241 {
242 if (*ptr)
243 {
244 fatal_malloc_check(*ptr, NULL, fn, line);
245 alloc_size(*ptr) = FREED_VAL;
246 #ifdef ALLOC_DEBUG
247 alloc_table.entries[mo_ptr(*ptr)->entry]
248 = alloc_table.entries[--alloc_table.size];
249 mo_ptr(alloc_table.entries[mo_ptr(*ptr)->entry])->entry = mo_ptr(*ptr)->entry;
250 #endif
251 #ifdef DELAYED_FREES
252 delay_free((void *)(mo_ptr(*ptr)));
253 #else
254 free((void *)(mo_ptr(*ptr)));
255 #endif
256 }
257 return ((*ptr = NULL));
258 }
259
260 #if 1
261
262 /* really_new_malloc in disguise */
really_new_realloc(void ** ptr,size_t size,const char * fn,int line)263 void * really_new_realloc (void **ptr, size_t size, const char *fn, int line)
264 {
265 void *newptr = NULL;
266
267 if (!size)
268 *ptr = really_new_free(ptr, fn, line);
269 else if (!*ptr)
270 *ptr = really_new_malloc(size, fn, line);
271 else
272 {
273 /* Make sure this is safe for realloc. */
274 fatal_malloc_check(*ptr, NULL, fn, line);
275
276 /* Copy everything, including the MO buffer */
277 if ((newptr = (char *)realloc(mo_ptr(*ptr), size + sizeof(MO))))
278 {
279 *ptr = newptr;
280 } else {
281 new_free(ptr);
282 panic("realloc() failed from [%s/%d], giving up!", fn, line);
283 }
284
285 /* Re-initalize the MO buffer; magic(*ptr) is already set. */
286 *ptr = (void *)((char *)*ptr + sizeof(MO));
287 alloc_size(*ptr) = size;
288 #ifdef ALLOC_DEBUG
289 alloc_table.entries[mo_ptr(*ptr)->entry] = *ptr;
290 #endif
291 }
292 return *ptr;
293 }
294
295 #else
296
new_realloc(void ** ptr,size_t size)297 void * new_realloc (void **ptr, size_t size)
298 {
299 char *ptr2 = NULL;
300 size_t foo,bar;
301
302 /* Yes the function is ifdefed out, but this serves as a proof of concept. */
303 for (foo=1, bar=size+sizeof(MO); bar; foo<<=1, bar>>=1) /* Nothing */ ;
304 if (foo) {size=foo;}
305
306 if (*ptr)
307 {
308 if (size)
309 {
310 size_t msize = alloc_size(*ptr);
311
312 if (msize >= size)
313 return *ptr;
314
315 ptr2 = new_malloc(size);
316 memmove(ptr2, *ptr, msize);
317 }
318 new_free(ptr);
319 }
320 else if (size)
321 ptr2 = new_malloc(size);
322
323 return ((*ptr = ptr2));
324 }
325
326 #endif
327
malloc_dump(const char * file)328 void malloc_dump (const char *file) {
329 #ifdef ALLOC_DEBUG
330 int foo, bar;
331 FILE *fd;
332
333 if (!(file && *file && (fd=fopen(file, "a"))))
334 fd=stdout;
335
336 for (foo = alloc_table.size; foo--;) {
337 fprintf(fd, "%s/%d\t%d\t", mo_ptr(alloc_table.entries[foo])->fn, mo_ptr(alloc_table.entries[foo])->line, mo_ptr(alloc_table.entries[foo])->size);
338 for (bar = 0; bar<mo_ptr(alloc_table.entries[foo])->size; bar++)
339 fprintf(fd, " %x", (unsigned char)(((char*)(alloc_table.entries[foo]))[bar]));
340 fprintf(fd, "\n");
341 }
342 fclose(fd);
343 #endif
344 }
345
upper(char * str)346 char * upper (char *str)
347 {
348 char *ptr = (char *) 0;
349
350 if (str)
351 {
352 ptr = str;
353 for (; *str; str++)
354 {
355 if (islower(*str))
356 *str = toupper(*str);
357 }
358 }
359 return (ptr);
360 }
361
lower(char * str)362 char * lower (char *str)
363 {
364 char *ptr = NULL;
365
366 if (str)
367 {
368 ptr = str;
369 for (; *str; str++)
370 {
371 if (isupper(*str))
372 *str = tolower(*str);
373 }
374 }
375 return ptr;
376 }
377
378 /* case insensitive string searching */
stristr(const char * start,const char * srch)379 ssize_t stristr (const char *start, const char *srch)
380 {
381 int x = 0;
382 const char *source = start;
383
384 if (!source || !*source || !srch || !*srch || strlen(source) < strlen(srch))
385 return -1;
386
387 while (*source)
388 {
389 if (source[x] && toupper(source[x]) == toupper(srch[x]))
390 x++;
391 else if (srch[x])
392 source++, x = 0;
393 else
394 return source - start;
395 }
396 return -1;
397 }
398
399 /* case insensitive string searching from the end */
rstristr(const char * start,const char * srch)400 ssize_t rstristr (const char *start, const char *srch)
401 {
402 const char *ptr;
403 int x = 0;
404
405 if (!start || !*start || !srch || !*srch || strlen(start) < strlen(srch))
406 return -1;
407
408 ptr = start + strlen(start) - strlen(srch);
409
410 while (ptr >= start)
411 {
412 if (!srch[x])
413 return ptr - start;
414
415 if (toupper(ptr[x]) == toupper(srch[x]))
416 x++;
417 else
418 ptr--, x = 0;
419 }
420 return -1;
421 }
422
423
remove_trailing_spaces(char * foo,size_t * cluep)424 char * remove_trailing_spaces (char *foo, size_t *cluep)
425 {
426 char *end;
427 size_t clue = cluep?*cluep:0;
428 if (!*foo)
429 return foo;
430
431 end = clue + foo + strlen(clue + foo) - 1;
432 while (end > foo && my_isspace(*end))
433 end--;
434 /* If this is a \, then it was a \ before a space. Go forward */
435 if (end[0] == '\\' && my_isspace(end[1]))
436 end++;
437 end[1] = 0;
438 if (cluep)
439 *cluep = end - foo;
440 return foo;
441 }
442
forcibly_remove_trailing_spaces(char * foo,size_t * cluep)443 char * forcibly_remove_trailing_spaces (char *foo, size_t *cluep)
444 {
445 char *end;
446 size_t clue = cluep?*cluep:0;
447 if (!*foo)
448 return foo;
449
450 end = clue + foo + strlen(clue + foo) - 1;
451 while (end > foo && my_isspace(*end))
452 end--;
453 /* Do not save spaces after \ at end of words! */
454 end[1] = 0;
455 if (cluep)
456 *cluep = end - foo;
457 return foo;
458 }
459
next_in_comma_list(char * str,char ** after)460 char * next_in_comma_list (char *str, char **after)
461 {
462 return next_in_div_list(str, after, ',');
463 }
464
next_in_div_list(char * str,char ** after,char delim)465 char * next_in_div_list (char *str, char **after, char delim)
466 {
467 *after = str;
468
469 while (*after && **after && **after != delim)
470 (*after)++;
471
472 if (*after && **after == delim)
473 {
474 **after = 0;
475 (*after)++;
476 }
477
478 return str;
479 }
480
481 /* Find the next instance of 'what' that isn't backslashed. */
findchar(char * str,int what)482 char * findchar (char *str, int what)
483 {
484 char *p;
485
486 for (p = str; *p; p++)
487 {
488 if (p[0] == '\\' && p[1])
489 p++;
490 else if (p[0] == what)
491 break;
492 }
493
494 if (*p == what)
495 return p;
496 else
497 return NULL;
498 }
499
500 unsigned char stricmp_table [] =
501 {
502 0, 1, 2, 3, 4, 5, 6, 7,
503 8, 9, 10, 11, 12, 13, 14, 15,
504 16, 17, 18, 19, 20, 21, 22, 23,
505 24, 25, 26, 27, 28, 29, 30, 31,
506 32, 33, 34, 35, 36, 37, 38, 39,
507 40, 41, 42, 43, 44, 45, 46, 47,
508 48, 49, 50, 51, 52, 53, 54, 55,
509 56, 57, 58, 59, 60, 61, 62, 63,
510 64, 65, 66, 67, 68, 69, 70, 71,
511 72, 73, 74, 75, 76, 77, 78, 79,
512 80, 81, 82, 83, 84, 85, 86, 87,
513 88, 89, 90, 91, 92, 93, 94, 95,
514 96, 65, 66, 67, 68, 69, 70, 71,
515 72, 73, 74, 75, 76, 77, 78, 79,
516 80, 81, 82, 83, 84, 85, 86, 87,
517 88, 89, 90, 91, 92, 93, 94, 127,
518
519 128, 129, 130, 131, 132, 133, 134, 135,
520 136, 137, 138, 139, 140, 141, 142, 143,
521 144, 145, 146, 147, 148, 149, 150, 151,
522 152, 153, 154, 155, 156, 157, 158, 159,
523 160, 161, 162, 163, 164, 165, 166, 167,
524 168, 169, 170, 171, 172, 173, 174, 175,
525 176, 177, 178, 179, 180, 181, 182, 183,
526 184, 185, 186, 187, 188, 189, 190, 191,
527 192, 193, 194, 195, 196, 197, 198, 199,
528 200, 201, 202, 203, 204, 205, 206, 207,
529 208, 209, 210, 211, 212, 213, 214, 215,
530 216, 217, 218, 219, 220, 221, 222, 223,
531 224, 225, 226, 227, 228, 229, 230, 231,
532 232, 233, 234, 235, 236, 237, 238, 239,
533 240, 241, 242, 243, 244, 245, 246, 247,
534 248, 249, 250, 251, 252, 253, 254, 255
535 };
536
537 /* my_stricmp: case insensitive version of strcmp */
my_stricmp(const unsigned char * str1,const unsigned char * str2)538 int my_stricmp (const unsigned char *str1, const unsigned char *str2)
539 {
540 while (*str1 && *str2 && (stricmp_table[(unsigned short)*str1] == stricmp_table[(unsigned short)*str2]))
541 str1++, str2++;
542
543 return (stricmp_table[(unsigned short)*str1] -
544 stricmp_table[(unsigned short)*str2]);
545 }
546
547 /* my_strnicmp: case insensitive version of strncmp */
my_strnicmp(const unsigned char * str1,const unsigned char * str2,size_t n)548 int my_strnicmp (const unsigned char *str1, const unsigned char *str2, size_t n)
549 {
550 while (n && *str1 && *str2 && (stricmp_table[(unsigned short)*str1] == stricmp_table[(unsigned short)*str2]))
551 str1++, str2++, n--;
552
553 return (n ?
554 (stricmp_table[(unsigned short)*str1] -
555 stricmp_table[(unsigned short)*str2]) : 0);
556 }
557
558 /* chop -- chops off the last character. capiche? */
chop(char * stuff,size_t nchar)559 char * chop (char *stuff, size_t nchar)
560 {
561 size_t sl = strlen(stuff);
562
563 if (nchar > 0 && sl > 0 && nchar <= sl)
564 stuff[sl - nchar] = 0;
565 else if (nchar > sl)
566 stuff[0] = 0;
567
568 return stuff;
569 }
570
571 /*
572 * strext: Makes a copy of the string delmited by two char pointers and
573 * returns it in malloced memory. Useful when you dont want to munge up
574 * the original string with a null. end must be one place beyond where
575 * you want to copy, ie, its the first character you dont want to copy.
576 */
strext(const char * start,const char * end)577 char * strext (const char *start, const char *end)
578 {
579 char *ptr, *retval;
580
581 ptr = retval = (char *)new_malloc(end-start+1);
582 while (start < end)
583 *ptr++ = *start++;
584 *ptr = 0;
585 return retval;
586 }
587
588
strlopencat(char * dest,size_t maxlen,...)589 char * strlopencat (char *dest, size_t maxlen, ...)
590 {
591 va_list args;
592 int size;
593 char * this_arg = NULL;
594 size_t this_len;
595 char * endp;
596 char * p;
597 size_t worklen;
598
599 endp = dest + maxlen; /* This better not be an error */
600 size = strlen(dest); /* Find the end of the string */
601 p = dest + size; /* We will start catting there */
602 va_start(args, maxlen);
603
604 for (;;)
605 {
606 /* Grab the next string, stop if no more */
607 if (!(this_arg = va_arg(args, char *)))
608 break;
609
610 this_len = strlen(this_arg); /* How much do we need? */
611 worklen = endp - p; /* How much do we have? */
612
613 /* If not enough space, copy what we can and stop */
614 if (this_len > worklen)
615 {
616 strlcpy(p, this_arg, worklen);
617 break; /* No point in continuing */
618 }
619
620 /* Otherwise, we have enough space, copy it */
621 p += strlcpy(p, this_arg, endp - p);
622 }
623
624 va_end(args);
625 return dest;
626 }
627
628 /*
629 * malloc_strcat_ues_c: Just as with malloc_strcat, append 'src' to the end
630 * of '*dest', optionally dequoting (not copying backslashes from) 'src'
631 * pursuant to the following rules:
632 *
633 * special == empty_string De-quote all characters (remove all \'s)
634 * special == NULL De-quote nothing ('src' is literal text)
635 * special is anything else De-quote only \X where X is one of the
636 * characters in 'special'.
637 *
638 * Examples where: dest == "one" and src == "t\w\o"
639 * special == empty_string result is "one two"
640 * (remove all \'s)
641 * special == NULL result is "one t\w\o"
642 * (remove no \'s)
643 * special == "lmnop" result is "one t\wo"
644 * (remove the \ before o, but not w,
645 * because "o" is in "lmnop")
646 *
647 * "ues" stands for "UnEscape Special" and was written to replace the old
648 * ``strmcat_ue'' which had string length limit problems. "_c" of course
649 * means this function takes a string length clue. The previous name,
650 * 'm_strcat_ues_c' was changed becuase ISO C does not allow user symbols
651 * to start with ``m_''.
652 *
653 * Just as with 'malloc_strcat', 'src' may be NULL and this function will
654 * no-op (as opposed to crashing)
655 *
656 * The technique we use here is a hack, and it's expensive, but it works.
657 * 1) Copy 'src' into a temporary buffer, removing any \'s as proscribed
658 * 2) Append the temporary buffer to '*dest'
659 *
660 * NOTES: This is the "dequoter", also known as "Quoting Hell". Everything
661 * that removes \'s uses this function to do it.
662 */
malloc_strcat_ues_c(char ** dest,const char * src,const char * special,size_t * cluep)663 char * malloc_strcat_ues_c (char **dest, const char *src, const char *special, size_t *cluep)
664 {
665 char *workbuf, *p;
666 const char *s;
667
668 /* If there is nothing to copy, just stop right here. */
669 if (!src || !*src)
670 return *dest;
671
672 /* If we're not dequoting, cut it short and return. */
673 if (special == NULL)
674 {
675 malloc_strcat_c(dest, src, cluep);
676 return *dest;
677 }
678
679 /*
680 * Set up a working buffer for our copy.
681 * Reserve two extra spaces because the algorithm below
682 * may copy two nuls to 'workbuf', and we need the space
683 * for the second nul.
684 */
685 workbuf = alloca(strlen(src) + 2);
686
687 /* Walk 'src' looking for characters to dequote */
688 for (s = src, p = workbuf; ; s++, p++)
689 {
690 /*
691 * If we see a backslash, it is not at the end of the
692 * string, and the character after it is contained in
693 * 'special', then skip the backslash.
694 */
695 if (*s == '\\')
696 {
697 /*
698 * If we are doing special dequote handling,
699 * and the \ is not at the end of the string,
700 * and the character after it is contained
701 * within ``special'', skip the \.
702 */
703 if (special != empty_string)
704 {
705 /*
706 * If this character is handled by 'special', then
707 * copy the next character and either continue to
708 * the next character or stop if we're done.
709 */
710 if (s[1] && strchr(special, s[1]))
711 {
712 if ((*p = *++s) == 0)
713 break;
714 else
715 continue;
716 /* NOTREACHED */
717 }
718 }
719
720 /*
721 * BACKWARDS COMPATABILITY:
722 * In any case where \n, \p, \r, and \0 are not
723 * explicitly caught by 'special', we have to
724 * convert them to \020 (dle) to maintain backwards
725 * compatability.
726 */
727 if (s[1] == 'n' || s[1] == 'p' ||
728 s[1] == 'r' || s[1] == '0')
729 {
730 s++; /* Skip the \ */
731 *p = '\020'; /* Copy a \n */
732 continue;
733 }
734
735 /*
736 * So it is not handled by 'special' and it is not
737 * a legacy escape. So we either need to copy or ignore
738 * this \ based on the value of special. If "special"
739 * is empty_string, we remove it. Otherwise, we keep it.
740 */
741 if (special == empty_string)
742 s++;
743
744 /*
745 * Copy this character (or in the above case, the character
746 * after the \). If we copy a nul, then immediately stop the
747 * process here!
748 */
749 if ((*p = *s) == 0)
750 break;
751 }
752
753 /*
754 * Always copy any non-slash character.
755 * Stop when we reach the nul.
756 */
757 else
758 if ((*p = *s) == 0)
759 break;
760 }
761
762 /*
763 * We're done! Append 'workbuf' to 'dest'.
764 */
765 malloc_strcat_c(dest, workbuf, cluep);
766 return *dest;
767 }
768
769 /*
770 * normalize_filename: replacement for expand_twiddle
771 *
772 * This is a front end to realpath(), has the same signature, except
773 * it expands twiddles for me, and it returns 0 or -1 instead of (char *).
774 */
normalize_filename(const char * str,Filename result)775 int normalize_filename (const char *str, Filename result)
776 {
777 Filename workpath;
778 char * pathname;
779 char * rest;
780 struct passwd *entry;
781
782 if (*str == '~')
783 {
784 /* make a copy of the path we can make changes to */
785 pathname = LOCAL_COPY(str + 1);
786
787 /* Stop the tilde-expansion at the first / (or nul) */
788 if ((rest = strchr(pathname, '/')))
789 *rest++ = 0;
790
791 /* Expand ~ to our homedir, ~user to user's homedir */
792 if (*pathname) {
793 if ((entry = getpwnam(pathname)) == NULL) {
794 snprintf(result, MAXPATHLEN + 1, "~%s", pathname);
795 return -1;
796 }
797 strlcpy(workpath, entry->pw_dir, sizeof(workpath));
798 } else
799 strlcpy(workpath, my_path, sizeof(workpath));
800
801 /* And tack on whatever is after the first / */
802 if (rest)
803 {
804 strlcat(workpath, "/", sizeof(workpath));
805 strlcat(workpath, rest, sizeof(workpath));
806 }
807
808 str = workpath;
809 }
810
811 if (realpath(str, result) == NULL)
812 return -1;
813
814 return 0;
815 }
816
817 /*
818 * expand_twiddle: expands ~ in pathnames.
819 *
820 * XXX WARNING XXX
821 *
822 * It is perfectly valid for (str == *result)! You must NOT change
823 * '*result' until you have first copied 'str' to 'buffer'! If you
824 * do not do this, you will corrupt the result! You have been warned!
825 */
expand_twiddle(const char * str,Filename result)826 int expand_twiddle (const char *str, Filename result)
827 {
828 Filename buffer;
829 char *rest;
830 struct passwd *entry;
831
832 /* Handle filenames without twiddles to expand */
833 if (*str != '~')
834 {
835 /* Only do the copy if the destination is not the source */
836 if (str != result)
837 strlcpy(result, str, MAXPATHLEN + 1);
838 return 0;
839 }
840
841 /* Handle filenames that are just ~ or ~/... */
842 str++;
843 if (!*str || *str == '/')
844 {
845 strlcpy(buffer, my_path, sizeof(buffer));
846 strlcat(buffer, str, sizeof(buffer));
847
848 strlcpy(result, buffer, MAXPATHLEN + 1);
849 return 0;
850 }
851
852 /* Handle filenames that are ~user or ~user/... */
853 if ((rest = strchr(str, '/')))
854 *rest++ = 0;
855 if ((entry = getpwnam(str)))
856 {
857 strlcpy(buffer, entry->pw_dir, sizeof(buffer));
858 if (rest)
859 {
860 strlcat(buffer, "/", sizeof(buffer));
861 strlcat(buffer, rest, sizeof(buffer));
862 }
863
864 strlcpy(result, buffer, MAXPATHLEN + 1);
865 return 0;
866 }
867
868 return -1;
869 }
870
871 /* islegal: true if c is a legal nickname char anywhere but first char */
872 #define islegal(c) ((((c) >= 'A') && ((c) <= '}')) || \
873 (((c) >= '0') && ((c) <= '9')) || \
874 ((c) == '-') || ((c) == '_'))
875
876 /*
877 * check_nickname: checks is a nickname is legal. If the first character is
878 * bad, null is returned. If the first character is not bad, the string is
879 * truncated down to only legal characters and returned
880 *
881 * rewritten, with help from do_nick_name() from the server code (2.8.5),
882 * phone, april 1993.
883 */
check_nickname(char * nick,int unused)884 char * check_nickname (char *nick, int unused)
885 {
886 char *s;
887
888 if (!nick || *nick == '-' || isdigit(*nick))
889 return NULL;
890
891 for (s = nick; *s && (s - nick) < NICKNAME_LEN; s++)
892 if (!islegal(*s) || my_isspace(*s))
893 break;
894 *s = '\0';
895
896 return *nick ? nick : NULL;
897 }
898
899 /*
900 * sindex: much like index(), but it looks for a match of any character in
901 * the group, and returns that position. If the first character is a ^, then
902 * this will match the first occurence not in that group.
903 *
904 * XXXX - sindex is a lot like strpbrk(), which is standard
905 */
sindex(char * string,const char * group)906 char * sindex (char *string, const char *group)
907 {
908 const char *ptr;
909
910 if (!string || !group)
911 return (char *) NULL;
912 if (*group == '^')
913 {
914 group++;
915 for (; *string; string++)
916 {
917 for (ptr = group; *ptr; ptr++)
918 {
919 if (*ptr == *string)
920 break;
921 }
922 if (*ptr == '\0')
923 return string;
924 }
925 }
926 else
927 {
928 for (; *string; string++)
929 {
930 for (ptr = group; *ptr; ptr++)
931 {
932 if (*ptr == *string)
933 return string;
934 }
935 }
936 }
937 return (char *) NULL;
938 }
939
940 /*
941 * rsindex: much like rindex(), but it looks for a match of any character in
942 * the group, and returns that position. If the first character is a ^, then
943 * this will match the first occurence not in that group.
944 */
rsindex(char * string,char * start,char * group,int howmany)945 char * rsindex (char *string, char *start, char *group, int howmany)
946 {
947 char *ptr;
948
949 if (howmany && string && start && group && start <= string)
950 {
951 if (*group == '^')
952 {
953 group++;
954 for (ptr = string; (ptr >= start) && howmany; ptr--)
955 {
956 if (!strchr(group, *ptr))
957 {
958 if (--howmany == 0)
959 return ptr;
960 }
961 }
962 }
963 else
964 {
965 for (ptr = string; (ptr >= start) && howmany; ptr--)
966 {
967 if (strchr(group, *ptr))
968 {
969 if (--howmany == 0)
970 return ptr;
971 }
972 }
973 }
974 }
975 return NULL;
976 }
977
978 /* is_number: returns true if the given string is a number, false otherwise */
is_number(const char * str)979 int is_number (const char *str)
980 {
981 if (!str || !*str)
982 return 0;
983
984 while (*str && isspace(*str))
985 str++;
986
987 if (*str == '-')
988 str++;
989
990 if (*str)
991 {
992 for (; *str; str++)
993 {
994 if (!isdigit((*str)))
995 return (0);
996 }
997 return 1;
998 }
999 else
1000 return 0;
1001 }
1002
1003 /* is_number: returns 1 if the given string is a real number, 0 otherwise */
is_real_number(const char * str)1004 int is_real_number (const char *str)
1005 {
1006 int period = 0;
1007
1008 if (!str || !*str)
1009 return 0;
1010
1011 while (*str && isspace(*str))
1012 str++;
1013
1014 if (*str == '-')
1015 str++;
1016
1017 if (!*str)
1018 return 0;
1019
1020 for (; *str; str++)
1021 {
1022 if (isdigit((*str)))
1023 continue;
1024
1025 if (*str == '.' && period == 0)
1026 {
1027 period = 1;
1028 continue;
1029 }
1030
1031 return 0;
1032 }
1033
1034 return 1;
1035 }
1036
1037 /*
1038 * path_search: given a file called name, this will search each element of
1039 * the given path to locate the file. If found in an element of path, the
1040 * full path name of the file is returned in a static string. If not, null
1041 * is returned. Path is a colon separated list of directories
1042 */
path_search(const char * name,const char * xpath,Filename result)1043 int path_search (const char *name, const char *xpath, Filename result)
1044 {
1045 Filename buffer;
1046 Filename candidate;
1047 char *path;
1048 char *ptr;
1049
1050 /* No Path -> Error */
1051 if (!xpath)
1052 return -1; /* Take THAT! */
1053
1054 /*
1055 * A "relative" path is valid if the file exists
1056 * based on the current directory. If it does not
1057 * exist from the current directory, then we will
1058 * search the path for it.
1059 *
1060 * PLEASE NOTE this catches things like ~foo/bar too!
1061 */
1062 if (strchr(name, '/'))
1063 {
1064 if (!normalize_filename(name, candidate))
1065 {
1066 if (file_exists(candidate))
1067 {
1068 strlcpy(result, candidate, MAXPATHLEN + 1);
1069 return 0;
1070 }
1071 }
1072 }
1073
1074 /*
1075 * The previous check already took care of absolute paths
1076 * that exist, so we need to check for absolute paths here
1077 * that DON'T exist. (is this cheating?). Also, ~user/foo
1078 * is considered an "absolute path".
1079 */
1080 if (*name == '/' || *name == '~')
1081 return -1;
1082
1083 *result = 0;
1084 for (path = LOCAL_COPY(xpath); path; path = ptr)
1085 {
1086 if ((ptr = strchr(path, ':')))
1087 *ptr++ = 0;
1088
1089 snprintf(buffer, sizeof(buffer), "%s/%s", path, name);
1090 if (normalize_filename(buffer, candidate))
1091 continue;
1092
1093 if (file_exists(candidate)) {
1094 strlcpy(result, candidate, MAXPATHLEN + 1);
1095 return 0;
1096 }
1097 }
1098
1099 return -1;
1100 }
1101
1102 /*
1103 * double_quote: Given a str of text, this will quote any character in the
1104 * set stuff with the QUOTE_CHAR. You have to pass in a buffer thats at
1105 * least twice the size of 'str' (in case every character is quoted.)
1106 * "output" is returned for your convenience.
1107 */
double_quote(const char * str,const char * stuff,char * buffer)1108 char * double_quote (const char *str, const char *stuff, char *buffer)
1109 {
1110 char c;
1111 int pos;
1112
1113 *buffer = 0; /* Whatever */
1114
1115 if (!stuff)
1116 return buffer; /* Whatever */
1117
1118 for (pos = 0; (c = *str); str++)
1119 {
1120 if (strchr(stuff, c))
1121 {
1122 if (c == '$')
1123 buffer[pos++] = '$';
1124 else
1125 buffer[pos++] = '\\';
1126 }
1127 buffer[pos++] = c;
1128 }
1129 buffer[pos] = '\0';
1130 return buffer;
1131 }
1132
panic(const char * format,...)1133 void panic (const char *format, ...)
1134 {
1135 char buffer[BIG_BUFFER_SIZE * 10 + 1];
1136 static int recursion = 0; /* Recursion is bad */
1137
1138 if (recursion)
1139 abort();
1140
1141 recursion = 1;
1142 if (format)
1143 {
1144 va_list arglist;
1145 va_start(arglist, format);
1146 vsnprintf(buffer, BIG_BUFFER_SIZE * 10, format, arglist);
1147 va_end(arglist);
1148 }
1149
1150 term_reset();
1151 fprintf(stderr, "An unrecoverable logic error has occurred.\n");
1152 fprintf(stderr, "Please fill out the BUG_FORM file, and include the following message:\n");
1153 fprintf(stderr, "Panic: [%s (%lu):%s]\n", irc_version, commit_id, buffer);
1154 panic_dump_call_stack();
1155
1156 if (x_debug & DEBUG_CRASH)
1157 irc_exit(0, "EPIC Panic: %s (%lu):%s", irc_version, commit_id, buffer);
1158 else
1159 irc_exit(1, "EPIC Panic: %s (%lu):%s", irc_version, commit_id, buffer);
1160 }
1161
1162 /* beep_em: Not hard to figure this one out */
beep_em(int beeps)1163 void beep_em (int beeps)
1164 {
1165 int cnt,
1166 i;
1167
1168 for (cnt = beeps, i = 0; i < cnt; i++)
1169 term_beep();
1170 }
1171
1172 /* Not really complicated, but a handy function to have */
end_strcmp(const char * val1,const char * val2,size_t bytes)1173 int end_strcmp (const char *val1, const char *val2, size_t bytes)
1174 {
1175 if (bytes < strlen(val1))
1176 return (strcmp(val1 + strlen(val1) - (size_t) bytes, val2));
1177 else
1178 return -1;
1179 }
1180
1181 /*
1182 * exec a program, given its arguments and input, return its entire output.
1183 * on call, *len is the length of input, and on return, it is set to the
1184 * length of the data returned.
1185 *
1186 * Reading is done more agressively than writing to keep the buffers
1187 * clean, and the data flowing.
1188 *
1189 * Potential Bugs:
1190 * - If the program in question locks up for any reason, so will epic.
1191 * This can be fixed with an appropriate timeout in the select call.
1192 * - If the program in question outputs enough data, epic will run out
1193 * of memory and dump core.
1194 * - Although input and the return values are char*'s, they are only
1195 * treated as blocks of data, the size of *len.
1196 *
1197 * Special Note: stdin and stdout are not expected to be textual.
1198 */
exec_pipe(const char * executable,char * input,size_t * len,char * const * args)1199 char* exec_pipe (const char *executable, char *input, size_t *len, char * const *args)
1200 {
1201 int pipe0[2] = {-1, -1};
1202 int pipe1[2] = {-1, -1};
1203 pid_t pid;
1204 char * ret = NULL;
1205 size_t retlen = 0, rdpos = 0, wrpos = 0;
1206 fd_set rdfds, wrfds;
1207 int fdmax;
1208
1209 if (pipe(pipe0) || pipe(pipe1))
1210 {
1211 yell("Cannot open pipes for %s: %s",
1212 executable, strerror(errno));
1213 close(pipe0[0]);
1214 close(pipe0[1]);
1215 close(pipe1[0]);
1216 close(pipe1[1]);
1217 return ret;
1218 }
1219
1220 switch (pid = fork())
1221 {
1222 case -1:
1223 yell("Cannot fork for %s: %s",
1224 executable, strerror(errno));
1225 close(pipe0[0]);
1226 close(pipe0[1]);
1227 close(pipe1[0]);
1228 close(pipe1[1]);
1229 return ret;
1230 case 0:
1231 dup2(pipe0[0], 0);
1232 dup2(pipe1[1], 1);
1233 close(pipe0[1]);
1234 close(pipe1[0]);
1235 close(2); /* we dont want to see errors yet */
1236 setuid(getuid());
1237 setgid(getgid());
1238 execvp(executable, args);
1239 #if 0
1240 /*
1241 * OK, well the problem with this is that the message
1242 * is going to go out on stdout right, and where does
1243 * that end up?
1244 */
1245 yell("Cannot exec %s: %s",
1246 executable, strerror(errno));
1247 #endif
1248 _exit(0);
1249 default :
1250 close(pipe0[0]);
1251 close(pipe1[1]);
1252 FD_ZERO(&rdfds);
1253 FD_ZERO(&wrfds);
1254 FD_SET(pipe1[0], &rdfds);
1255 FD_SET(pipe0[1], &wrfds);
1256 fdmax = 1 + MAX(pipe1[0], pipe0[1]);
1257 for (;;) {
1258 fd_set RDFDS = rdfds;
1259 fd_set WRFDS = wrfds;
1260 int foo;
1261 foo = select(fdmax, &RDFDS, &WRFDS, NULL, NULL);
1262 if (-1 == foo) {
1263 yell("Broken select call: %s", strerror(errno));
1264 if (EINTR == errno)
1265 continue;
1266 break;
1267 } else if (0 == foo) {
1268 break;
1269 }
1270 if (FD_ISSET(pipe1[0], &RDFDS)) {
1271 retlen = rdpos + 4096;
1272 new_realloc((void**)&ret, retlen);
1273 foo = read(pipe1[0], ret+rdpos, retlen-rdpos);
1274 if (0 == foo)
1275 break;
1276 else if (0 < foo)
1277 rdpos += foo;
1278 } else if (FD_ISSET(pipe0[1], &WRFDS)) {
1279 if (input && wrpos < *len)
1280 foo = write(pipe0[1], input+wrpos, MIN(512, *len-wrpos));
1281 else {
1282 FD_CLR(pipe0[1], &wrfds);
1283 close(pipe0[1]);
1284 }
1285 if (0 < foo)
1286 wrpos += foo;
1287 }
1288 }
1289 close(pipe0[1]);
1290 close(pipe1[0]);
1291 waitpid(pid, NULL, WNOHANG);
1292 new_realloc((void**)&ret, rdpos);
1293 break;
1294 }
1295 *len = rdpos;
1296 return ret;
1297 }
1298
1299 /*
1300 * exec() something and return three FILE's.
1301 *
1302 * On failure, close everything and return NULL.
1303 */
open_exec(const char * executable,char * const * args)1304 FILE ** open_exec (const char *executable, char * const *args)
1305 {
1306 static FILE * file_pointers[3];
1307 int pipe0[2] = {-1, -1};
1308 int pipe1[2] = {-1, -1};
1309 int pipe2[2] = {-1, -1};
1310
1311 if (pipe(pipe0) == -1 || pipe(pipe1) == -1 || pipe(pipe2) == -1)
1312 {
1313 yell("Cannot open exec pipes: %s\n", strerror(errno));
1314 close(pipe0[0]);
1315 close(pipe0[1]);
1316 close(pipe1[0]);
1317 close(pipe1[1]);
1318 close(pipe2[0]);
1319 close(pipe2[1]);
1320 return NULL;
1321 }
1322
1323 switch (fork())
1324 {
1325 case -1:
1326 {
1327 yell("Cannot fork for exec: %s\n",
1328 strerror(errno));
1329 close(pipe0[0]);
1330 close(pipe0[1]);
1331 close(pipe1[0]);
1332 close(pipe1[1]);
1333 close(pipe2[0]);
1334 close(pipe2[1]);
1335 return NULL;
1336 }
1337 case 0:
1338 {
1339 dup2(pipe0[0], 0);
1340 dup2(pipe1[1], 1);
1341 dup2(pipe2[1], 2);
1342 close(pipe0[1]);
1343 close(pipe1[0]);
1344 close(pipe2[0]);
1345 setuid(getuid());
1346 setgid(getgid());
1347 execvp(executable, args);
1348 _exit(0);
1349 }
1350 default :
1351 {
1352 close(pipe0[0]);
1353 close(pipe1[1]);
1354 close(pipe2[1]);
1355 if (!(file_pointers[0] = fdopen(pipe0[1], "w")))
1356 {
1357 yell("Cannot open exec STDIN: %s\n",
1358 strerror(errno));
1359 close(pipe0[1]);
1360 close(pipe1[0]);
1361 close(pipe2[0]);
1362 return NULL;
1363 }
1364 if (!(file_pointers[1] = fdopen(pipe1[0], "r")))
1365 {
1366 yell("Cannot open exec STDOUT: %s\n",
1367 strerror(errno));
1368 fclose(file_pointers[0]);
1369 close(pipe1[0]);
1370 close(pipe2[0]);
1371 return NULL;
1372 }
1373 if (!(file_pointers[2] = fdopen(pipe2[0], "r")))
1374 {
1375 yell("Cannot open exec STDERR: %s\n",
1376 strerror(errno));
1377 fclose(file_pointers[0]);
1378 fclose(file_pointers[1]);
1379 close(pipe2[0]);
1380 return NULL;
1381 }
1382 break;
1383 }
1384 }
1385 return file_pointers;
1386 }
1387
open_compression(char * executable,char * filename)1388 static FILE * open_compression (char *executable, char *filename)
1389 {
1390 FILE * file_pointer;
1391 int pipes[2] = {-1, -1};
1392
1393 if (pipe(pipes) == -1)
1394 {
1395 yell("Cannot start decompression: %s\n", strerror(errno));
1396 if (pipes[0] != -1)
1397 {
1398 close(pipes[0]);
1399 close(pipes[1]);
1400 }
1401 return NULL;
1402 }
1403
1404 switch (fork())
1405 {
1406 case -1:
1407 {
1408 yell("Cannot start decompression: %s\n",
1409 strerror(errno));
1410 return NULL;
1411 }
1412 case 0:
1413 {
1414 dup2(pipes[1], 1);
1415 close(pipes[0]);
1416 close(2); /* we dont want to see errors */
1417 setuid(getuid());
1418 setgid(getgid());
1419
1420 /*
1421 * 'compress', 'uncompress, 'gzip', 'gunzip',
1422 * 'bzip2' and 'bunzip'2 on my system all support
1423 * the -d option reasonably. I hope they do
1424 * elsewhere. :d
1425 */
1426 execl(executable, executable, "-d", "-c", filename, NULL);
1427 _exit(0);
1428 }
1429 default :
1430 {
1431 close(pipes[1]);
1432 if (!(file_pointer = fdopen(pipes[0], "r")))
1433 {
1434 yell("Cannot start decompression: %s\n",
1435 strerror(errno));
1436 return NULL;
1437 }
1438 break;
1439 }
1440 }
1441 return file_pointer;
1442 }
1443
1444 /*
1445 * Front end to fopen() that will open ANY file, compressed or not, and
1446 * is relatively smart about looking for the possibilities, and even
1447 * searches a path for you! ;-)
1448 *
1449 * NOTICE -- 'filename' is an input/output parameter. On input, it must
1450 * be a malloc()ed string containing a file to open. On output, it will
1451 * be changed to point to the actual filename that was opened. THE ORIGINAL
1452 * INPUT VALUE IS ALWAYS FREE()D IN EVERY CIRCUMSTANCE. IT WILL BE REPLACED
1453 * WITH A NEW VALUE (ie, the variable will be changed) UPON RETURN. You must
1454 * not save the original value of '*filename' and use it after calling uzfopen.
1455 */
uzfopen(char ** filename,const char * path,int do_error)1456 FILE * uzfopen (char **filename, const char *path, int do_error)
1457 {
1458 static int setup = 0;
1459 static Filename path_to_gunzip;
1460 static Filename path_to_uncompress;
1461 static Filename path_to_bunzip2;
1462 int ok_to_decompress = 0;
1463 Filename fullname;
1464 Filename candidate;
1465 Stat file_info;
1466 FILE * doh;
1467
1468 if (!setup)
1469 {
1470 *path_to_gunzip = 0;
1471 path_search("gunzip", getenv("PATH"), path_to_gunzip);
1472
1473 *path_to_uncompress = 0;
1474 path_search("uncompress", getenv("PATH"), path_to_uncompress);
1475
1476 *path_to_bunzip2 = 0;
1477 if (path_search("bunzip2", getenv("PATH"), path_to_bunzip2))
1478 path_search("bunzip", getenv("PATH"), path_to_bunzip2);
1479
1480 setup = 1;
1481 }
1482
1483 /*
1484 * It is allowed to pass to this function either a true filename
1485 * with the compression extention, or to pass it the base name of
1486 * the filename, and this will look to see if there is a compressed
1487 * file that matches the base name
1488 */
1489
1490 /*
1491 * Start with what we were given as an initial guess
1492 * kev asked me to call expand_twiddle here once,
1493 * Now that path_search() does ~'s, we don't need to do
1494 * so here any more.
1495 */
1496
1497 /*
1498 * Look to see if the passed filename is a full compressed filename
1499 */
1500 if ((!end_strcmp(*filename, ".gz", 3)) ||
1501 (!end_strcmp(*filename, ".z", 2)))
1502 {
1503 if (!*path_to_gunzip)
1504 {
1505 if (do_error)
1506 yell("Cannot open file %s because gunzip "
1507 "was not found", *filename);
1508 goto error_cleanup;
1509 }
1510
1511 ok_to_decompress = 2;
1512 if (path_search(*filename, path, fullname))
1513 goto file_not_found;
1514 }
1515 else if (!end_strcmp(*filename, ".Z", 2))
1516 {
1517 if (!*path_to_gunzip && !*path_to_uncompress)
1518 {
1519 if (do_error)
1520 yell("Cannot open file %s becuase uncompress "
1521 "was not found", *filename);
1522 goto error_cleanup;
1523 }
1524
1525 ok_to_decompress = 1;
1526 if (path_search(*filename, path, fullname))
1527 goto file_not_found;
1528 }
1529 else if (!end_strcmp(*filename, ".bz2", 4))
1530 {
1531 if (!*path_to_bunzip2)
1532 {
1533 if (do_error)
1534 yell("Cannot open file %s because bunzip "
1535 "was not found", *filename);
1536 goto error_cleanup;
1537 }
1538
1539 ok_to_decompress = 3;
1540 if (path_search(*filename, path, fullname))
1541 goto file_not_found;
1542 }
1543
1544 /* Right now it doesnt look like the file is a full compressed fn */
1545 else
1546 {
1547 do
1548 {
1549 /* Trivially, see if the file we were passed exists */
1550 if (!path_search(*filename, path, fullname)) {
1551 ok_to_decompress = 0;
1552 break;
1553 }
1554
1555 /* Is there a "filename.gz"? */
1556 snprintf(candidate, sizeof(candidate), "%s.gz", *filename);
1557 if (!path_search(candidate, path, fullname)) {
1558 ok_to_decompress = 2;
1559 break;
1560 }
1561
1562 /* Is there a "filename.Z"? */
1563 snprintf(candidate, sizeof(candidate), "%s.Z", *filename);
1564 if (!path_search(candidate, path, fullname)) {
1565 ok_to_decompress = 1;
1566 break;
1567 }
1568
1569 /* Is there a "filename.z"? */
1570 snprintf(candidate, sizeof(candidate), "%s.z", *filename);
1571 if (!path_search(candidate, path, fullname)) {
1572 ok_to_decompress = 2;
1573 break;
1574 }
1575
1576 /* Is there a "filename.bz2"? */
1577 snprintf(candidate, sizeof(candidate), "%s.bz2", *filename);
1578 if (!path_search(candidate, path, fullname)) {
1579 ok_to_decompress = 3;
1580 break;
1581 }
1582
1583 goto file_not_found;
1584 }
1585 while (0);
1586
1587 stat(fullname, &file_info);
1588 if (S_ISDIR(file_info.st_mode))
1589 {
1590 if (do_error)
1591 yell("%s is a directory", fullname);
1592 goto error_cleanup;
1593 }
1594 if (file_info.st_mode & 0111)
1595 {
1596 if (do_error)
1597 yell("Cannot open %s -- executable file", fullname);
1598 goto error_cleanup;
1599 }
1600 }
1601
1602 /*
1603 * At this point, we should have a filename in the variable
1604 * *filename, and it should exist. If ok_to_decompress is one, then
1605 * we can gunzip the file if gunzip is available. else we
1606 * uncompress the file.
1607 */
1608 malloc_strcpy(filename, fullname);
1609 if (ok_to_decompress)
1610 {
1611 if ((ok_to_decompress <= 2) && *path_to_gunzip)
1612 return open_compression(path_to_gunzip, *filename);
1613 else if ((ok_to_decompress == 1) && *path_to_uncompress)
1614 return open_compression(path_to_uncompress, *filename);
1615 else if ((ok_to_decompress == 3) && *path_to_bunzip2)
1616 return open_compression(path_to_bunzip2, *filename);
1617
1618 if (do_error)
1619 yell("Cannot open compressed file %s becuase no "
1620 "uncompressor was found", *filename);
1621 goto error_cleanup;
1622 }
1623
1624 /* Its not a compressed file... Try to open it regular-like. */
1625 else if ((doh = fopen(*filename, "r")))
1626 return doh;
1627
1628 /* nope.. we just cant seem to open this file... */
1629 else if (do_error)
1630 yell("Cannot open file %s: %s", *filename, strerror(errno));
1631
1632 goto error_cleanup;
1633
1634 file_not_found:
1635 if (do_error)
1636 yell("File not found: %s", *filename);
1637
1638 error_cleanup:
1639 new_free(filename);
1640 return NULL;
1641 }
1642
1643
1644 /*
1645 * slurp_file opens up a file and puts the contents into 'buffer'.
1646 * The size of 'buffer' is returned.
1647 */
slurp_file(char ** buffer,char * filename)1648 int slurp_file (char **buffer, char *filename)
1649 {
1650 char * local_buffer;
1651 size_t offset;
1652 off_t local_buffer_size;
1653 off_t filesize;
1654 Stat s;
1655 FILE * file;
1656 size_t count;
1657
1658 file = uzfopen(&filename, get_string_var(LOAD_PATH_VAR), 1);
1659 if (stat(filename, &s) < 0)
1660 {
1661 fclose(file);
1662 new_free(&filename);
1663 return -1; /* Whatever. */
1664 }
1665
1666 filesize = s.st_size;
1667 if (!end_strcmp(filename, ".gz", 3))
1668 filesize *= 7;
1669 else if (!end_strcmp(filename, ".bz2", 4))
1670 filesize *= 10;
1671 else if (!end_strcmp(filename, ".Z", 2))
1672 filesize *= 5;
1673
1674 local_buffer = new_malloc(filesize);
1675 local_buffer_size = filesize;
1676 offset = 0;
1677
1678 do
1679 {
1680 count = fread(local_buffer + offset,
1681 local_buffer_size - offset, 1, file);
1682 offset += count;
1683
1684 if (!feof(file))
1685 {
1686 local_buffer_size += (filesize * 3);
1687 new_realloc((void **)&local_buffer, local_buffer_size);
1688 continue;
1689 }
1690 }
1691 while (0);
1692
1693 *buffer = local_buffer;
1694 return offset;
1695 }
1696
1697
1698
fw_strcmp(comp_len_func * compar,char * v1,char * v2)1699 int fw_strcmp (comp_len_func *compar, char *v1, char *v2)
1700 {
1701 int len = 0;
1702 char *pos = one;
1703
1704 while (!my_isspace(*pos))
1705 pos++, len++;
1706
1707 return compar(v1, v2, len);
1708 }
1709
1710
1711
1712 /*
1713 * Compares the last word in 'one' to the string 'two'. You must provide
1714 * the compar function. my_stricmp is a good default.
1715 */
lw_strcmp(comp_func * compar,char * val1,char * val2)1716 int lw_strcmp(comp_func *compar, char *val1, char *val2)
1717 {
1718 char *pos = val1 + strlen(val1) - 1;
1719
1720 if (pos > val1) /* cant do pos[-1] if pos == val1 */
1721 while (!my_isspace(pos[-1]) && (pos > val1))
1722 pos--;
1723 else
1724 pos = val1;
1725
1726 if (compar)
1727 return compar(pos, val2);
1728 else
1729 return my_stricmp(pos, val2);
1730 }
1731
1732 /*
1733 * you give it a filename, some flags, and a position, and it gives you an
1734 * fd with the file pointed at the 'position'th byte.
1735 */
opento(const char * filename,int flags,off_t position)1736 int opento(const char *filename, int flags, off_t position)
1737 {
1738 int file;
1739
1740 file = open(filename, flags, 777);
1741 lseek(file, position, SEEK_SET);
1742 return file;
1743 }
1744
1745
1746 /* swift and easy -- returns the size of the file */
file_size(const char * filename)1747 off_t file_size (const char *filename)
1748 {
1749 Stat statbuf;
1750
1751 if (!stat(filename, &statbuf))
1752 return (off_t)(statbuf.st_size);
1753 else
1754 return -1;
1755 }
1756
file_exists(const char * filename)1757 int file_exists (const char *filename)
1758 {
1759 if (file_size(filename) == -1)
1760 return 0;
1761 else
1762 return 1;
1763 }
1764
isdir(const char * filename)1765 int isdir (const char *filename)
1766 {
1767 Stat statbuf;
1768
1769 if (!stat(filename, &statbuf))
1770 {
1771 if (S_ISDIR(statbuf.st_mode))
1772 return 1;
1773 }
1774 return 0;
1775 }
1776
timeval_to_metric(const Timeval * tv)1777 struct metric_time timeval_to_metric (const Timeval *tv)
1778 {
1779 struct metric_time retval;
1780 double my_timer;
1781 long sec;
1782
1783 retval.mt_days = tv->tv_sec / 86400;
1784 sec = tv->tv_sec % 86400; /* Seconds after midnight */
1785 sec = sec * 1000; /* Convert to ms */
1786 sec += (tv->tv_usec / 1000); /* Add ms fraction */
1787 my_timer = (double)sec / 86400.0; /* Convert to millidays */
1788 retval.mt_mdays = my_timer;
1789 return retval;
1790 }
1791
get_metric_time(double * timer)1792 struct metric_time get_metric_time (double *timer)
1793 {
1794 Timeval tv;
1795 struct metric_time mt;
1796
1797 get_time(&tv);
1798 mt = timeval_to_metric(&tv);
1799 if (timer)
1800 *timer = mt.mt_mdays;
1801 return mt;
1802 }
1803
1804
1805 /* Gets the time in second/usecond if you can, second/0 if you cant. */
get_time(Timeval * timer)1806 Timeval get_time (Timeval *timer)
1807 {
1808 static Timeval retval;
1809
1810 /* Substitute a dummy timeval if we need one. */
1811 if (!timer)
1812 timer = &retval;
1813
1814 {
1815 #ifdef HAVE_CLOCK_GETTIME
1816 struct timespec ts;
1817 clock_gettime(CLOCK_REALTIME, &ts);
1818 timer->tv_sec = ts.tv_sec;
1819 timer->tv_usec = ts.tv_nsec / 1000;
1820 #else
1821 # ifdef HAVE_GETTIMEOFDAY
1822 gettimeofday(timer, NULL);
1823 # else
1824 timer->tv_sec = time(NULL);
1825 timer->tv_usec = 0;
1826 # endif
1827 #endif
1828 }
1829
1830 return *timer;
1831 }
1832
1833 /*
1834 * calculates the time elapsed between 't1' and 't2' where they were
1835 * gotten probably with a call to get_time. 't1' should be the older
1836 * timer and 't2' should be the most recent timer.
1837 */
time_diff(const Timeval t1,const Timeval t2)1838 double time_diff (const Timeval t1, const Timeval t2)
1839 {
1840 Timeval td;
1841
1842 td.tv_sec = t2.tv_sec - t1.tv_sec;
1843 td.tv_usec = t2.tv_usec - t1.tv_usec;
1844
1845 return (double)td.tv_sec + ((double)td.tv_usec / 1000000.0);
1846 }
1847
double_to_timeval(double x)1848 Timeval double_to_timeval (double x)
1849 {
1850 Timeval td;
1851 time_t s;
1852
1853 s = (time_t) x;
1854 x = x - s;
1855 x = x * 1000000;
1856
1857 td.tv_sec = s;
1858 td.tv_usec = (long) x;
1859 return td;
1860 }
1861
1862 /*
1863 * calculates the time elapsed between 'one' and 'two' where they were
1864 * gotten probably with a call to get_time. 'one' should be the older
1865 * timer and 'two' should be the most recent timer.
1866 */
time_subtract(const Timeval t1,const Timeval t2)1867 Timeval time_subtract (const Timeval t1, const Timeval t2)
1868 {
1869 Timeval td;
1870
1871 td.tv_sec = t2.tv_sec - t1.tv_sec;
1872 td.tv_usec = t2.tv_usec - t1.tv_usec;
1873 if (td.tv_usec < 0)
1874 {
1875 td.tv_usec += 1000000;
1876 td.tv_sec--;
1877 }
1878 return td;
1879 }
1880
1881 /*
1882 * Adds the interval "two" to the base time "one" and returns it.
1883 */
time_add(const Timeval t1,const Timeval t2)1884 Timeval time_add (const Timeval t1, const Timeval t2)
1885 {
1886 Timeval td;
1887
1888 td.tv_usec = t1.tv_usec + t2.tv_usec;
1889 td.tv_sec = t1.tv_sec + t2.tv_sec;
1890 if (td.tv_usec >= 1000000)
1891 {
1892 td.tv_usec -= 1000000;
1893 td.tv_sec++;
1894 }
1895 return td;
1896 }
1897
1898
plural(int number)1899 const char * plural (int number)
1900 {
1901 return (number != 1) ? "s" : empty_string;
1902 }
1903
my_ctime(time_t when)1904 char * my_ctime (time_t when)
1905 {
1906 return chop(ctime(&when), 1);
1907 }
1908
1909
ltoa(long foo)1910 char * ltoa (long foo)
1911 {
1912 static char buffer[BIG_BUFFER_SIZE + 1];
1913 char *pos = buffer + BIG_BUFFER_SIZE - 1;
1914 unsigned long absv;
1915 int negative;
1916
1917 absv = (foo < 0) ? (unsigned long)-foo : (unsigned long)foo;
1918 negative = (foo < 0) ? 1 : 0;
1919
1920 buffer[BIG_BUFFER_SIZE] = 0;
1921 for (; absv > 9; absv /= 10)
1922 *pos-- = (absv % 10) + '0';
1923 *pos = (absv) + '0';
1924
1925 if (negative)
1926 *--pos = '-';
1927
1928 return pos;
1929 }
1930
ftoa(double foo)1931 char * ftoa (double foo)
1932 {
1933 static char buffer [BIG_BUFFER_SIZE + 1];
1934 extern double fmod (double, double);
1935
1936 if (get_int_var(FLOATING_POINT_MATH_VAR)) {
1937 snprintf(buffer, sizeof buffer, "%.*g",
1938 get_int_var(FLOATING_POINT_PRECISION_VAR), foo);
1939 } else {
1940 foo -= fmod(foo, 1);
1941 snprintf(buffer, sizeof buffer, "%.0f", foo);
1942 }
1943 return buffer;
1944 }
1945
1946 /*
1947 * Formats "src" into "dest" using the given length. If "length" is
1948 * negative, then the string is right-justified. If "length" is
1949 * zero, nothing happens. Sure, i cheat, but its cheaper then doing
1950 * two snprintf's.
1951 *
1952 * Changed to use the PAD_CHAR variable, which allows the user to specify
1953 * what character should be used to "fill out" the padding.
1954 */
strformat(char * dest,const char * src,ssize_t length,int pad)1955 char * strformat (char *dest, const char *src, ssize_t length, int pad)
1956 {
1957 char * ptr1 = dest;
1958 const char * ptr2 = src;
1959 int tmplen = length;
1960 int abslen;
1961 char padc;
1962
1963 abslen = (length >= 0 ? length : -length);
1964 if ((padc = (char)pad) == 0)
1965 padc = ' ';
1966
1967 /* Cheat by spacing out 'dest' */
1968 for (tmplen = abslen - 1; tmplen >= 0; tmplen--)
1969 dest[tmplen] = padc;
1970 dest[abslen] = 0;
1971
1972 /* Then cheat further by deciding where the string should go. */
1973 if (length > 0) /* left justified */
1974 {
1975 while ((length-- > 0) && *ptr2)
1976 *ptr1++ = *ptr2++;
1977 }
1978 else if (length < 0) /* right justified */
1979 {
1980 length = -length;
1981 ptr1 = dest;
1982 ptr2 = src;
1983 if ((int)strlen(src) < length)
1984 ptr1 += length - strlen(src);
1985 while ((length-- > 0) && *ptr2)
1986 *ptr1++ = *ptr2++;
1987 }
1988 return dest;
1989 }
1990
1991
1992 /*
1993 * MatchingBracket returns the next unescaped bracket of the given type
1994 * This used to be real simple (see the final else clause), but very
1995 * expensive. Since its called a lot, i unrolled the two most common cases
1996 * (parens and brackets) and parsed them out with switches, which should
1997 * really help the cpu usage. I hope. Everything else just falls through
1998 * and uses the old tried and true method.
1999 */
MatchingBracket(const char * start,char left,char right)2000 ssize_t MatchingBracket (const char *start, char left, char right)
2001 {
2002 int bracket_count = 1;
2003 const char *string = start;
2004
2005 if (left == '(')
2006 {
2007 for (; *string; string++)
2008 {
2009 switch (*string)
2010 {
2011 case '(':
2012 bracket_count++;
2013 break;
2014 case ')':
2015 bracket_count--;
2016 if (bracket_count == 0)
2017 return string - start;
2018 break;
2019 case '\\':
2020 if (string[1])
2021 string++;
2022 break;
2023 }
2024 }
2025 }
2026 else if (left == '[')
2027 {
2028 for (; *string; string++)
2029 {
2030 switch (*string)
2031 {
2032 case '[':
2033 bracket_count++;
2034 break;
2035 case ']':
2036 bracket_count--;
2037 if (bracket_count == 0)
2038 return string - start;
2039 break;
2040 case '\\':
2041 if (string[1])
2042 string++;
2043 break;
2044 }
2045 }
2046 }
2047 else /* Fallback for everyone else */
2048 {
2049 while (*string && bracket_count)
2050 {
2051 if (*string == '\\' && string[1])
2052 string++;
2053 else if (*string == left)
2054 bracket_count++;
2055 else if (*string == right)
2056 {
2057 if (--bracket_count == 0)
2058 return string - start;
2059 }
2060 string++;
2061 }
2062 }
2063
2064 return -1;
2065 }
2066
2067 /*
2068 * parse_number: returns the next number found in a string and moves the
2069 * string pointer beyond that point in the string. Here's some examples:
2070 *
2071 * "123harhar" returns 123 and str as "harhar"
2072 *
2073 * while:
2074 *
2075 * "hoohar" returns -1 and str as "hoohar"
2076 */
parse_number(char ** str)2077 int parse_number (char **str)
2078 {
2079 long ret;
2080 char *ptr = *str; /* sigh */
2081
2082 ret = strtol(ptr, str, 10);
2083 if (*str == ptr)
2084 ret = -1;
2085
2086 return (int)ret;
2087 }
2088
chop_word(char * str)2089 char * chop_word (char *str)
2090 {
2091 char *end = str + strlen(str) - 1;
2092
2093 while (my_isspace(*end) && (end > str))
2094 end--;
2095 while (!my_isspace(*end) && (end > str))
2096 end--;
2097
2098 if (end >= str)
2099 *end = 0;
2100
2101 return str;
2102 }
2103
skip_spaces(char * str)2104 char * skip_spaces (char *str)
2105 {
2106 while (str && *str && isspace(*str))
2107 str++;
2108 return str;
2109 }
2110
split_args(char * str,char ** to,size_t maxargs)2111 int split_args (char *str, char **to, size_t maxargs)
2112 {
2113 size_t counter;
2114 char * ptr;
2115
2116 ptr = str;
2117 for (counter = 0; counter < maxargs; counter++)
2118 {
2119 if (!ptr || !*ptr)
2120 break;
2121
2122 ptr = skip_spaces(ptr);
2123 if (*ptr == '{' || *ptr == '(')
2124 {
2125 if (counter > 0)
2126 ptr[-1] = 0;
2127 to[counter] = next_expr_with_type(&ptr, *ptr);
2128 }
2129 else
2130 to[counter] = new_next_arg(ptr, &ptr);
2131
2132 /* Syntax error? abort immediately. */
2133 if (to[counter] == NULL)
2134 break;
2135 }
2136 to[counter] = NULL;
2137 return counter;
2138 }
2139
splitw(char * str,char *** to)2140 int splitw (char *str, char ***to)
2141 {
2142 int numwords = count_words(str, DWORD_YES, "\"");
2143 int counter;
2144
2145 if (numwords)
2146 {
2147 *to = (char **)new_malloc(sizeof(char *) * numwords);
2148 for (counter = 0; counter < numwords; counter++)
2149 (*to)[counter] = safe_new_next_arg(str, &str);
2150 }
2151 else
2152 *to = NULL;
2153
2154 return numwords;
2155 }
2156
unsplitw(char *** container,int howmany)2157 char * unsplitw (char ***container, int howmany)
2158 {
2159 char *retval = NULL;
2160 char **str = *container;
2161 size_t clue = 0;
2162
2163 if (!str || !*str)
2164 return NULL;
2165
2166 while (howmany)
2167 {
2168 if (*str && **str)
2169 malloc_strcat_word_c(&retval, space, *str, &clue);
2170 str++, howmany--;
2171 }
2172
2173 new_free((char **)container);
2174 return retval;
2175 }
2176
2177 double strtod(); /* sunos must die. */
check_val(const char * sub)2178 int check_val (const char *sub)
2179 {
2180 double sval;
2181 char *endptr;
2182
2183 if (!*sub)
2184 return 0;
2185
2186 /* get the numeric value (if any). */
2187 errno = 0;
2188 sval = strtod(sub, &endptr);
2189
2190 /* Numbers that cause exceptional conditions in strtod() are true */
2191 if (errno == ERANGE
2192 #if defined(HAVE_FINITE)
2193 || finite(sval) == 0
2194 #elif defined(HAVE_INFINITE)
2195 || isfinite(sval) == 0
2196 #endif
2197 )
2198 return 1;
2199
2200 /*
2201 * - Any string with no leading number
2202 * - Any string containing anything after a leading number
2203 * - Any string wholly containing a non-zero number
2204 * are all true.
2205 */
2206 if (sub == endptr || *endptr || sval != 0.0)
2207 return 1;
2208
2209 /* Basically that leaves empty strings and the number 0 as false. */
2210 return 0;
2211 }
2212
2213 /*
2214 * Appends 'num' copies of 'app' to the end of 'str'.
2215 */
strextend(char * str,char app,int num)2216 char *strextend (char *str, char app, int num)
2217 {
2218 char *ptr = str + strlen(str);
2219
2220 for (;num;num--)
2221 *ptr++ = app;
2222
2223 *ptr = (char) 0;
2224 return str;
2225 }
2226
empty(const char * str)2227 int empty (const char *str)
2228 {
2229 #if 0
2230 while (str && *str && *str == ' ')
2231 str++;
2232 #endif
2233
2234 if (str && *str)
2235 return 0;
2236
2237 return 1;
2238 }
2239
2240
2241 /* makes foo[one][two] look like tmp.one.two -- got it? */
remove_brackets(const char * name,const char * args,int * arg_flag)2242 char * remove_brackets (const char *name, const char *args, int *arg_flag)
2243 {
2244 char *ptr,
2245 *right,
2246 *result1,
2247 *rptr,
2248 *retval = NULL;
2249 ssize_t span;
2250
2251 /* XXXX - ugh. */
2252 rptr = malloc_strdup(name);
2253
2254 while ((ptr = strchr(rptr, '[')))
2255 {
2256 *ptr++ = 0;
2257 right = ptr;
2258 if ((span = MatchingBracket(right, '[', ']')) >= 0)
2259 {
2260 ptr = right + span;
2261 *ptr++ = 0;
2262 }
2263 else
2264 ptr = NULL;
2265
2266 if (args)
2267 result1 = expand_alias(right, args, arg_flag, NULL);
2268 else
2269 result1 = right;
2270
2271 retval = malloc_strdup3(rptr, ".", result1);
2272 if (ptr)
2273 malloc_strcat(&retval, ptr);
2274
2275 if (args)
2276 new_free(&result1);
2277 if (rptr)
2278 new_free(&rptr);
2279 rptr = retval;
2280 }
2281 return upper(rptr);
2282 }
2283
my_atol(const char * str)2284 long my_atol (const char *str)
2285 {
2286 if (str)
2287 return (long) strtol(str, NULL, 0);
2288 else
2289 return 0L;
2290 }
2291
malloc_dupchar(int i)2292 char * malloc_dupchar (int i)
2293 {
2294 char c = (char) i; /* blah */
2295 char * ret = (char *)new_malloc(2);
2296
2297 ret[0] = c;
2298 ret[1] = 0;
2299 return ret;
2300 }
2301
2302 /*
2303 * This checks to see if ``root'' is a proper subname for ``var''.
2304 */
is_root(const char * root,const char * var,int descend)2305 int is_root (const char *root, const char *var, int descend)
2306 {
2307 int rootl, varl;
2308
2309 /* ``root'' must end in a dot */
2310 rootl = strlen(root);
2311 if (rootl == 0)
2312 return 0;
2313 if (root[rootl - 1] != '.')
2314 return 0;
2315
2316 /* ``root'' must be shorter than ``var'' */
2317 varl = strlen(var);
2318 if (varl <= rootl)
2319 return 0;
2320
2321 /* ``var'' must contain ``root'' as a leading subset */
2322 if (my_strnicmp(root, var, rootl))
2323 return 0;
2324
2325 /*
2326 * ``var'' must not contain any additional dots
2327 * if we are checking for the current level only
2328 */
2329 if (!descend && strchr(var + rootl, '.'))
2330 return 0;
2331
2332 /* Looks like its ok */
2333 return 1;
2334 }
2335
2336
2337 /* Returns the number of characters they are equal at. */
streq(const char * str1,const char * str2)2338 size_t streq (const char *str1, const char *str2)
2339 {
2340 size_t cnt = 0;
2341
2342 while (*str1 && *str2 && *str1 == *str2)
2343 cnt++, str1++, str2++;
2344
2345 return cnt;
2346 }
2347
malloc_strndup(const char * str,size_t len)2348 char * malloc_strndup (const char *str, size_t len)
2349 {
2350 char *retval = (char *)new_malloc(len + 1);
2351 strlcpy(retval, str, len + 1);
2352 return retval;
2353 }
2354
prntdump(const char * ptr,size_t size)2355 char * prntdump(const char *ptr, size_t size)
2356 {
2357 size_t i;
2358 static char dump[65];
2359
2360 strlcat(dump, ptr, sizeof dump);
2361
2362 for (i = 0; i < size && i < 64; i++)
2363 {
2364 if (!isgraph(dump[i]) && !isspace(dump[i]))
2365 dump[i] = '.';
2366 }
2367 if (i == 64)
2368 dump[63] = '>';
2369 dump[i] = 0;
2370 return dump;
2371 }
2372
2373 /* XXXX this doesnt belong here. im not sure where it goes, though. */
get_userhost(void)2374 char * get_userhost (void)
2375 {
2376 strlcpy(userhost, username, sizeof userhost);
2377 strlcat(userhost, "@", sizeof userhost);
2378 strlcat(userhost, hostname, sizeof userhost);
2379 return userhost;
2380 }
2381
2382
time_to_next_interval(int interval)2383 double time_to_next_interval (int interval)
2384 {
2385 Timeval right_now, then;
2386
2387 get_time(&right_now);
2388
2389 then.tv_usec = 1000000 - right_now.tv_usec;
2390 if (interval == 1)
2391 then.tv_sec = 0;
2392 else
2393 then.tv_sec = interval - (right_now.tv_sec + 1) % interval;
2394 return (double)then.tv_sec + (double)then.tv_usec / 1000000;
2395 }
2396
2397
2398 /* Fancy attempt to compensate for broken time_t's */
time_to_next_minute(void)2399 double time_to_next_minute (void)
2400 {
2401 static int which = 0;
2402 Timeval right_now, then;
2403
2404 get_time(&right_now);
2405
2406 /*
2407 * The first time called, try to determine if the system clock
2408 * is an exact multiple of 60 at the top of every minute. If it
2409 * is, then we will use the "60 trick" to optimize calculations.
2410 * If it is not, then we will do it the hard time every time.
2411 */
2412 if (which == 0)
2413 {
2414 time_t blargh;
2415 struct tm *now_tm;
2416
2417 blargh = right_now.tv_sec;
2418 now_tm = gmtime(&blargh);
2419
2420 if (!which)
2421 {
2422 if (now_tm->tm_sec == right_now.tv_sec % 60)
2423 which = 1;
2424 else
2425 which = 2;
2426 }
2427 }
2428
2429 then.tv_usec = 1000000 - right_now.tv_usec;
2430 if (which == 1)
2431 then.tv_sec = 60 - (right_now.tv_sec + 1) % 60;
2432 else /* which == 2 */
2433 {
2434 time_t blargh;
2435 struct tm *now_tm;
2436
2437 blargh = right_now.tv_sec;
2438 now_tm = gmtime(&blargh);
2439
2440 then.tv_sec = 60 - (now_tm->tm_sec + 1) % 60;
2441 }
2442
2443 return (double)then.tv_sec + (double)then.tv_usec / 1000000;
2444 }
2445
2446 /*
2447 * An strcpy that is guaranteed to be safe for overlaps.
2448 * Warning: This may _only_ be called when one and two overlap!
2449 */
ov_strcpy(char * str1,const char * str2)2450 char * ov_strcpy (char *str1, const char *str2)
2451 {
2452 if (str2 > str1)
2453 {
2454 while (str2 && *str2)
2455 *str1++ = *str2++;
2456 *str1 = 0;
2457 }
2458 return str1;
2459 }
2460
2461
2462 /*
2463 * Its like strcspn, except the second arg is NOT a string.
2464 */
ccspan(const char * string,int s)2465 size_t ccspan (const char *string, int s)
2466 {
2467 size_t count = 0;
2468 char c = (char) s;
2469
2470 while (string && *string && *string != c)
2471 string++, count++;
2472
2473 return count;
2474 }
2475
2476
last_char(const char * string)2477 int last_char (const char *string)
2478 {
2479 while (string && string[0] && string[1])
2480 string++;
2481
2482 return (int)*string;
2483 }
2484
charcount(const char * string,char what)2485 int charcount (const char *string, char what)
2486 {
2487 int x = 0;
2488 const char *place = string;
2489
2490 while (*place)
2491 if (*place++ == what)
2492 x++;
2493
2494 return x;
2495 }
2496
2497 /* Dest should be big enough to hold "src" */
strip_control(const char * src,char * dest)2498 void strip_control (const char *src, char *dest)
2499 {
2500 for (; *src; src++)
2501 if (isgraph(*src) || isspace(*src))
2502 *dest++ = *src;
2503
2504 *dest = 0; /* useless ++ removed - pegasus */
2505 }
2506
strfill(char c,int num)2507 const char * strfill (char c, int num)
2508 {
2509 static char buffer[BIG_BUFFER_SIZE / 4 + 1];
2510 int i;
2511
2512 if (num > BIG_BUFFER_SIZE / 4)
2513 num = BIG_BUFFER_SIZE / 4;
2514
2515 for (i = 0; i < num; i++)
2516 buffer[i] = c;
2517 buffer[i] = 0;
2518 return buffer;
2519 }
2520
2521
encode(const char * str,size_t len)2522 char * encode (const char *str, size_t len)
2523 {
2524 char *retval;
2525 char *ptr;
2526
2527 if ((int)len < 0)
2528 len = strlen(str);
2529
2530 ptr = retval = new_malloc(len * 2 + 1);
2531 while (len)
2532 {
2533 *ptr++ = ((unsigned char)*str >> 4) + 0x41;
2534 *ptr++ = ((unsigned char)*str & 0x0f) + 0x41;
2535 str++;
2536 len--;
2537 }
2538 *ptr = 0;
2539 return retval;
2540 }
2541
decode(const char * str)2542 char * decode (const char *str)
2543 {
2544 char *retval;
2545 char *ptr;
2546 int len = strlen(str);
2547
2548 ptr = retval = new_malloc(len / 2 + 1);
2549 while (len >= 2)
2550 {
2551 *ptr++ = ((str[0] - 0x41) << 4) | (str[1] - 0x41);
2552 str += 2;
2553 len -= 2;
2554 }
2555 *ptr = 0;
2556 return retval;
2557 }
2558
chomp(char * s)2559 char * chomp (char *s)
2560 {
2561 char *e = s + strlen(s);
2562
2563 if (e == s)
2564 return s;
2565
2566 while (*--e == '\n')
2567 {
2568 *e = 0;
2569 if (e == s)
2570 break;
2571 }
2572
2573 return s;
2574 }
2575
2576 /*
2577 * figure_out_address -- lets try this one more time.
2578 */
figure_out_address(const char * nuh,char ** nick,char ** user,char ** host)2579 int figure_out_address (const char *nuh, char **nick, char **user, char **host)
2580 {
2581 static char *mystuff = NULL;
2582 char *bang,
2583 *at,
2584 *adot = NULL;
2585
2586 /* Dont bother with channels, theyre ok. */
2587 if (*nuh == '#' || *nuh == '&')
2588 return -1;
2589
2590 malloc_strcpy(&mystuff, nuh);
2591
2592 *host = star;
2593
2594
2595 /*
2596 * Find and identify each of the three context clues
2597 * (A bang, an at, and a dot).
2598 */
2599 if ((bang = strchr(mystuff, '!')))
2600 {
2601 *bang = 0;
2602 if ((at = strchr(bang + 1, '@')))
2603 {
2604 *at = 0;
2605 adot = strchr(at + 1, '.');
2606 }
2607 }
2608 else if ((at = strchr(mystuff, '@')))
2609 {
2610 *at = 0;
2611 adot = strchr(at + 1, '.');
2612 }
2613 else
2614 adot = strchr(mystuff, '.');
2615
2616 /*
2617 * Hrm. How many cases are there? There are three context clues
2618 * (A bang, an at, and a dot.) So that makes 8 different cases.
2619 * Let us enumerate them:
2620 *
2621 * nick (no !, no @, no .)
2622 * nick!user (a !, no @, no .)
2623 * nick!user@host (a !, a @, no .)
2624 * nick!user@host.domain (a !, a @, a .)
2625 * nick!host.domain (a !, no @, a .)
2626 * user@host (no !, a @, no .)
2627 * user@host.domain (no !, a @, a .)
2628 * host.domain (no !, no @, yes .)
2629 */
2630
2631 /*
2632 * STAGE ONE -- EXTRACT THE NICK, USER, AND HOST PORTIONS.
2633 *
2634 * stage two is now in 'figure_out_domain', so functions which want it
2635 * that way can have it that way.
2636 */
2637
2638 /*
2639 * Now let us handle each of these eight cases in a reasonable way.
2640 */
2641 if (bang)
2642 {
2643 if (at)
2644 {
2645 /* nick!user@host */
2646 *nick = mystuff;
2647 *user = bang + 1;
2648 *host = at + 1;
2649 }
2650 else
2651 {
2652 if (adot) /* nick!host.domain */
2653 {
2654 *nick = mystuff;
2655 *user = star;
2656 *host = at + 1;
2657 }
2658 else /* nick!user */
2659 {
2660 *nick = mystuff;
2661 *user = star;
2662 *host = star;
2663 }
2664 }
2665 }
2666 else
2667 {
2668 if (at)
2669 {
2670 /* user@host.domain */
2671 *nick = star;
2672 *user = mystuff;
2673 *host = at + 1;
2674 }
2675 else
2676 {
2677 if (adot) /* host.domain */
2678 {
2679 *nick = star;
2680 *user = star;
2681 *host = mystuff;
2682 }
2683 else /* nick */
2684 {
2685 *nick = mystuff;
2686 *user = star;
2687 *host = star;
2688 }
2689 }
2690 }
2691
2692 return 0;
2693 }
2694
2695
figure_out_domain(char * fqdn,char ** host,char ** domain,int * ip)2696 int figure_out_domain (char *fqdn, char **host, char **domain, int *ip)
2697 {
2698 char *firstback,
2699 *secondback,
2700 *thirdback,
2701 *fourthback;
2702 char *endstring;
2703 char *adot;
2704 int number;
2705
2706 /* determine if we have an IP, use dot to hold this */
2707 /* is_number is better than my_atol since floating point
2708 * base 36 numbers are pretty much invalid as IPs.
2709 */
2710 if ((adot = strrchr(fqdn, '.')) && is_number(adot + 1))
2711 *ip = 1;
2712 else
2713 *ip = 0;
2714
2715 /*
2716 * STAGE TWO -- EXTRACT THE HOST AND DOMAIN FROM FQDN
2717 */
2718
2719 /*
2720 * At this point, 'fqdn' points what what we think the hostname
2721 * is. We chop it up into discrete parts and see what we end up with.
2722 */
2723 endstring = fqdn + strlen(fqdn);
2724 firstback = strnrchr(fqdn, '.', 1);
2725 secondback = strnrchr(fqdn, '.', 2);
2726 thirdback = strnrchr(fqdn, '.', 3);
2727 fourthback = strnrchr(fqdn, '.', 4);
2728
2729 /* Track foo@bar or some such thing. */
2730 if (!firstback)
2731 {
2732 *host = fqdn;
2733 return 0;
2734 }
2735
2736 /*
2737 * IP address (A.B.C.D)
2738 */
2739 if (my_atol(firstback + 1))
2740 {
2741 *domain = fqdn;
2742
2743 number = my_atol(fqdn);
2744 if (number < 128)
2745 *host = thirdback;
2746 else if (number < 192)
2747 *host = secondback;
2748 else
2749 *host = firstback;
2750
2751 if (!*host)
2752 return -1; /* Invalid hostname */
2753
2754 **host = 0;
2755 (*host)++;
2756 }
2757 /*
2758 * (*).(*.???)
2759 * Handles *.com, *.net, *.edu, etc
2760 */
2761 else if (secondback && (endstring - firstback == 4))
2762 {
2763 *host = fqdn;
2764 *domain = secondback;
2765 **domain = 0;
2766 (*domain)++;
2767 }
2768 /*
2769 * (*).(*.k12.??.us)
2770 * Handles host.school.k12.state.us
2771 */
2772 else if (fourthback &&
2773 (firstback - secondback == 3) &&
2774 !strncmp(thirdback, ".k12.", 5) &&
2775 !strncmp(firstback, ".us", 3))
2776 {
2777 *host = fqdn;
2778 *domain = fourthback;
2779 **domain = 0;
2780 (*domain)++;
2781 }
2782 /*
2783 * ()(*.k12.??.us)
2784 * Handles school.k12.state.us
2785 */
2786 else if (thirdback && !fourthback &&
2787 (firstback - secondback == 3) &&
2788 !strncmp(thirdback, ".k12.", 5) &&
2789 !strncmp(firstback, ".us", 3))
2790 {
2791 *host = empty_string;
2792 *domain = fqdn;
2793 }
2794 /*
2795 * (*).(*.???.??)
2796 * Handles host.domain.com.au
2797 */
2798 else if (thirdback &&
2799 (endstring - firstback == 3) &&
2800 (firstback - secondback == 4))
2801 {
2802 *host = fqdn;
2803 *domain = thirdback;
2804 **domain = 0;
2805 (*domain)++;
2806 }
2807 /*
2808 * ()(*.???.??)
2809 * Handles domain.com.au
2810 */
2811 else if (secondback && !thirdback &&
2812 (endstring - firstback == 3) &&
2813 (firstback - secondback == 4))
2814 {
2815 *host = empty_string;
2816 *domain = fqdn;
2817 }
2818 /*
2819 * (*).(*.??.??)
2820 * Handles host.domain.co.uk
2821 */
2822 else if (thirdback &&
2823 (endstring - firstback == 3) &&
2824 (firstback - secondback == 3))
2825 {
2826 *host = fqdn;
2827 *domain = thirdback;
2828 **domain = 0;
2829 (*domain)++;
2830 }
2831 /*
2832 * ()(*.??.??)
2833 * Handles domain.co.uk
2834 */
2835 else if (secondback && !thirdback &&
2836 (endstring - firstback == 3) &&
2837 (firstback - secondback == 3))
2838 {
2839 *host = empty_string;
2840 *domain = fqdn;
2841 }
2842 /*
2843 * (*).(*.??)
2844 * Handles domain.de
2845 */
2846 else if (secondback && (endstring - firstback == 3))
2847 {
2848 *host = fqdn;
2849 *domain = secondback;
2850 **domain = 0;
2851 (*domain)++;
2852 }
2853 /*
2854 * Everything else...
2855 */
2856 else
2857 {
2858 *host = empty_string;
2859 *domain = fqdn;
2860 }
2861
2862 return 0;
2863 }
2864
count_char(const unsigned char * src,const unsigned char look)2865 int count_char (const unsigned char *src, const unsigned char look)
2866 {
2867 const unsigned char *t;
2868 int cnt = 0;
2869
2870 while ((t = strchr(src, look)))
2871 cnt++, src = t + 1;
2872
2873 return cnt;
2874 }
2875
strnrchr(char * start,char which,int howmany)2876 char * strnrchr(char *start, char which, int howmany)
2877 {
2878 char *ends = start + strlen(start);
2879
2880 while (ends > start && howmany)
2881 {
2882 if (*--ends == which)
2883 howmany--;
2884 }
2885 if (ends == start)
2886 return NULL;
2887 else
2888 return ends;
2889 }
2890
2891 /*
2892 * This replaces some number of numbers (1 or more) with a single asterisk.
2893 */
mask_digits(char ** host)2894 void mask_digits (char **host)
2895 {
2896 char *src_ptr;
2897 char *retval, *retval_ptr;
2898 size_t size;
2899
2900 size = strlen(*host) + 1;
2901 retval = retval_ptr = alloca(size);
2902 src_ptr = *host;
2903
2904 while (*src_ptr)
2905 {
2906 if (isdigit(*src_ptr))
2907 {
2908 while (*src_ptr && isdigit(*src_ptr))
2909 src_ptr++;
2910
2911 *retval_ptr++ = '*';
2912 }
2913 else
2914 *retval_ptr++ = *src_ptr++;
2915 }
2916
2917 *retval_ptr = 0;
2918 strlcpy(*host, retval, size);
2919 }
2920
strlpcat(char * source,size_t size,const char * format,...)2921 char * strlpcat (char *source, size_t size, const char *format, ...)
2922 {
2923 va_list args;
2924 char buffer[BIG_BUFFER_SIZE + 1];
2925
2926 va_start(args, format);
2927 vsnprintf(buffer, sizeof buffer, format, args);
2928 va_end(args);
2929
2930 strlcat(source, buffer, size);
2931 return source;
2932 }
2933
2934
strcpy_nocolorcodes(u_char * dest,const u_char * source)2935 u_char *strcpy_nocolorcodes (u_char *dest, const u_char *source)
2936 {
2937 u_char *save = dest;
2938 ssize_t span;
2939
2940 do
2941 {
2942 while (*source == 3)
2943 {
2944 span = skip_ctl_c_seq(source, NULL, NULL);
2945 source += span;
2946 }
2947 *dest++ = *source;
2948 }
2949 while (*source++);
2950
2951 return save;
2952 }
2953
2954 /*
2955 * This mangles up 'incoming' corresponding to the current values of
2956 * /set mangle_inbound or /set mangle_outbound.
2957 * 'incoming' needs to be at least _ELEVEN_ as big as neccesary
2958 * (ie, sizeof(incoming) >= strlen(incoming) * 11 + 1)
2959 */
mangle_line(char * incoming,int how,size_t how_much)2960 size_t mangle_line (char *incoming, int how, size_t how_much)
2961 {
2962 int stuff;
2963 char *buffer;
2964 size_t i;
2965 char *s;
2966
2967 if (how_much == 0)
2968 panic("mangle_line passed a zero-size buffer [%s] [%d]", incoming, how);
2969
2970 stuff = how;
2971 buffer = alloca(how_much + 1); /* Absurdly large */
2972
2973 #if notyet
2974 if (stuff & STRIP_CTCP2)
2975 {
2976 char *output;
2977
2978 output = strip_ctcp2(incoming);
2979 strlcpy(incoming, output, how_much);
2980 new_free(&output);
2981 }
2982 else if (stuff & MANGLE_INBOUND_CTCP2)
2983 {
2984 char *output;
2985
2986 output = ctcp2_to_ircII(incoming);
2987 strlcpy(incoming, output, how_much);
2988 new_free(&output);
2989 }
2990 else if (stuff & MANGLE_OUTBOUND_CTCP2)
2991 {
2992 char *output;
2993
2994 output = ircII_to_ctcp2(incoming);
2995 strlcpy(incoming, output, how_much);
2996 new_free(&output);
2997 }
2998 #endif
2999
3000 if (stuff & MANGLE_ESCAPES)
3001 {
3002 for (i = 0; incoming[i]; i++)
3003 {
3004 if (incoming[i] == 0x1b)
3005 incoming[i] = 0x5b;
3006 }
3007 }
3008
3009 if (stuff & MANGLE_ANSI_CODES)
3010 {
3011 /* normalize_string can expand up to three times */
3012 char *output;
3013
3014 normalize_never_xlate = 1; /* XXXXX */
3015 output = normalize_string(incoming, 1); /* Should be ok */
3016 normalize_never_xlate = 0; /* XXXXX */
3017 if (strlcpy(incoming, output, how_much) > how_much)
3018 say("Mangle_line truncating results. #1 -- "
3019 "Email jnelson@acronet.net [%d] [%d]",
3020 strlen(output), how_much);
3021 new_free(&output);
3022
3023 /*
3024 * Turn off ALL_OFF if ANSI is used, unless all of the
3025 * "ATTRIBUTES" are being stripped.
3026 */
3027 #define ATTRIBUTES (STRIP_COLOR | STRIP_REVERSE | STRIP_UNDERLINE | \
3028 STRIP_BOLD | STRIP_BLINK | STRIP_ALT_CHAR)
3029 if (stuff & STRIP_ALL_OFF)
3030 {
3031 if ((stuff & ATTRIBUTES) != ATTRIBUTES)
3032 stuff &= ~(STRIP_ALL_OFF);
3033 }
3034 }
3035
3036 /*
3037 * Now we mangle the individual codes
3038 */
3039 for (i = 0, s = incoming; *s; s++)
3040 {
3041 /* If buffer[i] is past the end, then stop right here! */
3042 if (i >= how_much)
3043 break;
3044
3045 switch (*s)
3046 {
3047 case 003: /* color codes */
3048 {
3049 int lhs = 0,
3050 rhs = 0;
3051 char * end;
3052 ssize_t span;
3053
3054 span = skip_ctl_c_seq(s, &lhs, &rhs);
3055 end = s + span;
3056 if (!(stuff & STRIP_COLOR))
3057 {
3058 /*
3059 * Copy the string one byte at a time
3060 * but only as much as we have space for.
3061 */
3062 while (s < end && i < how_much)
3063 buffer[i++] = *s++;
3064 }
3065 s = end - 1;
3066 break;
3067 }
3068 case REV_TOG: /* Reverse */
3069 {
3070 if (!(stuff & STRIP_REVERSE))
3071 buffer[i++] = REV_TOG;
3072 break;
3073 }
3074 case UND_TOG: /* Underline */
3075 {
3076 if (!(stuff & STRIP_UNDERLINE))
3077 buffer[i++] = UND_TOG;
3078 break;
3079 }
3080 case BOLD_TOG: /* Bold */
3081 {
3082 if (!(stuff & STRIP_BOLD))
3083 buffer[i++] = BOLD_TOG;
3084 break;
3085 }
3086 case BLINK_TOG: /* Flashing */
3087 {
3088 if (!(stuff & STRIP_BLINK))
3089 buffer[i++] = BLINK_TOG;
3090 break;
3091 }
3092 case ROM_CHAR: /* Special rom-chars */
3093 {
3094 if (!(stuff & STRIP_ROM_CHAR))
3095 buffer[i++] = ROM_CHAR;
3096 break;
3097 }
3098 case ND_SPACE: /* Nondestructive spaces */
3099 {
3100 if (!(stuff & STRIP_ND_SPACE))
3101 buffer[i++] = ND_SPACE;
3102 break;
3103 }
3104 case ALT_TOG: /* Alternate character set */
3105 {
3106 if (!(stuff & STRIP_ALT_CHAR))
3107 buffer[i++] = ALT_TOG;
3108 break;
3109 }
3110 case ALL_OFF: /* ALL OFF attribute */
3111 {
3112 if (!(stuff & STRIP_ALL_OFF))
3113 buffer[i++] = ALL_OFF;
3114 break;
3115 }
3116 default: /* Everything else */
3117 if (!(stuff & STRIP_OTHER))
3118 buffer[i++] = *s;
3119 }
3120 }
3121
3122 /* If buffer[i] is off the end of the string, bring it back in. */
3123 if (i >= how_much)
3124 i = how_much - 1;
3125
3126 /* Terminate the mangled copy, and return to sender. */
3127 buffer[i] = 0;
3128 return strlcpy(incoming, buffer, how_much);
3129 }
3130
3131 /* RANDOM NUMBERS */
3132 /*
3133 * Random number generator #1 -- psuedo-random sequence
3134 * If you do not have /dev/random and do not want to use gettimeofday(), then
3135 * you can use the psuedo-random number generator. Its performance varies
3136 * from weak to moderate. It is a predictable mathematical sequence that
3137 * varies depending on the seed, and it provides very little repetition,
3138 * but with 4 or 5 samples, it should be trivial for an outside person to
3139 * find the next numbers in your sequence.
3140 *
3141 * If 'l' is not zero, then it is considered a "seed" value. You want
3142 * to call it once to set the seed. Subsequent calls should use 'l'
3143 * as 0, and it will return a value.
3144 */
randm(unsigned long l)3145 static unsigned long randm (unsigned long l)
3146 {
3147 /* patch from Sarayan to make $rand() better */
3148 static const long RAND_A = 16807L;
3149 static const long RAND_M = 2147483647L;
3150 static const long RAND_Q = 127773L;
3151 static const long RAND_R = 2836L;
3152 static unsigned long z = 0;
3153 long t;
3154
3155 if (z == 0)
3156 z = (unsigned long) getuid();
3157
3158 if (l == 0)
3159 {
3160 t = RAND_A * (z % RAND_Q) - RAND_R * (z / RAND_Q);
3161 if (t > 0)
3162 z = t;
3163 else
3164 z = t + RAND_M;
3165 return (z >> 8) | ((z & 255) << 23);
3166 }
3167 else
3168 {
3169 if ((long) l < 0)
3170 z = (unsigned long) getuid();
3171 else
3172 z = l;
3173 return 0;
3174 }
3175 }
3176
3177 /*
3178 * Random number generator #2 -- gettimeofday().
3179 * If you have gettimeofday(), then we could use it. Its performance varies
3180 * from weak to moderate. At best, it is a source of modest entropy, with
3181 * distinct linear qualities. At worst, it is a linear sequence. If you do
3182 * not have gettimeofday(), then it uses randm() instead.
3183 */
randt_2(void)3184 static unsigned long randt_2 (void)
3185 {
3186 Timeval tp1;
3187
3188 get_time(&tp1);
3189 return (unsigned long) tp1.tv_usec;
3190 }
3191
randt(unsigned long l)3192 static unsigned long randt (unsigned long l)
3193 {
3194 #ifdef HAVE_GETTIMEOFDAY
3195 unsigned long t1, t2, t;
3196
3197 if (l != 0)
3198 return 0;
3199
3200 t1 = randt_2();
3201 t2 = randt_2();
3202 t = (t1 & 65535) * 65536 + (t2 & 65535);
3203 return t;
3204 #else
3205 return randm(l);
3206 #endif
3207 }
3208
3209
3210 /*
3211 * Random number generator #3 -- /dev/urandom.
3212 * If you have the /dev/urandom device, then we will use it. Its performance
3213 * varies from moderate to very strong. At best, it is a source of pretty
3214 * substantial unpredictable numbers. At worst, it is mathematical psuedo-
3215 * random sequence (which randm() is).
3216 */
randd(unsigned long l)3217 static unsigned long randd (unsigned long l)
3218 {
3219 unsigned long value;
3220 static int random_fd = -1;
3221
3222 if (l != 0)
3223 return 0; /* No seeding appropriate */
3224
3225 if (random_fd == -2)
3226 return randm(l);
3227
3228 else if (random_fd == -1)
3229 {
3230 if ((random_fd = open("/dev/urandom", O_RDONLY)) == -1)
3231 {
3232 random_fd = -2;
3233 return randm(l); /* Fall back to randm */
3234 }
3235 }
3236
3237 read(random_fd, (void *)&value, sizeof(value));
3238 return value;
3239 }
3240
3241 /*
3242 * Random number generator #4 -- Arc4random.
3243 * If you have the /dev/urandom device, this this may very well be the best
3244 * random number generator for you. It spits out relatively good entropic
3245 * numbers, while not severely depleting the entropy pool (as reading directly
3246 * from /dev/random does). If you do not have the /dev/urandom device, then
3247 * this function uses the stack for its entropy, which may or may not be
3248 * suitable, but what the heck. This generator is always available.
3249 */
randa(unsigned long l)3250 static unsigned long randa (unsigned long l)
3251 {
3252 if (l != 0)
3253 return 0; /* No seeding appropriate */
3254
3255 return (unsigned long)bsd_arc4random();
3256 }
3257
random_number(unsigned long l)3258 unsigned long random_number (unsigned long l)
3259 {
3260 switch (get_int_var(RANDOM_SOURCE_VAR))
3261 {
3262 case 0:
3263 return randd(l);
3264 case 1:
3265 return randm(l);
3266 case 2:
3267 return randt(l);
3268 case 3:
3269 default:
3270 return randa(l);
3271 }
3272 }
3273
3274 /*
3275 * urlencode: converts non-alphanumeric characters to hexidecimal codes
3276 * Contributed by SrFrog
3277 */
urlencode(const char * s)3278 char * urlencode (const char *s)
3279 {
3280 static const char unsafe[] = "`'!@#$%^&*(){}<>~|\\\";? ,/";
3281 static const char hexnum[] = "0123456789ABCDEF";
3282 const char *p1;
3283 char * p2;
3284 size_t len;
3285 char * retval;
3286
3287 if (!s || !*s)
3288 return NULL;
3289
3290 len = strlen(s);
3291 retval = new_malloc(len * 3 + 1);
3292
3293 for (p1 = s, p2 = retval; *p1; p1++)
3294 {
3295 if (*p1 <= 0x20 || strchr(unsafe, *p1))
3296 {
3297 unsigned c = (unsigned)(unsigned char)*p1;
3298
3299 *p2++ = '%';
3300 *p2++ = hexnum[c >> 4];
3301 *p2++ = hexnum[c & 0x0f];
3302 }
3303 else
3304 *p2++ = *p1;
3305 }
3306 *p2 = 0;
3307
3308 return retval;
3309 }
3310
3311 #define XTOI(x) \
3312 ( \
3313 ((x) >= '0' && (x) <= '9') \
3314 ? ((x) - '0') \
3315 : ( ((x) >= 'A' && (x) <= 'F') \
3316 ? (((x) - 'A') + 10) \
3317 : ( ((x) >= 'a' && (x) <= 'f') \
3318 ? (((x) - 'a') + 10) \
3319 : -1 \
3320 ) \
3321 ) \
3322 )
3323
urldecode(char * s,size_t * length)3324 char * urldecode (char *s, size_t *length)
3325 {
3326 const char *p1;
3327 char * p2;
3328 size_t len;
3329 char * retval;
3330 int val1;
3331 int val2;
3332
3333 if (!s || !*s)
3334 return NULL;
3335
3336 len = length ? *length : strlen(s);
3337 retval = alloca(len + 1);
3338
3339 for (p1 = s, p2 = retval; len--; p1++, p2++)
3340 {
3341 if (*p1 == '%' && len >= 2 &&
3342 (((val1 = XTOI(p1[1])) != -1) &&
3343 ((val2 = XTOI(p1[2])) != -1)))
3344 {
3345 p1++, p1++;
3346 len--, len--;
3347 *p2 = (val1 << 4) | val2;
3348 }
3349 else
3350 *p2 = *p1;
3351 }
3352
3353 *p2 = 0;
3354 if (length)
3355 *length = p2 - retval;
3356 return memcpy(s, retval, p2 - retval + 1);
3357 }
3358
3359 /*
3360 * quote_it: This quotes the given string making it sendable via irc. A
3361 * pointer to the length of the data is required and the data need not be
3362 * null terminated (it can contain nulls). Returned is a malloced, null
3363 * terminated string.
3364 */
enquote_it(char * str,size_t len)3365 char *enquote_it (char *str, size_t len)
3366 {
3367 char *buffer = new_malloc(len + 5);
3368 char *ptr = buffer;
3369 size_t i;
3370 int size = len;
3371
3372 for (i = 0; i < len; i++)
3373 {
3374 if (ptr-buffer >= size)
3375 {
3376 int j = ptr-buffer;
3377 size += 256;
3378 RESIZE(buffer, char, size + 5);
3379 ptr = buffer + j;
3380 }
3381
3382 switch (str[i])
3383 {
3384 case CTCP_DELIM_CHAR: *ptr++ = CTCP_QUOTE_CHAR;
3385 *ptr++ = 'a';
3386 break;
3387 case '\n': *ptr++ = CTCP_QUOTE_CHAR;
3388 *ptr++ = 'n';
3389 break;
3390 case '\r': *ptr++ = CTCP_QUOTE_CHAR;
3391 *ptr++ = 'r';
3392 break;
3393 case CTCP_QUOTE_CHAR: *ptr++ = CTCP_QUOTE_CHAR;
3394 *ptr++ = CTCP_QUOTE_CHAR;
3395 break;
3396 case '\0': *ptr++ = CTCP_QUOTE_CHAR;
3397 *ptr++ = '0';
3398 break;
3399 default: *ptr++ = str[i];
3400 break;
3401 }
3402 }
3403 *ptr = '\0';
3404 return buffer;
3405 }
3406
3407 /*
3408 * ctcp_unquote_it: This takes a null terminated string that had previously
3409 * been quoted using ctcp_quote_it and unquotes it. Returned is a malloced
3410 * space pointing to the unquoted string. NOTE: a trailing null is added for
3411 * convenied, but the returned data may contain nulls!. The len is modified
3412 * to contain the size of the data returned.
3413 */
dequote_it(char * str,size_t * len)3414 char *dequote_it (char *str, size_t *len)
3415 {
3416 char *buffer;
3417 char *ptr;
3418 char c;
3419 size_t i, new_size = 0;
3420
3421 buffer = (char *) new_malloc(sizeof(char) * *len + 1);
3422 ptr = buffer;
3423 i = 0;
3424 while (i < *len)
3425 {
3426 if ((c = str[i++]) == CTCP_QUOTE_CHAR)
3427 {
3428 switch (c = str[i++])
3429 {
3430 case CTCP_QUOTE_CHAR:
3431 *ptr++ = CTCP_QUOTE_CHAR;
3432 break;
3433 case 'a':
3434 *ptr++ = CTCP_DELIM_CHAR;
3435 break;
3436 case 'n':
3437 *ptr++ = '\n';
3438 break;
3439 case 'r':
3440 *ptr++ = '\r';
3441 break;
3442 case '0':
3443 *ptr++ = '\0';
3444 break;
3445 default:
3446 *ptr++ = c;
3447 break;
3448 }
3449 }
3450 else
3451 *ptr++ = c;
3452 new_size++;
3453 }
3454 *ptr = '\0';
3455 *len = new_size;
3456 return (buffer);
3457 }
3458
my_strerror(int err1,int err2)3459 const char * my_strerror (int err1, int err2)
3460 {
3461 static char buffer[1024];
3462
3463 if (err1 == -1)
3464 {
3465 if (err2 < 0)
3466 {
3467 #ifdef HAVE_HSTRERROR
3468 return hstrerror(h_errno);
3469 #else
3470 return "Hostname lookup failure";
3471 #endif
3472 }
3473 else
3474 return strerror(errno);
3475 }
3476 else if (err1 == -2)
3477 return "The operation is not supported for the protocol family";
3478 else if (err1 == -3)
3479 return "The hostname has no address in the protocol family";
3480 else if (err1 == -4)
3481 return "The presentation internet address was invalid";
3482 else if (err1 == -5)
3483 return "The hostname does not resolve";
3484 else if (err1 == -6)
3485 return "There is no virtual host for the protocol family";
3486 else if (err1 == -7)
3487 return "The remote peer to connect to was not provided";
3488 else if (err1 == -8)
3489 return "The local and remote address are in different protocol families.";
3490 else if (err1 == -9)
3491 return "Connection was not successful (may have timed out)";
3492 else if (err1 == -10)
3493 return "Requested local port is not available.";
3494 else if (err1 == -11)
3495 {
3496 snprintf(buffer, 1024, "Connect failed: %s", strerror(err2));
3497 return buffer;
3498 }
3499 else if (err1 == -12)
3500 return "Connection was not successful (may have been reset)";
3501 else if (err1 == -13)
3502 return "The local address to bind to was not provided";
3503 else if (err1 == -14)
3504 return "The protocol family does not make sense";
3505 else
3506 {
3507 snprintf(buffer, 1024, "EPIC Network Error %d", err1);
3508 return buffer;
3509 }
3510 }
3511
3512 /*
3513 * Should I switch over to using getaddrinfo() directly or is using
3514 * inet_strton() sufficient?
3515 */
switch_hostname(const char * new_hostname)3516 char * switch_hostname (const char *new_hostname)
3517 {
3518 char * retval = NULL;
3519 ISA new_4;
3520 char v4_name[1024];
3521 int accept4 = 0;
3522 #ifdef INET6
3523 ISA6 new_6;
3524 #endif
3525 char v6_name[1024];
3526 int accept6 = 0;
3527
3528
3529 if (new_hostname == NULL)
3530 {
3531 new_free(&LocalIPv4Addr);
3532 #ifdef INET6
3533 new_free(&LocalIPv6Addr);
3534 #endif
3535
3536 if (LocalHostName)
3537 malloc_sprintf(&retval, "Virtual Hostname [%s] will no longer be used", LocalHostName);
3538 else
3539 malloc_sprintf(&retval, "Virtual Hostname support is not activated");
3540
3541 new_free(&LocalHostName);
3542 return retval;
3543 }
3544
3545 strlcpy(v4_name, "<none>", sizeof v4_name);
3546 new_4.sin_family = AF_INET;
3547 if (!inet_strton(new_hostname, zero, (SA *)&new_4, 0)) {
3548 inet_ntostr((SA *)&new_4, v4_name, 1024, NULL, 0, NI_NUMERICHOST);
3549 accept4 = 1;
3550 }
3551
3552 strlcpy(v6_name, "<none>", sizeof v6_name);
3553 #ifdef INET6
3554 new_6.sin6_family = AF_INET6;
3555 if (!inet_strton(new_hostname, zero, (SA *)&new_6, 0)) {
3556 inet_ntostr((SA *)&new_6, v6_name, 1024, NULL, 0, NI_NUMERICHOST);
3557 accept6 = 1;
3558 }
3559 #endif
3560
3561 if (accept4 || accept6)
3562 {
3563 new_free(&LocalIPv4Addr);
3564 #ifdef INET6
3565 new_free(&LocalIPv6Addr);
3566 #endif
3567
3568 if (accept4)
3569 {
3570 LocalIPv4Addr = (ISA *)new_malloc(sizeof(*LocalIPv4Addr));
3571 *LocalIPv4Addr = new_4;
3572 }
3573
3574 #ifdef INET6
3575 if (accept6)
3576 {
3577 LocalIPv6Addr = (ISA6 *)new_malloc(sizeof(*LocalIPv6Addr));
3578 *LocalIPv6Addr = new_6;
3579 }
3580 #endif
3581
3582 malloc_strcpy(&LocalHostName, new_hostname);
3583
3584 malloc_sprintf(&retval, "Local address changed to [%s] (%s) (%s)",
3585 LocalHostName, v4_name, v6_name);
3586 }
3587 else
3588 malloc_sprintf(&retval, "I cannot configure [%s] -- local address not changed.", new_hostname);
3589
3590 return retval;
3591 }
3592
3593
strlcpy_c(char * dst,const char * src,size_t size,size_t * cluep)3594 size_t strlcpy_c (char *dst, const char *src, size_t size, size_t *cluep)
3595 {
3596 size_t retval;
3597
3598 retval = strlcpy(dst, src, size);
3599 if (retval > size - 1)
3600 *cluep = size - 1;
3601 else
3602 *cluep = retval;
3603 return retval;
3604 }
3605
strlcat_c(char * dst,const char * src,size_t size,size_t * cluep)3606 size_t strlcat_c (char *dst, const char *src, size_t size, size_t *cluep)
3607 {
3608 size_t retval;
3609 size_t real_size;
3610 char * real_dst;
3611
3612 real_dst = dst + *cluep;
3613 real_size = size - *cluep;
3614
3615 retval = strlcat(real_dst, src, real_size);
3616 if (retval + *cluep > size - 1)
3617 *cluep = size - 1;
3618 else
3619 *cluep = retval + *cluep;
3620 return retval;
3621 }
3622
strlopencat_c(char * dest,size_t maxlen,size_t * cluep,...)3623 char * strlopencat_c (char *dest, size_t maxlen, size_t *cluep, ...)
3624 {
3625 va_list args;
3626 char * this_arg = NULL;
3627 size_t spare_clue;
3628
3629 if (cluep == NULL)
3630 {
3631 spare_clue = strlen(dest);
3632 cluep = &spare_clue;
3633 }
3634
3635 va_start(args, cluep);
3636 for (;;)
3637 {
3638 /* Grab the next string, stop if no more */
3639 if (!(this_arg = va_arg(args, char *)))
3640 break;
3641
3642 /* Add this string to the end, adjusting the clue */
3643 strlcat_c(dest, this_arg, maxlen, cluep);
3644
3645 /* If we reached the end of our space, stop here. */
3646 if (*cluep >= maxlen - 1)
3647 break;
3648 }
3649
3650 va_end(args);
3651 return dest;
3652 }
3653
is_string_empty(const char * str)3654 int is_string_empty (const char *str)
3655 {
3656 while (str && *str && isspace(*str))
3657 str++;
3658
3659 if (str && *str)
3660 return 0;
3661
3662 return 1;
3663 }
3664
3665 /*
3666 * malloc_strcpy_c: Make a copy of a string into heap space, which may
3667 * optionally be provided, with an optional clue.
3668 *
3669 * Arguments:
3670 * 'ptr' - A pointer to a variable pointer that is either:
3671 * 1) The value NULL or a valid heap pointer to space which is not
3672 * large enough to hold 'src', in which case heap space will be
3673 * allocated, and the original value of (*ptr) will be invalidated.
3674 * 2) A valid heap pointer to space which is large enough to hold 'src'
3675 * in which case 'src' will be copied to the heap space.
3676 * 'src' - The string to be copied. If NULL, (*ptr) is invalidated (freed).
3677 *
3678 * Return value:
3679 * If 'src' is NULL, an invalid heap pointer.
3680 * If 'src' is not NULL, a valid heap pointer that contains a copy of 'src'.
3681 * (*ptr) is set to the return value.
3682 * This function will not return (panic) if (*ptr) is not NULL and is
3683 * not a valid heap pointer.
3684 *
3685 * Notes:
3686 * If (*ptr) is not big enough to hold 'src' then the original value (*ptr)
3687 * will be invalidated and must not be used after this function returns.
3688 * You must deallocate the space later by passing (ptr) to the new_free()
3689 * function.
3690 */
malloc_strcpy_c(char ** ptr,const char * src,size_t * clue)3691 char * malloc_strcpy_c (char **ptr, const char *src, size_t *clue)
3692 {
3693 size_t size, size_src;
3694
3695 if (!src)
3696 {
3697 if (clue)
3698 *clue = 0;
3699 return new_free(ptr); /* shrug */
3700 }
3701
3702 if (*ptr)
3703 {
3704 size = alloc_size(*ptr);
3705 if (size == (size_t) FREED_VAL)
3706 panic("free()d pointer passed to malloc_strcpy");
3707
3708 /* No copy neccesary! */
3709 if (*ptr == src)
3710 return *ptr;
3711
3712 size_src = strlen(src);
3713 if (size > size_src)
3714 {
3715 strlcpy(*ptr, src, size);
3716 if (clue)
3717 *clue = size_src;
3718 return *ptr;
3719 }
3720
3721 new_free(ptr);
3722 }
3723
3724 size = strlen(src);
3725 *ptr = new_malloc(size + 1);
3726 strlcpy(*ptr, src, size + 1);
3727 if (clue)
3728 *clue = size;
3729 return *ptr;
3730 }
3731
3732 /*
3733 * malloc_strcat_c: Append a copy of 'src' to the end of '*ptr', with an
3734 * optional "clue" (length of (*ptr))
3735 *
3736 * Arguments:
3737 * 'ptr' - A pointer to a variable pointer that is either:
3738 * 1) The value NULL or a valid heap pointer to space which is not
3739 * large enough to hold 'src', in which case heap space will be
3740 * allocated, and the original value of (*ptr) will be invalidated.
3741 * 2) A valid heap pointer to space which shall contain a valid
3742 * nul-terminated C string.
3743 * 'src' - The string to be copied. If NULL, this function is a no-op.
3744 * 'cluep' - A pointer to an integer holding the string length of (*ptr).
3745 * may be NULL.
3746 *
3747 * Return value:
3748 * If 'src' is NULL, the original value of (*ptr) is returned.
3749 * If 'src' is not NULL, a valid heap pointer that contains the catenation
3750 * of the string originally contained in (*ptr) and 'src'.
3751 * (*ptr) is set to the return value.
3752 * This function will not return (panic) if (*ptr) is not NULL and is
3753 * not a valid heap pointer.
3754 * If 'cluep' is not NULL, it will be set to the string length of the
3755 * new value of (*ptr).
3756 *
3757 * Notes:
3758 * If (*ptr) is not big enough to take on the catenated string, then the
3759 * original value (*ptr) will be invalidated and must not be used after
3760 * this function returns.
3761 * This function needs to determine how long (*ptr) is, and unless you
3762 * provide 'cluep' it will do a strlen(*ptr). If (*ptr) is quite
3763 * large, this could be an expensive operation. The use of a clue
3764 * is an optimization option.
3765 * If you don't want to bother with the 'clue', use the malloc_strcat macro.
3766 * You must deallocate the space later by passing (ptr) to the new_free()
3767 * function.
3768 */
malloc_strcat_c(char ** ptr,const char * src,size_t * cluep)3769 char * malloc_strcat_c (char **ptr, const char *src, size_t *cluep)
3770 {
3771 size_t msize;
3772 size_t psize;
3773 size_t ssize;
3774 size_t clue = cluep ? *cluep : 0;
3775
3776 if (*ptr)
3777 {
3778 if (alloc_size(*ptr) == FREED_VAL)
3779 panic("free()d pointer passed to malloc_strcat");
3780
3781 if (!src)
3782 return *ptr;
3783
3784 psize = clue + strlen(clue + *ptr);
3785 ssize = strlen(src);
3786 msize = psize + ssize + 1;
3787
3788 RESIZE(*ptr, char, msize);
3789 if (cluep)
3790 *cluep = psize + ssize;
3791 strlcat(psize + *ptr, src, msize - psize);
3792 return (*ptr);
3793 }
3794
3795 return (*ptr = malloc_strdup(src));
3796 }
3797
3798 /*
3799 * malloc_strdup: Allocate and return a pointer to valid heap space into
3800 * which a copy of 'str' has been placed.
3801 *
3802 * Arguments:
3803 * 'str' - The string to be copied. If NULL, a zero length string will
3804 * be copied in its place.
3805 *
3806 * Return value:
3807 * If 'str' is not NULL, then a valid heap pointer containing a copy of 'str'.
3808 * If 'str' is NULL, then a valid heap pointer containing a 0-length string.
3809 *
3810 * Notes:
3811 * You must deallocate the space later by passing a pointer to the return
3812 * value to the new_free() function.
3813 */
malloc_strdup(const char * str)3814 char * malloc_strdup (const char *str)
3815 {
3816 char *ptr;
3817 size_t size;
3818
3819 if (!str)
3820 str = empty_string;
3821
3822 size = strlen(str) + 1;
3823 ptr = (char *)new_malloc(size);
3824 strlcpy(ptr, str, size);
3825 return ptr;
3826 }
3827
3828 /*
3829 * malloc_strdup2: Allocate and return a pointer to valid heap space into
3830 * which a catenation of 'str1' and 'str2' have been placed.
3831 *
3832 * Arguments:
3833 * 'str1' - The first string to be copied. If NULL, a zero-length string
3834 * will be used in its place.
3835 * 'str2' - The second string to be copied. If NULL, a zero-length string
3836 * will be used in its place.
3837 *
3838 * Return value:
3839 * A valid heap pointer containing a copy of 'str1' and 'str2' catenated
3840 * together. 'str1' and 'str2' may be substituted as indicated above.
3841 *
3842 * Notes:
3843 * You must deallocate the space later by passing a pointer to the return
3844 * value to the new_free() function.
3845 */
malloc_strdup2(const char * str1,const char * str2)3846 char * malloc_strdup2 (const char *str1, const char *str2)
3847 {
3848 size_t msize;
3849 char * buffer;
3850
3851 /* Prevent a crash. */
3852 if (str1 == NULL)
3853 str1 = empty_string;
3854 if (str2 == NULL)
3855 str2 = empty_string;
3856
3857 msize = strlen(str1) + strlen(str2) + 1;
3858 buffer = (char *)new_malloc(msize);
3859 *buffer = 0;
3860 strlopencat_c(buffer, msize, NULL, str1, str2, NULL);
3861 return buffer;
3862 }
3863
3864 /*
3865 * malloc_strdup3: Allocate and return a pointer to valid heap space into
3866 * which a catenation of 'str1', 'str2', and 'str3' have been placed.
3867 *
3868 * Arguments:
3869 * 'str1' - The first string to be copied. If NULL, a zero-length string
3870 * will be used in its place.
3871 * 'str2' - The second string to be copied. If NULL, a zero-length string
3872 * will be used in its place.
3873 * 'str3' - The third string to be copied. If NULL, a zero-length string
3874 * will be used in its place.
3875 *
3876 * Return value:
3877 * A valid heap pointer containing a copy of 'str1', 'str2', and 'str3'
3878 * catenated together. 'str1', 'str2', and 'str3' may be substituted
3879 * as indicated above.
3880 *
3881 * Notes:
3882 * You must deallocate the space later by passing a pointer to the return
3883 * value to the new_free() function.
3884 */
malloc_strdup3(const char * str1,const char * str2,const char * str3)3885 char * malloc_strdup3 (const char *str1, const char *str2, const char *str3)
3886 {
3887 size_t msize;
3888 char *buffer;
3889
3890 if (!str1)
3891 str1 = empty_string;
3892 if (!str2)
3893 str2 = empty_string;
3894 if (!str3)
3895 str3 = empty_string;
3896
3897 msize = strlen(str1) + strlen(str2) + strlen(str3) + 1;
3898 buffer = (char *)new_malloc(msize);
3899 *buffer = 0;
3900 strlopencat_c(buffer, msize, NULL, str1, str2, str3, NULL);
3901 return buffer;
3902 }
3903
3904 /*
3905 * malloc_strcat2_c: Append a copy of 'str1' and 'str2'' to the end of
3906 * '*ptr', with an optional "clue" (length of (*ptr))
3907 *
3908 * Arguments:
3909 * 'ptr' - A pointer to a variable pointer that is either NULL or a valid
3910 * heap pointer which shall contain a valid C string.
3911 * 'str1' - The first of two strings to be appended to '*ptr'.
3912 * May be NULL.
3913 * 'str2' - The second of two strings to be appended to '*ptr'.
3914 * May be NULL.
3915 * 'cluep' - A pointer to an integer holding the string length of (*ptr).
3916 * May be NULL.
3917 *
3918 * Return value:
3919 * The catenation of the three strings '*ptr', 'str1', and 'str2', except
3920 * if either 'str1' or 'str2' are NULL, those values are ignored.
3921 * (*ptr) is set to the return value.
3922 * This function will not return (panic) if (*ptr) is not NULL and is
3923 * not a valid heap pointer.
3924 * If 'cluep' is not NULL, it will be set to the string length of the
3925 * new value of (*ptr).
3926 *
3927 * Notes:
3928 * The original value of (*ptr) is always invalidated by this function and
3929 * may not be used after this function returns.
3930 * This function needs to determine how long (*ptr) is, and unless you
3931 * provide 'cluep' it will do a strlen(*ptr). If (*ptr) is quite
3932 * large, this could be an expensive operation. The use of a clue
3933 * is an optimization option.
3934 * If you don't want to bother with the 'clue', use the malloc_strcat2 macro.
3935 * You must deallocate the space later by passing (ptr) to the new_free()
3936 * function.
3937 */
malloc_strcat2_c(char ** ptr,const char * str1,const char * str2,size_t * clue)3938 char * malloc_strcat2_c (char **ptr, const char *str1, const char *str2, size_t *clue)
3939 {
3940 size_t csize;
3941 int msize;
3942
3943 csize = clue ? *clue : 0;
3944 msize = csize;
3945
3946 if (*ptr)
3947 {
3948 if (alloc_size(*ptr) == FREED_VAL)
3949 panic("free()d pointer passed to malloc_strcat2");
3950 msize += strlen(csize + *ptr);
3951 }
3952 if (str1)
3953 msize += strlen(str1);
3954 if (str2)
3955 msize += strlen(str2);
3956
3957 if (!*ptr)
3958 {
3959 *ptr = new_malloc(msize + 1);
3960 **ptr = 0;
3961 }
3962 else
3963 RESIZE(*ptr, char, msize + 1);
3964
3965 if (str1)
3966 strlcat(csize + *ptr, str1, msize + 1 - csize);
3967 if (str2)
3968 strlcat(csize + *ptr, str2, msize + 1 - csize);
3969 if (clue)
3970 *clue = msize;
3971
3972 return *ptr;
3973 }
3974
3975 /*
3976 * malloc_strcat_wordlist_c: Append a word list to another word list using
3977 * a delimiter, with an optional "clue" (length of (*ptr))
3978 *
3979 * Arguments:
3980 * 'ptr' - A pointer to a variable pointer that is either NULL or a valid
3981 * heap pointer which shall contain a valid C string which
3982 * represents a word list (words separated by delimiters)
3983 * 'word_delim' - The delimiter to use to separate (*ptr) from 'word_list'.
3984 * May be NULL if no delimiter is desired.
3985 * 'word_list' - The word list to append to (*ptr).
3986 * May be NULL.
3987 * 'cluep' - A pointer to an integer holding the string length of (*ptr).
3988 * May be NULL.
3989 *
3990 * Return value:
3991 * If "wordlist" is either NULL or a zero-length string, this function
3992 * does nothing, and returns the original value of (*ptr).
3993 * If "wordlist" is not NULL and not a zero-length string, and (*ptr) is
3994 * either NULL or a zero-length string, (*ptr) is set to "wordlist",
3995 * and the new value of (*ptr) is returned.
3996 * If "wordlist" is not NULL and not a zero-length string, and (*ptr) is
3997 * not NULL and not a zero-length string, (*ptr) is set to the
3998 * catenation of (*ptr), 'word_delim', and 'wordlist' and is the
3999 * return value.
4000 * This function will not return (panic) if (*ptr) is not NULL and is
4001 * not a valid heap pointer.
4002 * If 'cluep' is not NULL, it will be set to the string length of the
4003 * new value of (*ptr).
4004 *
4005 * Notes:
4006 * The idea of this function is given two word lists, either of which
4007 * may contain zero or more words, paste them together using a
4008 * delimiter, which for word lists, is usually a space, but could
4009 * be any character.
4010 * Unless "wordlist" is NULL or a zero-length string, the original value
4011 * of (*ptr) is invalidated and may not be used after this function
4012 * returns.
4013 * This function needs to determine how long (*ptr) is, and unless you
4014 * provide 'cluep' it will do a strlen(*ptr). If (*ptr) is quite
4015 * large, this could be an expensive operation. The use of a clue
4016 * is an optimization option.
4017 * If you don't want to bother with the 'clue', use the
4018 * malloc_strcat_wordlist macro.
4019 * You must deallocate the space later by passing (ptr) to the new_free()
4020 * function.
4021 * A WORD LIST IS CONSIDERED TO HAVE ONE ELEMENT IF IT HAS ANY CHARACTERS
4022 * EVEN IF THAT CHARACTER IS A DELIMITER (ie, a space).
4023 */
malloc_strcat_wordlist_c(char ** ptr,const char * word_delim,const char * wordlist,size_t * clue)4024 char * malloc_strcat_wordlist_c (char **ptr, const char *word_delim, const char *wordlist, size_t *clue)
4025 {
4026 if (wordlist && *wordlist)
4027 {
4028 if (*ptr && **ptr)
4029 return malloc_strcat2_c(ptr, word_delim, wordlist, clue);
4030 else
4031 return malloc_strcpy_c(ptr, wordlist, clue);
4032 }
4033 else
4034 return *ptr;
4035 }
4036
malloc_strcat_word_c(char ** ptr,const char * word_delim,const char * word,size_t * clue)4037 char * malloc_strcat_word_c (char **ptr, const char *word_delim, const char *word, size_t *clue)
4038 {
4039 /* You MUST turn on extractw to get double quoted words */
4040 if (!(x_debug & DEBUG_EXTRACTW))
4041 return malloc_strcat_wordlist_c(ptr, word_delim, word, clue);
4042
4043 if (word && *word)
4044 {
4045 int quote_word = strpbrk(word, word_delim) ? 1 : 0;
4046 #if 0
4047 if (!*ptr || !**ptr)
4048 malloc_strcpy_c(ptr, empty_string, clue);
4049 #endif
4050
4051 if (*ptr && **ptr)
4052 malloc_strcat_c(ptr, word_delim, clue);
4053 if (quote_word)
4054 malloc_strcat_c(ptr, "\"", clue);
4055 malloc_strcat_c(ptr, word, clue);
4056 if (quote_word)
4057 malloc_strcat_c(ptr, "\"", clue);
4058 }
4059
4060 return *ptr;
4061 }
4062
4063 /*
4064 * malloc_sprintf: write a formatted string to heap memory
4065 *
4066 * Arguments:
4067 * 'ptr' - A NULL pointer, or a pointer to a variable pointer that is
4068 * either NULL or a valid heap pointer which shall contain
4069 * a valid C string which represents a word list (words
4070 * separated by delimiters)
4071 * 'format' - A *printf() format string
4072 * ... - The rest of the arguments map to 'format' in the normal way for
4073 * *printf() functions.
4074 *
4075 * Return value:
4076 * If 'format' is NULL, The return value will be set to a valid heap pointer
4077 * to a zero-length C string.
4078 * If 'format' is not NULL, The return value will be set to a valid heap
4079 * pointer sufficiently large to contain a C string of the form 'format',
4080 * filled in with the rest of the arguments in accordance with sprintf().
4081 * In either case, if ptr is not NULL, (*ptr) is set to the return value.
4082 * This function will not return (panic) if ptr is not NULL, *ptr is not NULL,
4083 * and is (*ptr) is not a valid heap pointer.
4084 *
4085 * Notes:
4086 * This function has an arbitrarily limit of 20k on the return value.
4087 * If the arguments passed do not match up with 'format', chaos may result.
4088 * If ptr is not NULL then the original value of (*ptr) is invalidated and
4089 * may not be used after this function returns.
4090 * You must deallocate the space later by passing a pointer to the return
4091 * value to the new_free() function.
4092 */
malloc_sprintf(char ** ptr,const char * format,...)4093 char * malloc_sprintf (char **ptr, const char *format, ...)
4094 {
4095 char booya[BIG_BUFFER_SIZE * 10 + 1];
4096 *booya = 0;
4097
4098 if (format)
4099 {
4100 va_list args;
4101 va_start(args, format);
4102 vsnprintf(booya, sizeof booya, format, args);
4103 va_end(args);
4104 }
4105
4106 if (ptr)
4107 {
4108 malloc_strcpy(ptr, booya);
4109 return *ptr;
4110 }
4111 else
4112 return malloc_strdup(booya);
4113 }
4114
4115 /*
4116 * universal_next_arg_count: Remove the first "count" words from "str",
4117 * where ``word'' is defined by all this scary text below here...
4118 *
4119 * Arguments:
4120 * 'str' - A standard word list (words are separated by spaces only)
4121 * This string will be modified!
4122 * 'new_ptr' - A pointer to a variable pointer into which shall be placed
4123 * the new start of 'str' after the words have been removed.
4124 * It's customary to pass a pointer to "str" for this param.
4125 * 'count' - The number of words to remove. If you want to remove one
4126 * word, use the next_arg() macro.
4127 * 'extended' - One of the three "DWORD" macros:
4128 * DWORD_NEVER - Do not honor double-quoted words in 'str'
4129 * DWORD_YES - Honor them if /xdebug extractw is on.
4130 * DWORD_ALWAYS - Always honor double-quoted words in 'str'.
4131 * 'dequote' - The double quotes that surround double-quoted words
4132 * should be stripped from the return value.
4133 *
4134 * Definition:
4135 * A "word" is either a "standard word" or a "double quoted word".
4136 * A "standard word" is one or more characters that are not spaces, as
4137 * defined by your locale's "isspace(3)" rules. A "standard word"
4138 * is separated from other "standard words" by spaces, as defined
4139 * by "isspace(3)". "Standard words" do not contain any spaces.
4140 * A "double quoted word" is one or more characters that are surrounded
4141 * by double quotes ("). A word is considered "double quoted" if it
4142 * begins with a double quote that occurs at the start of the string,
4143 * or immediately after one or more spaces as defined by isspace(3);
4144 * and if it ends with a double quote that occurs at the end of the
4145 * string or immediately before one or more spaces. Every word that
4146 * is not a "double quoted word" as defined here is a Standard Word.
4147 *
4148 * If "extended" is DWORD_NEVER, or DWORD_YES and /xdebug extractw is off,
4149 * then all words shall be treated as Standard Words, even if they
4150 * are surrounded in double quotes.
4151 *
4152 * If "dequote" is 0, then any Double Quoted Words shall be modified to
4153 * remove the double quotes that surround them. Dequoting multiple
4154 * words is expensive.
4155 *
4156 * Return value:
4157 * The first position of the first word in 'str'; the start of a string
4158 * that includes the first 'count' words in 'str', perhaps modified
4159 * by the above rules. Spaces between words are retained, but words
4160 * before the first word and after the last word will be trimmed.
4161 * Furthermore, because the whitespace character after the last word in
4162 * the return value shall be filled in with a NUL character, the
4163 * '*new_ptr' value will be set to the position after this NUL.
4164 * Subject to the following conditions:
4165 * If "str" is NULL or a zero-length string, NULL is returned.
4166 * If "str" contains only spaces the return value shall be a
4167 * zero-length string.
4168 * If "str" does not contain more words than requested, The return
4169 * value shall be as normal, but '*new_ptr' shall be set to
4170 * a zero-length string.
4171 *
4172 * Notes:
4173 * "Contain more words than requested" means if you request 1 word
4174 * and there is only one word in 'str', then the return value
4175 * will point to that word, but '*new_ptr' will be set to a zero
4176 * length string.
4177 * You can loop over a string, pulling each word off doing something
4178 * like the following:
4179 * while ((ptr = universal_next_arg_count(str, &str, 1, 1, 0))) {
4180 * ... operate on ptr ...
4181 * }
4182 * 'str' will be modified, so if you need to remove words from a
4183 * (const char *), make a LOCAL_COPY() of it first.
4184 *
4185 * There are some shorthand macros available:
4186 * next_arg(char *str, char **new_ptr);
4187 * next_arg_count(char *str, char **new_ptr, int count);
4188 * new_next_arg(char *str, char **new_ptr);
4189 * new_next_arg_count(char *str, char **new_ptr, int count);
4190 */
universal_next_arg_count(char * str,char ** new_ptr,int count,int extended,int dequote,const char * delims)4191 char * universal_next_arg_count (char *str, char **new_ptr, int count, int extended, int dequote, const char *delims)
4192 {
4193 size_t clue;
4194
4195 if (!str || !*str)
4196 return NULL;
4197
4198 while (str && *str && my_isspace(*str))
4199 str++;
4200
4201 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4202 yell(">>>> universal_next_arg_count: Start: [%s], count [%d], extended [%d], dequote [%d], delims [%s]", str, count, extended, dequote, delims);
4203
4204 real_move_to_abs_word(str, (const char **)new_ptr, count, extended, delims);
4205 if (**new_ptr && *new_ptr > str)
4206 (*new_ptr)[-1] = 0;
4207
4208 clue = (*new_ptr) - str - 1;
4209 remove_trailing_spaces(str, &clue);
4210 if (dequote)
4211 dequoter(&str, &clue, count == 1 ? 0 : 1, extended, delims);
4212
4213 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4214 yell("<<<< universal_next_arg_count: End: [%s] [%s]",
4215 str, *new_ptr);
4216 #if 0 /* This can't possibly be right! */
4217 if (!str || !*str)
4218 return NULL;
4219 #endif
4220 return str;
4221 }
4222
4223 /*
4224 * dequoter: Remove double quotes around Double Quoted Words
4225 *
4226 * Arguments:
4227 * 'str' - A pointer to a string that contains Double Quoted Words.
4228 * Double quotes around Double Quoted Words in (*str) will be
4229 * removed.
4230 * 'clue' - A pointer to an integer holding the size of '*str'. You must
4231 * provide this correct value. If '*str' is shortened, this
4232 * value will be changed to reflect the new length of '*str'.
4233 * 'full' - Assume '*str' contains more than one word and an exhaustive
4234 * dequoting is neccessary. THIS IS VERY EXPENSIVE. If '*str'
4235 * contains one word, this should be 0.
4236 * 'extended' - The extended word policy for this string. This should
4237 * usually be DWORD_ALWAYS unless you're doing something fancy.
4238 *
4239 * Return value:
4240 * There is no return value, but '*str' and '*clue' may be modified as
4241 * described in the above notes.
4242 *
4243 * Notes:
4244 * None.
4245 */
dequoter(char ** str,size_t * clue,int full,int extended,const char * delims)4246 void dequoter (char **str, size_t *clue, int full, int extended, const char *delims)
4247 {
4248 int simple;
4249 char what;
4250 size_t orig_size;
4251 orig_size = *clue + 1;
4252
4253 /*
4254 * Solve the problem of a string with one word...
4255 */
4256 if (full == 0)
4257 {
4258 if (delims && delims[0] && delims[1] == 0)
4259 {
4260 simple = 1;
4261 what = delims[0];
4262 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4263 yell("#### dequoter: Dequoting [%s] simply with delim [%c]", *str, what);
4264 }
4265 else
4266 {
4267 simple = 0;
4268 what = 255;
4269 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4270 yell("#### dequoter: Dequoting [%s] fully with delims [%s]", *str, delims);
4271 }
4272
4273 if (str && *str && ((simple == 1 && **str == what) ||
4274 (simple == 0 && strchr(delims, **str))))
4275 {
4276 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4277 yell("#### dequoter: simple string starts with delim...");
4278
4279 if (*clue > 0 && ((simple == 1 && (*str)[*clue] == what) ||
4280 (simple == 0 && strchr(delims, (*str)[*clue]))))
4281 {
4282 if (x_debug & DEBUG_EXTRACTW_DEBUG)
4283 yell("#### dequoter: simple string ends with delim...");
4284
4285 /* Kill the closing quote. */
4286 (*str)[*clue] = 0;
4287 (*clue)--;
4288
4289 /* Kill the opening quote. */
4290 (*str)++;
4291 (*clue)--;
4292 }
4293 }
4294 return;
4295 }
4296
4297 /*
4298 * I'm going to perdition for writing this, aren't I...
4299 */
4300 else
4301 {
4302 char *orig_str; /* Where to start the dest string */
4303 char *retval; /* our temp working buffer */
4304 size_t rclue; /* A working clue for 'retval' */
4305 char *this_word; /* The start of each word */
4306 size_t this_len; /* How long the word is */
4307
4308 orig_str = *str; /* Keep this for later use */
4309 retval = alloca(orig_size); /* Reserve space for a full copy */
4310 *retval = 0; /* Prep retval for use... */
4311 rclue = 0;
4312
4313 /*
4314 * Solve the problem of dequoting N words iteratively by
4315 * solving the problem for the first word and repeating
4316 * until we've worked through the entire list. Then copy
4317 * the results back to the original string.
4318 */
4319 while ((this_word = universal_next_arg_count(*str, str, 1, extended, 0, delims)))
4320 {
4321 this_len = strlen(this_word) - 1;
4322 dequoter(&this_word, &this_len, 0, extended, delims);
4323 if (rclue > 0)
4324 strlcat_c(retval, space, orig_size, &rclue);
4325 strlcat_c(retval, this_word, orig_size, &rclue);
4326 }
4327
4328 *orig_str = 0;
4329 *clue = 0;
4330 strlcpy_c(orig_str, retval, orig_size, clue);
4331 *str = orig_str;
4332 }
4333 }
4334
4335
new_new_next_arg_count(char * str,char ** new_ptr,char * type,int count)4336 char * new_new_next_arg_count (char *str, char **new_ptr, char *type, int count)
4337 {
4338 char kludge[2];
4339
4340 /* Skip leading spaces, blah blah blah */
4341 while (str && *str && my_isspace(*str))
4342 str++;
4343
4344 if (!str || !*str)
4345 return NULL;
4346
4347 if (*str == '\'')
4348 *type = '\'';
4349 else
4350 *type = '"';
4351
4352 kludge[0] = *type;
4353 kludge[1] = 0;
4354 return universal_next_arg_count(str, new_ptr, 1, DWORD_ALWAYS, 1, kludge);
4355 }
4356
4357 /*
4358 * Note that the old version is now out of sync with epics word philosophy.
4359 */
safe_new_next_arg(char * str,char ** new_ptr)4360 char * safe_new_next_arg (char *str, char **new_ptr)
4361 {
4362 char * ret;
4363
4364 if (!(ret = new_next_arg(str, new_ptr)))
4365 ret = empty_string;
4366
4367 return ret;
4368 }
4369
4370 /*
4371 * yanks off the last word from 'src'
4372 * kinda the opposite of next_arg
4373 */
last_arg(char ** src,size_t * cluep)4374 char * last_arg (char **src, size_t *cluep)
4375 {
4376 char *mark, *start, *end;
4377
4378 start = *src;
4379 end = start + *cluep;
4380 mark = end + strlen(end);
4381 /* Always support double-quoted words. */
4382 move_word_rel(start, (const char **)&mark, -1, DWORD_ALWAYS, "\"");
4383 *cluep = (mark - *src - 1);
4384
4385 if (mark > start)
4386 mark[-1] = 0;
4387 else
4388 *src = NULL; /* We're done, natch! */
4389
4390 return mark;
4391 }
4392
findchar_quoted(const char * source,int delim)4393 ssize_t findchar_quoted (const char *source, int delim)
4394 {
4395 ssize_t retval = 0;
4396 const char *p;
4397
4398 for (p = source; *p; p++)
4399 {
4400 if (*p == '\\' && p[1])
4401 p++;
4402 else if (*p == delim)
4403 break;
4404 }
4405
4406 if (*p)
4407 return p - source;
4408 else
4409 return -1;
4410 }
4411
4412