src/Platform-Windows.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jan 12 16:35:26 2013 -0800 (2013-01-12)
changeset 260 05de34f712fe
parent 251 ca99a81745fe
permissions -rw-r--r--
Add support for mutually recursive imports.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of SourcePawn.
     6  *
     7  * SourcePawn is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18  */
    19 
    20 #define WIN32_LEAN_AND_MEAN
    21 #include <Windows.h>
    22 #include <direct.h>
    23 #include <sys/stat.h>
    24 #include "Platform.h"
    25 
    26 using namespace ke;
    27 
    28 static inline DWORD
    29 ToProtBits(OS::Protection prot)
    30 {
    31     switch (prot) {
    32       case OS::Prot_ReadWrite:
    33         return PAGE_READWRITE;
    34       case OS::Prot_ReadWriteExecute:
    35         return PAGE_EXECUTE_READWRITE;
    36       default:
    37         assert(prot == OS::Prot_ReadExecute);
    38         return PAGE_EXECUTE_READ;
    39     }
    40 }
    41 
    42 Address
    43 OS::MapMemory(size_t amount, MapMode mode, Protection prot_)
    44 {
    45     DWORD prot = ToProtBits(prot_);
    46     DWORD type = MEM_RESERVE;
    47     if (mode == Map_Commit)
    48         type |= MEM_COMMIT;
    49 
    50     return (Address)VirtualAlloc(NULL, amount, type, prot);
    51 }
    52 
    53 bool
    54 OS::CommitMemory(Address address, size_t amount, Protection prot_)
    55 {
    56     DWORD prot = ToProtBits(prot_);
    57     return !!VirtualAlloc(address, amount, MEM_COMMIT, prot);
    58 }
    59 
    60 void
    61 OS::UnmapMemory(Address address, size_t size)
    62 {
    63     VirtualFree(address, 0, MEM_RELEASE);
    64 }
    65 
    66 static Address
    67 MapMemoryAt(Address address, size_t amount, OS::MapMode mode, OS::Protection prot_)
    68 {
    69     DWORD bits = ToProtBits(prot_);
    70     DWORD flags = MEM_RESERVE;
    71     if (mode == OS::Map_Commit)
    72         flags |= MEM_COMMIT;
    73 
    74     return (Address)VirtualAlloc((LPVOID)address, amount, flags, bits);
    75 }
    76 
    77 OS::AlignableMapping
    78 OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode)
    79 {
    80     Address addr = MapMemory(amount, mode, OS::Prot_ReadWrite);
    81     if (!addr)
    82         return AlignableMapping(NULL, alignment, 0);
    83 
    84     if (!IsAligned(addr, alignment)) {
    85         UnmapMemory(addr, amount);
    86 
    87         // Try to grab the next available aligned address.
    88         addr = AlignedBase(addr, alignment);
    89         addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
    90         while (!addr) {
    91             // Try to over-allocate to get the right region. This can race
    92             // with other threads; we expect this to be rare. If this turns
    93             // out to be a problem, the API is set up such that we can just
    94             // return two pointers: the base, and the aligned address into
    95             // the over-allocated region.
    96             addr = MapMemory(amount + alignment, mode, OS::Prot_ReadWrite);
    97             if (!addr)
    98                 return AlignableMapping(NULL, alignment, 0);
    99             UnmapMemory(addr, amount + alignment);
   100             addr = AlignedBase(addr, alignment);
   101             addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
   102         }
   103     }
   104 
   105     return AlignableMapping(addr, alignment, amount);
   106 }
   107 
   108 void
   109 OS::UnmapAlignedMemory(Address address, size_t size)
   110 {
   111     OS::UnmapMemory(address, size);
   112 }
   113 
   114 bool
   115 OS::GetAbsolutePath(const char *path, AutoFree<char> &chars)
   116 {
   117     char try1[MAX_PATH];
   118     DWORD result = GetFullPathName(path, sizeof(try1), try1, NULL);
   119     if (result <= 0)
   120         return false;
   121 
   122     // +1 because if result < MAX_PATH, it doesn't include the null terminator.
   123     chars = (char *)calloc(result + 1, sizeof(char));
   124     if (!*chars)
   125         return false;
   126 
   127     if (result <= MAX_PATH) {
   128         strcpy(*chars, try1);
   129         return true;
   130     }
   131 
   132     // We should get the same output on the next try.
   133     return GetFullPathName(path, result, *chars, NULL) == result - 1;
   134 }
   135 
   136 bool
   137 OS::SplitPath(const char *path, AutoFree<char> &base, AutoFree<char> &name)
   138 {
   139     size_t len = strlen(path);
   140 
   141     // Skip trailing slashes.
   142     while (len > 1 && (path[len - 1] == '/' || path[len - 1] == '\\'))
   143         len--;
   144 
   145     for (size_t i = len - 1; i < len; i--) {
   146         if (path[i] == '\\' || path[i] == '/') {
   147             name = (char *)calloc(len - i, sizeof(char));
   148             if (!*name)
   149                 return false;
   150 
   151             strcpy(*name, &path[i + 1]);
   152 
   153             base = (char *)calloc(i + 1, sizeof(char));
   154             if (!*base)
   155                 return false;
   156 
   157             memcpy(*base, path, i);
   158             (*base)[i] = '\0';
   159             return true;
   160         }
   161     }
   162     
   163     // The path should have been absolute, which contains at least one separator.
   164     return false;
   165 }
   166 
   167 const char *
   168 OS::PathSeparator()
   169 {
   170     return "\\";
   171 }
   172 
   173 OS::PathType
   174 OS::InspectPath(const char *path)
   175 {
   176     struct _stat s;
   177     int result = _stat(path, &s);
   178     if (result != 0)
   179         return OS::Path_Invalid;
   180 
   181     if (s.st_mode & _S_IFDIR)
   182         return OS::Path_Folder;
   183     if (s.st_mode & _S_IFREG)
   184         return OS::Path_File;
   185 
   186     return OS::Path_Invalid;
   187 }