From 16afaed1afbcdd2fa1880dfc2940d8deeb99b564 Mon Sep 17 00:00:00 2001 From: CaS Date: Tue, 8 Jan 2002 17:31:38 +0000 Subject: [PATCH] lots of autogsdoc improvements. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@12049 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 20 +++ Tools/AGSHtml.h | 2 + Tools/AGSHtml.m | 316 +++++++++++++++++++++++-------------- Tools/AGSIndex.h | 9 +- Tools/AGSIndex.m | 99 +++++++----- Tools/AGSOutput.h | 1 + Tools/AGSOutput.m | 45 ++++++ Tools/AGSParser.h | 30 ++-- Tools/AGSParser.m | 358 +++++++++++++++++++++++++++++++++++------- Tools/autogsdoc.m | 16 +- Tools/gsdoc-0_6_7.dtd | 10 +- 11 files changed, 669 insertions(+), 237 deletions(-) diff --git a/ChangeLog b/ChangeLog index f85f4d0e0..9aa870be5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2002-01-08 Richard Frith-Macdonald + + * Tools/AGSHtml.h: + * Tools/AGSHtml.m: + * Tools/AGSIndex.h: + * Tools/AGSIndex.m: + * Tools/AGSOutput.h: + * Tools/AGSOutput.m: + * Tools/AGSParser.h: + * Tools/AGSParser.m: + * Tools/autogsdoc.m: + * Tools/gsdoc-0_6_7.dtd: + Updated for several changes ... + Support documentation of instance variables + Index class and category method names identically + Extend index to have a listing of methods by unit + Extend index to have a listing of ivariablese by class + Use new extensions to double speed of generation of method + indexes for classes. + 2002-01-07 Adam Fedor * Version: 1.1.0 diff --git a/Tools/AGSHtml.h b/Tools/AGSHtml.h index 7c96c3f3c..4a703de6c 100644 --- a/Tools/AGSHtml.h +++ b/Tools/AGSHtml.h @@ -32,6 +32,8 @@ NSMutableString *indent; NSString *base; // Not retained NSString *unit; // Not retained + NSString *category; // Not retained + NSString *classname; // Not retained NSString *heading; // Not retained NSString *nextFile; // Not retained NSString *prevFile; // Not retained diff --git a/Tools/AGSHtml.m b/Tools/AGSHtml.m index c5c11178c..2ac38ca63 100644 --- a/Tools/AGSHtml.m +++ b/Tools/AGSHtml.m @@ -193,11 +193,25 @@ static NSMutableSet *textNodes = nil; } else if (u == nil) { - u = unit; + if (category == nil) + { + u = unit; + } + else + { + u = classname; + } s = [localRefs unitRef: r type: t unit: &u]; if (s == nil) { - u = unit; + if (category == nil) + { + u = unit; + } + else + { + u = classname; + } s = [globalRefs unitRef: r type: t unit: &u]; } } @@ -264,65 +278,127 @@ static NSMutableSet *textNodes = nil; title: (NSString*)title to: (NSMutableString*)buf { - NSDictionary *dict = [localRefs refs]; + NSDictionary *refs = [localRefs refs]; + NSDictionary *dict; + NSArray *a; + unsigned c; + unsigned i; if (globalRefs != nil && [scope isEqual: @"global"] == YES) { - dict = [globalRefs refs]; + refs = [globalRefs refs]; } else if (projectRefs != nil && [scope isEqual: @"project"] == YES) { - dict = [projectRefs refs]; + refs = [projectRefs refs]; } - dict = [dict objectForKey: type]; - if ([dict count] > 1 - || ([dict count] > 0 && [type isEqual: @"title"] == NO)) + if ([type isEqualToString: @"method"] == YES) + { + if (unit == nil) + { + refs = nil; // Can't index methods outside a unit. + } + dict = [refs objectForKey: @"unitmethods"]; + dict = [dict objectForKey: unit]; + } + else if ([type isEqualToString: @"ivariable"] == YES) + { + if (unit == nil) + { + refs = nil; // Can't index instance variables outside a class. + } + dict = [refs objectForKey: @"classvars"]; + dict = [dict objectForKey: unit]; + } + else + { + dict = [refs objectForKey: type]; + } + + if ([dict count] > 1 && [type isEqual: @"title"] == YES) + { + [buf appendString: indent]; + [buf appendFormat: @"%@\n", title]; + [buf appendString: indent]; + [buf appendString: @"
    \n"]; + [self incIndent]; + + a = [dict allKeys]; + a = [a sortedArrayUsingSelector: @selector(compare:)]; + c = [a count]; + + for (i = 0; i < c; i++) + { + NSString *ref = [a objectAtIndex: i]; + NSString *text = [dict objectForKey: ref]; + NSString *file = ref; + + if ([file isEqual: base] == YES) + { + continue; // Don't list current file. + } + + [buf appendString: indent]; + [buf appendString: @"
  • %@
  • \n", + file, type, ref, text]; + } + + [self decIndent]; + [buf appendString: indent]; + [buf appendString: @"
