/* テスト */
/*
 * Debug Status: Not checked.
 * - Fixed __T on this page.
 */
/*
 * File: z-util.c
 * Purpose: Low-level string handling and other utilities.
 *
 * Copyright (c) 1997-2005 Ben Harrison, Robert Ruehlmann.
 *
 * This work is free software; you can redistribute it and/or modify it
 * under the terms of either:
 *
 * a) the GNU General Public License as published by the Free Software
 *    Foundation, version 2, or
 *
 * b) the "Angband licence":
 *    This software may be copied and distributed for educational, research,
 *    and not for profit purposes provided that this copyright and statement
 *    are included in all such copies.  Other copyrights may also apply.
 */
#include "z-util.h"

/*
 * Convenient storage of the program name
 */
const _TCHAR *argv0 = NULL;

/*
 * Case insensitive comparison between two strings
 */
int my_stricmp(const _TCHAR *s1, const _TCHAR *s2)
{
	_TCHAR ch1 = 0;
	_TCHAR ch2 = 0;

	/* Just loop */
	while (TRUE)
	{
		/* We've reached the end of both strings simultaneously */
		if ((*s1 == 0) && (*s2 == 0))
		{
			/* We're still here, so s1 and s2 are equal */
			return (0);
		}
		ch1 = _totupper(*s1);
		ch2 = _totupper(*s2);

		/* If the characters don't match */
		if (ch1 != ch2)
		{
			/* return the difference between them */
			return ((int)(ch1 - ch2));
		}
		/* Step on through both strings */
		s1++;
		s2++;
	}
}

/*
 * Case insensitive comparison between the first n characters of two strings
 */
int my_strnicmp(const _TCHAR *a, const _TCHAR *b, int n)
{
	const _TCHAR *s1;
	const _TCHAR *s2;
	_TCHAR z1, z2;

	/* Scan the strings */
	for (s1 = a, s2 = b; n > 0; s1++, s2++, n--)
	{
		z1 = _totupper(*s1);
		z2 = _totupper(*s2);
		if (z1 < z2) return (-1);
		if (z1 > z2) return (1);
		if (!z1) return (0);
	}
	return 0;
}

/*
 * An ANSI version of _tcsstr() with case insensitivity.
 *
 * In the public domain; found at:
 *    http://c.snippets.org/code/stristr.c
 */
const _TCHAR *my_stristr(const _TCHAR *string, const _TCHAR *pattern)
{
      const _TCHAR *pptr, *sptr;
      const _TCHAR *start;

      for (start = string; *start != 0; start++)
      {
            /* find start of pattern in string */
            for ( ; ((*start != 0) &&
			        (_totupper(*start) != _totupper(*pattern))); start++)
                  ;
            if (*start == 0)
                  return NULL;

            pptr = (const _TCHAR *)pattern;
            sptr = (const _TCHAR *)start;

            while (_totupper(*sptr) == _totupper(*pptr))
            {
                  sptr++;
                  pptr++;

                  /* if end of pattern then pattern was found */
                  if (*pptr == 0)
                        return (start);
            }
      }
      return NULL;
}

/* Replace my_strcpy with _tcscpy_s */
#if 0
/*
 * The my_strcpy() function copies up to 'bufsize'-1 characters from 'src'
 * to 'buf' and NUL-terminates the result.  The 'buf' and 'src' strings may
 * not overlap.
 *
 * my_strcpy() returns _tcslen(src).  This makes checking for truncation
 * easy.  Example: if (_tcscpy_s(buf, src, _countof(buf)) >= _countof(buf)) ...;
 *
 * This function should be equivalent to the strlcpy() function in BSD.
 */

size_t my_strcpy(_TCHAR *buf, const _TCHAR *src, size_t bufsize)
{
	size_t len = _tcslen(src) * sizeof(_TCHAR);
	size_t ret = len;

	/* Paranoia */
	if (bufsize == 0)
		return ret;

	/* Truncate */
	if (len >= bufsize)
		len = bufsize - 1;

	/* Copy the string and terminate it */
	memcpy(buf, src, len * sizeof(_TCHAR));
	buf[len] = 0;

	/* Return _tcslen(src) */
	return ret;
}
#endif

#if 0
/*
 * The my_strcat() tries to append a string to an existing NUL-terminated string.
 * It never writes more characters into the buffer than indicated by 'bufsize' and
 * NUL-terminates the buffer.  The 'buf' and 'src' strings may not overlap.
 *
 * my_strcat() returns _tcslen(buf) + _tcslen(src).  This makes checking for
 * truncation easy.  Example:
 * if (my_strcat(buf, src, _countof(buf)) >= _countof(buf)) ...;
 *
 * This function should be equivalent to the strlcat() function in BSD.
 */
