#include "ftpd.h"

STRING *string_new(void)
{
	STRING *ns = mallocwrapper(sizeof(STRING) + MINLEN + 1);
	
	STRLENGTH(ns) = 0;
	STRTOCHARN(ns, 0) = 0;
	return(ns);
}

void string_cat(STRING **s, char *catstr, int len)
{
	if (len == -1)
		len = strlen(catstr);
	
	if (len + STRLENGTH(*s) >= MINLEN)
		reallocwrapper(len + STRCURSIZE(*s), (void *)s);

	memcpy(STRTOCHAR(*s) + STRLENGTH(*s), catstr, len);
	STRLENGTH(*s) += len;
	STRTOCHARN(*s, (*s)->strlen) = 0;
}

void string_clear(STRING **s)
{
	if (STRLENGTH(*s) > MINLEN)
		reallocwrapper(sizeof(STRING) + MINLEN + 1, (void *)s);

	STRLENGTH(*s) = 0;
	STRTOCHARN(*s, 0) = 0;
}

void string_dropfront(STRING **s, int nchars)
{
	int oldlen = STRLENGTH(*s);
	
	if ((*s)->strlen < nchars)
		nchars = (*s)->strlen;
	
	memmove(STRTOCHAR(*s), STRTOCHAR(*s) + nchars, STRLENGTH(*s) - nchars);
	STRLENGTH(*s) -= nchars;
	STRTOCHARN(*s, STRLENGTH(*s)) = 0;
	
	if (oldlen >= MINLEN)
	{
		if (STRLENGTH(*s) >= MINLEN)
			reallocwrapper(sizeof(STRING) + STRLENGTH(*s) + 1, (void *)s);
		else
			reallocwrapper(sizeof(STRING) + MINLEN + 1, (void *)s);
	}
}

void string_catvprintf(STRING **s, int len, char *format, va_list ap)
{
	if (STRLENGTH(*s) + len >= MINLEN)
		reallocwrapper(len + STRCURSIZE(*s), (void *)s);
	
	vsnprintf(STRTOCHAR(*s) + STRLENGTH(*s), len+1, format, ap);

	STRLENGTH(*s) += len;
}

void string_catprintf(STRING **s, char *format, ...)
{
	va_list printfargs;
	int len;
	
	va_start(printfargs, format);
	len = vsnprintf(NULL, 0, format, printfargs);
	va_end(printfargs);
	
	va_start(printfargs, format);
	string_catvprintf(s, len, format, printfargs);
	va_end(printfargs);
}

/* this is for input to ftp. Make very strict. (No tabs or nofing, only /r/n) */
void string_filterbadchars_telnet(STRING **s, int start)
{
	int count, slen;
	unsigned char *pos1, *pos2;
	
	if (start > STRLENGTH(*s))
		return;
	
	pos1 = pos2 = STRTOCHAR(*s) + start;
	slen = STRLENGTH(*s);
	count = start;
	
	while(count < slen)
	{
		/* be very aggressive. Only printable charaters! */
		if ((*pos1 >= 32) && (*pos1 <= 126))
		{
			*pos2 = *pos1;
			pos2++;
		}
		else
		{
			switch(*pos1)
			{
				case '\r':
					/* allow specific case of \r\n only. */
					if (count != (slen - 1))
					{
						if (*(pos1 + 1) == '\n')
						{
							// forward 2 chars
							*pos2 = *pos1;
							*(pos2 + 1) = *(pos1 + 1);
							pos1++; 
							pos2 += 2;
							count++;
						}
						else
							STRLENGTH(*s) -= 1;
					}
					else
						STRLENGTH(*s) -= 1;
					
					break;
				default:
					STRLENGTH(*s) -= 1;
					break;
			}
		}
		pos1++;
		count++;
	}
	*pos2 = 0;
}

/* this is for input files. Be quite relaxed, but still remove annoying
   chars */
   
void string_filterbadchars_unix(STRING **s, int start)
{
	int count, slen;
	unsigned char *pos1, *pos2;
	
	if (start > STRLENGTH(*s))
		return;
	
	pos1 = pos2 = STRTOCHAR(*s) + start;
	slen = STRLENGTH(*s);
	count = start;
	
	while(count < slen)
	{
		/* be very aggressive. Only printable charaters! */
		if (*pos1 >= 32)
		{
			*pos2 = *pos1;
			pos2++;
		}
		else
		{
			switch(*pos1)
			{
				case '\n':
				case '\t':
					*pos2 = *pos1;
					pos2++;
					break;
				default:
					STRLENGTH(*s) -= 1;
					break;
			}
		}
		pos1++;
		count++;
	}
	*pos2 = 0;
}
