// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if NETFRAMEWORK || NETCOREAPP

using System;
using System.Runtime.InteropServices;

namespace Internal.Microsoft.DotNet.PlatformAbstractions.Native
{
    internal static partial class NativeMethods
    {
        public static class Darwin
        {
            private const int CTL_KERN = 1;
            private const int KERN_OSRELEASE = 2;

            public unsafe static string GetKernelRelease()
            {
                const uint BUFFER_LENGTH = 32;

                var name = stackalloc int[2];
                name[0] = CTL_KERN;
                name[1] = KERN_OSRELEASE;

                var buf = stackalloc byte[(int)BUFFER_LENGTH];
                var len = stackalloc uint[1];
                *len = BUFFER_LENGTH;

                try
                {
                    // If the buffer isn't big enough, it seems sysctl still returns 0 and just sets len to the
                    // necessary buffer size. This appears to be contrary to the man page, but it's easy to detect
                    // by simply checking len against the buffer length.
                    if (sysctl(name, 2, buf, len, IntPtr.Zero, 0) == 0 && *len < BUFFER_LENGTH)
                    {
                        return Marshal.PtrToStringAnsi((IntPtr)buf, (int)*len);
                    }
                }
                catch (Exception ex)
                {
                    throw new PlatformNotSupportedException("Error reading Darwin Kernel Version", ex);
                }
                throw new PlatformNotSupportedException("Unknown error reading Darwin Kernel Version");
            }

            [DllImport("libc")]
            private unsafe static extern int sysctl(
                int* name,
                uint namelen,
                byte* oldp,
                uint* oldlenp,
                IntPtr newp,
                uint newlen);
        }
    }
}

#endif
