Line data Source code
1 0 : /*
2 :
3 : OOOXPVerifier.m
4 :
5 :
6 : Copyright (C) 2007-2013 Jens Ayton and contributors
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : /* Design notes:
29 : see "verifier design.txt".
30 : */
31 :
32 : #import "OOOXPVerifier.h"
33 :
34 : #if OO_OXP_VERIFIER_ENABLED
35 :
36 : #if OOLITE_WINDOWS
37 :
38 : #ifdef __OBJC__
39 : #pragma push_macro("interface")
40 : #undef interface
41 : #define interface struct
42 : #endif
43 :
44 : #include <shlwapi.h>
45 :
46 : #ifdef __OBJC__
47 : #pragma pop_macro("interface")
48 : #endif
49 :
50 : #include <tchar.h>
51 : #endif
52 :
53 : #import "OOOXPVerifierStageInternal.h"
54 : #import "OOLoggingExtended.h"
55 : #import "ResourceManager.h"
56 : #import "OOCollectionExtractors.h"
57 : #import "GameController.h"
58 : #import "OOCacheManager.h"
59 : #import "OODebugStandards.h"
60 :
61 : static void SwitchLogFile(NSString *name);
62 : static void NoteVerificationStage(NSString *displayName, NSString *stage);
63 : static void OpenLogFile(NSString *name);
64 :
65 : @interface OOOXPVerifier (OOPrivate)
66 :
67 0 : - (id)initWithPath:(NSString *)path;
68 0 : - (void)run;
69 :
70 0 : - (void)setUpLogOverrides;
71 :
72 0 : - (void)registerBaseStages;
73 0 : - (void)buildDependencyGraph;
74 0 : - (void)runStages;
75 :
76 0 : - (BOOL)setUpDependencies:(NSSet *)dependencies
77 : forStage:(OOOXPVerifierStage *)stage;
78 :
79 0 : - (void)setUpDependents:(NSSet *)dependents
80 : forStage:(OOOXPVerifierStage *)stage;
81 :
82 0 : - (void)dumpDebugGraphviz;
83 :
84 : @end
85 :
86 :
87 : @implementation OOOXPVerifier
88 :
89 : /**
90 : * \ingroup cli
91 : * Scans the command line for -verify-oxp or --verify-oxp, followed by a
92 : * path to the oxp to verify.
93 : *
94 : * @return YES or NO
95 : */
96 : + (BOOL)runVerificationIfRequested
97 : {
98 : NSArray *arguments = nil;
99 : NSEnumerator *argEnum = nil;
100 : NSString *arg = nil;
101 : NSString *foundPath = nil;
102 : BOOL exists, isDirectory;
103 : OOOXPVerifier *verifier = nil;
104 : NSAutoreleasePool *pool = nil;
105 :
106 : pool = [[NSAutoreleasePool alloc] init];
107 :
108 : arguments = [[NSProcessInfo processInfo] arguments];
109 :
110 : // Scan for -verify-oxp or --verify-oxp followed by relative path
111 : for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); )
112 : {
113 : if ([arg isEqual:@"-verify-oxp"] || [arg isEqual:@"--verify-oxp"])
114 : {
115 : foundPath = [argEnum nextObject];
116 : if (foundPath == nil)
117 : {
118 : OOLog(@"verifyOXP.noPath", @"***** ERROR: %@ passed without path argument; nothing to verify.", arg);
119 : [pool release];
120 : return YES;
121 : }
122 : foundPath = [foundPath stringByExpandingTildeInPath];
123 : break;
124 : }
125 : }
126 :
127 : if (foundPath == nil)
128 : {
129 : [pool release];
130 : return NO;
131 : }
132 :
133 : // We got a path; does it point to a directory?
134 : exists = [[NSFileManager defaultManager] fileExistsAtPath:foundPath isDirectory:&isDirectory];
135 : if (!exists)
136 : {
137 : OOLog(@"verifyOXP.badPath", @"***** ERROR: no OXP exists at path \"%@\"; nothing to verify.", foundPath);
138 : }
139 : else if (!isDirectory)
140 : {
141 : OOLog(@"verifyOXP.badPath", @"***** ERROR: \"%@\" is a file, not an OXP directory; nothing to verify.", foundPath);
142 : }
143 : else
144 : {
145 : verifier = [[OOOXPVerifier alloc] initWithPath:foundPath];
146 : [pool release];
147 : pool = [[NSAutoreleasePool alloc] init];
148 : [verifier run];
149 : [verifier release];
150 : }
151 : [pool release];
152 :
153 : // Whether or not we got a valid path, -verify-oxp was passed.
154 : return YES;
155 : }
156 :
157 :
158 0 : - (void)dealloc
159 : {
160 : [_verifierPList release];
161 : [_basePath release];
162 : [_displayName release];
163 : [_stagesByName release];
164 : [_waitingStages release];
165 :
166 : [super dealloc];
167 : }
168 :
169 :
170 : - (void)registerStage:(OOOXPVerifierStage *)stage
171 : {
172 : NSString *name = nil;
173 : OOOXPVerifierStage *existing = nil;
174 :
175 : // Sanity checking
176 : if (stage == nil) return;
177 :
178 : if (![stage isKindOfClass:[OOOXPVerifierStage class]])
179 : {
180 : OOLog(@"verifyOXP.registration.failed", @"Attempt to register class %@ as a verifier stage, but it is not a subclass of OOOXPVerifierStage; ignoring.", [stage class]);
181 : return;
182 : }
183 :
184 : if (!_openForRegistration)
185 : {
186 : OOLog(@"verifyOXP.registration.failed", @"Attempt to register verifier stage %@ after registration closed, ignoring.", stage);
187 : return;
188 : }
189 :
190 : name = [stage name];
191 : if (name == nil)
192 : {
193 : OOLog(@"verifyOXP.registration.failed", @"Attempt to register verifier stage %@ with nil name, ignoring.", stage);
194 : return;
195 : }
196 :
197 : // We can only have one stage with a given name. Registering the same stage twice is OK, though.
198 : existing = [_stagesByName objectForKey:name];
199 : if (existing == stage) return;
200 : if (existing != nil)
201 : {
202 : OOLog(@"verifyOXP.registration.failed", @"Attempt to register verifier stage %@ with same name as stage %@, ignoring.", stage, existing);
203 : return;
204 : }
205 :
206 : // Checks passed, store state.
207 : [stage setVerifier:self];
208 : [_stagesByName setObject:stage forKey:name];
209 : [_waitingStages addObject:stage];
210 : }
211 :
212 :
213 : - (NSString *)oxpPath
214 : {
215 : return [[_basePath retain] autorelease];
216 : }
217 :
218 :
219 : - (NSString *)oxpDisplayName
220 : {
221 : return [[_displayName retain] autorelease];
222 : }
223 :
224 :
225 : - (id)stageWithName:(NSString *)name
226 : {
227 : if (name == nil) return nil;
228 :
229 : return [_stagesByName objectForKey:name];
230 : }
231 :
232 :
233 : - (id)configurationValueForKey:(NSString *)key
234 : {
235 : return [_verifierPList objectForKey:key];
236 : }
237 :
238 :
239 : - (NSArray *)configurationArrayForKey:(NSString *)key
240 : {
241 : return [_verifierPList oo_arrayForKey:key];
242 : }
243 :
244 :
245 : - (NSDictionary *)configurationDictionaryForKey:(NSString *)key
246 : {
247 : return [_verifierPList oo_dictionaryForKey:key];
248 : }
249 :
250 :
251 : - (NSString *)configurationStringForKey:(NSString *)key
252 : {
253 : return [_verifierPList oo_stringForKey:key];
254 : }
255 :
256 :
257 : - (NSSet *)configurationSetForKey:(NSString *)key
258 : {
259 : NSArray *array = [_verifierPList oo_arrayForKey:key];
260 : return array != nil ? [NSSet setWithArray:array] : nil;
261 : }
262 :
263 : @end
264 :
265 :
266 : @implementation OOOXPVerifier (OOPrivate)
267 :
268 : - (id)initWithPath:(NSString *)path
269 : {
270 : self = [super init];
271 :
272 : OOSetStandardsForOXPVerifierMode();
273 :
274 : NSString *verifierPListPath = [[[ResourceManager builtInPath] stringByAppendingPathComponent:@"Config"] stringByAppendingPathComponent:@"verifyOXP.plist"];
275 : _verifierPList = [[NSDictionary dictionaryWithContentsOfFile:verifierPListPath] retain];
276 :
277 : _basePath = [path copy];
278 : _displayName = [[NSFileManager defaultManager] displayNameAtPath:_basePath];
279 : if (_displayName == nil) _displayName = [_basePath lastPathComponent];
280 : [_displayName retain];
281 :
282 : _stagesByName = [[NSMutableDictionary alloc] init];
283 : _waitingStages = [[NSMutableSet alloc] init];
284 :
285 : if (_verifierPList == nil ||
286 : _basePath == nil)
287 : {
288 : OOLog(@"verifyOXP.setup.failed", @"%@", @"***** ERROR: failed to set up OXP verifier.");
289 : [self release];
290 : return nil;
291 : }
292 :
293 : _openForRegistration = YES;
294 :
295 : return self;
296 : }
297 :
298 :
299 : - (void)run
300 : {
301 : NoteVerificationStage(_displayName, @"");
302 :
303 : [self setUpLogOverrides];
304 :
305 : /* We need to be able to look up internal files, but not other OXP files.
306 : To do this without clobbering the disk cache, we disable cache writes.
307 : */
308 : [[OOCacheManager sharedCache] flush];
309 : [[OOCacheManager sharedCache] setAllowCacheWrites:NO];
310 : /* FIXME: the OXP verifier should load files from OXPs which have
311 : * been explicitly listed as required_oxps in the
312 : * manifest. Reading the manifest from the OXP being verified and
313 : * setting 'id:<its identifier>' below will do this. */
314 : [ResourceManager setUseAddOns:SCENARIO_OXP_DEFINITION_NONE];
315 :
316 : SwitchLogFile(_displayName);
317 : OOLog(@"verifyOXP.start", @"Running OXP verifier for %@", _basePath);//_displayName);
318 :
319 : [self registerBaseStages];
320 : [self buildDependencyGraph];
321 : [self runStages];
322 :
323 : NoteVerificationStage(_displayName, @"");
324 : OOLog(@"verifyOXP.done", @"%@", @"OXP verification complete.");
325 :
326 : OpenLogFile(_displayName);
327 : }
328 :
329 :
330 : - (void)setUpLogOverrides
331 : {
332 : NSDictionary *overrides = nil;
333 : NSEnumerator *messageClassEnum = nil;
334 : NSString *messageClass = nil;
335 : id verbose = nil;
336 :
337 : OOLogSetShowMessageClassTemporary([_verifierPList oo_boolForKey:@"logShowMessageClassOverride" defaultValue:NO]);
338 :
339 : overrides = [_verifierPList oo_dictionaryForKey:@"logControlOverride"];
340 : for (messageClassEnum = [overrides keyEnumerator]; (messageClass = [messageClassEnum nextObject]); )
341 : {
342 : OOLogSetDisplayMessagesInClass(messageClass, [overrides oo_boolForKey:messageClass defaultValue:NO]);
343 : }
344 :
345 : /* Since actually editing logControlOverride is a pain, we also allow
346 : overriding verifyOXP.verbose through user defaults. This is at least
347 : as much a pain under GNUstep, but very convenient under OS X.
348 : */
349 : verbose = [[NSUserDefaults standardUserDefaults] objectForKey:@"oxp-verifier-verbose-logging"];
350 : if (verbose != nil) OOLogSetDisplayMessagesInClass(@"verifyOXP.verbose", OOBooleanFromObject(verbose, NO));
351 : }
352 :
353 :
354 : - (void)registerBaseStages
355 : {
356 : NSAutoreleasePool *pool = nil;
357 : NSSet *stages = nil;
358 : NSSet *excludeStages = nil;
359 : NSEnumerator *stageEnum = nil;
360 : NSString *stageName = nil;
361 : Class stageClass = Nil;
362 : OOOXPVerifierStage *stage = nil;
363 :
364 : pool = [[NSAutoreleasePool alloc] init];
365 :
366 : // Load stages specified as array of class names in verifyOXP.plist
367 : stages = [self configurationSetForKey:@"stages"];
368 : excludeStages = [self configurationSetForKey:@"excludeStages"];
369 : if ([excludeStages count] != 0)
370 : {
371 : stages = [[stages mutableCopy] autorelease];
372 : [(NSMutableSet *)stages minusSet:excludeStages];
373 : }
374 : for (stageEnum = [stages objectEnumerator]; (stageName = [stageEnum nextObject]); )
375 : {
376 : if ([stageName isKindOfClass:[NSString class]])
377 : {
378 : stageClass = NSClassFromString(stageName);
379 : if (stageClass == Nil)
380 : {
381 : OOLog(@"verifyOXP.registration.failed", @"Attempt to register unknown class %@ as a verifier stage, ignoring.", stageName);
382 : continue;
383 : }
384 : stage = [[stageClass alloc] init];
385 : [self registerStage:stage];
386 : [stage release];
387 : }
388 : }
389 :
390 : [pool release];
391 : }
392 :
393 :
394 : - (void)buildDependencyGraph
395 : {
396 : NSAutoreleasePool *pool = nil;
397 : NSArray *stageKeys = nil;
398 : NSEnumerator *stageEnum = nil;
399 : NSString *stageKey = nil;
400 : OOOXPVerifierStage *stage = nil;
401 : NSString *name = nil;
402 : NSMutableDictionary *dependenciesByStage = nil,
403 : *dependentsByStage = nil;
404 : NSSet *dependencies = nil,
405 : *dependents = nil;
406 : NSValue *key = nil;
407 :
408 : pool = [[NSAutoreleasePool alloc] init];
409 :
410 : /* Iterate over all stages, getting dependency and dependent sets.
411 : This is done in advance so that -dependencies and -dependents may
412 : register stages.
413 : */
414 : dependenciesByStage = [NSMutableDictionary dictionary];
415 : dependentsByStage = [NSMutableDictionary dictionary];
416 :
417 : for (;;)
418 : {
419 : /* Loop while there are stages whose dependency lists haven't been
420 : checked. This is an indeterminate loop since new ones can be
421 : added.
422 : */
423 : stage = [_waitingStages anyObject];
424 : if (stage == nil) break;
425 : [_waitingStages removeObject:stage];
426 :
427 : key = [NSValue valueWithNonretainedObject:stage];
428 :
429 : dependencies = [stage dependencies];
430 : if (dependencies != nil)
431 : {
432 : [dependenciesByStage setObject:dependencies
433 : forKey:key];
434 : }
435 :
436 : dependents = [stage dependents];
437 : if (dependents != nil)
438 : {
439 : [dependentsByStage setObject:dependents
440 : forKey:key];
441 : }
442 : }
443 : [_waitingStages release];
444 : _waitingStages = nil;
445 : _openForRegistration = NO;
446 :
447 : // Iterate over all stages, resolving dependencies.
448 : stageKeys = [_stagesByName allKeys]; // Get the keys up front because we may need to remove entries from dictionary.
449 :
450 : for (stageEnum = [stageKeys objectEnumerator]; (stageKey = [stageEnum nextObject]); )
451 : {
452 : stage = [_stagesByName objectForKey:stageKey];
453 : if (stage == nil) continue;
454 :
455 : // Sanity check
456 : name = [stage name];
457 : if (![stageKey isEqualToString:name])
458 : {
459 : OOLog(@"verifyOXP.buildDependencyGraph.badName", @"***** Stage name appears to have changed from \"%@\" to \"%@\" for verifier stage %@, removing.", stageKey, name, stage);
460 : [_stagesByName removeObjectForKey:stageKey];
461 : continue;
462 : }
463 :
464 : // Get dependency set
465 : key = [NSValue valueWithNonretainedObject:stage];
466 : dependencies = [dependenciesByStage objectForKey:key];
467 :
468 : if (dependencies != nil && ![self setUpDependencies:dependencies forStage:stage])
469 : {
470 : [_stagesByName removeObjectForKey:stageKey];
471 : }
472 : }
473 :
474 : /* Iterate over all stages again, resolving reverse dependencies.
475 : This is done in a separate pass because reverse dependencies are "weak"
476 : while forward dependencies are "strong".
477 : */
478 : stageKeys = [_stagesByName allKeys];
479 :
480 : for (stageEnum = [stageKeys objectEnumerator]; (stageKey = [stageEnum nextObject]); )
481 : {
482 : stage = [_stagesByName objectForKey:stageKey];
483 : if (stage == nil) continue;
484 :
485 : // Get dependent set
486 : key = [NSValue valueWithNonretainedObject:stage];
487 : dependents = [dependentsByStage objectForKey:key];
488 :
489 : if (dependents != nil)
490 : {
491 : [self setUpDependents:dependents forStage:stage];
492 : }
493 : }
494 :
495 : _waitingStages = [[NSMutableSet alloc] initWithArray:[_stagesByName allValues]];
496 : [_waitingStages makeObjectsPerformSelector:@selector(dependencyRegistrationComplete)];
497 :
498 : if ([[NSUserDefaults standardUserDefaults] boolForKey:@"oxp-verifier-dump-debug-graphviz"])
499 : {
500 : [self dumpDebugGraphviz];
501 : }
502 :
503 : [pool release];
504 : }
505 :
506 :
507 : - (void)runStages
508 : {
509 : NSAutoreleasePool *pool = nil;
510 : NSEnumerator *stageEnum = nil;
511 : OOOXPVerifierStage *candidateStage = nil,
512 : *stageToRun = nil;
513 : NSString *stageName = nil;
514 :
515 : // Loop while there are still stages to run.
516 : for (;;)
517 : {
518 : pool = [[NSAutoreleasePool alloc] init];
519 :
520 : // Look through queue for a stage that's ready
521 : stageToRun = nil;
522 : for (stageEnum = [_waitingStages objectEnumerator]; (candidateStage = [stageEnum nextObject]); )
523 : {
524 : if ([candidateStage canRun])
525 : {
526 : stageToRun = candidateStage;
527 : break;
528 : }
529 : }
530 : if (stageToRun == nil)
531 : {
532 : // No more runnable stages
533 : [pool release];
534 : break;
535 : }
536 :
537 : stageName = nil;
538 : OOLogPushIndent();
539 : @try
540 : {
541 : stageName = [stageToRun name];
542 : if ([stageToRun shouldRun])
543 : {
544 : NoteVerificationStage(_displayName, stageName);
545 : OOLog(@"verifyOXP.runStage", @"%@", stageName);
546 : OOLogIndent();
547 : [stageToRun performRun];
548 : }
549 : else
550 : {
551 : OOLog(@"verifyOXP.verbose.skipStage", @"- Skipping stage: %@ (nothing to do).", stageName);
552 : [stageToRun noteSkipped];
553 : }
554 : }
555 : @catch (NSException *exception)
556 : {
557 : if (stageName == nil) stageName = [[stageToRun class] description];
558 : OOLog(@"verifyOXP.exception", @"***** Exception occurred when running OXP verifier stage \"%@\": %@: %@", stageName, [exception name], [exception reason]);
559 : }
560 : OOLogPopIndent();
561 :
562 : [_waitingStages removeObject:stageToRun];
563 : [pool release];
564 : }
565 :
566 : pool = [[NSAutoreleasePool alloc] init];
567 :
568 : if ([_waitingStages count] != 0)
569 : {
570 : OOLog(@"verifyOXP.incomplete", @"%@", @"Some verifier stages could not be run:");
571 : OOLogIndent();
572 : for (stageEnum = [_waitingStages objectEnumerator]; (candidateStage = [stageEnum nextObject]); )
573 : {
574 : OOLog(@"verifyOXP.incomplete.item", @"%@", candidateStage);
575 : }
576 : OOLogOutdent();
577 : }
578 : [_waitingStages release];
579 : _waitingStages = nil;
580 :
581 : [pool release];
582 : }
583 :
584 :
585 : - (BOOL)setUpDependencies:(NSSet *)dependencies
586 : forStage:(OOOXPVerifierStage *)stage
587 : {
588 : NSString *depName = nil;
589 : NSEnumerator *depEnum = nil;
590 : OOOXPVerifierStage *depStage = nil;
591 :
592 : // Iterate over dependencies, connecting them up.
593 : for (depEnum = [dependencies objectEnumerator]; (depName = [depEnum nextObject]); )
594 : {
595 : depStage = [_stagesByName objectForKey:depName];
596 : if (depStage == nil)
597 : {
598 : OOLog(@"verifyOXP.buildDependencyGraph.unresolved", @"Verifier stage %@ has unresolved dependency \"%@\", skipping.", stage, depName);
599 : return NO;
600 : }
601 :
602 : if ([depStage isDependentOf:stage])
603 : {
604 : OOLog(@"verifyOXP.buildDependencyGraph.circularReference", @"Verifier stages %@ and %@ have a dependency loop, skipping.", stage, depStage);
605 : [_stagesByName removeObjectForKey:depName];
606 : return NO;
607 : }
608 :
609 : [stage registerDependency:depStage];
610 : }
611 :
612 : return YES;
613 : }
614 :
615 :
616 : - (void)setUpDependents:(NSSet *)dependents
617 : forStage:(OOOXPVerifierStage *)stage
618 : {
619 : NSString *depName = nil;
620 : NSEnumerator *depEnum = nil;
621 : OOOXPVerifierStage *depStage = nil;
622 :
623 : // Iterate over dependents, connecting them up.
624 : for (depEnum = [dependents objectEnumerator]; (depName = [depEnum nextObject]); )
625 : {
626 : depStage = [_stagesByName objectForKey:depName];
627 : if (depStage == nil)
628 : {
629 : OOLog(@"verifyOXP.buildDependencyGraph.unresolved", @"Verifier stage %@ has unresolved dependent \"%@\".", stage, depName);
630 : continue; // Unresolved/conflicting dependents are non-fatal
631 : }
632 :
633 : if ([stage isDependentOf:depStage])
634 : {
635 : OOLog(@"verifyOXP.buildDependencyGraph.circularReference", @"Verifier stage %@ lists %@ as both dependent and dependency (possibly indirectly); will execute %@ after %@.", stage, depStage, stage, depStage);
636 : continue;
637 : }
638 :
639 : [depStage registerDependency:stage];
640 : }
641 : }
642 :
643 :
644 : - (void)dumpDebugGraphviz
645 : {
646 : NSMutableString *graphViz = nil;
647 : NSDictionary *graphVizTemplate = nil;
648 : NSString *template = nil,
649 : *startTemplate = nil,
650 : *endTemplate = nil;
651 : NSEnumerator *stageEnum = nil;
652 : OOOXPVerifierStage *stage = nil;
653 : NSSet *deps = nil;
654 : NSEnumerator *depEnum = nil;
655 : OOOXPVerifierStage *dep = nil;
656 :
657 : graphVizTemplate = [self configurationDictionaryForKey:@"debugGraphvizTempate"];
658 : graphViz = [NSMutableString stringWithFormat:[graphVizTemplate oo_stringForKey:@"preamble"], [NSDate date]];
659 :
660 : /* Pass 1: enumerate over graph setting node attributes for each stage.
661 : We use pointers as node names for simplicity of generation.
662 : */
663 : template = [graphVizTemplate oo_stringForKey:@"node"];
664 : for (stageEnum = [_stagesByName objectEnumerator]; (stage = [stageEnum nextObject]); )
665 : {
666 : [graphViz appendFormat:template, stage, [stage class], [stage name]];
667 : }
668 :
669 : [graphViz appendString:[graphVizTemplate oo_stringForKey:@"forwardPreamble"]];
670 :
671 : /* Pass 2: enumerate over graph setting forward arcs for each dependency.
672 : */
673 : template = [graphVizTemplate oo_stringForKey:@"forwardArc"];
674 : startTemplate = [graphVizTemplate oo_stringForKey:@"startArc"];
675 : for (stageEnum = [_stagesByName objectEnumerator]; (stage = [stageEnum nextObject]); )
676 : {
677 : deps = [stage resolvedDependencies];
678 : if ([deps count] != 0)
679 : {
680 : for (depEnum = [deps objectEnumerator]; (dep = [depEnum nextObject]); )
681 : {
682 : [graphViz appendFormat:template, dep, stage];
683 : }
684 : }
685 : else
686 : {
687 : [graphViz appendFormat:startTemplate, stage];
688 : }
689 : }
690 :
691 : [graphViz appendString:[graphVizTemplate oo_stringForKey:@"backwardPreamble"]];
692 :
693 : /* Pass 3: enumerate over graph setting backward arcs for each dependent.
694 : */
695 : template = [graphVizTemplate oo_stringForKey:@"backwardArc"];
696 : endTemplate = [graphVizTemplate oo_stringForKey:@"endArc"];
697 : for (stageEnum = [_stagesByName objectEnumerator]; (stage = [stageEnum nextObject]); )
698 : {
699 : deps = [stage resolvedDependents];
700 : if ([deps count] != 0)
701 : {
702 : for (depEnum = [deps objectEnumerator]; (dep = [depEnum nextObject]); )
703 : {
704 : [graphViz appendFormat:template, dep, stage];
705 : }
706 : }
707 : else
708 : {
709 : [graphViz appendFormat:endTemplate, stage];
710 : }
711 : }
712 :
713 : [graphViz appendString:[graphVizTemplate oo_stringForKey:@"postamble"]];
714 :
715 : // Write file
716 : [ResourceManager writeDiagnosticString:graphViz toFileNamed:@"OXPVerifierStageDependencies.dot"];
717 : }
718 :
719 : @end
720 :
721 :
722 : #import "OOLogOutputHandler.h"
723 :
724 :
725 0 : static void SwitchLogFile(NSString *name)
726 : {
727 : //#ifndef OOLITE_LINUX
728 : name = [name stringByAppendingPathExtension:@"log"];
729 : OOLog(@"verifyOXP.switchingLog", @"Switching log files -- logging to \"%@\".", name);
730 : OOLogOutputHandlerChangeLogFile(name);
731 : //#else
732 : // OOLog(@"verifyOXP.switchingLog", @"Switching logging to <stdout>.");
733 : // OOLogOutputHandlerStartLoggingToStdout();
734 : //#endif
735 : }
736 :
737 :
738 0 : static void NoteVerificationStage(NSString *displayName, NSString *stage)
739 : {
740 : [[GameController sharedController] logProgress:[NSString stringWithFormat:@"Verifying %@\n%@", displayName, stage]];
741 : }
742 :
743 :
744 0 : static void OpenLogFile(NSString *name)
745 : {
746 : // Open log file in appropriate application / provide feedback.
747 :
748 : if ([[NSUserDefaults standardUserDefaults] oo_boolForKey:@"oxp-verifier-open-log" defaultValue:YES])
749 : {
750 : #if OOLITE_MAC_OS_X
751 : [[NSWorkspace sharedWorkspace] openFile:OOLogHandlerGetLogPath()];
752 : #elif OOLITE_WINDOWS
753 : // identify the application set by the OS as the default app for opening .log files
754 : // in case anything goes wrong, fall back to opening the log file in Motepad
755 : DWORD dwSize = MAX_PATH;
756 : TCHAR applicationPath[MAX_PATH] = TEXT("notepad");
757 : HRESULT hr = AssocQueryString (0, //ASSOCF_NONE
758 : ASSOCSTR_EXECUTABLE,
759 : _T(".log"),
760 : _T("open"),
761 : applicationPath,
762 : &dwSize);
763 :
764 : if (FAILED (hr))
765 : {
766 : OOLog(@"OXP Verifier", @"Could not find application for opening .log files - using Notepad by default.");
767 : }
768 :
769 : // open the log file
770 : system([[NSString stringWithFormat:@"start \"\" \"%s\" \"Logs\\%@.log\"", applicationPath, name] UTF8String]);
771 : #elif OOLITE_LINUX
772 : // MKW - needed to suppress 'ignoring return value' warning for system() call
773 : // int ret;
774 : // CIM - and now the compiler complains about that too... casting return
775 : // value to void seems to keep it quiet for now
776 : // Nothing to do here, since we dump to stdout instead of to a file.
777 : //OOLogOutputHandlerStopLoggingToStdout();
778 : (void) system([[NSString stringWithFormat:@"cat \"%@\"", OOLogHandlerGetLogPath()] UTF8String]);
779 : #else
780 : do {} while (0);
781 : #endif
782 : }
783 : }
784 :
785 :
786 : #endif // OO_OXP_VERIFIER_ENABLED
|