// RuntimeForStatic base library | C+- (SysRoutine) | Author: Sergei Y.Kitáev
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace RuntimeForStatic {
//==================================================================================================

bool HelpersRT::TLSAlloc($A,DWORD volatile* pIndex $out) $last_system_error
{
   $$VERIFY_POINTER_ARG( pIndex );
   DWORD index = ::TlsAlloc();
   return $Interlocked::Write($ci, pIndex, index ) != TLS_OUT_OF_INDEXES;
}

//--------------------------------------------------------------------------------------------------

PWSTR HelpersRT::GetSystemMessage($M,DWORD dwError) $null_on_failure $last_system_error $needs_free
{
   PWSTR pMessageText;
   if ( !::FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, dwError, $Thread::LanguageId(), (PWSTR)&pMessageText, 0, nullptr ) )
      return nullptr;
   int idxLast;
   for ( idxLast = $SZ::Length($, pMessageText ) - 1;
         idxLast >= 0 && $Char::IsSpace( pMessageText[ idxLast ] );
         idxLast -- );
   bool addDot = false;
   if ( idxLast >= 0 )
   {
      WCHAR ch = pMessageText[ idxLast ];
      if ( !::wcschr( L".!?", ch ) )
      {
         addDot = true;
         idxLast++;
      }
   }
   PWSTR pMessageCopy = DuplicateStr($,$m, pMessageText, idxLast + 1 );
   $Memory::SysLocalFree($, pMessageText );
   if ( pMessageCopy && addDot )
      pMessageCopy[ idxLast ] = L'.';
   return $RESET_LAST_SYS_ERROR( pMessageCopy );
}

PWSTR HelpersRT::GetLastSystemMessage($M) $null_on_failure $last_system_error $needs_free
{
   return GetSystemMessage($m, ::GetLastError() );
}

//==================================================================================================

PWSTR HelpersRT::GetExeName($M) $null_on_failure $needs_free
{
   PWSTR pExePath = GetExePath($m);
   if ( !pExePath ) return nullptr;
   PWSTR pExeName = nullptr;
   for (PWCHAR pCh=pExePath; *pCh; pCh++)
      if ( *pCh == L'\\' || *pCh == L'/' )
         pExeName = pCh + 1;
   if ( !*pExeName )
      pExeName = nullptr;
   if ( pExeName )
      pExeName = DuplicateSZ($,$m, pExeName );
   $Memory::Free( pExePath );
   return pExeName;
}

PWSTR HelpersRT::GetExePath($M) $null_on_failure $needs_free
{
   SIZE_T capacity = 128;
   PWSTR pBuffer = (PWSTR)Allocate($,$m, capacity * $CHAR_SIZE );
   if ( !pBuffer ) return nullptr;
   SIZE_T length; PWSTR pBuffer_2;
   $LOOP
   {
      if ( length = ::GetProcessImageFileName( ::GetCurrentProcess(), pBuffer, (DWORD)capacity ) )
         break;
      if ( ::GetLastError() != ERROR_INSUFFICIENT_BUFFER || capacity == STRSAFE_MAX_CCH )
         goto FAILURE;
      capacity = $arith::Min<SIZE_T>( capacity * 2, STRSAFE_MAX_CCH );
      if (!( pBuffer_2 = (PWSTR)ReAllocate($,$m, pBuffer, capacity * $CHAR_SIZE ) ))
         goto FAILURE;
      pBuffer = pBuffer_2;
   }
   capacity = $SZ::Length($, pBuffer ) + 1;
   if ( pBuffer_2 = (PWSTR)ReAllocate($,$m, pBuffer, capacity * $CHAR_SIZE ) )
      return pBuffer_2;
FAILURE:
   return $memory::Free( pBuffer );
}

PWSTR HelpersRT::GetExeBaseName($M) $null_on_failure $needs_free
{
   PWSTR pExeName = GetExeName($m);
   if ( !pExeName ) return nullptr;
   PWSTR pLastDot = nullptr;
   for (PWCHAR pCh=pExeName; *pCh; pCh++)
      if ( *pCh == L'.' )
         pLastDot = pCh;
   if ( !pLastDot )
      return pExeName;
   SIZE_T length = pLastDot - pExeName;
   PWSTR pExeBaseName = (int)length == length ?
      DuplicateStr($,$m, pExeName, (int)length ) :
      nullptr;
   $Memory::Free( pExeName );
   return pExeBaseName;
}

//==================================================================================================
} // RuntimeForStatic
