summaryrefslogtreecommitdiff
path: root/lib/builtins/os_version_check.c
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2017-03-09 14:17:36 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2017-03-09 14:17:36 +0000
commitae68970583589b453f55dae5269e7fa332324505 (patch)
tree5e314a065a0a959e0c3f11efb46955955db4205b /lib/builtins/os_version_check.c
parent47bb7f41bd24d5edcc0931c4a89d7c1cceb41bc6 (diff)
downloadcompiler-rt-ae68970583589b453f55dae5269e7fa332324505.tar.gz
[compiler-rt][builtins] Add __isOSVersionAtLeast()
This predicate compares the host's marketing OS version to one passed as argument. Currently, only darwin targets are supported. This is done by parsing the SystemVersion.plist file. Also added in this patch is some lit testing infrastructure for builtins, which previously had none. This part of the patch was written by Alex Lorenz (with some minor modifications). This patch is part of a feature I proposed here: http://lists.llvm.org/pipermail/cfe-dev/2016-July/049851.html Differential revision: https://reviews.llvm.org/D30136 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297382 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/builtins/os_version_check.c')
-rw-r--r--lib/builtins/os_version_check.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c
new file mode 100644
index 000000000..05edb18f9
--- /dev/null
+++ b/lib/builtins/os_version_check.c
@@ -0,0 +1,115 @@
+/* ===-- os_version_check.c - OS version checking -------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements the function __isOSVersionAtLeast, used by
+ * Objective-C's @available
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifdef __APPLE__
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Dispatch/Dispatch.h>
+#include <TargetConditionals.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* These three variables hold the host's OS version. */
+static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
+static dispatch_once_t DispatchOnceCounter;
+
+/* Find and parse the SystemVersion.plist file. */
+static void parseSystemVersionPList(void *Unused) {
+ (void)Unused;
+
+ char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
+
+#if TARGET_OS_SIMULATOR
+ char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
+ if (!PListPathPrefix)
+ return;
+ char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
+ strcpy(FullPath, PListPathPrefix);
+ strcat(FullPath, PListPath);
+ PListPath = FullPath;
+#endif
+ FILE *PropertyList = fopen(PListPath, "r");
+ if (!PropertyList)
+ return;
+
+ /* Dynamically allocated stuff. */
+ CFDictionaryRef PListRef = NULL;
+ CFDataRef FileContentsRef = NULL;
+ UInt8 *PListBuf = NULL;
+
+ fseek(PropertyList, 0, SEEK_END);
+ long PListFileSize = ftell(PropertyList);
+ if (PListFileSize < 0)
+ goto Fail;
+ rewind(PropertyList);
+
+ PListBuf = malloc((size_t)PListFileSize);
+ if (!PListBuf)
+ goto Fail;
+
+ size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
+ if (NumRead != (size_t)PListFileSize)
+ goto Fail;
+
+ /* Get the file buffer into CF's format. We pass in a null allocator here *
+ * because we free PListBuf ourselves */
+ FileContentsRef = CFDataCreateWithBytesNoCopy(
+ NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
+ if (!FileContentsRef)
+ goto Fail;
+
+ if (&CFPropertyListCreateWithData)
+ PListRef = CFPropertyListCreateWithData(
+ NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
+ else
+ PListRef = CFPropertyListCreateFromXMLData(NULL, FileContentsRef,
+ kCFPropertyListImmutable, NULL);
+ if (!PListRef)
+ goto Fail;
+
+ CFTypeRef OpaqueValue =
+ CFDictionaryGetValue(PListRef, CFSTR("ProductVersion"));
+ if (!OpaqueValue || CFGetTypeID(OpaqueValue) != CFStringGetTypeID())
+ goto Fail;
+
+ char VersionStr[32];
+ if (!CFStringGetCString((CFStringRef)OpaqueValue, VersionStr,
+ sizeof(VersionStr), kCFStringEncodingUTF8))
+ goto Fail;
+ sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
+
+Fail:
+ if (PListRef)
+ CFRelease(PListRef);
+ if (FileContentsRef)
+ CFRelease(FileContentsRef);
+ free(PListBuf);
+ fclose(PropertyList);
+}
+
+int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
+ /* Populate the global version variables, if they haven't already. */
+ dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
+
+ if (Major < GlobalMajor) return 1;
+ if (Major > GlobalMajor) return 0;
+ if (Minor < GlobalMinor) return 1;
+ if (Minor > GlobalMinor) return 0;
+ return Subminor <= GlobalSubminor;
+}
+
+#endif