/****************************************************************
 * Copyright (c) 2001-2018 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *                                                              *
 *      This source code contains the intellectual property     *
 *      of its copyright holder(s), and is made available       *
 *      under a license.  If you do not know the terms of       *
 *      the license, please stop and do not read further.       *
 *                                                              *
 ****************************************************************/

#include "mdef.h"
#include "stringpool.h"
#include "op.h"

GBLREF spdesc stringpool;

/*
 * -----------------------------------------------
 * op_fnreverse()
 * MUMPS Reverse String function
 *
 * Arguments:
 *	src	- Pointer to Source string mval
 *	dst	- Pointer to destination mval to save the inverted string
 *
 * Return:
 *	none
 * -----------------------------------------------
 */
#ifdef UTF8_SUPPORTED
#include "gtm_utf8.h"
GBLREF	boolean_t	badchar_inhibit;

/* UTF character-oriented $REVERSE (for $ZCHSET="UTF-8") */
void op_fnreverse(mval *src, mval *dst)
{
	unsigned char	*srcptr, *srctop, *dstptr, *dsttop;
	int		char_len, chlen;

	MV_FORCE_STR(src);
	ENSURE_STP_FREE_SPACE(src->str.len);
	dstptr = stringpool.free + src->str.len;
	srcptr = (unsigned char *)src->str.addr;
	srctop = (unsigned char *)src->str.addr + src->str.len;
	for (char_len = 0; srcptr < srctop; srcptr += chlen, ++char_len)
	{
		if (!UTF8_VALID(srcptr, srctop, chlen) && !badchar_inhibit)
			utf8_badchar(0, srcptr, srctop, 0, NULL);
		assert(chlen > 0 && chlen <= 4);
		switch (chlen) /* byte length of next character */
		{ /* NOTE: all fall-thru's below */
			case 4: *--dstptr = srcptr[3];
			case 3: *--dstptr = srcptr[2];
			case 2: *--dstptr = srcptr[1];
			case 1: *--dstptr = srcptr[0];
				break;
		}
	}
	assert(dstptr == stringpool.free);
	stringpool.free += src->str.len;
	MV_INIT_STRING(dst, src->str.len, dstptr);

	/* set character length of both source and destination mvals */
	dst->mvtype |= MV_UTF_LEN;
	dst->str.char_len = char_len;
	assert(!(MV_UTF_LEN & src->mvtype) || char_len == src->str.char_len);
	if (!(MV_UTF_LEN & src->mvtype))
	{
		src->mvtype |= MV_UTF_LEN;
		src->str.char_len = char_len;
	}
}
#endif /* UTF8_SUPPORTED */

/* byte-oriented $REVERSE (for $ZCHSET="M") */
void op_fnzreverse(mval *src, mval *dst)
{
	int	lcnt;
	char    *in, *out;

	MV_FORCE_STR(src);
	ENSURE_STP_FREE_SPACE(src->str.len);
	out = (char *)stringpool.free;
	stringpool.free += src->str.len;
	in = src->str.addr + src->str.len * SIZEOF(char);
	dst->mvtype = MV_STR;
	dst->str.addr = out;
	dst->str.len = src->str.len;
	for (lcnt = src->str.len; lcnt > 0; lcnt--)
		*out++ = *--in;
	return;
}
