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