diff --git a/ChangeLog b/ChangeLog index ca4652ced..fbd8b412f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,7 +18,11 @@ Thu Jan 3 19:38:42 2002 Nicola Pero * Header/Foundation/GSXML.h: Correction standards complience * Source/GSXML.m: A few documentation tidyups - * Tools/autogsdoc.m: Some tidyups for improved performance. + * Tools/autogsdoc.m: Some tidyups for improved performance + and added code to relocate html documents. + * Source/AGSIndex.[hm]: Minor API change to ease index handling, + bugfix for class index generation. + * Source/AGSHtml.m: Made index handling more consistent. 2002-01-02 Adam Fedor diff --git a/Tools/AGSHtml.m b/Tools/AGSHtml.m index 61db591c4..fa0a0645a 100644 --- a/Tools/AGSHtml.m +++ b/Tools/AGSHtml.m @@ -149,7 +149,7 @@ static NSMutableSet *textNodes = nil; isRef: (BOOL)f { NSString *s; - NSString *kind = (f == YES) ? @"href" : @"name"; + NSString *kind = (f == YES) ? @"rel=\"gsdoc\" href" : @"name"; NSString *hash = (f == YES) ? @"#" : @""; if (f == NO || (s = [localRefs globalRef: r type: t]) != nil) @@ -172,8 +172,6 @@ static NSMutableSet *textNodes = nil; * the html element is returned (<a ...>).
* If the boolean f is YES, then the link is a reference to somewhere, * otherwise the link is an anchor for some element being output.
- * The method will try to infer the unit in which the element was - * defined if the value of u is nil.
* If there is an error, the method returns nil. */ - (NSString*) makeLink: (NSString*)r @@ -182,110 +180,60 @@ static NSMutableSet *textNodes = nil; isRef: (BOOL)f { NSString *s = nil; - BOOL isLocal = YES; - NSString *kind = (f == YES) ? @"href" : @"name"; + NSString *kind = (f == YES) ? @"rel=\"gsdoc\" href" : @"name"; NSString *hash = (f == YES) ? @"#" : @""; - /* - * No unit specified ... try to infer it. - */ - if (u == nil) + if (f == YES) { - /* - * If we are currently inside a class, category, or protocol - * we see if the required item exists in that unit and if so, - * we assume that this is the unit to be used. - */ - if (unit != nil) + if (u == nil) { - s = [localRefs unitRef: r type: t unit: unit]; - if (s != nil) - { - u = unit; - } - else - { - NSString *x = unit; - - /* - * Try stepping up superclasses until we find a match. - */ - while (x != nil) - { - x = [localRefs globalRef: x type: @"super"]; - if (x != nil) - { - s = [localRefs unitRef: r type: t unit: x]; - if (s != nil) - { - u = x; - break; - } - } - } - } + u = unit; } - /* - * If we are making a reference, and we have not found it in the - * current unit, we check all known references to see if the item - * is uniquely documented somewhere. - */ - if (u == nil && f == YES) + s = base; + } + else if (u == nil) + { + u = unit; + s = [localRefs unitRef: r type: t unit: &u]; + if (s == nil) { - NSDictionary *d; - - d = [localRefs unitRef: r type: t]; - if ([d count] == 0) - { - isLocal = NO; - d = [globalRefs unitRef: r type: t]; - } - if ([d count] == 1) - { - /* - * Record the class where the item is documented - * and the file where that documentation occurs. - */ - u = [[d allKeys] objectAtIndex: 0]; - s = [d objectForKey: u]; - } + u = unit; + s = [globalRefs unitRef: r type: t unit: &u]; } } else { + NSString *tmp = u; + /* * Simply look up the reference. */ - s = [localRefs unitRef: r type: t unit: u]; - if (s == nil && f == YES) + s = [localRefs unitRef: r type: t unit: &u]; + if (s == nil) { - isLocal = NO; - s = [globalRefs unitRef: r type: t unit: u]; + u = tmp; + s = [globalRefs unitRef: r type: t unit: &u]; } } - /** - * There are only two types of unit specific element ... methods - * and instance variables. The names within a unit are unique - * since you can't have two methods or two variables with the - * same name in a unit, and all method names contain either a - * a plus or minus as a prefix, while no variables do.
- * This means that we do not need to incorporate any type - * information into anchors and references for methods or - * instance varibales. - */ if (s != nil) { - if (isLocal == YES) + NSString *sep = @""; + + if ([t isEqual: @"ivariable"] == YES) { - s = [NSString stringWithFormat: @"", - kind, hash, u, r]; + sep = @"*"; + } + if ([s isEqual: base] == YES) + { + s = [NSString stringWithFormat: @"", + kind, hash, t, u, sep, r]; } else { s = [s stringByAppendingPathExtension: @"html"]; - s = [NSString stringWithFormat: @"", - kind, s, hash, u, r]; + s = [NSString stringWithFormat: @"", + kind, s, hash, t, u, sep, r]; } } return s; @@ -822,7 +770,12 @@ static NSMutableSet *textNodes = nil; NSArray *a = [dict allKeys]; unsigned c = [a count]; unsigned i; + NSString *sep = @""; + if ([type isEqual: @"ivariable"]) + { + sep = @"*"; + } a = [a sortedArrayUsingSelector: @selector(compare:)]; [buf appendString: indent]; @@ -850,9 +803,10 @@ static NSMutableSet *textNodes = nil; NSString *file = [units objectForKey: u]; [buf appendString: indent]; - [buf appendFormat: - @"
  • %@ in %@
  • \n", - file, u, ref, ref, u]; + [buf appendFormat: @"
  • ", + file, type, u, sep, ref]; + [buf appendFormat: @"%@ in %@
  • \n", ref, u]; } } else @@ -877,8 +831,8 @@ static NSMutableSet *textNodes = nil; } [buf appendString: indent]; - [buf appendFormat: - @"
  • %@
  • \n", + [buf appendString: @"
  • %@
  • \n", file, type, ref, text]; } } diff --git a/Tools/AGSIndex.h b/Tools/AGSIndex.h index 1e9e7aab1..352e5e131 100644 --- a/Tools/AGSIndex.h +++ b/Tools/AGSIndex.h @@ -43,6 +43,6 @@ - (void) setGlobalRef: (NSString*)ref type: (NSString*)type; - (void) setUnitRef: (NSString*)ref type: (NSString*)type; - (NSDictionary*) unitRef: (NSString*)ref type: (NSString*)type; -- (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString*)u; +- (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString**)u; @end #endif diff --git a/Tools/AGSIndex.m b/Tools/AGSIndex.m index 76d101e32..9c77000d8 100644 --- a/Tools/AGSIndex.m +++ b/Tools/AGSIndex.m @@ -205,7 +205,7 @@ setDirectory(NSMutableDictionary *dict, NSString *path) unit = [NSString stringWithFormat: @"%@(%@)", [prop objectForKey: @"class"], [prop objectForKey: @"name"]]; - [self setGlobalRef: unit type: name]; + [self setGlobalRef: unit type: @"category"]; } else if ([name isEqual: @"chapter"] == YES) { @@ -234,6 +234,7 @@ setDirectory(NSMutableDictionary *dict, NSString *path) } [t setObject: tmp forKey: unit]; } + [self setGlobalRef: unit type: @"class"]; } else if ([name isEqual: @"gsdoc"] == YES) { @@ -355,7 +356,7 @@ setDirectory(NSMutableDictionary *dict, NSString *path) newUnit = YES; unit = [NSString stringWithFormat: @"(%@)", [prop objectForKey: @"name"]]; - [self setGlobalRef: unit type: name]; + [self setGlobalRef: unit type: @"protocol"]; } else if ([name isEqual: @"constant"] == YES || [name isEqual: @"EOEntity"] == YES @@ -515,6 +516,10 @@ setDirectory(NSMutableDictionary *dict, NSString *path) [r setObject: base forKey: unit]; } +/** + * Return a dictionary containing info on all the units containing the + * specified method or instance variable. + */ - (NSDictionary*) unitRef: (NSString*)ref type: (NSString*)type { NSDictionary *t; @@ -523,13 +528,79 @@ setDirectory(NSMutableDictionary *dict, NSString *path) return [t objectForKey: ref]; } -- (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString*)u +/** + * Return the name of the file containing the ref and return + * the unit name in which it was found. If not found, return nil for both. + */ +- (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString**)u { + NSString *s; NSDictionary *t; - t = [refs objectForKey: type]; - t = [t objectForKey: ref]; - return [t objectForKey: u]; + /** + * If ref does not occur in the index, this method returns nil. + */ + t = [self unitRef: ref type: type]; + if (t == nil) + { + *u = nil; + return nil; + } + + if (*u == nil) + { + /** + * If the method was given no unit to look in, then it will succeed + * and return a value if (and only if) the required reference is + * defined only in one unit. + */ + if ([t count] == 1) + { + *u = [[t allKeys] lastObject]; + return [t objectForKey: *u]; + } + return nil; + } + + /** + * If ref exists in the unit specified, the method will succeed and + * return the name of the file in which the reference is located. + */ + s = [t objectForKey: *u]; + if (s != nil) + { + return s; + } + + /** + * If the unit that the method has been asked to look in is a + * category or protocol which is not found, the lookup must fail. + */ + if ([t objectForKey: *u] == nil + && ([*u length] == 0 || [*u characterAtIndex: [*u length] - 1] == ')')) + { + *u = nil; + return nil; + } + + /** + * If the unit is a class, and ref was not found in it, then this + * method will succeed if ref can be found in any superclass of the class. + */ + while (*u != nil) + { + *u = [self globalRef: *u type: @"super"]; + if (*u != nil) + { + s = [t objectForKey: *u]; + if (s != nil) + { + return s; + } + } + } + + return nil; } @end diff --git a/Tools/autogsdoc.m b/Tools/autogsdoc.m index 3912becaa..2fc43d2e1 100644 --- a/Tools/autogsdoc.m +++ b/Tools/autogsdoc.m @@ -353,6 +353,7 @@ main(int argc, char **argv, char **env) BOOL modifiedRefs = NO; NSDate *rDate = nil; NSMutableArray *files = nil; + NSMutableArray *hFiles = nil; CREATE_AUTORELEASE_POOL(outer); CREATE_AUTORELEASE_POOL(pool); @@ -447,6 +448,7 @@ main(int argc, char **argv, char **env) * Build an array of files to be processed. */ files = AUTORELEASE([[proc arguments] mutableCopy]); + hFiles = [NSMutableArray array]; [files removeObjectAtIndex: 0]; for (i = 0; i < [files count]; i++) { @@ -463,13 +465,21 @@ main(int argc, char **argv, char **env) && [arg hasSuffix: @".m"] == NO && [arg hasSuffix: @".gsdoc"] == NO) { - // Skip this value ... not a known file type. - NSLog(@"Unknown argument '%@' ... ignored", arg); + if ([arg hasSuffix: @".html"] == YES) + { + // Make a note of any html files found. + [hFiles addObject: [files objectAtIndex: i]]; + } + else + { + // Skip this value ... not a known file type. + NSLog(@"Unknown argument '%@' ... ignored", arg); + } [files removeObjectAtIndex: i]; i--; } } - if ([files count] < 1) + if ([files count] < 1 && [hFiles count] < 1) { NSLog(@"No filename arguments found ... giving up"); return 1; @@ -829,13 +839,14 @@ main(int argc, char **argv, char **env) RELEASE(pool); - if (generateHtml == YES) + /* + * If we are either generating html output, or relocating existing + * html documents, we must build up the indexing information needed + * for any cross-referencing etc. + */ + if (generateHtml == YES || [hFiles count] > 0) { - /* - * Second pass ... generate html output from gsdoc files. - */ pool = [NSAutoreleasePool new]; - /* * Merge any external project references into the * main cross reference index. @@ -967,6 +978,13 @@ main(int argc, char **argv, char **env) [globalRefs mergeRefs: [projectRefs refs] override: YES]; RELEASE(pool); + } + + /* + * Next pass ... generate html output from gsdoc files if required. + */ + if (generateHtml == YES) + { pool = [NSAutoreleasePool new]; for (i = 0; i < [files count]; i++) @@ -1083,6 +1101,187 @@ main(int argc, char **argv, char **env) RELEASE(pool); } + /* + * Relocate existing html documents if required ... adjust all cross + * referencing within those documents. + */ + if ([hFiles count] > 0) + { + pool = [NSAutoreleasePool new]; + + for (i = 0; i < [hFiles count]; i++) + { + NSString *file = [hFiles objectAtIndex: i]; + NSString *src; + NSString *dst; + NSString *sdir; + NSString *ddir; + + if (pool != nil) + { + RELEASE(pool); + pool = [NSAutoreleasePool new]; + } + file = [file lastPathComponent]; + sdir = sourceDirectory; + ddir = documentationDirectory; + + src = [sdir stringByAppendingPathComponent: file]; + dst = [ddir stringByAppendingPathComponent: file]; + + /* + * If we can't find the file in the source directory, assume + * it is in the ddocumentation directory already, and just needs + * cross-refs rebuilding. + */ + if ([mgr isReadableFileAtPath: src] == NO) + { + src = dst; + } + + if ([mgr isReadableFileAtPath: src] == YES) + { + NSMutableString *s; + NSRange r; + unsigned l; + unsigned p; + AGSHtml *html; + + html = AUTORELEASE([AGSHtml new]); + [html setGlobalRefs: globalRefs]; + [html setProjectRefs: projectRefs]; + [html setLocalRefs: nil]; + + s = [NSMutableString stringWithContentsOfFile: src]; + l = [s length]; + p = 0; + r = NSMakeRange(p, l); + r = [s rangeOfString: @" 0) + { + NSRange replace; + NSString *repstr; + NSString *href; + NSString *type; + NSString *unit = nil; + + replace.location = r.location; + p = NSMaxRange(r); + + r = [s rangeOfString: @"\">" + options: NSLiteralSearch + range: NSMakeRange(p, l - p)]; + if (r.length == 0) + { + NSLog(@"Unterminated gsdoc rel at %u", p); + break; + } + else + { + replace = NSMakeRange(replace.location, + r.location - replace.location); + href = [s substringWithRange: + NSMakeRange(p, r.location - p)]; + p = NSMaxRange(replace); + } + + /* + * Skip past the '#' to the local reference. + */ + r = [href rangeOfString: @"#" + options: NSLiteralSearch]; + if (r.length == 0) + { + NSLog(@"Missing '#' in href at %u", replace.location); + break; + } + href = [href substringFromIndex: NSMaxRange(r)]; + + /* + * Split out the reference type information. + */ + r = [href rangeOfString: @"$" + options: NSLiteralSearch]; + if (r.length == 0) + { + NSLog(@"Missing '$' in href at %u", replace.location); + break; + } + type = [href substringToIndex: r.location]; + href = [href substringFromIndex: NSMaxRange(r)]; + + /* + * Parse unit name from method or instance variable link. + */ + if ([type isEqual: @"method"] == YES + || [type isEqual: @"ivariable"] == YES) + { + if ([type isEqual: @"method"] == YES) + { + r = [href rangeOfString: @"-" + options: NSLiteralSearch]; + if (r.length == 0) + { + r = [href rangeOfString: @"+" + options: NSLiteralSearch]; + } + if (r.length > 0) + { + unit = [href substringToIndex: r.location]; + href = [href substringFromIndex: NSMaxRange(r)-1]; + } + } + else + { + r = [href rangeOfString: @"*" + options: NSLiteralSearch]; + if (r.length > 0) + { + unit = [href substringToIndex: r.location]; + href = [href substringFromIndex: NSMaxRange(r)]; + } + } + if (unit == nil) + { + NSLog(@"Missing unit name terminator at %u", + replace.location); + break; + } + } + if (unit == nil) + { + repstr = [html makeLink: href + ofType: type + isRef: YES]; + } + else + { + repstr = [html makeLink: href + ofType: type + inUnit: unit + isRef: YES]; + } + if (repstr != nil) + { + p += ([repstr length] - replace.length); + [s replaceCharactersInRange: replace withString: repstr]; + } + + r = [s rangeOfString: @"