//	Zinc Application Framework - Z_SCANF.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA
//
//	This file is a modified version of vfscanf.c obtained from the
//	Berkeley Source Tree administered by The Regents of the University of
//	California (the "Regents")
//
//	Modifications made by Zinc are:
//	  COPYRIGHT (C) 1994-1999.  All Rights Reserved.
//	  Zinc Software Incorporated.  Pleasant Grove, Utah  USA
//
//	Permission from the Regents is conditioned on inclusion of the following
//	notice from the Regents which applies only to vfscanf.c:
//
//	  Copyright (c) 1990 The Regents of the University of California.
//	  All rights reserved.
//
//	  This code is derived from software contributed to Berkeley by
//	  Chris Torek.
//
//	  Redistribution and use in source and binary forms, with or without
//	  modification, are permitted provided that the following conditions
//	  are met:
//	  1. Redistributions of source code must retain the above copyright
//	     notice, this list of conditions and the following disclaimer.
//	  2. Redistributions in binary form must reproduce the above copyright
//	     notice, this list of conditions and the following disclaimer in the
//	     documentation and/or other materials provided with the distribution.
//	  3. All advertising materials mentioning features or use of this software
//	     must display the following acknowledgement:
//	       This product includes software developed by the University of
//	       California, Berkeley and its contributors.
//	  4. Neither the name of the University nor the names of its contributors
//	     may be used to endorse or promote products derived from this software
//	     without specific prior written permission.
//
//	  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
//	  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//	  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//	  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
//	  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//	  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
//	  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//	  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//	  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//	  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//	  SUCH DAMAGE.

#include <z_fdata.hpp>
#include <z_ctype.hpp>
#include <z_stdio.hpp>
#include <z_stdarg.hpp>
#include <z_string.hpp>

#undef sscanf
int ZafFormatData::sscanf(const ZafIChar *dst, const ZafIChar *format, ...)
{
	va_list args;
	va_start(args, format);
#if defined(ZAF_REARRANGEARGS)
	ZafIChar *newFormat = new ZafIChar[ZAF_MAXPARAMLEN];
	char buff[ZAF_MAXPARAMLEN];	// Borland expects this in the stack.
	va_list newArgs;
	ZafStandardArg::RearrangeArgs(true, buff, format, args, newFormat, &newArgs);
	int i = ZafFormatData::_vsscanf(dst, newFormat, newArgs);
	delete []newFormat;
#else
	int i = ZafFormatData::_vsscanf(dst, format, &args);
#endif
	va_end(args);
	return i;
}

/* START BLOCK COMMENT
**	static struct
**	{
**		ZafIChar fmtCH;
**		objectParse Parse;
**	} table[40];
**	static int tableEntries = 0;
END BLOCK COMMENT */

ZafFormatData::ParseTable ZafFormatData::parseTable[40];
int ZafFormatData::parseTableEntries = 0;

void ZafFormatData::SetSscanf(ZafIChar fmtch, objectParse parse)
{
	for (int i = 0; i < parseTableEntries; i++)
		if (parseTable[i].fmtCH == fmtch)
			return;
	parseTable[parseTableEntries].fmtCH = fmtch;
	parseTable[parseTableEntries].Parse = parse;
	parseTableEntries++;
}

// -- Code below here was derived from BSD

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfscanf.c	5.6 (Berkeley) 2/24/91";
#endif /* LIBC_SCCS and not lint */

#if defined(__SC__) && !defined(macintosh)
#	undef va_arg
#	define va_arg(ap,type)	   (*(type *)((*(char **)&(ap)+=__va_size(type))-(__va_size(type))))
#endif

#define	BUF	40

/*
 * Conversion types.
 */
#define	CT_CCL		1	/* %[...] conversion */

/*
 * vfscanf
 */
