Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/macdoc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremie Laval <jeremie.laval@gmail.com>2012-04-03 16:22:00 +0400
committerJeremie Laval <jeremie.laval@gmail.com>2012-04-03 16:22:33 +0400
commite12e340b3eacbc44c977365b6a93712dd1ca3cab (patch)
tree6ff247add0b4eb3116bdd598b41085760d2d486a /monostub.m
parent256bc7aa3a4fd02b3b5a1ae861bc99d0d3d3898d (diff)
[macdoc] Create an automated build system
Diffstat (limited to 'monostub.m')
-rw-r--r--monostub.m372
1 files changed, 372 insertions, 0 deletions
diff --git a/monostub.m b/monostub.m
new file mode 100644
index 0000000..3ce332b
--- /dev/null
+++ b/monostub.m
@@ -0,0 +1,372 @@
+//gcc -m32 monostub.m -o monostub -framework AppKit
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <ctype.h>
+
+#import <Cocoa/Cocoa.h>
+
+#define ALSO_WITH_MONO_LIB(lib) lib,"/Library/Frameworks/Mono.framework/Versions/Current/lib/"lib
+
+typedef int (* mono_main) (int argc, char **argv);
+typedef void (* mono_free) (void *ptr);
+typedef char * (* mono_get_runtime_build_info) (void);
+
+static void
+exit_with_message (char *reason, char *argv0)
+{
+ NSString *appName = nil;
+ NSDictionary *plist = [[NSBundle mainBundle] infoDictionary];
+ if (plist) {
+ appName = (NSString *) [plist objectForKey:(NSString *)kCFBundleNameKey];
+ }
+ if (!appName) {
+ appName = [[NSString stringWithUTF8String: argv0] lastPathComponent];
+ }
+
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setMessageText:[NSString stringWithFormat:@"Could not launch %@", appName]];
+ NSString *fmt = @"%s\n\nPlease download and install the latest version of Mono.";
+ NSString *msg = [NSString stringWithFormat:fmt, reason];
+ [alert setInformativeText:msg];
+ [alert addButtonWithTitle:@"Download Mono Framework"];
+ [alert addButtonWithTitle:@"Cancel"];
+ NSInteger answer = [alert runModal];
+ [alert release];
+
+ if (answer == NSAlertFirstButtonReturn) {
+ NSString *mono_download_url = @"http://www.go-mono.com/mono-downloads/download.html";
+ CFURLRef url = CFURLCreateWithString (NULL, (CFStringRef) mono_download_url, NULL);
+ LSOpenCFURLRef (url, NULL);
+ CFRelease (url);
+ }
+ exit (1);
+}
+
+static int
+check_mono_version (const char *version, const char *req_version)
+{
+ char *req_end, *end;
+ long req_val, val;
+
+ while (*req_version) {
+ req_val = strtol (req_version, &req_end, 10);
+ if (req_version == req_end || (*req_end && *req_end != '.')) {
+ fprintf (stderr, "Bad version requirement string '%s'\n", req_end);
+ return FALSE;
+ }
+
+ req_version = req_end;
+ if (*req_version)
+ req_version++;
+
+ val = strtol (version, &end, 10);
+ if (version == end || val < req_val)
+ return FALSE;
+
+ if (val > req_val)
+ return TRUE;
+
+ if (*end != '.')
+ return FALSE;
+
+ version = end + 1;
+ }
+
+ return TRUE;
+}
+
+static int
+mkdir_with_parents (const char *dirname, int mode)
+{
+ char *path, *d;
+ char dirsep;
+ int rv;
+
+ if (dirname == NULL || *dirname == '\0') {
+ errno = EINVAL;
+ return -1;
+ }
+
+ d = path = strdup (dirname);
+ while (*d == '/')
+ d++;
+
+ while (*d != '\0') {
+ while (*d && *d != '/')
+ d++;
+
+ dirsep = *d;
+ *d = '\0';
+
+ if ((rv = mkdir (path, mode)) == -1 && errno != EEXIST)
+ break;
+
+ *d = dirsep;
+ while (*d == '/')
+ d++;
+ }
+
+ free (path);
+
+ return rv;
+}
+
+static int
+redirect_io (int from_fd, const char *to_path)
+{
+ int err;
+ int fd;
+
+ if ((fd = open (to_path, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1)
+ return -1;
+
+ if (dup2 (fd, from_fd) == -1) {
+ err = errno;
+ close (fd);
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+init_logdir (const char *app)
+{
+ const char *env;
+ size_t dirlen;
+ char *path;
+
+ if ((env = getenv ("MONOMAC_LOGDIR")) != NULL && *env) {
+ // Redirect stdout/err to log files...
+ if (mkdir_with_parents (env, 0755) == -1 && errno != EEXIST) {
+ fprintf (stderr, "Could not create log directory: %s\n", strerror (errno));
+ return;
+ }
+
+ dirlen = strlen (env);
+ path = malloc (dirlen + 12);
+ strcpy (path, env);
+
+ if (path[dirlen - 1] != '/')
+ path[dirlen++] = '/';
+
+ strcpy (path + dirlen, "stdout.log");
+ if (redirect_io (STDOUT_FILENO, path) == -1)
+ fprintf (stderr, "Could not redirect stdout to `%s': %s\n", path, strerror (errno));
+
+ strcpy (path + dirlen, "stderr.log");
+ if (redirect_io (STDERR_FILENO, path) == -1)
+ fprintf (stderr, "Could not redirect stderr to `%s': %s\n", path, strerror (errno));
+
+ free (path);
+ }
+}
+
+typedef struct _ListNode {
+ struct _ListNode *next;
+ char *value;
+} ListNode;
+
+static char *
+decode_qstring (unsigned char **in, unsigned char qchar)
+{
+ unsigned char *inptr = *in;
+ unsigned char *start = *in;
+ char *value, *v;
+ size_t len = 0;
+
+ while (*inptr) {
+ if (*inptr == qchar)
+ break;
+
+ if (*inptr == '\\') {
+ if (inptr[1] == '\0')
+ break;
+
+ inptr++;
+ }
+
+ inptr++;
+ len++;
+ }
+
+ v = value = (char *) malloc (len + 1);
+ while (start < inptr) {
+ if (*start == '\\')
+ start++;
+
+ *v++ = (char) *start++;
+ }
+
+ *v = '\0';
+
+ if (*inptr)
+ inptr++;
+
+ *in = inptr;
+
+ return value;
+}
+
+static char **
+get_mono_env_options (int *count)
+{
+ const char *env = getenv ("MONO_ENV_OPTIONS");
+ ListNode *list = NULL, *node, *tail = NULL;
+ unsigned char *start, *inptr;
+ char *value, **argv;
+ int i, n = 0;
+
+ if (env == NULL) {
+ *count = 0;
+ return NULL;
+ }
+
+ inptr = (unsigned char *) env;
+
+ while (*inptr) {
+ while (isblank ((int) *inptr))
+ inptr++;
+
+ if (*inptr == '\0')
+ break;
+
+ start = inptr++;
+ switch (*start) {
+ case '\'':
+ case '"':
+ value = decode_qstring (&inptr, *start);
+ break;
+ default:
+ while (*inptr && !isblank ((int) *inptr))
+ inptr++;
+
+ value = strndup ((char *) start, (size_t) (inptr - start));
+ break;
+ }
+
+ node = (ListNode *) malloc (sizeof (ListNode));
+ node->value = value;
+ node->next = NULL;
+ n++;
+
+ if (tail != NULL)
+ tail->next = node;
+ else
+ list = node;
+
+ tail = node;
+ }
+
+ *count = n;
+
+ if (n == 0)
+ return NULL;
+
+ argv = (char **) malloc (sizeof (char *) * (n + 1));
+ i = 0;
+
+ while (list != NULL) {
+ node = list->next;
+ argv[i++] = list->value;
+ free (list);
+ list = node;
+ }
+
+ argv[i] = NULL;
+
+ return argv;
+}
+
+int main (int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSDictionary *plist = [[NSBundle mainBundle] infoDictionary];
+ NSString *resources = [[NSBundle mainBundle] resourcePath];
+ NSString *exePath, *exeName = nil, *monoVersion = nil;
+ char **extra_argv;
+ int extra_argc;
+
+ init_logdir (argv[0]);
+
+ if (plist != NULL) {
+ monoVersion = (NSString *) [plist objectForKey:@"MonoMinimumVersion"];
+ exeName = (NSString *) [plist objectForKey:@"MonoBundleExecutable"];
+ } else {
+ fprintf (stderr, "Could not load Info.plist.");
+ }
+
+ if (!monoVersion)
+ monoVersion = @"2.10.8";
+
+ if (!exeName) {
+ const char *basename;
+
+ if (!(basename = strrchr (argv[0], '/')))
+ basename = argv[0];
+ else
+ basename++;
+
+ exeName = [NSString stringWithFormat:@"%s.exe", basename];
+ }
+
+ exePath = [resources stringByAppendingPathComponent: exeName];
+
+ char* lib_search_paths[] = { ALSO_WITH_MONO_LIB("libmono-2.0.dylib"),
+ ALSO_WITH_MONO_LIB("libmono-0.dylib") };
+ void *libmono = NULL;
+ int j = 0, search_path_count = sizeof (lib_search_paths) / sizeof (char*);
+ for (j = 0; libmono == NULL && j < search_path_count; j++)
+ libmono = dlopen (lib_search_paths[j], RTLD_LAZY);
+ if (libmono == NULL)
+ exit_with_message ("This application requires the Mono framework.", argv[0]);
+
+ mono_main _mono_main = (mono_main) dlsym (libmono, "mono_main");
+ if (!_mono_main) {
+ fprintf (stderr, "Could not load mono_main\n");
+ exit_with_message ("Failed to load the Mono framework.", argv[0]);
+ }
+
+ mono_free _mono_free = (mono_free) dlsym (libmono, "mono_free");
+ if (!_mono_free) {
+ fprintf (stderr, "Could not load mono_free\n");
+ exit_with_message ("Failed to load the Mono framework.", argv[0]);
+ }
+
+ mono_get_runtime_build_info _mono_get_runtime_build_info = (mono_get_runtime_build_info) dlsym (libmono, "mono_get_runtime_build_info");
+ if (!_mono_get_runtime_build_info) {
+ fprintf (stderr, "Could not load mono_get_runtime_build_info\n");
+ exit_with_message ("Failed to load the Mono framework.", argv[0]);
+ }
+
+ char *mono_version = _mono_get_runtime_build_info ();
+ if (!check_mono_version (mono_version, [monoVersion UTF8String]))
+ exit_with_message ("This application requires a newer version of the Mono framework.", argv[0]);
+
+ extra_argv = get_mono_env_options (&extra_argc);
+
+ char **new_argv = (char **) malloc (sizeof (char *) * (argc + extra_argc + 2));
+ int i, n = 0;
+
+ new_argv[n++] = argv[0];
+ for (i = 0; i < extra_argc; i++)
+ new_argv[n++] = extra_argv[i];
+
+ new_argv[n++] = strdup ([exePath UTF8String]);
+
+ for (i = 1; i < argc; i++)
+ new_argv[n++] = argv[i];
+ new_argv[n] = NULL;
+
+ free (extra_argv);
+ [pool drain];
+
+ return _mono_main (argc + extra_argc + 1, new_argv);
+}