/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

/*
 * Token manipulation functions.
 */

#include "hostenv.h"
#include "mailer.h"
#include "../libsh/io.h"
#include <ctype.h>

struct token *
makeToken(s, n)
	u_char	*s;
	register int	n;
{
	register struct token	*t;

	t = (struct token *)tmalloc(sizeof (struct token));
	t->t_pname = (u_char *)strnsave((char *)s, n);
	t->t_len = 0;
	t->t_type = Empty;
	t->t_next = 0;
	return t;
}

struct token *
copyToken(t)
	register struct token *t;
{
	register struct token *ct;
	
	ct = (struct token *)tmalloc(sizeof (struct token));
	if (stickymem != MEM_TEMP) {
		ct->t_len = TOKENLEN(t);
		ct->t_pname = (u_char *)strnsave((char *)t->t_pname, (int)ct->t_len);
	} else {
		ct->t_pname = t->t_pname;
		ct->t_len = t->t_len;
	}
	if (ct->t_len > 100000)
		abort();
	ct->t_type = t->t_type;
	ct->t_next = t->t_next;
	return ct;
}

char *
formatToken(t)
	register struct token *t;
{
	char *name;
	int len;
	static char buf[256];

	switch (t->t_type) {
	case String:	name = "string"; break;
	case Atom:	name = "atom"; break;
	case Special:	name = "special"; break;
	case DomainLiteral:	name = "domainLiteral"; break;
	case Line:	name = "line"; break;
	case Space:	name = "space"; break;
	case Word:	name = "word"; break;
	case Comment:	name = "comment"; break;
	case Empty:	name = "empty"; break;
	case Error:	name = "error"; break;
	default:	name = "unknown"; break;
	}
	buf[0] = '\'';
	len = TOKENLEN(t);
	if ((len + 4 + strlen(name)) >= sizeof(buf))
	  len = sizeof(buf) - strlen(name) - 4;
	memcpy(buf+1, (char *)(t->t_pname), len);
	sprintf(buf + len + 1, "'(%s)", name);
	return buf;
}

char *
formatAddr(d)
	AddrComponent d;
{
	switch (d) {
	case aPhrase:	return "aPhrase";
	case aComment:	return "aComment";
	case aSpecial:	return "aSpecial";
	case aGroup:	return "aGroup";
	case anAddress:	return "anAddress";
	case aDomain:	return "aDomain";
	case aWord:	return "aWord";
	case anError:	return "anError";
	case reSync:	return "reSync";
	/*case aSpace:	return "aSpace";*/
	}
	return "unknown";
}

int
printToken(buf, eob, t, tend, quotespecials)
	u_char *buf, *eob;
	register struct token *t, *tend;
	int quotespecials;
{
	register u_char *cp, *s;
	register int len;

	--eob;		/* make space for terminating NUL */
	for (cp = buf; t != NULL && t != tend && cp < eob; t = t->t_next) {
		if (t->t_type == DomainLiteral)
			*cp++ = '[';
		else if (t->t_type == String)
			*cp++ = '"';
		else if (quotespecials && t->t_type == Special)
			*cp++ = '\\';
		for (s = t->t_pname, len = TOKENLEN(t); len > 0; --len)
			*cp++ = *s++;
		if (t->t_type == DomainLiteral)
			*cp++ = ']';
		else if (t->t_type == String)
			*cp++ = '"';
	}
	*cp = '\0';
	return cp - buf;
}

int
fprintToken(fp, t, onlylength)
	FILE *fp;
	struct token *t;
	int onlylength;
{
	int len;

	len = TOKENLEN(t);
	if (t->t_type == DomainLiteral) {
		if (onlylength) ++onlylength;
		else putc('[', fp);
	} else if (t->t_type == String) {
		if (onlylength) ++onlylength;
		else putc('"', fp);
	} else if (t->t_type == Error) {
		if (onlylength) ++onlylength;
		else putc('?', fp);
	}
	if (onlylength)
		onlylength += len;
	else
		fwrite((char *)t->t_pname, sizeof (char), len, fp);
	if (t->t_type == DomainLiteral) {
		if (onlylength) ++onlylength;
		else putc(']', fp);
	} else if (t->t_type == String) {
		if (onlylength) ++onlylength;
		else putc('"', fp);
	} else if (t->t_type == Error) {
		if (onlylength) ++onlylength;
		else putc('?', fp);
	}
	return onlylength;
}

#define LINELEN	80

int
fprintFold(fp, t, col)
	FILE *fp;
	struct token *t;
	int col;
{
	int len, sawlwsp;
	u_char *cp, *ncp;

	len = TOKENLEN(t);
	if (t->t_type == DomainLiteral)
		++col, putc('[', fp);
	else if (t->t_type == String)
		++col, putc('"', fp);
	else if (t->t_type == Error)
		++col, putc('?', fp);

	cp = t->t_pname;
	do {
		/* find a breakpoint */
		if (col < LINELEN && len > (LINELEN-col)) {
			/* there is a breakpoint */
			for (ncp = cp + (LINELEN-col); ncp > cp; --ncp) {
				if (isascii(*ncp)
				    && (isspace(*ncp) || *ncp == ','))
					break;
			}
			if (ncp == cp) {
				for (ncp = cp + (LINELEN-col); ncp < cp + len;
								++ncp)
					if (isascii(*ncp)
					    && (isspace(*ncp) || *ncp == ','))
						break;
			}
			/* found breakpoint */
		} else
			ncp = cp + len;
		while (cp < ncp && len > 0) {
			if (isascii(*cp) && isspace(*cp)) {
				++col, putc(' ', fp);
				while (cp < ncp && len > 0 && isascii(*cp) && isspace(*cp))
					--len, ++cp;
			} else {
				++col, putc(*cp, fp);
				--len, ++cp;
			}
		}
		if (len > 0) {
			/* gobble LWSP at beginning of line */
			while (len > 0 && isascii(*cp) && isspace(*cp))
				--len, ++cp;
			if (len > 0) {
				putc('\n', fp);
				putc('\t', fp);
				col = 8;
			}
		}
	} while (len > 0);
		
	if (t->t_type == DomainLiteral)
		++col, putc(']', fp);
	else if (t->t_type == String)
		++col, putc('"', fp);
	else if (t->t_type == Error)
		++col, putc('?', fp);
	return col;
}

void
freeTokens(t, memtype)
	struct token *t;
	int memtype;
{
	struct token *nt;

	if (memtype != MEM_MALLOC)
		return;
	while (t != NULL) {
		if (t->t_len > 10000)
			abort();
		nt = t->t_next;
		free((char *)t->t_pname);
		free((char *)t);
		t = nt;
	}
}
