1//
2//  FileSettings.m
3//  PythonLauncher
4//
5//  Created by Jack Jansen on Sun Jul 21 2002.
6//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
7//
8
9#import "FileSettings.h"
10
11@implementation FileSettings
12
13+ (id)getFactorySettingsForFileType: (NSString *)filetype
14{
15    static FileSettings *fsdefault_py, *fsdefault_pyw, *fsdefault_pyc;
16    FileSettings **curdefault;
17
18    if ([filetype isEqualToString: @"Python Script"]) {
19        curdefault = &fsdefault_py;
20    } else if ([filetype isEqualToString: @"Python GUI Script"]) {
21        curdefault = &fsdefault_pyw;
22    } else if ([filetype isEqualToString: @"Python Bytecode Document"]) {
23        curdefault = &fsdefault_pyc;
24    } else {
25        NSLog(@"Funny File Type: %@\n", filetype);
26        curdefault = &fsdefault_py;
27        filetype = @"Python Script";
28    }
29    if (!*curdefault) {
30        *curdefault = [[FileSettings new] initForFSDefaultFileType: filetype];
31    }
32    return *curdefault;
33}
34
35+ (id)getDefaultsForFileType: (NSString *)filetype
36{
37    static FileSettings *default_py, *default_pyw, *default_pyc;
38    FileSettings **curdefault;
39
40    if ([filetype isEqualToString: @"Python Script"]) {
41        curdefault = &default_py;
42    } else if ([filetype isEqualToString: @"Python GUI Script"]) {
43        curdefault = &default_pyw;
44    } else if ([filetype isEqualToString: @"Python Bytecode Document"]) {
45        curdefault = &default_pyc;
46    } else {
47        NSLog(@"Funny File Type: %@\n", filetype);
48        curdefault = &default_py;
49        filetype = @"Python Script";
50    }
51    if (!*curdefault) {
52        *curdefault = [[FileSettings new] initForDefaultFileType: filetype];
53    }
54    return *curdefault;
55}
56
57+ (id)newSettingsForFileType: (NSString *)filetype
58{
59    FileSettings *cur;
60
61    cur = [FileSettings new];
62    [cur initForFileType: filetype];
63    return [cur retain];
64}
65
66- (id)initWithFileSettings: (FileSettings *)source
67{
68    self = [super init];
69    if (!self) return self;
70
71    interpreter = [source->interpreter retain];
72    honourhashbang = source->honourhashbang;
73    debug = source->debug;
74    verbose = source->verbose;
75    inspect = source->inspect;
76    optimize = source->optimize;
77    nosite = source->nosite;
78    tabs = source->tabs;
79    others = [source->others retain];
80    scriptargs = [source->scriptargs retain];
81    with_terminal = source->with_terminal;
82    prefskey = source->prefskey;
83    if (prefskey) [prefskey retain];
84
85    return self;
86}
87
88- (id)initForFileType: (NSString *)filetype
89{
90    FileSettings *defaults;
91
92    defaults = [FileSettings getDefaultsForFileType: filetype];
93    self = [self initWithFileSettings: defaults];
94    origsource = [defaults retain];
95    return self;
96}
97
98- (id)initForFSDefaultFileType: (NSString *)filetype
99{
100    int i;
101    NSString *filename;
102    NSDictionary *dict;
103    static NSDictionary *factorySettings;
104
105    self = [super init];
106    if (!self) return self;
107
108    if (factorySettings == NULL) {
109        NSBundle *bdl = [NSBundle mainBundle];
110        NSString *path = [ bdl pathForResource: @"factorySettings"
111                ofType: @"plist"];
112        factorySettings = [[NSDictionary dictionaryWithContentsOfFile:
113            path] retain];
114        if (factorySettings == NULL) {
115            NSLog(@"Missing %@", path);
116            return NULL;
117        }
118    }
119    dict = [factorySettings objectForKey: filetype];
120    if (dict == NULL) {
121        NSLog(@"factorySettings.plist misses file type \"%@\"", filetype);
122        interpreter = [@"no default found" retain];
123        return NULL;
124    }
125    [self applyValuesFromDict: dict];
126    interpreters = [dict objectForKey: @"interpreter_list"];
127    interpreter = NULL;
128    for (i=0; i < [interpreters count]; i++) {
129        filename = [interpreters objectAtIndex: i];
130        filename = [filename stringByExpandingTildeInPath];
131        if ([[NSFileManager defaultManager] fileExistsAtPath: filename]) {
132            interpreter = [filename retain];
133            break;
134        }
135    }
136    if (interpreter == NULL)
137        interpreter = [@"no default found" retain];
138    origsource = NULL;
139    return self;
140}
141
142- (void)applyUserDefaults: (NSString *)filetype
143{
144    NSUserDefaults *defaults;
145    NSDictionary *dict;
146
147    defaults = [NSUserDefaults standardUserDefaults];
148    dict = [defaults dictionaryForKey: filetype];
149    if (!dict)
150        return;
151    [self applyValuesFromDict: dict];
152}
153
154- (id)initForDefaultFileType: (NSString *)filetype
155{
156    FileSettings *fsdefaults;
157
158    fsdefaults = [FileSettings getFactorySettingsForFileType: filetype];
159    self = [self initWithFileSettings: fsdefaults];
160    if (!self) return self;
161    interpreters = [fsdefaults->interpreters retain];
162    scriptargs = [@"" retain];
163    [self applyUserDefaults: filetype];
164    prefskey = [filetype retain];
165    return self;
166}
167
168- (void)reset
169{
170    if (origsource) {
171        [self updateFromSource: origsource];
172    } else {
173        FileSettings *fsdefaults;
174        fsdefaults = [FileSettings getFactorySettingsForFileType: prefskey];
175        [self updateFromSource: fsdefaults];
176    }
177}
178
179- (void)updateFromSource: (id <FileSettingsSource>)source
180{
181    interpreter = [[source interpreter] retain];
182    honourhashbang = [source honourhashbang];
183    debug = [source debug];
184    verbose = [source verbose];
185    inspect = [source inspect];
186    optimize = [source optimize];
187    nosite = [source nosite];
188    tabs = [source tabs];
189    others = [[source others] retain];
190    scriptargs = [[source scriptargs] retain];
191    with_terminal = [source with_terminal];
192    // And if this is a user defaults object we also save the
193    // values
194    if (!origsource) {
195        NSUserDefaults *defaults;
196        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
197            interpreter, @"interpreter",
198            [NSNumber numberWithBool: honourhashbang], @"honourhashbang",
199            [NSNumber numberWithBool: debug], @"debug",
200            [NSNumber numberWithBool: verbose], @"verbose",
201            [NSNumber numberWithBool: inspect], @"inspect",
202            [NSNumber numberWithBool: optimize], @"optimize",
203            [NSNumber numberWithBool: nosite], @"nosite",
204            [NSNumber numberWithBool: tabs], @"tabs",
205            others, @"others",
206            scriptargs, @"scriptargs",
207            [NSNumber numberWithBool: with_terminal], @"with_terminal",
208            nil];
209        defaults = [NSUserDefaults standardUserDefaults];
210        [defaults setObject: dict forKey: prefskey];
211    }
212}
213
214- (void)applyValuesFromDict: (NSDictionary *)dict
215{
216    id value;
217
218    value = [dict objectForKey: @"interpreter"];
219    if (value) interpreter = [value retain];
220    value = [dict objectForKey: @"honourhashbang"];
221    if (value) honourhashbang = [value boolValue];
222    value = [dict objectForKey: @"debug"];
223    if (value) debug = [value boolValue];
224    value = [dict objectForKey: @"verbose"];
225    if (value) verbose = [value boolValue];
226    value = [dict objectForKey: @"inspect"];
227    if (value) inspect = [value boolValue];
228    value = [dict objectForKey: @"optimize"];
229    if (value) optimize = [value boolValue];
230    value = [dict objectForKey: @"nosite"];
231    if (value) nosite = [value boolValue];
232    value = [dict objectForKey: @"tabs"];
233    if (value) tabs = [value boolValue];
234    value = [dict objectForKey: @"others"];
235    if (value) others = [value retain];
236    value = [dict objectForKey: @"scriptargs"];
237    if (value) scriptargs = [value retain];
238    value = [dict objectForKey: @"with_terminal"];
239    if (value) with_terminal = [value boolValue];
240}
241
242- (NSString*)_replaceSingleQuotes: (NSString*)string
243{
244    /* Replace all single-quotes by '"'"', that way shellquoting will
245     * be correct when the result value is delimited  using single quotes.
246     */
247    NSArray* components = [string componentsSeparatedByString:@"'"];
248
249    return [components componentsJoinedByString:@"'\"'\"'"];
250}
251
252- (NSString *)commandLineForScript: (NSString *)script
253{
254    NSString *cur_interp = NULL;
255    NSString* script_dir = NULL;
256    char hashbangbuf[1024];
257    FILE *fp;
258    char *p;
259
260    script_dir = [script substringToIndex:
261	    [script length]-[[script lastPathComponent] length]];
262
263    if (honourhashbang &&
264       (fp=fopen([script fileSystemRepresentation], "r")) &&
265       fgets(hashbangbuf, sizeof(hashbangbuf), fp) &&
266       strncmp(hashbangbuf, "#!", 2) == 0 &&
267       (p=strchr(hashbangbuf, '\n'))) {
268            *p = '\0';
269            p = hashbangbuf + 2;
270            while (*p == ' ') p++;
271            cur_interp = [NSString stringWithUTF8String: p];
272    }
273    if (!cur_interp)
274        cur_interp = interpreter;
275
276    return [NSString stringWithFormat:
277        @"cd '%@' && '%@'%s%s%s%s%s%s %@ '%@' %@ %s",
278    	[self _replaceSingleQuotes:script_dir],
279        [self _replaceSingleQuotes:cur_interp],
280        debug?" -d":"",
281        verbose?" -v":"",
282        inspect?" -i":"",
283        optimize?" -O":"",
284        nosite?" -S":"",
285        tabs?" -t":"",
286        others,
287        [self _replaceSingleQuotes:script],
288        scriptargs ? scriptargs : @"",
289        with_terminal? "&& echo Exit status: $? && exit 1" : " &"];
290}
291
292- (NSArray *) interpreters { return interpreters;};
293
294// FileSettingsSource protocol
295- (NSString *) interpreter { return interpreter;};
296- (BOOL) honourhashbang { return honourhashbang; };
297- (BOOL) debug { return debug;};
298- (BOOL) verbose { return verbose;};
299- (BOOL) inspect { return inspect;};
300- (BOOL) optimize { return optimize;};
301- (BOOL) nosite { return nosite;};
302- (BOOL) tabs { return tabs;};
303- (NSString *) others { return others;};
304- (NSString *) scriptargs { return scriptargs;};
305- (BOOL) with_terminal { return with_terminal;};
306
307@end
308