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