2007-11-14 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / WebKitTools / WebKitLauncher / main.m
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import <Cocoa/Cocoa.h>
30 #import <CoreFoundation/CoreFoundation.h>
31
32 void displayErrorAndQuit(NSString *title, NSString *message)
33 {
34     NSApplicationLoad();
35     NSRunCriticalAlertPanel(title, message, @"Quit", nil, nil);
36     exit(0);
37 }
38
39 void checkMacOSXVersion()
40 {
41     long versionNumber = 0;
42     OSErr error = Gestalt(gestaltSystemVersion, &versionNumber);
43     if (error != noErr || versionNumber < 0x1040)
44         displayErrorAndQuit(@"Mac OS X 10.4 is Required", @"Nightly builds of WebKit require Mac OS X 10.4 or newer.");
45 }
46
47 int getLastVersionShown()
48 {
49     [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:@"-1" forKey:@"StartPageShownInVersion"]];
50     return [[NSUserDefaults standardUserDefaults] integerForKey:@"StartPageShownInVersion"];
51 }
52
53 void saveLastVersionShown(int lastVersion)
54 {
55     [[NSUserDefaults standardUserDefaults] setInteger:lastVersion forKey:@"StartPageShownInVersion"];
56     [[NSUserDefaults standardUserDefaults] synchronize];
57 }
58
59 NSString *getPathForStartPage()
60 {
61     return [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"start.html"];
62 }
63
64 int getShowStartPageVersion()
65 {
66     return getCurrentVersion() + 1;
67 }
68
69 int getCurrentVersion()
70 {
71     return [[[[NSBundle mainBundle] infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] intValue];
72 }
73
74 BOOL startPageDisabled()
75 {
76     return [[NSUserDefaults standardUserDefaults] boolForKey:@"StartPageDisabled"];
77 }
78
79 void addStartPageToArgumentsIfNeeded(NSMutableArray *arguments)
80 {
81     if (startPageDisabled())
82         return;
83
84     if (getLastVersionShown() < getShowStartPageVersion()) {
85         saveLastVersionShown(getCurrentVersion());
86         NSString *startPagePath = getPathForStartPage();
87         if (startPagePath)
88             [arguments addObject:startPagePath];
89     }
90 }
91
92 static void myExecve(NSString *executable, NSArray *args, NSDictionary *environment)
93 {
94     char **argv = (char **)calloc(sizeof(char *), [args count] + 1);
95     char **env = (char **)calloc(sizeof(char *), [environment count] + 1);
96     
97     NSEnumerator *e = [args objectEnumerator];
98     NSString *s;
99     int i = 0;
100     while (s = [e nextObject])
101         argv[i++] = (char *) [s UTF8String];
102     
103     e = [environment keyEnumerator];
104     i = 0;
105     while (s = [e nextObject])
106         env[i++] = (char *) [[NSString stringWithFormat:@"%@=%@", s, [environment objectForKey:s]] UTF8String];
107    
108     execve([executable fileSystemRepresentation], argv, env);
109 }
110
111 NSBundle *locateSafariBundle()
112 {
113     NSArray *applicationDirectories = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES);
114     NSEnumerator *e = [applicationDirectories objectEnumerator];
115     NSString *applicationDirectory;
116     while (applicationDirectory = [e nextObject]) {
117         NSString *possibleSafariPath = [applicationDirectory stringByAppendingPathComponent:@"Safari.app"];
118         NSBundle *possibleSafariBundle = [NSBundle bundleWithPath:possibleSafariPath];
119         if ([[possibleSafariBundle bundleIdentifier] isEqualToString:@"com.apple.Safari"])
120             return possibleSafariBundle;
121     }
122
123     CFURLRef safariURL = nil;
124     OSStatus err = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.Safari"), nil, nil, &safariURL);
125     if (err != noErr)
126         displayErrorAndQuit(@"Unable to locate Safari", @"Nightly builds of WebKit require Safari to run.  Please check that it is available and then try again.");
127
128     NSBundle *safariBundle = [NSBundle bundleWithPath:[(NSURL *)safariURL path]];
129     CFRelease(safariURL);
130     return safariBundle;
131 }
132
133 int main(int argc, char *argv[])
134 {
135     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
136     checkMacOSXVersion();
137
138     NSBundle *safariBundle = locateSafariBundle();
139     NSString *executablePath = [safariBundle executablePath];
140     NSString *frameworkPath = [[NSBundle mainBundle] resourcePath];
141     NSString *pathToEnablerLib = [[NSBundle mainBundle] pathForResource:@"WebKitNightlyEnabler" ofType:@"dylib"];
142
143     if ([frameworkPath rangeOfString:@":"].location != NSNotFound ||
144         [pathToEnablerLib rangeOfString:@":"].location != NSNotFound)
145         displayErrorAndQuit(@"Unable to launch Safari",
146                             @"WebKit is located at a path containing an unsupported character.  Please move WebKit to a different location and try again.");
147     
148     NSMutableArray *arguments = [NSMutableArray arrayWithObjects:executablePath, @"-WebKitDeveloperExtras", @"YES", @"-WebKitScriptDebuggerEnabled", @"YES", nil];
149     NSMutableDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys:frameworkPath, @"DYLD_FRAMEWORK_PATH", @"YES", @"WEBKIT_UNSET_DYLD_FRAMEWORK_PATH",
150                                                                                   pathToEnablerLib, @"DYLD_INSERT_LIBRARIES", [[NSBundle mainBundle] executablePath], @"WebKitAppPath", nil];
151     addStartPageToArgumentsIfNeeded(arguments);
152
153     while (*++argv)
154         [arguments addObject:[NSString stringWithUTF8String:*argv]];
155
156     myExecve(executablePath, arguments, environment);
157
158     char *error = strerror(errno);
159     NSString *errorMessage = [NSString stringWithFormat:@"Launching Safari at %@ failed with the error '%s' (%d)", [safariBundle bundlePath], error, errno];
160     displayErrorAndQuit(@"Unable to launch Safari", errorMessage);
161
162     [pool release];
163     return 0;
164 }