/*
    psftools: Manipulate console fonts in the .PSF format
    Copyright (C) 2005, 2007  John Elliott

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "psfio.h"
#include <ctype.h>

psf_errno_t unicode_add(PSF_UNICODE_DIR *f, psf_word nchar, psf_dword token);


psf_errno_t psf_unicode_to_string(psf_unicode_dirent *chain, char **str)
{
	psf_unicode_dirent *n;
	int bytes = 1;
	char *txt;
	int inmulti = 0;
	char tokbuf[9];

	/* Each character takes at most 12 bytes */
	for (n = chain; n != NULL; n = n->psfu_next) bytes += 12;
	txt = malloc(bytes);
	if (!txt) return PSF_E_NOMEM;
	txt[0] = 0;
	for (n = chain; n != NULL; n = n->psfu_next)
	{
		sprintf(tokbuf, "%08lx", n->psfu_token);
		if (inmulti)
		{
			if (n->psfu_token == 0xFFFE) 
			{
				inmulti = 1;
				continue;
			}
			if (inmulti == 1) 
			{
				strcat(txt, "[");
				inmulti = 2;
			}
			strcat(txt, tokbuf);
			if ((n->psfu_next && n->psfu_next->psfu_token == 0xFFFE)
			|| n->psfu_next == NULL)
			{
				strcat(txt, "];");
			}
			else	strcat(txt, "+");
		}
		else
		{
			if (n->psfu_token == 0xFFFE) 
			{
				inmulti = 1;
				continue;
			}
			strcat(txt, "[");
			strcat(txt, tokbuf);
			strcat(txt, "];");
		}
	}	
	*str = txt;
	return PSF_E_OK;
}


/* Convert a string of the form 
 *
 *     [token];[token];...[token+token];[token+token];...
 *
 * to a Unicode chain.
 */

static psf_errno_t unicode_from_string(PSF_UNICODE_DIR *dir, psf_word nchar, const char *str)
{
	int rv;
	psf_dword token;
	char *buf, *tok, *c;
	int inmulti = 0;

	buf = malloc(1 + strlen(str));
	if (!buf) return PSF_E_NOMEM;
	strcpy(buf, str);

	for (tok = strtok(buf, ";"); tok != NULL; tok = strtok(NULL, ";"))
	{
		if (strchr(tok, '+'))
		{
			tok++;
			inmulti = 1;
			rv = unicode_add(dir, nchar, 0xFFFE);
			if (rv) { free(buf); return rv; }
			while (isalnum(tok[0]))
			{
				if (!sscanf(tok, "%lx", &token))
				{
					free(buf);
					return PSF_E_PARSE;
				}
				rv = unicode_add(dir, nchar, token);
				if (rv) { free(buf); return rv; }
				c = strchr(tok, '+');
				if (c) tok = c + 1;
				else
				{
					c = strchr(tok, ']');
					if (!c) c = strchr(tok, ';');
					if (!c) c = tok + strlen(tok);
					tok = c;
				}	
			}
		}
		else	/* Single char */
		{
			if (inmulti) { free(buf); return PSF_E_PARSE; }
			if (!sscanf(tok + 1, "%lx", &token))
			{
				free(buf);
				return PSF_E_PARSE;
			}
			rv = unicode_add(dir, nchar, token);	
			if (rv) { free(buf); return rv; }
		}
	}
	free(buf);
	return PSF_E_OK;
}


psf_errno_t psf_unicode_from_string(PSF_FILE *f, psf_word nchar, const char *str)
{
	if (nchar >= f->psf_length) return PSF_E_RANGE;

	return unicode_from_string(&f->psf_dir, nchar, str);
}

psf_errno_t vfont_unicode_from_string(VFONT *f, psf_word nchar, const char *str)
{
	if (nchar >= f->vf_length) return PSF_E_RANGE;

	return unicode_from_string(&f->vf_dir, nchar, str);
}



