123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
/*******************************************************************************

        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)

        version:        Initial release: November 2005

        author:         Kris

*******************************************************************************/

module tango.sys.Common;

version (Win32)
        {
        public import tango.sys.win32.UserGdi;
        }

version (linux)
        {
        public import tango.sys.linux.linux;
        alias tango.sys.linux.linux posix;
        }

version (darwin)
        {
        public import tango.sys.darwin.darwin;
        alias tango.sys.darwin.darwin posix;
        }
version (FreeBSD)
        {
        public import tango.sys.freebsd.freebsd;
        alias tango.sys.freebsd.freebsd posix;
        }
version (solaris)
        {
        public import tango.sys.solaris.solaris;
        alias tango.sys.solaris.solaris posix;
        }

/*******************************************************************************

        Stuff for sysErrorMsg(), kindly provided by Regan Heath.

*******************************************************************************/

version (Win32)
        {
        private enum FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
        private enum FORMAT_MESSAGE_IGNORE_INSERTS  = 0x00000200;
        private enum FORMAT_MESSAGE_FROM_STRING     = 0x00000400;
        private enum FORMAT_MESSAGE_FROM_HMODULE    = 0x00000800;
        private enum FORMAT_MESSAGE_FROM_SYSTEM     = 0x00001000;
        private enum FORMAT_MESSAGE_ARGUMENT_ARRAY  = 0x00002000;
        private enum FORMAT_MESSAGE_MAX_WIDTH_MASK  = 0x000000FF;

        private DWORD MAKELANGID(WORD p, WORD s)  { return (((cast(WORD)s) << 10) | cast(WORD)p); }

        private alias HGLOBAL HLOCAL;

        private enum LANG_NEUTRAL = 0x00;
        private enum SUBLANG_DEFAULT = 0x01;

        private extern (Windows)
                       {
                       DWORD FormatMessageW (DWORD dwFlags,
                                             LPCVOID lpSource,
                                             DWORD dwMessageId,
                                             DWORD dwLanguageId,
                                             LPWSTR lpBuffer,
                                             DWORD nSize,
                                             LPCVOID args
                                             );

                       HLOCAL LocalFree(HLOCAL hMem);
                       }
        }
else
version (Posix)
        {
        private import tango.stdc.errno;
        private import tango.stdc.string;
        }
else
   {
   pragma (msg, "Unsupported environment; neither Win32 or Posix is declared");
   static assert(0);
   }

   
/*******************************************************************************

*******************************************************************************/

struct SysError
{   
        /***********************************************************************

        ***********************************************************************/

        @property static uint lastCode ()
        {
                version (Win32)
                         return GetLastError();
                     else
                         return errno;
        }

        /***********************************************************************

        ***********************************************************************/

        @property static char[] lastMsg ()
        {
                return lookup (lastCode);
        }

        /***********************************************************************

        ***********************************************************************/

        @property static char[] lookup (uint errcode)
        {
                char[] text;

                version (Win32)
                        {
                        DWORD  i;
                        LPWSTR lpMsgBuf;

                        i = FormatMessageW (
                                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                                FORMAT_MESSAGE_FROM_SYSTEM |
                                FORMAT_MESSAGE_IGNORE_INSERTS,
                                null,
                                errcode,
                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                cast(LPWSTR)&lpMsgBuf,
                                0,
                                null);

                        /* Remove \r\n from error string */
                        if (i >= 2) i -= 2;
                        text = new char[i * 3];
                        i = WideCharToMultiByte (CP_UTF8, 0, lpMsgBuf, i, 
                                                 cast(PCHAR)text.ptr, text.length, null, null);
                        text = text [0 .. i];
                        LocalFree (cast(HLOCAL) lpMsgBuf);
                        }
                     else
                        {
                        size_t  r;
                        char* pemsg;

                        pemsg = strerror(errcode);
                        r = strlen(pemsg);

                        /* Remove \r\n from error string */
                        if (pemsg[r-1] == '\n') r--;
                        if (pemsg[r-1] == '\r') r--;
                        text = pemsg[0..r].dup;
                        }

                return text;
        }
}