/*
* Copyright (c) 2008, 2009, 2010, 2011
* 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"
#define OF_APPLICATION_M
#include <stdlib.h>
#include <string.h>
#import "OFApplication.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFAutoreleasePool.h"
#import "OFNotImplementedException.h"
#import "macros.h"
#if defined(__MACH__) && !defined(OF_IOS)
# include <crt_externs.h>
#elif !defined(OF_IOS)
extern char **environ;
#endif
static OFApplication *app = nil;
static void
atexit_handler(void)
{
id <OFApplicationDelegate> delegate = [app delegate];
[delegate applicationWillTerminate];
}
int
of_application_main(int *argc, char **argv[], Class cls)
{
OFApplication *app = [OFApplication sharedApplication];
id <OFApplicationDelegate> delegate = [[cls alloc] init];
[app setArgumentCount: argc
andArgumentValues: argv];
[app setDelegate: delegate];
[(id)delegate release];
[app run];
return 0;
}
@implementation OFApplication
+ sharedApplication
{
if (app == nil)
app = [[self alloc] init];
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
{
exit(status);
}
- init
{
self = [super init];
@try {
OFAutoreleasePool *pool;
#if defined(__MACH__) && !defined(OF_IOS)
char **env = *_NSGetEnviron();
#elif !defined(OF_IOS)
char **env = environ;
#else
char *env;
#endif
environment = [[OFMutableDictionary alloc] init];
atexit(atexit_handler);
pool = [[OFAutoreleasePool alloc] init];
#ifndef OF_IOS
for (; *env != NULL; env++) {
OFString *key;
OFString *value;
char *sep;
if ((sep = strchr(*env, '=')) == NULL) {
fprintf(stderr, "Warning: Invalid environment "
"variable: %s\n", *env);
continue;
}
key = [OFString stringWithCString: *env
length: sep - *env];
value = [OFString stringWithCString: sep + 1];
[environment setObject: value
forKey: key];
[pool releaseObjects];
}
#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.
*/
if ((env = getenv("HOME")) != NULL)
[environment
setObject: [OFString stringWithCString: env]
forKey: @"HOME"];
if ((env = getenv("PATH")) != NULL)
[environment
setObject: [OFString stringWithCString: env]
forKey: @"PATH"];
if ((env = getenv("SHELL")) != NULL)
[environment
setObject: [OFString stringWithCString: env]
forKey: @"SHELL"];
if ((env = getenv("TMPDIR")) != NULL)
[environment
setObject: [OFString stringWithCString: env]
forKey: @"TMPDIR"];
if ((env = getenv("USER")) != NULL)
[environment
setObject: [OFString stringWithCString: env]
forKey: @"USER"];
#endif
[pool release];
/*
* Class swizzle the environment to be immutable, as we don't
* need to change it anymore and expose it only as
* OFDictionary*. But not swizzling it would create a real copy
* each time -[copy] is called.
*/
environment->isa = [OFDictionary class];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (void)setArgumentCount: (int*)argc_
andArgumentValues: (char***)argv_
{
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
int i;
[programName release];
[arguments release];
argc = argc_;
argv = argv_;
programName = [[OFString alloc] initWithCString: (*argv)[0]];
arguments = [[OFMutableArray alloc] init];
for (i = 1; i < *argc; i++)
[arguments addObject: [OFString stringWithCString: (*argv)[i]]];
/*
* Class swizzle the arguments to be immutable, as we don't need to
* change them anymore and expose them only as OFArray*. But not
* swizzling it would create a real copy each time -[copy] is called.
*/
arguments->isa = [OFArray class];
[pool release];
}
- (void)getArgumentCount: (int**)argc_
andArgumentValues: (char****)argv_
{
*argc_ = argc;
*argv_ = argv;
}
- (OFString*)programName
{
OF_GETTER(programName, YES)
}
- (OFArray*)arguments
{
OF_GETTER(arguments, YES)
}
- (OFDictionary*)environment
{
OF_GETTER(environment, YES)
}
- (id <OFApplicationDelegate>)delegate
{
OF_GETTER(delegate, YES)
}
- (void)setDelegate: (id <OFApplicationDelegate>)delegate_
{
OF_SETTER(delegate, delegate_, YES, NO)
}
- (void)run
{
[delegate applicationDidFinishLaunching];
}
- (void)terminate
{
exit(0);
}
- (void)terminateWithStatus: (int)status
{
exit(status);
}
- (void)dealloc
{
[arguments release];
[environment release];
[(id)delegate release];
[super dealloc];
}
@end
@implementation OFObject (OFApplicationDelegate)
- (void)applicationDidFinishLaunching
{
@throw [OFNotImplementedException newWithClass: isa
selector: _cmd];
}
- (void)applicationWillTerminate
{
}
@end