Artifact faff25c7591063877aaa8dbb850a944a1d1bd62b0a698ff5ae26eeb9ee42da0a:
- File
src/OFApplication.m
— part of check-in
[48980f2297]
at
2015-11-29 11:43:05
on branch trunk
— Make properties a requirement and clean up code
This increases the required GCC version from 4.0 to 4.6 (exception:
Apple GCC, which already supports this with >= 4.0 starting with OS X
10.5). Since even GCC 4.6 is really old by now, there is no point in
still supporting something even older and making the code ugly because
of that. While some hardware and OS support was dropped from GCC 4.6
compared to GCC 4.0, there is nothing in there that would be an
interesting target with the exception of BeOS maybe - but a port to BeOS
can also be achieved using the Haiku support. The other dropped OSes are
mostly old versions of OSes while newer ones are still being supported
(and those newer versions of those OSes still support the same
hardware). (user: js, size: 10755) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #import "OFApplication.h" #import "OFString.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFSystemInfo.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFThread.h" #import "OFThread+Private.h" #if defined(OF_MAC_OS_X) # include <crt_externs.h> #elif defined(OF_WINDOWS) # include <windows.h> extern int _CRT_glob; extern void __wgetmainargs(int*, wchar_t***, wchar_t***, int, int*); #elif !defined(OF_IOS) extern char **environ; #endif #ifdef OF_PSP # include <pspkerneltypes.h> # include <psploadexec.h> #endif #ifdef OF_NINTENDO_DS # define asm __asm__ # include <nds.h> # undef asm #endif @interface OFApplication (OF_PRIVATE_CATEGORY) - (void)OF_setArgumentCount: (int*)argc andArgumentValues: (char**[])argv; #ifdef OF_WINDOWS - (void)OF_setArgumentCount: (int)argc andWideArgumentValues: (wchar_t*[])argv; #endif - (void)OF_run; @end static OFApplication *app = nil; static void atexitHandler(void) { id <OFApplicationDelegate> delegate = [app delegate]; if ([delegate respondsToSelector: @selector(applicationWillTerminate)]) [delegate applicationWillTerminate]; [delegate release]; } #define SIGNAL_HANDLER(sig) \ static void \ handle##sig(int signal) \ { \ app->_##sig##Handler(app->_delegate, \ @selector(applicationDidReceive##sig)); \ } SIGNAL_HANDLER(SIGINT) #ifndef OF_WINDOWS SIGNAL_HANDLER(SIGHUP) SIGNAL_HANDLER(SIGUSR1) SIGNAL_HANDLER(SIGUSR2) #endif #undef SIGNAL_HANDLER int of_application_main(int *argc, char **argv[], Class cls) { id <OFApplicationDelegate> delegate; #ifdef OF_WINDOWS wchar_t **wargv, **wenvp; int wargc, si = 0; #endif if ([cls isSubclassOfClass: [OFApplication class]]) { fprintf(stderr, "FATAL ERROR:\n Class %s is a subclass of " "class OFApplication, but class\n %s was specified as " "application delegate!\n Most likely, you wanted to " "subclass OFObject instead or specified\n the wrong class " "with OF_APPLICATION_DELEGATE().\n", class_getName(cls), class_getName(cls)); exit(1); } app = [[OFApplication alloc] init]; [app OF_setArgumentCount: argc andArgumentValues: argv]; #ifdef OF_WINDOWS __wgetmainargs(&wargc, &wargv, &wenvp, _CRT_glob, &si); [app OF_setArgumentCount: wargc andWideArgumentValues: wargv]; #endif delegate = [[cls alloc] init]; [app setDelegate: delegate]; [app OF_run]; [delegate release]; return 0; } @implementation OFApplication @synthesize programName = _programName, arguments = _arguments; @synthesize environment = _environment; + (OFApplication*)sharedApplication { return app; } + (OFString*)programName { return [app programName]; } + (OFArray*)arguments { return [app arguments]; } + (OFDictionary*)environment { return [app environment]; } + (void)terminate { exit(0); } + (void)terminateWithStatus: (int)status { #ifdef OF_PSP sceKernelExitGame(); abort(); /* sceKernelExitGame() is not marked noreturn */ #else exit(status); #endif } - init { self = [super init]; @try { void *pool; OFMutableDictionary *environment; #if defined(OF_MAC_OS_X) char **env = *_NSGetEnviron(); #elif defined(OF_WINDOWS) of_char16_t *env, *env0; #elif !defined(OF_IOS) char **env = environ; #else char *env; #endif environment = [[OFMutableDictionary alloc] init]; atexit(atexitHandler); #if defined(OF_WINDOWS) env = env0 = GetEnvironmentStringsW(); while (*env != 0) { OFString *tmp, *key, *value; size_t length, pos; pool = objc_autoreleasePoolPush(); length = of_string_utf16_length(env); tmp = [OFString stringWithUTF16String: env length: length]; env += length + 1; /* * cmd.exe seems to add some special variables which * start with a "=", even though variable names are not * allowed to contain a "=". */ if ([tmp hasPrefix: @"="]) { objc_autoreleasePoolPop(pool); continue; } pos = [tmp rangeOfString: @"="].location; if (pos == OF_NOT_FOUND) { fprintf(stderr, "Warning: Invalid environment " "variable: %s\n", [tmp UTF8String]); continue; } key = [tmp substringWithRange: of_range(0, pos)]; value = [tmp substringWithRange: of_range(pos + 1, [tmp length] - pos - 1)]; [environment setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } FreeEnvironmentStringsW(env0); #elif !defined(OF_IOS) if (env != NULL) { for (; *env != NULL; env++) { OFString *key, *value; char *sep; const of_string_encoding_t encoding = [OFSystemInfo native8BitEncoding]; pool = objc_autoreleasePoolPush(); if ((sep = strchr(*env, '=')) == NULL) { fprintf(stderr, "Warning: Invalid " "environment variable: %s\n", *env); continue; } key = [OFString stringWithCString: *env encoding: encoding length: sep - *env]; value = [OFString stringWithCString: sep + 1 encoding: encoding]; [environment setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } } #else /* * iOS does not provide environ and Apple does not allow using * _NSGetEnviron on iOS. Therefore, we just get a few common * variables from the environment which applications might * expect. */ pool = objc_autoreleasePoolPush(); if ((env = getenv("HOME")) != NULL) { OFString *home = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; [environment setObject: home forKey: @"HOME"]; } if ((env = getenv("PATH")) != NULL) { OFString *path = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; [environment setObject: path forKey: @"PATH"]; } if ((env = getenv("SHELL")) != NULL) { OFString *shell = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; [environment setObject: shell forKey: @"SHELL"]; } if ((env = getenv("TMPDIR")) != NULL) { OFString *tmpdir = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; [environment setObject: tmpdir forKey: @"TMPDIR"]; } if ((env = getenv("USER")) != NULL) { OFString *user = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; [environment setObject: user forKey: @"USER"]; } objc_autoreleasePoolPop(pool); #endif [environment makeImmutable]; _environment = environment; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_arguments release]; [_environment release]; [super dealloc]; } - (void)OF_setArgumentCount: (int*)argc andArgumentValues: (char***)argv { #ifndef OF_WINDOWS void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; int i; of_string_encoding_t encoding; _argc = argc; _argv = argv; encoding = [OFSystemInfo native8BitEncoding]; # ifndef OF_NINTENDO_DS if (*argc > 0) { # else if (__system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc > 0) { # endif _programName = [[OFString alloc] initWithCString: (*argv)[0] encoding: encoding]; arguments = [[OFMutableArray alloc] init]; _arguments = arguments; for (i = 1; i < *argc; i++) [arguments addObject: [OFString stringWithCString: (*argv)[i] encoding: encoding]]; [arguments makeImmutable]; } objc_autoreleasePoolPop(pool); #else _argc = argc; _argv = argv; #endif } #ifdef OF_WINDOWS - (void)OF_setArgumentCount: (int)argc andWideArgumentValues: (wchar_t**)argv { void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; int i; if (argc > 0) { _programName = [[OFString alloc] initWithUTF16String: argv[0]]; arguments = [[OFMutableArray alloc] init]; for (i = 1; i < argc; i++) [arguments addObject: [OFString stringWithUTF16String: argv[i]]]; [arguments makeImmutable]; _arguments = arguments; } objc_autoreleasePoolPop(pool); } #endif - (void)getArgumentCount: (int**)argc andArgumentValues: (char****)argv { *argc = _argc; *argv = _argv; } - (id <OFApplicationDelegate>)delegate { return _delegate; } - (void)setDelegate: (id <OFApplicationDelegate>)delegate { #ifdef HAVE_SIGACTION struct sigaction sa = { .sa_flags = SA_RESTART }; sigemptyset(&sa.sa_mask); # define REGISTER_SIGNAL(sig) \ if ([delegate respondsToSelector: \ @selector(applicationDidReceive##sig)]) { \ _##sig##Handler = (void(*)(id, SEL))[(id)delegate \ methodForSelector: \ @selector(applicationDidReceive##sig)]; \ \ sa.sa_handler = handle##sig; \ } else \ sa.sa_handler = SIG_DFL; \ \ OF_ENSURE(sigaction(sig, &sa, NULL) == 0); #else # define REGISTER_SIGNAL(sig) \ if ([delegate respondsToSelector: \ @selector(applicationDidReceive##sig)]) { \ _##sig##Handler = (void(*)(id, SEL))[(id)delegate \ methodForSelector: \ @selector(applicationDidReceive##sig)]; \ signal(sig, handle##sig); \ } else \ signal(sig, SIG_DFL); #endif _delegate = delegate; REGISTER_SIGNAL(SIGINT) #ifndef OF_WINDOWS REGISTER_SIGNAL(SIGHUP) REGISTER_SIGNAL(SIGUSR1) REGISTER_SIGNAL(SIGUSR2) #endif #undef REGISTER_SIGNAL } - (void)OF_run { void *pool = objc_autoreleasePoolPush(); OFRunLoop *runLoop; #ifdef OF_HAVE_THREADS [OFThread OF_createMainThread]; runLoop = [OFRunLoop currentRunLoop]; #else runLoop = [[[OFRunLoop alloc] init] autorelease]; #endif [OFRunLoop OF_setMainRunLoop: runLoop]; objc_autoreleasePoolPop(pool); /* * Note: runLoop is still valid after the release of the pool, as * OF_setMainRunLoop: retained it. However, we only have a weak * reference to it now, whereas we had a strong reference before. */ pool = objc_autoreleasePoolPush(); [_delegate applicationDidFinishLaunching]; objc_autoreleasePoolPop(pool); [runLoop run]; } - (void)terminate { exit(EXIT_SUCCESS); } - (void)terminateWithStatus: (int)status { exit(status); } @end