size_t my_strcat(TCHAR *buf, const TCHAR *src, size_t bufsize)
{
	size_t dlen = _tcslen(buf);

	/* Is there room left in the buffer? */
	if (dlen < bufsize - 1)
	{
		/* Append as much as possible  */
		return (dlen + _tcscpy_s(buf + dlen, src, bufsize - dlen));
	}
	else
	{
		/* Return without appending */
		return (dlen + _tcslen(src));
	}
}
#endif

#if 0
/*
 * Determine if string "a" is equal to string "b"
 *
 * TODO Is this needed?
 */
#undef streq
bool streq(_TCHAR *a, _TCHAR *b)
{
	return (!_tcscmp(a, b));
}
#endif

/*
 * Determine if string "t" is a suffix of string "s"
 */
bool suffix(const _TCHAR *s, const _TCHAR *t)
{
	size_t tlen = _tcslen(t);
	size_t slen = _tcslen(s);

	/* Check for incompatible lengths */
	if (tlen > slen) return (FALSE);

	/* Compare "t" to the end of "s" */
	return (!_tcscmp(s + slen - tlen, t));
}

/*
 * Determine if string "t" is a prefix of string "s"
 */
bool prefix(const _TCHAR *s, const _TCHAR *t)
{
	/* Scan "t" */
	while (*t)
	{
		/* Compare content and length */
		if (*t++ != *s++)
			return (FALSE);
	}
	/* Matched, we have a prefix */
	return (TRUE);
}

/*
 * Redefinable "plog" action
 */
void (*plog_aux)(const _TCHAR *) = NULL;

/*
 * Print (or log) a "warning" message (ala "perror()")
 * Note the use of the (optional) "plog_aux" hook.
 */
void plog(const _TCHAR* str)
{
	/* Use the "alternative" function if possible */
	if (plog_aux) (*plog_aux)(str);

	/* Just do a labeled _ftprintf to stderr */
	else (void)(_ftprintf(stderr, __T("%s: %s\n"), argv0 ? argv0 : __T("?"), str));
}

/*
 * Redefinable "quit" action
 */
void (*quit_aux)(const _TCHAR *) = NULL;

/*
 * Exit (ala "exit()").  If 'str' is NULL, do "exit(EXIT_SUCCESS)".
 * Otherwise, plog() 'str' and exit with an error code of -1.
 * But always use 'quit_aux', if set, before anything else.
 */
void quit(const _TCHAR *str)
{
	/* Attempt to use the aux function */
	if (quit_aux) (*quit_aux)(str);

	/* Success */
	if (!str) (void)(exit(EXIT_SUCCESS));

	/* Send the string to plog() */
	plog(str);

	/* Failure */
	(void)(exit(EXIT_FAILURE));
}

/* Compare and swap hooks */
bool (*ang_sort_comp)(const void *u, const void *v, int a, int b);
void (*ang_sort_swap)(void *u, void *v, int a, int b);

/*
 * Angband sorting algorithm -- quick sort in place
 *
 * Note that the details of the data we are sorting is hidden,
 * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
 * function hooks to interact with the data, which is given as
 * two pointers, and which may have any user-defined form.
 */
void ang_sort_aux(void *u, void *v, int p, int q)
{
	int z, a, b;

	/* Done sort */
	if (p >= q) return;

	/* Pivot */
	z = p;

	/* Begin */
	a = p;
	b = q;

	/* Partition */
	while (TRUE)
	{
		/* Slide i2 */
		while (!(*ang_sort_comp)(u, v, b, z)) b--;

		/* Slide i1 */
		while (!(*ang_sort_comp)(u, v, z, a)) a++;

		/* Done partition */
		if (a >= b) break;

		/* Swap */
		(*ang_sort_swap)(u, v, a, b);

		/* Advance */
		a++, b--;
	}

	/* Recurse left side */
	ang_sort_aux(u, v, p, b);

	/* Recurse right side */
	ang_sort_aux(u, v, b+1, q);
}

/*
 * Angband sorting algorithm -- quick sort in place
 *
 * Note that the details of the data we are sorting is hidden,
 * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
 * function hooks to interact with the data, which is given as
 * two pointers, and which may have any user-defined form.
 */
void ang_sort(void *u, void *v, int n)
{
	/* Sort the array */
	ang_sort_aux(u, v, 0, n-1);
}