\n"]; + } + else if ([dict count] > 0) { - NSArray *a = [dict allKeys]; - unsigned c = [a count]; - NSMutableSet *unitNames = nil; - unsigned i; NSString *sep = @""; + NSString *u = unit; BOOL isInUnit = NO; - if ([type isEqual: @"method"] || [type isEqual: @"ivariable"]) + if (unit != nil) { - isInUnit = YES; - if ([type isEqual: @"ivariable"]) + if ([type isEqual: @"method"] || [type isEqual: @"ivariable"]) { - sep = @"*"; - } - else if (unit != nil) - { - /* - * Create a mutable set containing the unit name. - */ - unitNames = [NSMutableSet setWithObject: unit]; - /* - * if the unit is a class, add all its categories to the set. - */ - if ([unit hasSuffix: @")"] == NO) + isInUnit = YES; + if ([type isEqual: @"ivariable"]) { - NSArray *categoryNames; - unsigned l = [unit length]; + sep = @"*"; // List ivars in class + } + else if (category != nil) + { + u = classname; // List methods in category + } + else if (classname != nil) + { + NSArray *catNames; - categoryNames = [[dict objectForKey: @"category"] allKeys]; - i = [categoryNames count]; - while (i-- > 0) + /* + * For a clss, we want to list methods in any associated + * categories as well as those of the class itsself. + */ + catNames = [[[refs objectForKey: @"categories"] + objectForKey: classname] allKeys]; + if ((c = [catNames count]) > 0) { - NSString *n = [categoryNames objectAtIndex: i]; + NSMutableDictionary *m = [dict mutableCopy]; + NSDictionary *unitDict; - if ([n hasPrefix: unit] == YES && [n length] > l - && [n characterAtIndex: i] == '(') + unitDict = [refs objectForKey: @"unitmethods"]; + for (i = 0; i < c; i++) { - [unitNames addObject: n]; + NSString *catName = [catNames objectAtIndex: i]; + NSDictionary *catDict; + + catName = [classname stringByAppendingFormat: @"(%@)", + catName]; + catDict = [unitDict objectForKey: catName]; + [m addEntriesFromDictionary: catDict]; } + dict = AUTORELEASE(m); } } } } - a = [a sortedArrayUsingSelector: @selector(compare:)]; [buf appendString: indent]; [buf appendFormat: @"%@\n", title]; @@ -330,75 +406,25 @@ static NSMutableSet *textNodes = nil; [buf appendString: @"
    \n"]; [self incIndent]; + a = [dict allKeys]; + a = [a sortedArrayUsingSelector: @selector(compare:)]; + c = [a count]; + for (i = 0; i < c; i++) { + NSString *ref = [a objectAtIndex: i]; + NSString *file = [dict objectForKey: ref]; + NSString *text = ref; + + [buf appendString: indent]; + [buf appendString: @"
  • ", - file, type, u, sep, ref]; - if ([u isEqual: unit] == YES) - { - [buf appendFormat: @"%@
  • \n", ref]; - } - else - { - [buf appendFormat: @"%@ in %@\n", ref, u]; - } - } - RELEASE(b); + [buf appendFormat: @"\"%@.html#%@$%@%@%@\">%@\n", + file, type, u, sep, ref, text]; } else { - NSString *ref = [a objectAtIndex: i]; - NSString *file = [dict objectForKey: ref]; - NSString *text = ref; - - /* - * Special case ... title listings are done - * with the name of the file being the unique key - * and the value being the title string. - */ - if ([type isEqual: @"title"] == YES) - { - text = file; - file = ref; - if ([file isEqual: base] == YES) - { - continue; // Don't list current file. - } - } - - [buf appendString: indent]; - [buf appendString: @"
  • %@
  • \n", file, type, ref, text]; } @@ -466,20 +492,22 @@ static NSMutableSet *textNodes = nil; } else if ([name isEqual: @"category"] == YES) { - NSString *name = [prop objectForKey: @"name"]; - NSString *cls = [prop objectForKey: @"class"]; NSString *s; + category = [prop objectForKey: @"name"]; + classname = [prop objectForKey: @"class"]; + unit = [NSString stringWithFormat: @"%@(%@)", classname, category]; [buf appendString: indent]; [buf appendString: @"

    "]; - [buf appendString: [self typeRef: cls]]; + [buf appendString: [self typeRef: classname]]; [buf appendString: @"("]; - unit = [NSString stringWithFormat: @"%@(%@)", cls, name]; - s = [self makeAnchor: unit ofType: @"category" name: name]; + s = [self makeAnchor: unit ofType: @"category" name: category]; [buf appendString: s]; [buf appendString: @")

    \n"]; [self outputUnit: node to: buf]; unit = nil; + classname = nil; + category = nil; } else if ([name isEqual: @"chapter"] == YES) { @@ -492,14 +520,14 @@ static NSMutableSet *textNodes = nil; } else if ([name isEqual: @"class"] == YES) { - NSString *name = [prop objectForKey: @"name"]; NSString *sup = [prop objectForKey: @"super"]; - unit = name; + classname = [prop objectForKey: @"name"]; + unit = classname; [buf appendString: indent]; [buf appendString: @"

    "]; [buf appendString: - [self makeAnchor: name ofType: @"class" name: name]]; + [self makeAnchor: classname ofType: @"class" name: classname]]; sup = [self typeRef: sup]; if (sup != nil) { @@ -509,6 +537,7 @@ static NSMutableSet *textNodes = nil; [buf appendString: @"

    \n"]; [self outputUnit: node to: buf]; unit = nil; + classname = nil; } else if ([name isEqual: @"code"] == YES) { @@ -919,9 +948,50 @@ static NSMutableSet *textNodes = nil; } else if ([name isEqual: @"ivariable"] == YES) { - NSString *tmp = [prop objectForKey: @"name"]; + NSString *n = [prop objectForKey: @"name"]; + NSString *t = [prop objectForKey: @"type"]; + NSString *v = [prop objectForKey: @"validity"]; + NSString *s; + GSXMLNode *tmp = children; - NSLog(@"Element '%@' not implemented", name); // FIXME + [buf appendString: indent]; + [buf appendString: @"

    "]; + s = [self makeLink: n ofType: @"ivariable" inUnit: nil isRef: NO]; + if (s != nil) + { + [buf appendString: s]; + [buf appendString: n]; + [buf appendString: @""]; + } + else + { + [buf appendString: n]; + } + [buf appendString: @"

    \n"]; + if (v == nil) + { + v = @"public"; + } + [buf appendFormat: @"%@@%@ %@ %@;
    \n", indent, v, t, n]; + + if ([[children name] isEqual: @"desc"] == YES) + { + children = [children next]; + } + /* + * List standards with which method complies + */ + if ([[children name] isEqual: @"standards"]) + { + [self outputNode: children to: buf]; + } + if ([[tmp name] isEqual: @"desc"]) + { + [self outputNode: tmp to: buf]; + } + + [buf appendString: indent]; + [buf appendString: @"
    \n"]; } else if ([name isEqual: @"label"] == YES) // %anchor { @@ -1531,8 +1601,8 @@ NSLog(@"Element '%@' not implemented", name); // FIXME - (void) outputUnit: (GSXMLNode*)node to: (NSMutableString*)buf { - GSXMLNode *t; - NSMutableArray *a; + GSXMLNode *t; + NSArray *a; node = [node children]; if (node != nil && [[node name] isEqual: @"declared"] == YES) @@ -1607,6 +1677,19 @@ NSLog(@"Element '%@' not implemented", name); // FIXME node = [node next]; } + if (node != nil && [[node name] isEqual: @"ivariable"] == YES) + { + [buf appendString: indent]; + [buf appendString: @"
    \n"]; + [buf appendString: indent]; + [buf appendString: @"

    Instance variables

    \n"]; + while (node != nil && [[node name] isEqual: @"ivariable"] == YES) + { + [self outputNode: node to: buf]; + node = [node next]; + } + } + a = [localRefs methodsInUnit: unit]; if ([a count] > 0) { @@ -1614,12 +1697,13 @@ NSLog(@"Element '%@' not implemented", name); // FIXME scope: @"global" title: @"Method summary" to: buf]; + [buf appendString: indent]; [buf appendString: @"
    \n"]; - } - while (node != nil && [[node name] isEqual: @"method"] == YES) - { - [self outputNode: node to: buf]; - node = [node next]; + while (node != nil && [[node name] isEqual: @"method"] == YES) + { + [self outputNode: node to: buf]; + node = [node next]; + } } } diff --git a/Tools/AGSIndex.h b/Tools/AGSIndex.h index 352e5e131..4d0e8d66a 100644 --- a/Tools/AGSIndex.h +++ b/Tools/AGSIndex.h @@ -27,8 +27,10 @@ @interface AGSIndex : NSObject { NSMutableDictionary *refs; - NSString *base; // Not retained - NSString *unit; // Not retained + NSString *base; // Not retained + NSString *unit; // Not retained + NSString *classname; // Not retained + NSString *category; // Not retained unsigned chap; unsigned sect; unsigned ssect; @@ -37,10 +39,11 @@ - (NSString*) globalRef: (NSString*)ref type: (NSString*)type; - (void) makeRefs: (GSXMLNode*)node; - (void) mergeRefs: (NSDictionary*)more override: (BOOL)flag; -- (NSMutableArray*) methodsInUnit: (NSString*)aUnit; +- (NSArray*) methodsInUnit: (NSString*)aUnit; - (NSMutableDictionary*) refs; - (void) setDirectory: (NSString*)path; - (void) setGlobalRef: (NSString*)ref type: (NSString*)type; +- (void) setRelationship: (NSString*)r from: (NSString*)from to: (NSString*)to; - (void) setUnitRef: (NSString*)ref type: (NSString*)type; - (NSDictionary*) unitRef: (NSString*)ref type: (NSString*)type; - (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString**)u; diff --git a/Tools/AGSIndex.m b/Tools/AGSIndex.m index 9c77000d8..cc78ce8f7 100644 --- a/Tools/AGSIndex.m +++ b/Tools/AGSIndex.m @@ -133,7 +133,6 @@ setDirectory(NSMutableDictionary *dict, NSString *path) * The references are held in a tree consisting of dictionaries * with strings at the leaves -
    * method method-name class-name file-name
    - * method method-name category-name file-name
    * method method-name protocol-name file-name
    * ivariable variable-name class-name file-name
    * class class-name file-name
    @@ -147,6 +146,9 @@ setDirectory(NSMutableDictionary *dict, NSString *path) * label label-name file-name ref
    * contents ref text
    * super class-name superclass-name
    + * categories class-name category-name file-name
    + * unitmethods unit-name method-name
    + * classvars class-name variables-name
    * title file-name text
    */ @implementation AGSIndex @@ -202,9 +204,14 @@ setDirectory(NSMutableDictionary *dict, NSString *path) if ([name isEqual: @"category"] == YES) { newUnit = YES; - unit = [NSString stringWithFormat: @"%@(%@)", - [prop objectForKey: @"class"], [prop objectForKey: @"name"]]; - + classname = [prop objectForKey: @"class"]; + category = [prop objectForKey: @"name"]; + unit = classname; + /* + * Add this category to the list of those for the class. + */ + [self setUnitRef: category type: @"categories"]; + unit = [NSString stringWithFormat: @"%@(%@)", classname, category]; [self setGlobalRef: unit type: @"category"]; } else if ([name isEqual: @"chapter"] == YES) @@ -219,20 +226,12 @@ setDirectory(NSMutableDictionary *dict, NSString *path) NSString *tmp; newUnit = YES; - unit = [prop objectForKey: @"name"]; + classname = [prop objectForKey: @"name"]; + unit = classname; tmp = [prop objectForKey: @"super"]; if (tmp != nil) { - NSMutableDictionary *t; - - t = [refs objectForKey: @"super"]; - if (t == nil) - { - t = [NSMutableDictionary new]; - [refs setObject: t forKey: @"super"]; - RELEASE(t); - } - [t setObject: tmp forKey: unit]; + [self setRelationship: @"super" from: unit to: tmp]; } [self setGlobalRef: unit type: @"class"]; } @@ -267,7 +266,8 @@ setDirectory(NSMutableDictionary *dict, NSString *path) { NSString *tmp = [prop objectForKey: @"name"]; - [self setUnitRef: tmp type: name]; + [self setUnitRef: tmp type: @"ivariable"]; + [self setUnitRef: tmp type: @"classvars"]; } else if ([name isEqual: @"entry"] || [name isEqual: @"label"]) { @@ -348,7 +348,8 @@ setDirectory(NSMutableDictionary *dict, NSString *path) } if ([sel length] > 1) { - [self setUnitRef: sel type: name]; + [self setUnitRef: sel type: @"method"]; + [self setUnitRef: sel type: @"unitmethods"]; } } else if ([name isEqual: @"protocol"] == YES) @@ -413,6 +414,8 @@ setDirectory(NSMutableDictionary *dict, NSString *path) if (newUnit == YES) { unit = nil; + category = nil; + classname = nil; } if (next != nil) { @@ -430,23 +433,12 @@ setDirectory(NSMutableDictionary *dict, NSString *path) mergeDictionaries(refs, more, flag); } -- (NSMutableArray*) methodsInUnit: (NSString*)aUnit +- (NSArray*) methodsInUnit: (NSString*)aUnit { - NSDictionary *d = [refs objectForKey: @"method"]; - NSEnumerator *e = [d keyEnumerator]; - NSMutableArray *a = [NSMutableArray array]; - NSString *k; + NSDictionary *d = [refs objectForKey: @"unitmethods"]; - while ((k = [e nextObject]) != nil) - { - NSDictionary *m = [d objectForKey: k]; - - if ([m objectForKey: aUnit] != nil) - { - [a addObject: k]; - } - } - return a; + d = [d objectForKey: aUnit]; + return [d allKeys]; } - (NSMutableDictionary*) refs @@ -486,13 +478,50 @@ setDirectory(NSMutableDictionary *dict, NSString *path) [t setObject: base forKey: ref]; } +- (void) setRelationship: (NSString*)r from: (NSString*)from to: (NSString*)to +{ + NSMutableDictionary *dict; + + dict = [refs objectForKey: r]; + if (dict == nil) + { + dict = [NSMutableDictionary new]; + [refs setObject: dict forKey: r]; + RELEASE(dict); + } + [dict setObject: to forKey: from]; +} + +/** + * Set up a reference for something inside a unit (class, category or protocol) + * We store 'method' and 'ivariable' by ref then unit (class), + * but we store 'unitmethods' * and 'classvars' by unit then ref. + */ - (void) setUnitRef: (NSString*)ref type: (NSString*)type { NSMutableDictionary *t; NSMutableDictionary *r; + NSString *u = unit; NSString *old; + if ([type isEqualToString: @"method"] || [type isEqualToString: @"ivariable"]) + { + if (category != nil) + { + u = classname; // Store category methods by classname. + } + // type ... ref ... unit ... file + } + else + { + NSString *tmp = ref; + + ref = u; + u = tmp; + // type ... unit ... ref ... file + } + t = [refs objectForKey: type]; if (t == nil) { @@ -507,13 +536,13 @@ setDirectory(NSMutableDictionary *dict, NSString *path) [t setObject: r forKey: ref]; RELEASE(r); } - old = [r objectForKey: unit]; + old = [r objectForKey: u]; if (old != nil && [old isEqual: base] == NO) { NSLog(@"Warning ... %@ %@ %@ appears in %@ and %@ ... using the latter", - type, ref, unit, old, base); + type, ref, u, old, base); } - [r setObject: base forKey: unit]; + [r setObject: base forKey: u]; } /** diff --git a/Tools/AGSOutput.h b/Tools/AGSOutput.h index 5b22c689e..212705e6a 100644 --- a/Tools/AGSOutput.h +++ b/Tools/AGSOutput.h @@ -41,6 +41,7 @@ output: (NSMutableString*)buf; - (NSString*) output: (NSDictionary*)d; - (BOOL) output: (NSDictionary*)d file: (NSString*)name; +- (void) outputInstanceVariable: (NSDictionary*)d to: (NSMutableString*)str; - (void) outputMethod: (NSDictionary*)d to: (NSMutableString*)str; - (void) outputUnit: (NSDictionary*)d to: (NSMutableString*)str; - (unsigned) reformat: (NSString*)str diff --git a/Tools/AGSOutput.m b/Tools/AGSOutput.m index 51d810f22..a08485958 100644 --- a/Tools/AGSOutput.m +++ b/Tools/AGSOutput.m @@ -409,6 +409,42 @@ static BOOL snuggleStart(NSString *t) return [str writeToFile: name atomically: YES]; } +/** + * Output the gsdoc code for an instance variable. + */ +- (void) outputInstanceVariable: (NSDictionary*)d to: (NSMutableString*)str +{ + NSString *type = [d objectForKey: @"Type"]; + NSString *validity = [d objectForKey: @"Validity"]; + NSString *name = [d objectForKey: @"Name"]; + NSString *comment = [d objectForKey: @"Comment"]; + NSString *standards = [d objectForKey: @"Standards"]; + + [str appendString: @" \n"]; + + [str appendString: @" \n"]; + if ([comment length] == 0) + { + comment = @"Description forthcoming."; + } + [self reformat: comment withIndent: 12 to: str]; + [str appendString: @" \n"]; + if (standards != nil) + { + [self reformat: standards withIndent: 10 to: str]; + } + [str appendString: @" \n"]; +} + /** * Uses -split: and -reformat:withIndent:to:. * Also has fun with YES, NO, and nil. @@ -583,6 +619,7 @@ static BOOL snuggleStart(NSString *t) NSString *name = [d objectForKey: @"Name"]; NSString *type = [d objectForKey: @"Type"]; NSDictionary *methods = [d objectForKey: @"Methods"]; + NSDictionary *ivars = [d objectForKey: @"InstanceVariables"]; NSString *comment = [d objectForKey: @"Comment"]; NSArray *names; NSArray *protocols; @@ -757,6 +794,14 @@ static BOOL snuggleStart(NSString *t) for (j = 0; j < ind; j++) [str appendString: @" "]; [str appendString: @"\n"]; + names = [[ivars allKeys] sortedArrayUsingSelector: @selector(compare:)]; + for (i = 0; i < [names count]; i++) + { + NSString *vName = [names objectAtIndex: i]; + + [self outputInstanceVariable: [ivars objectForKey: vName] to: str]; + } + names = [[methods allKeys] sortedArrayUsingSelector: @selector(compare:)]; for (i = 0; i < [names count]; i++) { diff --git a/Tools/AGSParser.h b/Tools/AGSParser.h index 979ea7e75..3f23c61f2 100644 --- a/Tools/AGSParser.h +++ b/Tools/AGSParser.h @@ -43,10 +43,10 @@ /* * The following items are used for logging/debug purposes. */ - NSString *fileName; // Not retained - file being parsed. - NSString *unitName; // Not retained - unit being parsed. - NSString *itemName; // Not retained - item being parsed. - NSArray *lines; // Not retained - line number mapping. + NSString *fileName; /** Not retained - file being parsed. */ + NSString *unitName; /** Not retained - unit being parsed. */ + NSString *itemName; /** Not retained - item being parsed. */ + NSArray *lines; /** Not retained - line number mapping. */ /* * The next few ivars represent the data currently being parsed. @@ -56,20 +56,23 @@ unsigned pos; BOOL commentsRead; BOOL haveSource; - NSString *declared; // Where classes were declared. - NSMutableArray *ifStack; // track preprocessor conditionals. + BOOL inInstanceVariables; + BOOL documentAllInstanceVariables; + NSString *declared; /** Where classes were declared. */ + NSMutableArray *ifStack; /** Track preprocessor conditionals. */ - NSString *comment; // Documentation accumulator. - NSMutableDictionary *info; // All information parsed. - NSMutableArray *source; // Names of source files. - NSCharacterSet *identifier; // Legit char in identifier - NSCharacterSet *identStart; // Legit initial char of identifier - NSCharacterSet *spaces; // All blank characters - NSCharacterSet *spacenl; // Blanks excluding newline + NSString *comment; /** Documentation accumulator. */ + NSMutableDictionary *info; /** All information parsed. */ + NSMutableArray *source; /** Names of source files. */ + NSCharacterSet *identifier; /** Legit char in identifier */ + NSCharacterSet *identStart; /** Legit initial char of identifier */ + NSCharacterSet *spaces; /** All blank characters */ + NSCharacterSet *spacenl; /** Blanks excluding newline */ } - (NSMutableDictionary*) info; - (id) init; /** Simple initialiser */ +- (NSMutableDictionary*) parseDeclIsSource: (BOOL)isSource; - (NSMutableDictionary*) parseFile: (NSString*)name isSource: (BOOL)isSource; - (NSString*) parseIdentifier; - (NSMutableDictionary*) parseImplementation; @@ -82,6 +85,7 @@ - (NSMutableArray*) parseProtocolList; - (void) reset; - (void) setDeclared: (NSString*)name; +- (void) setDocumentAllInstanceVariables: (BOOL)flag; - (void) setGenerateStandards: (BOOL)flag; - (void) setStandards: (NSMutableDictionary*)dict; - (void) setupBuffer; diff --git a/Tools/AGSParser.m b/Tools/AGSParser.m index 25c17ead2..ed6889547 100644 --- a/Tools/AGSParser.m +++ b/Tools/AGSParser.m @@ -122,6 +122,263 @@ va_end (ap); } +- (NSString*) parseDeclaratorInto: (NSMutableArray*)a +{ + while ([self skipWhiteSpace] < length) + { + while (buffer[pos] == '*') + { + [a addObject: @"*"]; + pos++; + } + if (buffer[pos] == '(') + { + NSString *result; + + [a addObject: @"("]; + pos++; + result = [self parseDeclaratorInto: a]; + if ([self skipWhiteSpace] < length && buffer[pos] == ')') + { + [a addObject: @")"]; + pos++; + return result; + } + else + { + [self log: @"missing ')' in declarator."]; + return nil; + } + } + else + { + NSString *s; + + s = [self parseIdentifier]; + if ([s isEqualToString: @"const"] || [s isEqualToString: @"volatile"]) + { + [a addObject: s]; + } + else + { + return s; // Parsed all asterisks, consts, and volatiles + } + } + } + return nil; +} + +- (NSMutableDictionary*) parseDeclIsSource: (BOOL)isSource +{ + CREATE_AUTORELEASE_POOL(arp); + static NSSet *qualifiers = nil; + NSString *baseType = nil; + NSString *declName = nil; + NSMutableArray *a1; + NSMutableArray *a2; + NSString *s; + BOOL isTypedef = NO; + + if (qualifiers == nil) + { + qualifiers = [NSSet setWithObjects: + @"auto", + @"const", + @"extern", + @"inline", + @"long", + @"register", + @"short", + @"signed", + @"static", + @"typedef", + @"unsigned", + @"volatile", + nil]; + RETAIN(qualifiers); + } + + a1 = [NSMutableArray array]; + a2 = [NSMutableArray array]; + while ((s = [self parseIdentifier]) != nil) + { + if ([s isEqualToString: @"GS_EXTERN"] == YES) + { + s = @"extern"; + } + if ([qualifiers member: s] == nil) + { + break; + } + else + { + if ([s isEqualToString: @"typedef"] == YES) + { + isTypedef = YES; + } + [a1 addObject: s]; + } + } + + baseType = s; + if (baseType == nil) + { + /* + * If there is no identifier here, the line must have been + * something like 'unsigned *length' so we must set the default + * base type of 'int' + */ + baseType = @"int"; + } + + /** + * We handle struct, union, and enum declarations by skipping the + * stuff enclosed in curly braces. If there was an identifier + * after the keyword we use it as the struct name, otherwise we + * use '...' to denote a nameless type. + */ + if ([s isEqualToString: @"struct"] == YES + || [s isEqualToString: @"union"] == YES + || [s isEqualToString: @"enum"] == YES) + { + s = [self parseIdentifier]; + if (s == nil) + { + baseType = [NSString stringWithFormat: @"%@ ...", baseType]; + } + else + { + baseType = [NSString stringWithFormat: @"%@ %@", baseType, s]; + } + if ([self skipWhiteSpace] < length && buffer[pos] == '{') + { + [self skipBlock]; + } + } + + /* + * FIXME ... the next code should cope with bracketing and with + * pointers to functions etc. It doesn't! + */ + while ([self skipWhiteSpace] < length) + { + while (buffer[pos] == '*') + { + [a2 addObject: @"*"]; + pos++; + } + if (buffer[pos] == '(') + { + } + s = [self parseIdentifier]; + if ([s isEqualToString: @"const"] || [s isEqualToString: @"volatile"]) + { + [a2 addObject: s]; + } + else + { + break; // Parsed all asterisks, consts, and volatiles + } + } + + declName = s; + if (declName == nil) + { + /* + * If there is no identifier here, the line must have been + * something like 'unsigned length' and we assumed that 'length' + * was the base type rather than the declared name. + * The fix is to set the base type to be 'int' and use the value + * we had as the declaration name. + */ + declName = baseType; + baseType = @"int"; + } + + [a1 addObject: baseType]; + [a1 addObjectsFromArray: a2]; + + if ([self skipWhiteSpace] < length) + { + if (buffer[pos] == ';') + { + [self skipStatement]; + } + else if (buffer[pos] == '[') + { + [self log: @"ignoring array variable ... not supported yet"]; + [self skipStatement]; + } + else if (buffer[pos] == '(') + { + [self log: @"parse function '%@' of type '%@'", + declName, [a1 componentsJoinedByString: @" "]]; + [self skipStatement]; + RELEASE(arp); + return nil; + } + else if (buffer[pos] == ',') + { + [self log: @"ignoring multiple comma separated declarations"]; + [self skipStatement]; + } + else if (buffer[pos] == '=') + { + [self skipStatement]; + } + else + { + [self log: @"unexpected char (%c) parsing declaration", buffer[pos]]; + goto fail; + } + + /* + * Read in any comment on the same line in case it + * contains documentation for the declaration. + */ + if ([self skipSpaces] < length && buffer[pos] == '/') + { + [self skipComment]; + } + + if (inInstanceVariables == YES) + { + NSMutableDictionary *d; + NSString *t; + + t = [a1 componentsJoinedByString: @" "]; + d = [[NSMutableDictionary alloc] initWithCapacity: 4]; + [d setObject: declName forKey: @"Name"]; + [d setObject: t forKey: @"Type"]; + if (comment != nil) + { + [d setObject: comment forKey: @"Comment"]; + DESTROY(comment); + } + RELEASE(arp); + return AUTORELEASE(d); + } + else if (isTypedef == YES) + { + [self log: @"parse typedef '%@' of type '%@'", + declName, [a1 componentsJoinedByString: @" "]]; + } + else + { + [self log: @"parse variable/constant '%@' of type '%@'", + declName, [a1 componentsJoinedByString: @" "]]; + } + } + else + { + [self log: @"unexpected end of data parsing declaration"]; + } +fail: + DESTROY(comment); + RELEASE(arp); + return nil; +} + - (NSMutableDictionary*) parseFile: (NSString*)name isSource: (BOOL)isSource { NSString *token; @@ -481,59 +738,6 @@ fail: return nil; } -/* -- (NSString*) parseType -{ - NSMutableString *m; - NSString *s; - BOOL hadName = NO; - - s = [self parseIdentifier]; - if (s == nil) - { - return nil; - } - m = [NSMutableString string]; - [m appendString: s]; - if ([qualifiers member: s] == nil) - { - hadName = YES; - } - [self skipWhiteSpace]; - while (pos < length) - { - unsigned saved; - BOOL hadStar = NO; - - while (pos < length && buffer[pos] == '*') - { - if (hadStar == NO) - { - [m appendString: @" "]; - hadStar = YES; - } - [m appendString: @"*"]; - pos++; - [self skipWhiteSpace]; - } - saved = pos; - s = [self parseIdentifier]; - if ([qualifiers member: s] == nil) - { - if (hadName == YES) - { - pos = saved; - break; - } - hadName = YES; - } - [m appendString: @" "]; - [m appendString: s]; - } - return m; -} -*/ - - (NSString*) parseIdentifier { unsigned start; @@ -558,11 +762,14 @@ fail: - (NSMutableDictionary*) parseInstanceVariables { - enum { IsPrivate, IsProtected, IsPublic } visibility = IsPrivate; + NSString *visibility = @"private"; NSMutableDictionary *ivars; + BOOL shouldDocument = documentAllInstanceVariables; DESTROY(comment); + inInstanceVariables = YES; + ivars = [NSMutableDictionary dictionaryWithCapacity: 8]; pos++; while ([self skipWhiteSpace] < length && buffer[pos] != '}') @@ -576,24 +783,27 @@ fail: || [self skipWhiteSpace] >= length) { [self log: @"interface with bad visibility directive"]; - return nil; + goto fail; } if ([token isEqual: @"private"] == YES) { - visibility = IsPrivate; + ASSIGN(visibility, token); + shouldDocument = documentAllInstanceVariables; } else if ([token isEqual: @"protected"] == YES) { - visibility = IsProtected; + ASSIGN(visibility, token); + shouldDocument = YES; } else if ([token isEqual: @"public"] == YES) { - visibility = IsPublic; + ASSIGN(visibility, token); + shouldDocument = YES; } else { [self log: @"interface with bad visibility (%@)", token]; - return nil; + goto fail; } } else if (buffer[pos] == '#') @@ -601,11 +811,24 @@ fail: [self skipPreprocessor]; // Ignore preprocessor directive. DESTROY(comment); } + else if (shouldDocument == YES) + { + NSMutableDictionary *iv = [self parseDeclIsSource: NO]; + + if (iv != nil) + { + [iv setObject: visibility forKey: @"Visibility"]; + [ivars setObject: iv forKey: [iv objectForKey: @"Name"]]; + } + } else { - [self skipStatement]; /* FIXME - currently we ignore ivars */ + [self skipStatement]; } } + + inInstanceVariables = NO; + if (pos >= length) { [self log: @"interface with bad instance variables"]; @@ -613,6 +836,10 @@ fail: } pos++; // Step past closing bracket. return ivars; +fail: + DESTROY(comment); + inInstanceVariables = NO; + return nil; } - (NSMutableDictionary*) parseMethodIsDeclaration: (BOOL)flag @@ -1274,6 +1501,17 @@ fail: ASSIGN(declared, name); } +/** + * This method is used to enable (or disable) documentation of all + * instance variables. If it is turned off, only those instance + * variables that are explicitly declared 'public' or 'protected' + * will be documented. + */ +- (void) setDocumentAllInstanceVariables: (BOOL)flag +{ + documentAllInstanceVariables = flag; +} + /** * Turn on or off parsing of preprocessor conditional compilation info * indicating the standards complied with. When this is turned on, we diff --git a/Tools/autogsdoc.m b/Tools/autogsdoc.m index 967a41dc9..4678e11f6 100644 --- a/Tools/autogsdoc.m +++ b/Tools/autogsdoc.m @@ -174,11 +174,12 @@
    eg. [ NSObject-init], will create a reference to the init method of NSObject, while
    [ (NSCopying)-copyWithZone:], creates a - reference to a method in the NSCopyIng protocol, and -
    [ NSObject(TimedPerformers)-performSelector:withObject:afterDelay:], - creates a reference to a method in the TimedPerformers category. + reference to a method in the NSCopyIng protocol.
    Note that no spaces must appear between the square brackets in these specifiers. +
    Protocol namnes are enclosed in round brackets rather than + the customary angle brackets, because gsdoc is an XML language, and + XML treats angle brackets specially.

    @@ -199,6 +200,11 @@ would result in the documentation saying that NSString is declared in Foundation/NSString.h + DocumentAllInstanceVariables + This flag permits you to generate documentation for all instance + variables. Normally, only those explicitly declared 'public' or + 'protected' will be documented. + DocumentationDirectory May be used to specify the directory in which generated documentation is to be placed. If this is not set, output @@ -480,6 +486,10 @@ main(int argc, char **argv, char **env) { [parser setGenerateStandards: YES]; } + if ([defs boolForKey: @"DocumentAllInstanceVariables"] == YES) + { + [parser setDocumentAllInstanceVariables: YES]; + } for (i = 0; i < count; i++) { diff --git a/Tools/gsdoc-0_6_7.dtd b/Tools/gsdoc-0_6_7.dtd index 772a849a9..8c040d756 100644 --- a/Tools/gsdoc-0_6_7.dtd +++ b/Tools/gsdoc-0_6_7.dtd @@ -273,21 +273,16 @@ - +