/*
* Copyright (c) 2003-2024 Rony Shapiro <ronys@pwsafe.org>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/

/**
 * \file MacOS-specific implementation of some wide-string related functionality
 */

#include <wchar.h>
#include "pws_str.h"
#include "../utf8conv.h"
#include <cerrno>
#include <cstdio>

int pws_os::wctoi(const wchar_t *s)
{
  return int(wcstol(s, NULL, 10));
}

double pws_os::wctof(const wchar_t *s)
{
  return double(wcstold(s, NULL));
}

/*
 * had to define this for gcc 4.0 on osx.
 * http://trac.wildfiregames.com/ticket/414
 */
int pws_os::wcscasecmp(const wchar_t* s1, const wchar_t* s2)
{
  wchar_t wc1, wc2;

  if (s1 == s2) 
    return 0; 

  do { 
    wc1 = towlower(*s1++); 
    wc2 = towlower(*s2++); 
    if (wc1 == L'\0') 
      break; 
  } 
  while (wc1 == wc2); 

  return wc1 - wc2; 
}

wchar_t* pws_os::wcsdup (const wchar_t *src)
{
  if (!src) return NULL;
  const size_t len = wcslen(src) + 1;
  wchar_t *dest = (wchar_t*)malloc(len*sizeof(wchar_t));
  if (!dest) {
    errno = ENOMEM;
    return NULL;
  }
  return (wchar_t *)memcpy(dest, src, len*sizeof(wchar_t));
}

/**
 * Get TCHAR buffer size by format string with parameters
 * @param[in] fmt - format string
 * @param[in] args - arguments for format string
 * @return buffer size including nullptr-terminating character
*/
unsigned int pws_os::GetStringBufSize(const TCHAR *fmt, va_list args)
{
  TCHAR *buffer=nullptr;
  unsigned int len = 0;
  va_list ar;
  va_copy(ar, args);
  // Linux doesn't do this correctly :-(
  unsigned int guess = 16;
  int nBytes = -1;
  while (true) {
    len = guess;
    buffer = new TCHAR[len];
    nBytes = vswprintf(buffer, len, fmt, ar); // looks like this is vswprintf_s for Xcode
    va_end(ar);//after using args we should reset list
    va_copy(ar, args);
    /*
     * If 'nBytes' is zero due to an empty format string,
     * it would result in an endless memory-consuming loop.
     */
    ASSERT(nBytes != 0);
    if (nBytes++ > 0) {
      len = nBytes;
      break;
    } else { // too small, resize & try again
      delete[] buffer;
      buffer = nullptr;
      guess *= 2;
    }
  }

  va_end(ar);
  delete[] buffer;
  return len;
}