int ZafFormatData::_vsscanf(const ZafIChar *fp, const ZafIChar *fmt, va_list *ap)
{
	int c;		// character from format, or conversion
	size_t width;	// field width, or 0
	int flags;	// flags as defined above
	int nassigned;	// number of fields assigned
	int nread;	// number of characters consumed from fp

	nassigned = 0;
	nread = 0;
	for (;;) {
		c = *fmt++;
		if (c == 0)
			return (nassigned);
		if (isspace((ZafIChar)c))
		{
			for (;;)
			{
				if (!isspace(*fp))
					break;
				nread++, fp++;
			}
			continue;
		}
		if (c != '%')
			goto literal;
		width = 0;
		flags = 0;
		/*
		 * switch on the format.  continue if done;
		 * break once format type is derived.
		 */
again:		c = *fmt++;
switchAgain:		switch (c) {
		case '%':
literal:
			if (*fp != c)
				goto match_failure;
			fp++;
			nread++;
			continue;

		case '*':
			flags |= ZAF_SUPPRESS;
			goto again;
		case 'l':
			flags |= ZAF_LONGVAL;
			goto again;
		case 'L':
			flags |= ZAF_LONGDBL;
			goto again;
		case 'h':
			flags |= ZAF_SHORTVAL;
			goto again;
		case 'Z':
			flags |= ZAF_OBJ;
			goto again;

		case '$':
			flags |= ZAF_CURRENCYx;
			goto again;

		case '@':
			flags |= ZAF_CREDIT;
			goto again;

		case ',':
			flags |= ZAF_COMMAS;
			goto again;

		case '.':
			// This is part of the output format and means that the width
			// previously calculated is incorrect.
  			width = 0;
			if ((c = *fmt++) == '*') {
				goto again;
			}
			while ((c >= '0') && (c <= '9'))
			{
				c = *fmt++;
			}
			goto switchAgain;

		case '+':
		case '-':
			// Fix for + & - in input format (copied from output format).
			goto again;

		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			width = width * 10 + c - '0';
			goto again;
		/*
		 * Conversions.
		 * Those marked `compat' are for 4.[123]BSD compatibility.
		 *
		 * (According to ANSI, E and X formats are supposed
		 * to the same as e and x.  Sorry about that.)
		 */
/* START BLOCK COMMENT
**			case 'p':	#* pointer format is like hex #/
**				{
**				ZafIChar *buffer = (ZafIChar *)fp;
**				int i = ZafIntegerData::Parse(ap, &buffer, 'x', flags | ZAF_POINTER, width, &fmt);
**				if (i < 0)
**					goto match_failure;
**				nassigned += i;
**				nread += (int)(buffer - fp);
**				fp = buffer;
**				}
**				break;
END BLOCK COMMENT */
		case 'n':
			if (flags & ZAF_SUPPRESS)	/* ??? */
				continue;
			if (flags & ZAF_SHORTVAL)
				*va_arg(*ap, short *) = (short)nread;
			else if (flags & ZAF_LONGVAL)
				*va_arg(*ap, long *) = nread;
			else
				*va_arg(*ap, int *) = nread;
			continue;
		/*
		 * Disgusting backwards compatibility hacks.	XXX
		 */
		case '\0':	/* compat */
			return (-1);
		default:	/* compat */
			{
			ZafIChar *buffer = (ZafIChar *)fp;
			int j = -1;
			for (int i=0; i < parseTableEntries; i++)
				if (parseTable[i].fmtCH == c)
				{
					j = parseTable[i].Parse(ap, &buffer, (ZafIChar)c, flags, (int)width, &fmt);
					goto next;
				}
/* START BLOCK COMMENT
**				if (isupper((ZafIChar)c))
**					flags |= ZAF_LONGVAL;
**				j = ZafIntegerData::Parse(ap, &buffer, 'i', flags, width, &fmt);
END BLOCK COMMENT */
	next:
			if (j < 0)
				goto match_failure;
			nassigned += j;
			nread += (int)(buffer - fp);
			fp = buffer;
			}
			break;
		}
	}
//input_failure:
//	return (nassigned ? nassigned : -1);
match_failure:
	return (nassigned);
}

