vastly improved auto generation of documentation.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@11456 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2001-11-21 17:10:22 +00:00
parent cba9edb901
commit 4c5a1105f2
10 changed files with 1055 additions and 321 deletions

View file

@ -1,3 +1,20 @@
2001-11-21 Richard Frith-Macdonald <rfm@gnu.org>
* Tools/AGSOutput.m:
* Tools/AGSOutput.h:
* Tools/AGSIndex.h:
* Tools/AGSIndex.m:
* Tools/AGSParser.h:
* Tools/AGSParser.m:
* Tools/AGSHtml.h:
* Tools/AGSHtml.m:
* Tools/autogsdoc.m: Many bugfixes and enhancements ... generate
html as well as gsdoc.
2001-11-19 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSXML.m: Implement NSCopying protocol for most classes.
2001-11-19 Adam Fedor <fedor@gnu.org> 2001-11-19 Adam Fedor <fedor@gnu.org>
* Source/simple-load.h (__objc_dynamic_get_symbol_path): Fix * Source/simple-load.h (__objc_dynamic_get_symbol_path): Fix

View file

@ -43,7 +43,7 @@
@class GSSAXHandler; @class GSSAXHandler;
@interface GSXMLDocument : NSObject @interface GSXMLDocument : NSObject <NSCopying>
{ {
void *lib; // pointer to xmllib pointer of xmlDoc struct void *lib; // pointer to xmllib pointer of xmlDoc struct
BOOL native; BOOL native;
@ -74,7 +74,7 @@
@interface GSXMLNamespace : NSObject @interface GSXMLNamespace : NSObject <NSCopying>
{ {
void *lib; /* pointer to struct xmlNs in the gnome xmllib */ void *lib; /* pointer to struct xmlNs in the gnome xmllib */
BOOL native; BOOL native;
@ -103,7 +103,7 @@
/* XML Node */ /* XML Node */
@interface GSXMLNode : NSObject @interface GSXMLNode : NSObject <NSCopying>
{ {
void *lib; /* pointer to struct xmlNode from libxml */ void *lib; /* pointer to struct xmlNode from libxml */
BOOL native; BOOL native;
@ -147,7 +147,7 @@
/* Attribute */ /* Attribute */
@interface GSXMLAttribute : GSXMLNode @interface GSXMLAttribute : GSXMLNode <NSCopying>
{ {
} }

View file

@ -119,10 +119,9 @@ loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr *ctxt);
@implementation GSXMLDocument : NSObject @implementation GSXMLDocument : NSObject
+ (void) initialize + (GSXMLDocument*) documentFrom: (void*)data
{ {
if (cacheDone == NO) return AUTORELEASE([[self alloc] initFrom: data]);
setupCache();
} }
+ (GSXMLDocument*) documentWithVersion: (NSString*)version + (GSXMLDocument*) documentWithVersion: (NSString*)version
@ -130,25 +129,31 @@ loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr *ctxt);
return AUTORELEASE([[self alloc] initWithVersion: version]); return AUTORELEASE([[self alloc] initWithVersion: version]);
} }
- (id) initWithVersion: (NSString*)version + (void) initialize
{ {
void *data = xmlNewDoc([version cString]); if (cacheDone == NO)
setupCache();
if (data == 0)
{
NSLog(@"Can't create GSXMLDocument object");
DESTROY(self);
}
else if ((self = [self initFrom: data]) != nil)
{
native = YES;
}
return self;
} }
+ (GSXMLDocument*) documentFrom: (void*)data - (id) copyWithZone: (NSZone*)z
{ {
return AUTORELEASE([[self alloc] initFrom: data]); return RETAIN(self);
}
- (void) dealloc
{
if ((native) && lib != NULL)
{
xmlFreeDoc(lib);
}
[super dealloc];
}
- (id) init
{
NSLog(@"GSXMLDocument: calling -init is not legal");
RELEASE(self);
return nil;
} }
- (id) initFrom: (void*)data - (id) initFrom: (void*)data
@ -173,11 +178,20 @@ loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr *ctxt);
return self; return self;
} }
- (id) init - (id) initWithVersion: (NSString*)version
{ {
NSLog(@"GSXMLDocument: calling -init is not legal"); void *data = xmlNewDoc([version cString]);
RELEASE(self);
return nil; if (data == 0)
{
NSLog(@"Can't create GSXMLDocument object");
DESTROY(self);
}
else if ((self = [self initFrom: data]) != nil)
{
native = YES;
}
return self;
} }
- (GSXMLNode*) root - (GSXMLNode*) root
@ -204,15 +218,6 @@ loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr *ctxt);
return [NSString_class stringWithCString: ((xmlDocPtr)(lib))->encoding]; return [NSString_class stringWithCString: ((xmlDocPtr)(lib))->encoding];
} }
- (void) dealloc
{
if ((native) && lib != NULL)
{
xmlFreeDoc(lib);
}
[super dealloc];
}
- (void*) lib - (void*) lib
{ {
return lib; return lib;
@ -316,6 +321,11 @@ static NSMapTable *nsNames = 0;
prefix: prefix]); prefix: prefix]);
} }
- (id) copyWithZone: (NSZone*)z
{
return RETAIN(self);
}
- (id) initWithNode: (GSXMLNode*)node - (id) initWithNode: (GSXMLNode*)node
href: (NSString*)href href: (NSString*)href
prefix: (NSString*)prefix prefix: (NSString*)prefix
@ -540,6 +550,11 @@ static NSMapTable *nodeNames = 0;
return AUTORELEASE([[self alloc] initWithNamespace: ns name: name]); return AUTORELEASE([[self alloc] initWithNamespace: ns name: name]);
} }
- (id) copyWithZone: (NSZone*)z
{
return RETAIN(self);
}
- (id) initWithNamespace: (GSXMLNamespace*) ns name: (NSString*) name - (id) initWithNamespace: (GSXMLNamespace*) ns name: (NSString*) name
{ {
self = [super init]; self = [super init];
@ -828,7 +843,7 @@ static NSMapTable *nodeNames = 0;
/* /*
* *
* GSXMLAttribure * GSXMLAttribute
* *
*/ */
@ -892,6 +907,11 @@ static NSMapTable *attrNames = 0;
return desc; return desc;
} }
- (id) copyWithZone: (NSZone*)z
{
return RETAIN(self);
}
- (int) type - (int) type
{ {
return (int)((xmlAttrPtr)(lib))->atype; return (int)((xmlAttrPtr)(lib))->atype;

View file

@ -41,13 +41,16 @@
- (void) incIndent; - (void) incIndent;
- (NSString*) outputDocument: (GSXMLNode*)node; - (NSString*) outputDocument: (GSXMLNode*)node;
- (void) outputNode: (GSXMLNode*)node to: (NSMutableString*)buf; - (void) outputNode: (GSXMLNode*)node to: (NSMutableString*)buf;
- (void) outputNodeList: (GSXMLNode*)node to: (NSMutableString*)buf;
- (GSXMLNode*) outputBlock: (GSXMLNode*)node - (GSXMLNode*) outputBlock: (GSXMLNode*)node
to: (NSMutableString*)buf to: (NSMutableString*)buf
inPara: (BOOL)flag; inPara: (BOOL)flag;
- (GSXMLNode*) outputList: (GSXMLNode*)node to: (NSMutableString*)buf; - (GSXMLNode*) outputList: (GSXMLNode*)node to: (NSMutableString*)buf;
- (GSXMLNode*) outputText: (GSXMLNode*)node to: (NSMutableString*)buf; - (GSXMLNode*) outputText: (GSXMLNode*)node to: (NSMutableString*)buf;
- (void) outputUnit: (GSXMLNode*)node to: (NSMutableString*)buf; - (void) outputUnit: (GSXMLNode*)node to: (NSMutableString*)buf;
- (NSString*) protocolRef: (NSString*)t;
- (void) setGlobalRefs: (AGSIndex*)r; - (void) setGlobalRefs: (AGSIndex*)r;
- (void) setLocalRefs: (AGSIndex*)r; - (void) setLocalRefs: (AGSIndex*)r;
- (NSString*) typeRef: (NSString*)t;
@end @end
#endif #endif

View file

@ -27,8 +27,23 @@
static int XML_ELEMENT_NODE; static int XML_ELEMENT_NODE;
static int XML_TEXT_NODE; static int XML_TEXT_NODE;
static GSXMLNode *firstElement(GSXMLNode *nodes)
{
while (nodes != nil)
{
if ([nodes type] == XML_ELEMENT_NODE)
{
return nodes;
}
nodes = [nodes next];
}
return nil;
}
@implementation AGSHtml @implementation AGSHtml
static NSMutableSet *textNodes = nil;
+ (void) initialize + (void) initialize
{ {
if (self == [AGSHtml class]) if (self == [AGSHtml class])
@ -38,6 +53,21 @@ static int XML_TEXT_NODE;
*/ */
XML_ELEMENT_NODE = [GSXMLNode typeFromDescription: @"XML_ELEMENT_NODE"]; XML_ELEMENT_NODE = [GSXMLNode typeFromDescription: @"XML_ELEMENT_NODE"];
XML_TEXT_NODE = [GSXMLNode typeFromDescription: @"XML_TEXT_NODE"]; XML_TEXT_NODE = [GSXMLNode typeFromDescription: @"XML_TEXT_NODE"];
textNodes = [NSMutableSet new];
[textNodes addObject: @"br"];
[textNodes addObject: @"code"];
[textNodes addObject: @"em"];
[textNodes addObject: @"email"];
[textNodes addObject: @"entry"];
[textNodes addObject: @"file"];
[textNodes addObject: @"label"];
[textNodes addObject: @"prjref"];
[textNodes addObject: @"ref"];
[textNodes addObject: @"site"];
[textNodes addObject: @"uref"];
[textNodes addObject: @"url"];
[textNodes addObject: @"var"];
[textNodes addObject: @"footnote"];
} }
} }
@ -83,7 +113,7 @@ static int XML_TEXT_NODE;
[buf appendString: @"<html>\n"]; [buf appendString: @"<html>\n"];
[self incIndent]; [self incIndent];
[self outputNode: node to: buf]; [self outputNodeList: [node children] to: buf];
[self decIndent]; [self decIndent];
[buf appendString: @"</html>\n"]; [buf appendString: @"</html>\n"];
@ -92,9 +122,8 @@ static int XML_TEXT_NODE;
- (void) outputNode: (GSXMLNode*)node to: (NSMutableString*)buf - (void) outputNode: (GSXMLNode*)node to: (NSMutableString*)buf
{ {
CREATE_AUTORELEASE_POOL(arp);
GSXMLNode *children = [node children]; GSXMLNode *children = [node children];
GSXMLNode *next = [node next];
BOOL newUnit = NO;
if ([node type] == XML_ELEMENT_NODE) if ([node type] == XML_ELEMENT_NODE)
{ {
@ -107,8 +136,7 @@ static int XML_TEXT_NODE;
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"<div>\n"]; [buf appendString: @"<div>\n"];
[self incIndent]; [self incIndent];
[self outputNode: children to: buf]; [self outputNodeList: children to: buf];
children = nil;
// Close back division // Close back division
[self decIndent]; [self decIndent];
@ -117,35 +145,61 @@ static int XML_TEXT_NODE;
} }
else if ([name isEqual: @"body"] == YES) else if ([name isEqual: @"body"] == YES)
{ {
[buf appendString: indent]; /* Should already be in html body */
[buf appendString: @"<body>\n"]; [self outputNodeList: children to: buf];
[self incIndent];
[self outputNode: children to: buf];
children = nil;
[self decIndent]; [self decIndent];
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"</body>\n"]; [buf appendString: @"</body>\n"];
} }
else if ([name isEqual: @"br"] == YES)
{
[buf appendString: @"<br />"];
}
else if ([name isEqual: @"category"] == YES) else if ([name isEqual: @"category"] == YES)
{ {
newUnit = YES; NSString *name = [prop objectForKey: @"name"];
unit = [NSString stringWithFormat: @"%@(%@)", NSString *cls = [prop objectForKey: @"class"];
[prop objectForKey: @"class"], [prop objectForKey: @"name"]];
cls = [self typeRef: cls];
unit = [NSString stringWithFormat: @"%@(%@)", cls, name];
[buf appendFormat: @"<h2>%@(<a name=\"category$%@\">%@</a>)</h2>\n",
unit, cls, name];
[self outputUnit: node to: buf]; [self outputUnit: node to: buf];
children = nil; unit = nil;
} }
else if ([name isEqual: @"chapter"] == YES) else if ([name isEqual: @"chapter"] == YES)
{ {
heading = @"h1"; heading = @"h1";
[self outputNode: children to: buf]; [self outputNodeList: children to: buf];
children = nil;
} }
else if ([name isEqual: @"class"] == YES) else if ([name isEqual: @"class"] == YES)
{ {
newUnit = YES; NSString *name = [prop objectForKey: @"name"];
unit = [prop objectForKey: @"name"]; NSString *sup = [prop objectForKey: @"super"];
unit = name;
sup = [self typeRef: sup];
if (sup == nil)
{
/*
* This is a root class.
*/
[buf appendFormat: @"<h3><a name=\"class$%@\">%@</a></h3>\n",
unit, name];
}
else
{
[buf appendFormat: @"<h3><a name=\"class$%@\">%@</a> : %@</h3>\n",
unit, name, sup];
}
[self outputUnit: node to: buf]; [self outputUnit: node to: buf];
children = nil; unit = nil;
}
else if ([name isEqual: @"code"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
} }
else if ([name isEqual: @"desc"] == YES) else if ([name isEqual: @"desc"] == YES)
{ {
@ -157,14 +211,67 @@ static int XML_TEXT_NODE;
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"</p>\n"]; [buf appendString: @"</p>\n"];
} }
else if ([name isEqual: @"em"] == YES)
{
[buf appendString: @"<em>"];
[self outputText: children to: buf];
[buf appendString: @"</em>"];
}
else if ([name isEqual: @"email"] == YES)
{
NSString *ename;
ename = [prop objectForKey: @"address"];
if (ename == nil)
{
[buf appendString: @"<code>"];
}
else
{
[buf appendFormat: @"<a href=\"%@\"><code>", ename];
}
[self outputText: [node children] to: buf];
if (ename == nil)
{
[buf appendString: @"</code>"];
}
else
{
[buf appendFormat: @"</code></a>", ename];
}
}
else if ([name isEqual: @"entry"])
{
NSString *text;
NSString *val;
text = [children content];
val = [prop objectForKey: @"id"];
if (val == nil)
{
val = text;
}
[buf appendFormat: @"<a name=\"label$%@\"></a>", val];
}
else if ([name isEqual: @"file"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
}
else if ([name isEqual: @"footnote"] == YES)
{
[buf appendString: @"<blockquote>"];
[self outputText: children to: buf];
[buf appendString: @"</blockquote>"];
}
else if ([name isEqual: @"front"] == YES) else if ([name isEqual: @"front"] == YES)
{ {
// Open front division // Open front division
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"<div>\n"]; [buf appendString: @"<div>\n"];
[self incIndent]; [self incIndent];
[self outputNode: children to: buf]; [self outputNodeList: children to: buf];
children = nil;
// Close front division // Close front division
[self decIndent]; [self decIndent];
[buf appendString: indent]; [buf appendString: indent];
@ -184,17 +291,138 @@ static int XML_TEXT_NODE;
prevFile = [prevFile stringByAppendingPathExtension: @"html"]; prevFile = [prevFile stringByAppendingPathExtension: @"html"];
upFile = [prop objectForKey: @"up"]; upFile = [prop objectForKey: @"up"];
upFile = [upFile stringByAppendingPathExtension: @"html"]; upFile = [upFile stringByAppendingPathExtension: @"html"];
[self outputNodeList: children to: buf];
} }
else if ([name isEqual: @"head"] == YES) else if ([name isEqual: @"head"] == YES)
{ {
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"<head>\n"]; [buf appendString: @"<head>\n"];
[self incIndent]; [self incIndent];
[self outputNode: children to: buf]; children = firstElement(children);
children = nil; [buf appendString: indent];
[buf appendString: @"<title>"];
[self incIndent];
[self outputText: [children children] to: buf];
[self decIndent];
[buf appendString: @"</title>\n"];
[self decIndent]; [self decIndent];
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"</head>\n"]; [buf appendString: @"</head>\n"];
[buf appendString: indent];
[buf appendString: @"<body>\n"];
[self incIndent];
[buf appendString: indent];
[buf appendString: @"<h1>"];
[self outputText: [children children] to: buf];
[buf appendString: @"</h1>\n"];
[buf appendString: indent];
[buf appendString: @"<h3>Authors</h3>\n"];
[buf appendString: indent];
[buf appendString: @"<dl>\n"];
[self incIndent];
children = firstElement([children next]);
while ([[children name] isEqual: @"author"] == YES)
{
GSXMLNode *author = children;
GSXMLNode *tmp;
GSXMLNode *email = nil;
GSXMLNode *url = nil;
GSXMLNode *desc = nil;
children = [children next];
children = firstElement(children);
tmp = firstElement([author children]);
if ([[tmp name] isEqual: @"email"] == YES)
{
email = tmp;
tmp = firstElement([tmp next]);
}
if ([[tmp name] isEqual: @"url"] == YES)
{
url = tmp;
tmp = firstElement([tmp next]);
}
if ([[tmp name] isEqual: @"desc"] == YES)
{
desc = tmp;
tmp = firstElement([tmp next]);
}
[buf appendString: indent];
if (url == nil)
{
[buf appendString: @"<dt>"];
[buf appendString: [[author propertiesAsDictionary]
objectForKey: @"name"]];
}
else
{
[buf appendString: @"<dt><a href=\""];
[buf appendString: [[url propertiesAsDictionary]
objectForKey: @"url"]];
[buf appendString: @"\">"];
[buf appendString: [[author propertiesAsDictionary]
objectForKey: @"name"]];
[buf appendString: @"</a>"];
}
if (email != nil)
{
[buf appendString: @"("];
[self outputNode: email to: buf];
[buf appendString: @")"];
}
[buf appendString: @"</dt>\n"];
[buf appendString: indent];
[buf appendString: @"<dd>\n"];
if (desc != nil)
{
[self incIndent];
[self outputBlock: desc to: buf inPara: NO];
[self decIndent];
}
[buf appendString: indent];
[buf appendString: @"</dd>\n"];
}
[self decIndent];
[buf appendString: indent];
[buf appendString: @"</dl>\n"];
if ([[children name] isEqual: @"version"] == YES)
{
[buf appendString: indent];
[buf appendString: @"<p>Version: "];
[self outputNode: [children children] to: buf];
[buf appendString: @"</p>\n"];
children = firstElement([children next]);
}
if ([[children name] isEqual: @"date"] == YES)
{
[buf appendString: indent];
[buf appendString: @"<p>Date: "];
[self outputNode: [children children] to: buf];
[buf appendString: @"</p>\n"];
children = firstElement([children next]);
}
if ([[children name] isEqual: @"abstract"] == YES)
{
[buf appendString: indent];
[buf appendString: @"<blockquote>\n"];
[self incIndent];
[self outputBlock: [children children] to: buf inPara: NO];
[self decIndent];
[buf appendString: indent];
[buf appendString: @"</blockquote>\n"];
children = firstElement([children next]);
}
if ([[children name] isEqual: @"copy"] == YES)
{
[buf appendString: indent];
[buf appendString: @"<p>Copyright: "];
[self outputNode: [children children] to: buf];
[buf appendString: @"</p>\n"];
children = firstElement([children next]);
}
} }
else if ([name isEqual: @"heading"] == YES) else if ([name isEqual: @"heading"] == YES)
{ {
@ -203,7 +431,6 @@ static int XML_TEXT_NODE;
[buf appendString: heading]; [buf appendString: heading];
[buf appendString: @">"]; [buf appendString: @">"];
[self outputText: children to: buf]; [self outputText: children to: buf];
children = nil;
[buf appendString: @"</"]; [buf appendString: @"</"];
[buf appendString: heading]; [buf appendString: heading];
[buf appendString: @">\n"]; [buf appendString: @">\n"];
@ -212,33 +439,43 @@ static int XML_TEXT_NODE;
{ {
NSString *tmp = [prop objectForKey: @"name"]; NSString *tmp = [prop objectForKey: @"name"];
NSLog(@"Element '%@' not implemented", name); // FIXME
} }
else if ([name isEqual: @"entry"] || [name isEqual: @"label"]) else if ([name isEqual: @"label"] == YES) // %anchor
{ {
NSString *text; NSString *text;
NSString *val; NSString *val;
text = [children content]; text = [children content];
children = nil;
val = [prop objectForKey: @"id"]; val = [prop objectForKey: @"id"];
if (val == nil) if (val == nil)
{ {
val = text; val = text;
} }
[buf appendFormat: @"<a name=\"label$%@\">", val];
[self outputText: children to: buf];
[buf appendString: @"</a>"];
} }
else if ([name isEqual: @"method"] == YES) else if ([name isEqual: @"method"] == YES)
{ {
NSString *sel = @""; NSString *sel;
NSString *str;
GSXMLNode *tmp = children; GSXMLNode *tmp = children;
BOOL hadArg = NO;
sel = [prop objectForKey: @"factory"]; sel = [prop objectForKey: @"factory"];
str = [prop objectForKey: @"type"];
if (sel != nil && [sel boolValue] == YES) if (sel != nil && [sel boolValue] == YES)
{ {
sel = @"+"; sel = @"+";
str = [NSString stringWithFormat: @"+ (%@) ",
[self typeRef: str]];
} }
else else
{ {
sel = @"-"; sel = @"-";
str = [NSString stringWithFormat: @"- (%@)",
[self typeRef: str]];
} }
children = nil; children = nil;
while (tmp != nil) while (tmp != nil)
@ -249,39 +486,250 @@ static int XML_TEXT_NODE;
{ {
GSXMLNode *t = [tmp children]; GSXMLNode *t = [tmp children];
str = [str stringByAppendingString: @"<b>"];
while (t != nil) while (t != nil)
{ {
if ([t type] == XML_TEXT_NODE) if ([t type] == XML_TEXT_NODE)
{ {
sel = [sel stringByAppendingString: [t content]]; NSString *content = [t content];
sel = [sel stringByAppendingString: content];
if (hadArg == YES)
{
str = [str stringByAppendingString: @" "];
}
str = [str stringByAppendingString: content];
} }
t = [t next]; t = [t next];
} }
str = [str stringByAppendingString: @"</b>"];
} }
else if ([[tmp name] isEqual: @"arg"] == NO) else if ([[tmp name] isEqual: @"arg"] == YES)
{ {
children = tmp; GSXMLNode *t = [tmp children];
break; NSString *s;
s = [[tmp propertiesAsDictionary] objectForKey: @"type"];
s = [self typeRef: s];
str = [str stringByAppendingFormat: @" (%@)", s];
while (t != nil)
{
if ([t type] == XML_TEXT_NODE)
{
str = [str stringByAppendingString: [t content]];
}
t = [t next];
}
hadArg = YES; // Say we have found an arg.
} }
else if ([[tmp name] isEqual: @"vararg"] == YES) else if ([[tmp name] isEqual: @"vararg"] == YES)
{ {
sel = [sel stringByAppendingString: @",..."]; sel = [sel stringByAppendingString: @",..."];
str = [str stringByAppendingString: @"<b>,...</b>"];
children = [tmp next]; children = [tmp next];
break; break;
} }
else
{
children = tmp;
break;
}
} }
tmp = [tmp next]; tmp = [tmp next];
} }
if ([sel length] > 1) if ([sel length] > 1)
{ {
/*
* Output selector heading.
*/
[buf appendString: indent];
[buf appendFormat: @"<h3><a name=\"%@%@\">%@</a></h3>\n",
unit, sel, [sel substringFromIndex: 1]];
[buf appendString: indent];
[buf appendString: str];
[buf appendString: @";<br />\n"];
node = children;
/*
* List standards with which method complies
*/
children = [node next];
if ([[children name] isEqual: @"standards"])
{
tmp = [node children];
if (tmp != nil)
{
[buf appendString: @"Standards:"];
while (tmp != nil)
{
[buf appendString: @" "];
[buf appendString: [tmp name]];
tmp = [tmp next];
}
[buf appendString: @"<br />\n"];
}
}
if ((str = [prop objectForKey: @"init"]) != nil
&& [str boolValue] == YES)
{
[buf appendString: @"This is a designated initialiser "
@"for the class.<br />\n"];
}
str = [prop objectForKey: @"override"];
if ([str isEqual: @"subclass"] == YES)
{
[buf appendString: @"Subclasses <strong>should</strong> "
@"override this method.<br />\n"];
}
else if ([str isEqual: @"never"] == YES)
{
[buf appendString: @"Subclasses should <strong>NOT</strong> "
@"override this method.<br />\n"];
}
if ([[node name] isEqual: @"desc"])
{
[self outputNode: node to: buf];
}
[buf appendString: indent];
[buf appendString: @"<hr />\n"];
}
}
else if ([name isEqual: @"prjref"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"ref"] == YES) // %xref
{
NSString *type = [prop objectForKey: @"type"];
NSString *r = [prop objectForKey: @"id"];
NSString *f = nil;
BOOL isLocal = YES;
if ([type isEqual: @"method"] || [type isEqual: @"variable"])
{
NSString *c = [prop objectForKey: @"class"];
/*
* No class specified ... try to infer it.
*/
if (c == nil)
{
/*
* 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 we need a local reference.
*/
if (unit != nil)
{
f = [localRefs unitRef: r type: type unit: unit];
if (f == nil)
{
f = [globalRefs unitRef: r type: type unit: unit];
if (f != nil)
{
isLocal = NO;
c = unit;
}
}
else
{
c = unit;
}
}
/*
* If we have not found it in the current unit, we check
* all known references to see if the item is uniquely
* documented somewhere.
*/
if (c == nil)
{
NSDictionary *d;
d = [localRefs unitRef: r type: type];
if ([d count] == 0)
{
isLocal = NO;
d = [globalRefs unitRef: r type: type];
}
if ([d count] == 1)
{
/*
* Record the class where the item is documented
* and the file where that documentation occurs.
*/
c = [[d allKeys] objectAtIndex: 0];
f = [d objectForKey: c];
}
}
}
else
{
/*
* Simply look up the reference.
*/
f = [localRefs unitRef: r type: type unit: c];
if (f == nil)
{
isLocal = NO;
f = [globalRefs unitRef: r type: type unit: c];
}
}
if (f != nil)
{
f = [f stringByAppendingPathExtension: @"html"];
if (isLocal == YES)
{
[buf appendFormat: @"<a href=\"#%@%@\">", c, r];
}
else
{
[buf appendFormat: @"<a href=\"%@#%@%@\">", f, c, r];
}
}
}
else
{
f = [localRefs globalRef: r type: type];
if (f == nil)
{
isLocal = NO;
f = [globalRefs globalRef: r type: type];
}
if (f != nil)
{
f = [f stringByAppendingPathExtension: @"html"];
if (isLocal == YES)
{
[buf appendFormat: @"<a href=\"#%@$%@\">", type, r];
}
else
{
[buf appendFormat: @"<a href=\"%@#%@$%@\">", f, type, r];
}
}
}
if (f == nil)
{
NSLog(@"ref '%@' not found for %@", name, type);
}
else
{
[self outputText: [node children] to: buf];
[buf appendString: @"</a>\n"];
} }
} }
else if ([name isEqual: @"protocol"] == YES) else if ([name isEqual: @"protocol"] == YES)
{ {
newUnit = YES; NSString *name = [prop objectForKey: @"name"];
unit = [prop objectForKey: @"name"];
unit = [NSString stringWithFormat: @"(%@)", name];
[buf appendFormat:
@"<h3><a name=\"protocol$%@\">&lt;%@&gt;</a></h3>\n", unit, name];
[self outputUnit: node to: buf]; [self outputUnit: node to: buf];
children = nil; unit = nil;
} }
else if ([name isEqual: @"constant"] == YES else if ([name isEqual: @"constant"] == YES
|| [name isEqual: @"EOEntity"] == YES || [name isEqual: @"EOEntity"] == YES
@ -293,34 +741,75 @@ static int XML_TEXT_NODE;
{ {
NSString *tmp = [prop objectForKey: @"name"]; NSString *tmp = [prop objectForKey: @"name"];
NSLog(@"Element '%@' not implemented", name); // FIXME
} }
else if ([name isEqual: @"section"] == YES) else if ([name isEqual: @"section"] == YES)
{ {
heading = @"h2"; heading = @"h2";
[self outputNode: children to: buf]; [self outputNode: children to: buf];
children = nil; }
else if ([name isEqual: @"site"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
} }
else if ([name isEqual: @"subsect"] == YES) else if ([name isEqual: @"subsect"] == YES)
{ {
heading = @"h3"; heading = @"h3";
[self outputNode: children to: buf]; [self outputNode: children to: buf];
children = nil;
} }
else if ([name isEqual: @"subsubsect"] == YES) else if ([name isEqual: @"subsubsect"] == YES)
{ {
heading = @"h4"; heading = @"h4";
[self outputNode: children to: buf]; [self outputNode: children to: buf];
children = nil;
} }
else if ([name isEqual: @"title"] == YES) else if ([name isEqual: @"type"] == YES)
{ {
NSString *n = [prop objectForKey: @"name"];
node = [node children];
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"<title>"]; [buf appendFormat: @"<h3><a name=\"type$%@\">typedef %@ %@</a></h3>",
[self incIndent]; n, [node content], n];
node = [node next];
if (node != nil && [[node name] isEqual: @"declared"] == YES)
{
[buf appendString: indent];
[buf appendString: @"Declared: "];
[self outputText: [node children] to: buf];
[buf appendString: @"<br />\n"];
node = [node next];
}
if (node != nil && [[node name] isEqual: @"desc"] == YES)
{
[self outputNode: node to: buf];
node = [node next];
}
if (node != nil && [[node name] isEqual: @"standards"] == YES)
{
[self outputNode: node to: buf];
node = [node next];
}
}
else if ([name isEqual: @"uref"] == YES)
{
[buf appendString: @"<a href=\""];
[buf appendString: [prop objectForKey: @"url"]];
[buf appendString: @"\">"];
[self outputText: children to: buf]; [self outputText: children to: buf];
children = nil; [buf appendString: @"</a>"];
[self decIndent]; }
[buf appendString: @"</title>\n"]; else if ([name isEqual: @"url"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"var"] == YES) // %phrase
{
[buf appendString: @"<var>"];
[self outputText: children to: buf];
[buf appendString: @"</var>"];
} }
else else
{ {
@ -333,24 +822,19 @@ static int XML_TEXT_NODE;
{ {
NSLog(@"Element '%@' not implemented", name); // FIXME NSLog(@"Element '%@' not implemented", name); // FIXME
} }
else
{
next = tmp;
}
} }
} }
RELEASE(arp);
}
if (children != nil) - (void) outputNodeList: (GSXMLNode*)node to: (NSMutableString*)buf
{
while (node != nil)
{ {
[self outputNode: children to: buf]; GSXMLNode *next = [node next];
}
if (newUnit == YES) [self outputNode: node to: buf];
{ node = next;
unit = nil;
}
if (next != nil)
{
[self outputNode: next to: buf];
} }
} }
@ -566,80 +1050,10 @@ NSLog(@"Element '%@' not implemented", name); // FIXME
else if ([node type] == XML_ELEMENT_NODE) else if ([node type] == XML_ELEMENT_NODE)
{ {
NSString *name = [node name]; NSString *name = [node name];
GSXMLNode *children = [node children];
NSDictionary *prop = [node propertiesAsDictionary];
if ([name isEqual: @"br"] == YES) if ([textNodes member: name] != nil)
{ {
[buf appendString: @"<br />"]; [self outputNode: node to: buf];
}
else if ([name isEqual: @"ref"] == YES) // %xref
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"uref"] == YES)
{
[buf appendString: @"<a href=\""];
[buf appendString: [prop objectForKey: @"url"]];
[buf appendString: @"\">"];
[self outputText: children to: buf];
[buf appendString: @"</a>"];
}
else if ([name isEqual: @"url"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"email"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"prjref"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"label"] == YES) // %anchor
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"entry"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"var"] == YES) // %phrase
{
[buf appendString: @"<var>"];
[self outputText: children to: buf];
[buf appendString: @"</var>"];
}
else if ([name isEqual: @"em"] == YES)
{
[buf appendString: @"<em>"];
[self outputText: children to: buf];
[buf appendString: @"</em>"];
}
else if ([name isEqual: @"code"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
}
else if ([name isEqual: @"file"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
}
else if ([name isEqual: @"site"] == YES)
{
[buf appendString: @"<code>"];
[self outputText: children to: buf];
[buf appendString: @"</code>"];
}
else if ([name isEqual: @"footnote"] == YES)
{
[buf appendString: @"<blockquote>"];
[self outputText: children to: buf];
[buf appendString: @"</blockquote>"];
} }
else else
{ {
@ -653,8 +1067,6 @@ NSLog(@"Element '%@' not implemented", name); // FIXME
- (void) outputUnit: (GSXMLNode*)node to: (NSMutableString*)buf - (void) outputUnit: (GSXMLNode*)node to: (NSMutableString*)buf
{ {
GSXMLNode *u = node;
node = [node children]; node = [node children];
if (node != nil && [[node name] isEqual: @"declared"] == YES) if (node != nil && [[node name] isEqual: @"declared"] == YES)
{ {
@ -666,9 +1078,11 @@ NSLog(@"Element '%@' not implemented", name); // FIXME
} }
while (node != nil && [[node name] isEqual: @"conform"] == YES) while (node != nil && [[node name] isEqual: @"conform"] == YES)
{ {
NSString *text = [[node children] content];
[buf appendString: indent]; [buf appendString: indent];
[buf appendString: @"Conform: "]; [buf appendString: @"Conform: "];
[self outputText: [node children] to: buf]; [buf appendString: [self protocolRef: text]];
[buf appendString: @"<br />\n"]; [buf appendString: @"<br />\n"];
node = [node next]; node = [node next];
} }
@ -682,13 +1096,36 @@ NSLog(@"Element '%@' not implemented", name); // FIXME
[self outputNode: node to: buf]; [self outputNode: node to: buf];
node = [node next]; node = [node next];
} }
if (node != nil && [[node name] isEqual: @"standaards"] == YES) if (node != nil && [[node name] isEqual: @"standards"] == YES)
{ {
[self outputNode: node to: buf]; [self outputNode: node to: buf];
node = [node next]; node = [node next];
} }
} }
/**
* Try to make a link to the documentation for the supplied protocol.
*/
- (NSString*) protocolRef: (NSString*)t
{
NSString *n;
NSString *s;
t = [t stringByTrimmingSpaces];
n = [NSString stringWithFormat: @"(%@)", t];
if ((s = [localRefs globalRef: n type: @"protocol"]) != nil)
{
t = [NSString stringWithFormat: @"<a href=\"#protocol$%@\">%@</a>", n, t];
}
else if ((s = [globalRefs globalRef: t type: @"protocol"]) != nil)
{
s = [s stringByAppendingPathExtension: @"html"];
t = [NSString stringWithFormat: @"<a href=\"%@#protocol$%@\">%@</a>",
s, n, t];
}
return t;
}
- (void) setGlobalRefs: (AGSIndex*)r - (void) setGlobalRefs: (AGSIndex*)r
{ {
ASSIGN(globalRefs, r); ASSIGN(globalRefs, r);
@ -699,5 +1136,74 @@ NSLog(@"Element '%@' not implemented", name); // FIXME
ASSIGN(localRefs, r); ASSIGN(localRefs, r);
} }
/**
* Assuming that the supplied string contains type information (as used
* in a method declaration or type cast), we make an attempt at extracting
* the basic type, and seeing if we can find a documented declaration for
* it. If we can, we return a modified version of the string containing
* a link to the appropriate documentation. Otherwise, we just return the
* plain type string. In all cases, we strip leading and trailing white space.
*/
- (NSString*) typeRef: (NSString*)t
{
NSString *orig = [t stringByTrimmingSpaces];
NSString *s;
unsigned end = [orig length];
unsigned start;
t = orig;
while (end > 0)
{
unichar c = [t characterAtIndex: end-1];
if (c != '*' && !isspace(c))
{
break;
}
end--;
}
start = end;
while (start > 0)
{
unichar c = [t characterAtIndex: start-1];
if (c != '_' && !isalnum(c))
{
break;
}
start--;
}
t = [orig substringWithRange: NSMakeRange(start, end - start)];
if ((s = [localRefs globalRef: t type: @"type"]) != nil)
{
s = [NSString stringWithFormat: @"<a href=\"#type$%@\">%@</a>", t, t];
}
else if ((s = [localRefs globalRef: t type: @"class"]) != nil)
{
s = [NSString stringWithFormat: @"<a href=\"#class$%@\">%@</a>", t, t];
}
else if ((s = [globalRefs globalRef: t type: @"type"]) != nil)
{
s = [s stringByAppendingPathExtension: @"html"];
s = [NSString stringWithFormat: @"<a href=\"%@#type$%@\">%@</a>",
s, t, t];
}
else if ((s = [globalRefs globalRef: t type: @"class"]) != nil)
{
s = [s stringByAppendingPathExtension: @"html"];
s = [NSString stringWithFormat: @"<a href=\"%@#class$%@\">%@</a>",
s, t, t];
}
if (s != nil)
{
if ([orig length] == [t length])
{
return s;
}
return [orig stringByReplacingString: t withString: s];
}
return orig;
}
@end @end

View file

@ -31,10 +31,13 @@
NSString *base; // Not retained NSString *base; // Not retained
NSString *unit; // Not retained NSString *unit; // Not retained
} }
- (NSString*) globalRef: (NSString*)ref type: (NSString*)type;
- (void) makeRefs: (GSXMLNode*)node; - (void) makeRefs: (GSXMLNode*)node;
- (void) mergeRefs: (NSDictionary*)more; - (void) mergeRefs: (NSDictionary*)more;
- (NSMutableDictionary*) refs; - (NSMutableDictionary*) refs;
- (void) setGlobalRef: (NSString*)ref type: (NSString*)type; - (void) setGlobalRef: (NSString*)ref type: (NSString*)type;
- (void) setUnitRef: (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;
@end @end
#endif #endif

View file

@ -104,6 +104,14 @@ mergeDictionaries(NSMutableDictionary *dst, NSDictionary *src)
[super dealloc]; [super dealloc];
} }
- (NSString*) globalRef: (NSString*)ref type: (NSString*)type
{
NSDictionary *t;
t = [refs objectForKey: type];
return [t objectForKey: ref];
}
- (id) init - (id) init
{ {
refs = [[NSMutableDictionary alloc] initWithCapacity: 8]; refs = [[NSMutableDictionary alloc] initWithCapacity: 8];
@ -263,7 +271,8 @@ mergeDictionaries(NSMutableDictionary *dst, NSDictionary *src)
else if ([name isEqual: @"protocol"] == YES) else if ([name isEqual: @"protocol"] == YES)
{ {
newUnit = YES; newUnit = YES;
unit = [prop objectForKey: @"name"]; unit = [NSString stringWithFormat: @"(%@)",
[prop objectForKey: @"name"]];
[self setGlobalRef: unit type: name]; [self setGlobalRef: unit type: name];
} }
else if ([name isEqual: @"constant"] == YES else if ([name isEqual: @"constant"] == YES
@ -359,5 +368,22 @@ mergeDictionaries(NSMutableDictionary *dst, NSDictionary *src)
[r setObject: base forKey: unit]; [r setObject: base forKey: unit];
} }
- (NSDictionary*) unitRef: (NSString*)ref type: (NSString*)type
{
NSDictionary *t;
t = [refs objectForKey: type];
return [t objectForKey: ref];
}
- (NSString*) unitRef: (NSString*)ref type: (NSString*)type unit: (NSString*)u
{
NSDictionary *t;
t = [refs objectForKey: type];
t = [t objectForKey: ref];
return [t objectForKey: unit];
}
@end @end

View file

@ -49,6 +49,7 @@
unsigned length; unsigned length;
unsigned pos; unsigned pos;
BOOL commentsRead; BOOL commentsRead;
NSString *declared; // Where classes were declared.
NSString *comment; // Documentation accumulator. NSString *comment; // Documentation accumulator.
NSMutableDictionary *info; // All information parsed. NSMutableDictionary *info; // All information parsed.
@ -72,6 +73,7 @@
- (NSMutableDictionary*) parseProtocol; - (NSMutableDictionary*) parseProtocol;
- (NSMutableArray*) parseProtocolList; - (NSMutableArray*) parseProtocolList;
- (void) reset; - (void) reset;
- (void) setDeclared: (NSString*)name;
- (void) setupBuffer; - (void) setupBuffer;
- (unsigned) skipBlock; - (unsigned) skipBlock;
- (unsigned) skipComment; - (unsigned) skipComment;

View file

@ -26,6 +26,7 @@
- (void) dealloc - (void) dealloc
{ {
DESTROY(declared);
DESTROY(info); DESTROY(info);
DESTROY(comment); DESTROY(comment);
DESTROY(identifier); DESTROY(identifier);
@ -124,6 +125,10 @@
commentsRead = NO; commentsRead = NO;
fileName = name; fileName = name;
if (declared == nil)
{
ASSIGN(declared, fileName);
}
unitName = nil; unitName = nil;
itemName = nil; itemName = nil;
DESTROY(comment); DESTROY(comment);
@ -422,7 +427,7 @@ fail:
[dict setObject: methods forKey: @"Methods"]; [dict setObject: methods forKey: @"Methods"];
} }
[dict setObject: fileName forKey: @"Declared"]; [dict setObject: declared forKey: @"Declared"];
if (category == nil) if (category == nil)
{ {
@ -522,6 +527,11 @@ fail:
return nil; return nil;
} }
} }
else if (buffer[pos] == '#')
{
[self skipRemainderOfLine]; // Ignore preprocessor directive.
DESTROY(comment);
}
else else
{ {
[self skipStatement]; /* FIXME - currently we ignore ivars */ [self skipStatement]; /* FIXME - currently we ignore ivars */
@ -758,7 +768,11 @@ fail:
/* /*
* Get a list of known methods. * Get a list of known methods.
*/ */
if ([unitName hasSuffix: @")"]) if ([unitName hasPrefix: @"("])
{
exist = nil; // A protocol ... no method implementations.
}
else if ([unitName hasSuffix: @")"])
{ {
exist = [info objectForKey: @"Categories"]; exist = [info objectForKey: @"Categories"];
} }
@ -770,7 +784,7 @@ fail:
exist = [exist objectForKey: @"Methods"]; exist = [exist objectForKey: @"Methods"];
/* /*
* If there were no methods in the interface, we can't * If there were no methods in the interface, we can't
* document any now so we mak as well skip to the end. * document any now so we may as well skip to the end.
*/ */
if (exist == nil) if (exist == nil)
{ {
@ -1006,7 +1020,7 @@ fail:
goto fail; goto fail;
} }
[dict setObject: name forKey: @"Name"]; [dict setObject: name forKey: @"Name"];
unitName = name; unitName = [NSString stringWithFormat: @"(%@)", name];
/* /*
* Protocols may themselves conform to protocols. * Protocols may themselves conform to protocols.
@ -1092,6 +1106,7 @@ fail:
- (void) reset - (void) reset
{ {
[info removeAllObjects]; [info removeAllObjects];
DESTROY(declared);
DESTROY(comment); DESTROY(comment);
fileName = nil; fileName = nil;
unitName = nil; unitName = nil;
@ -1102,6 +1117,11 @@ fail:
pos = 0; pos = 0;
} }
- (void) setDeclared: (NSString*)name
{
ASSIGN(declared, name);
}
/** /**
* Read in the file to be parsed and store it in a temporary unicode * Read in the file to be parsed and store it in a temporary unicode
* buffer. Perform basic transformations on the buffer to simplify * buffer. Perform basic transformations on the buffer to simplify
@ -1449,7 +1469,7 @@ fail:
{ {
r = NSMakeRange(i, r.location - i); r = NSMakeRange(i, r.location - i);
author = [comment substringWithRange: r]; author = [comment substringWithRange: r];
author = [author stringByTrimmingWhiteSpaces]; author = [author stringByTrimmingSpaces];
authors = [NSMutableArray arrayWithObject: author]; authors = [NSMutableArray arrayWithObject: author];
[info setObject: authors forKey: @"authors"]; [info setObject: authors forKey: @"authors"];
} }
@ -1525,7 +1545,7 @@ fail:
{ {
r = NSMakeRange(i, r.location - i); r = NSMakeRange(i, r.location - i);
date = [comment substringWithRange: r]; date = [comment substringWithRange: r];
date = [date stringByTrimmingWhiteSpaces]; date = [date stringByTrimmingSpaces];
date = [NSString stringWithFormat: date = [NSString stringWithFormat:
@"<date>%@</date>", date]; @"<date>%@</date>", date];
[info setObject: date forKey: @"date"]; [info setObject: date forKey: @"date"];
@ -1552,7 +1572,7 @@ fail:
{ {
r = NSMakeRange(i, r.location - i); r = NSMakeRange(i, r.location - i);
version = [comment substringWithRange: r]; version = [comment substringWithRange: r];
version = [version stringByTrimmingWhiteSpaces]; version = [version stringByTrimmingSpaces];
version = [NSString stringWithFormat: version = [NSString stringWithFormat:
@"<version>%@</version>", version]; @"<version>%@</version>", version];
[info setObject: version forKey: @"version"]; [info setObject: version forKey: @"version"];

View file

@ -25,13 +25,16 @@
The autogsdoc tool is a command-line utility for parsing ObjectiveC The autogsdoc tool is a command-line utility for parsing ObjectiveC
source code (header files and optionally source files) in order to source code (header files and optionally source files) in order to
generate documentation covering the public interface of the various generate documentation covering the public interface of the various
classes in the source. classes, categories, and protocols in the source.
</p> </p>
<p> <p>
The simple way to use this is to run the command with one or more The simple way to use this is to run the command with one or more
header file names as arguments ... the tool will automatically header file names as arguments ... the tool will automatically
parse corresponding source files in the saem directory, and produce parse corresponding source files in the same directory, and produce
gsdoc files as output. gsdoc files as output. You may also supply source file names
(in which case documentation will be produced for the private
methods within the source files), and the names of existing gsdoc
documentation files (in which case their contents will be indexed).
</p> </p>
<p> <p>
Even without any human assistance, this tool will produce skeleton Even without any human assistance, this tool will produce skeleton
@ -40,8 +43,8 @@
from the source files and insert those comments into the gsdoc output. from the source files and insert those comments into the gsdoc output.
</p> </p>
<p> <p>
Any comment beginning with slash and <em>two</em> asterisks rathr than Any comment beginning with slash and <em>two</em> asterisks rather than
the common slash and single asterisk, is taken to be gsdoc markup to the common slash and single asterisk, is taken to be gsdoc markup, to
be use as the description of the class or method following it. This be use as the description of the class or method following it. This
comment text is reformatted and then inserted into the output. comment text is reformatted and then inserted into the output.
</p> </p>
@ -75,7 +78,7 @@
of the gsdoc output. of the gsdoc output.
</item> </item>
<item><strong>&lt;date&gt;</strong> <item><strong>&lt;date&gt;</strong>
Date off the revision of the document ... placed in the head Date of the revision of the document ... placed in the head
of the gsdoc output. If this is omitted the tool will try to of the gsdoc output. If this is omitted the tool will try to
construct a value from the RCS Date tag (if available). construct a value from the RCS Date tag (if available).
</item> </item>
@ -141,7 +144,12 @@
enclosed in &lt;var&gt; ... &lt;/var&gt; markup. enclosed in &lt;var&gt; ... &lt;/var&gt; markup.
</item> </item>
<item>Method names (beginning with a plus or minus) are enclosed <item>Method names (beginning with a plus or minus) are enclosed
in &lt;ref...&gt; ... &lt;/ref&gt; markup. in &lt;ref...&gt; ... &lt;/ref&gt; markup.<br />
eg. -init
</item>
<item>Method specifiers including class names (beginning and ending with
square brackets) are enclosed in &lt;ref...&gt; ... &lt;/ref&gt; markup.
<br />eg. [NSObject -init]
</item> </item>
</list> </list>
<p> <p>
@ -149,16 +157,35 @@
supplied as command-line arguments as usual) - supplied as command-line arguments as usual) -
</p> </p>
<list> <list>
<item><strong>Declared</strong>
Specify where headers are to be documented as being found.<br />
The actual name produced in the documentation is formed by appending
the last component of the header file name to the value of this
default.<br />
If this default is not specified, the full name of the header file
(as supplied on the command line), with the HeaderDirectory
default prepended, is used.
</item>
<item><strong>DocumentationDirectory</strong> <item><strong>DocumentationDirectory</strong>
May be used to specify the directory in which generated May be used to specify the directory in which generated
gsdoc files are to be placed. If this is not set, output documentation is to be placed. If this is not set, output
is placed in thge same directory as the source files. is placed in the current directory.
</item>
<item><strong>HeaderDirectory</strong>
May be used to specify the directory to be searched for header files.
If this is not specified, headers are looked for relative to the
current directory or using absolute path names if given.
</item>
<item><string>Project</strong>
May be used to specify the name of this project ... determines the
name of the index reference file produced as part of the documentation
to provide information enabling other projects to cross-reference to
items in this project.
</item> </item>
<item><strong>SourceDirectory</strong> <item><strong>SourceDirectory</strong>
May be used to specify the directory in which the tool looks May be used to specify the directory to be searched for header files.
for source files. If this is not set, the tool looks for the If this is not specified, headers are looked for relative to the
source in the same directory as the header files named on the current directory or using absolute path names if given.
command line.
</item> </item>
</list> </list>
<section> <section>
@ -196,12 +223,18 @@ main(int argc, char **argv, char **env)
NSUserDefaults *defs; NSUserDefaults *defs;
NSFileManager *mgr; NSFileManager *mgr;
NSString *documentationDirectory; NSString *documentationDirectory;
NSString *declared;
NSString *headerDirectory;
NSString *sourceDirectory; NSString *sourceDirectory;
NSString *projectName;
NSString *refsFile;
AGSIndex *prjRefs;
AGSIndex *indexer; AGSIndex *indexer;
AGSParser *parser; AGSParser *parser;
AGSOutput *output; AGSOutput *output;
NSString *up = nil; NSString *up = nil;
NSString *prev = nil; NSString *prev = nil;
unsigned pass;
CREATE_AUTORELEASE_POOL(pool); CREATE_AUTORELEASE_POOL(pool);
#ifdef GS_PASS_ARGUMENTS #ifdef GS_PASS_ARGUMENTS
@ -210,10 +243,30 @@ main(int argc, char **argv, char **env)
defs = [NSUserDefaults standardUserDefaults]; defs = [NSUserDefaults standardUserDefaults];
[defs registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [defs registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys:
@"Yes", @"Monolithic", nil]]; @"Untitled", @"ProjectName",
nil]];
projectName = [defs stringForKey: @"ProjectName"];
declared = [defs stringForKey: @"Declared"];
headerDirectory = [defs stringForKey: @"HeaderDirectory"];
if (headerDirectory == nil)
{
headerDirectory = @".";
}
sourceDirectory = [defs stringForKey: @"SourceDirectory"]; sourceDirectory = [defs stringForKey: @"SourceDirectory"];
if (sourceDirectory == nil)
{
sourceDirectory = headerDirectory;
}
documentationDirectory = [defs stringForKey: @"DocumentationDirectory"]; documentationDirectory = [defs stringForKey: @"DocumentationDirectory"];
if (documentationDirectory == nil)
{
documentationDirectory = @".";
}
proc = [NSProcessInfo processInfo]; proc = [NSProcessInfo processInfo];
if (proc == nil) if (proc == nil)
@ -224,169 +277,253 @@ main(int argc, char **argv, char **env)
mgr = [NSFileManager defaultManager]; mgr = [NSFileManager defaultManager];
prjRefs = [AGSIndex new];
indexer = [AGSIndex new]; indexer = [AGSIndex new];
parser = [AGSParser new]; parser = [AGSParser new];
output = [AGSOutput new]; output = [AGSOutput new];
args = [proc arguments]; args = [proc arguments];
for (i = 1; i < [args count]; i++)
/*
* On the initial pass (pass0), we parse all files, produce indexes,
* and write gsdoc output, but not html output.
*
* On the next pass, we have all the indexing info, so we can use it
* to produce html output.
*/
for (pass = 0; pass < 2; pass++)
{ {
NSString *arg = [args objectAtIndex: i]; CREATE_AUTORELEASE_POOL(arp);
if ([arg hasPrefix: @"-"]) for (i = 1; i < [args count]; i++)
{ {
i++; // Skip next value ... it is a default. NSString *arg = [args objectAtIndex: i];
}
else if ([arg hasSuffix: @".h"] || [arg hasSuffix: @".m"])
{
NSString *ddir;
NSString *sdir;
NSString *file;
NSString *generated;
BOOL isSource = [arg hasSuffix: @".m"];
file = [[arg lastPathComponent] stringByDeletingPathExtension]; if ([arg hasPrefix: @"-"])
if (isSource == YES)
{ {
sdir = arg; i++; // Skip next value ... it is a default.
} }
else else if ([arg hasSuffix: @".h"] == YES
|| [arg hasSuffix: @".m"] == YES
|| [arg hasSuffix: @".gsdoc"]== YES)
{ {
if (sourceDirectory == nil) NSString *gsdocfile;
NSString *htmlfile;
NSString *hfile;
NSString *sfile;
NSString *ddir;
NSString *hdir;
NSString *sdir;
NSString *file;
NSString *generated;
BOOL isSource = [arg hasSuffix: @".m"];
BOOL isDocumentation = [arg hasSuffix: @".gsdoc"];
file = [[arg lastPathComponent] stringByDeletingPathExtension];
hdir = [arg stringByDeletingLastPathComponent];
if ([hdir length] == 0)
{ {
sdir = [arg stringByDeletingLastPathComponent]; hdir = headerDirectory;
sdir = sourceDirectory;
}
else if ([hdir isAbsolutePath] == YES)
{
sdir = hdir;
} }
else else
{ {
sdir = sourceDirectory; hdir = [headerDirectory stringByAppendingPathComponent: hdir];
sdir = [sourceDirectory stringByAppendingPathComponent: sdir];
} }
sdir = [sdir stringByAppendingPathComponent: file];
sdir = [sdir stringByAppendingPathExtension: @"m"];
}
if (documentationDirectory == nil)
{
ddir = [arg stringByDeletingLastPathComponent];
}
else
{
ddir = documentationDirectory; ddir = documentationDirectory;
}
ddir = [ddir stringByAppendingPathComponent: file];
ddir = [ddir stringByAppendingPathExtension: @"gsdoc"];
if ([mgr isReadableFileAtPath: arg] == NO) hfile = [hdir stringByAppendingPathComponent: file];
{ hfile = [hfile stringByAppendingPathExtension: @"h"];
NSLog(@"No readable header at '%@' ... skipping", arg); sfile = [sdir stringByAppendingPathComponent: file];
continue; sfile = [sfile stringByAppendingPathExtension: @"m"];
} gsdocfile = [ddir stringByAppendingPathComponent: file];
[parser reset]; gsdocfile = [gsdocfile stringByAppendingPathExtension: @"gsdoc"];
[parser parseFile: arg isSource: NO]; htmlfile = [ddir stringByAppendingPathComponent: file];
htmlfile = [htmlfile stringByAppendingPathExtension: @"html"];
if ([mgr isReadableFileAtPath: sdir] == YES) if (pass == 0)
{
[parser parseFile: sdir isSource: YES];
}
[[parser info] setObject: file forKey: @"base"];
if (up == nil)
{
up = file;
}
else
{
[[parser info] setObject: up forKey: @"up"];
}
if (prev != nil)
{
[[parser info] setObject: prev forKey: @"prev"];
}
prev = file;
if (i < [args count] - 1)
{
unsigned j = i + 1;
while (j < [args count])
{ {
NSString *name = [args objectAtIndex: j++]; /*
* We perform parsing of source code in pass 0 only.
*/
[parser reset];
if ([name hasSuffix: @".h"] || [name hasSuffix: @".m"]) if (isSource == NO && isDocumentation == NO)
{ {
name = [[name lastPathComponent] /*
stringByDeletingPathExtension]; * Try to parse header to see what needs documenting.
[[parser info] setObject: name forKey: @"next"]; */
break; if ([mgr isReadableFileAtPath: hfile] == NO)
{
NSLog(@"No readable header at '%@' ... skipping",
hfile);
continue;
}
if (declared != nil)
{
[parser setDeclared:
[declared stringByAppendingPathComponent:
[hfile lastPathComponent]]];
}
[parser parseFile: hfile isSource: NO];
}
else if (isSource == YES)
{
/*
* Try to parse source *as-if-it-was-a-header*
* to see what needs documenting.
*/
if ([mgr isReadableFileAtPath: sfile] == NO)
{
NSLog(@"No readable source at '%@' ... skipping",
sfile);
continue;
}
if (declared != nil)
{
[parser setDeclared:
[declared stringByAppendingPathComponent:
[sfile lastPathComponent]]];
}
[parser parseFile: sfile isSource: NO];
}
if (isDocumentation == NO)
{
/*
* If we can read a source file, parse it for any
* additional information on items found in the header.
*/
if ([mgr isReadableFileAtPath: sfile] == YES)
{
[parser parseFile: sfile isSource: YES];
}
/*
* Set up linkage for this file.
*/
[[parser info] setObject: file forKey: @"base"];
if (up == nil)
{
up = file;
}
else
{
[[parser info] setObject: up forKey: @"up"];
}
if (prev != nil)
{
[[parser info] setObject: prev forKey: @"prev"];
}
prev = file;
if (i < [args count] - 1)
{
unsigned j = i + 1;
while (j < [args count])
{
NSString *name = [args objectAtIndex: j++];
if ([name hasSuffix: @".h"]
|| [name hasSuffix: @".m"]
|| [name hasSuffix: @".gsdoc"])
{
name = [[name lastPathComponent]
stringByDeletingPathExtension];
[[parser info] setObject: name
forKey: @"next"];
break;
}
}
}
generated = [output output: [parser info]];
if ([generated writeToFile: gsdocfile
atomically: YES] == NO)
{
NSLog(@"Sorry unable to write %@", gsdocfile);
}
} }
} }
}
generated = [output output: [parser info]]; if ([mgr isReadableFileAtPath: gsdocfile] == YES)
{
CREATE_AUTORELEASE_POOL(pool);
GSXMLParser *parser;
AGSIndex *locRefs;
AGSHtml *html;
NSString *result;
if ([generated writeToFile: ddir atomically: YES] == NO) parser = [GSXMLParser parserWithContentsOfFile: gsdocfile];
{ [parser substituteEntities: YES];
NSLog(@"Sorry unable to write %@", ddir); [parser doValidityChecking: YES];
if ([parser parse] == NO)
{
NSLog(@"WARNING %@ is not a valid document", gsdocfile);
}
if (![[[[parser doc] root] name] isEqualToString: @"gsdoc"])
{
NSLog(@"not a gsdoc document - because name node is %@",
[[[parser doc] root] name]);
return 1;
}
locRefs = AUTORELEASE([AGSIndex new]);
[locRefs makeRefs: [[parser doc] root]];
if (pass == 1)
{
/*
* We only perform final outpu in pass 1
*/
html = AUTORELEASE([AGSHtml new]);
[html setGlobalRefs: prjRefs];
[html setLocalRefs: locRefs];
result = [html outputDocument: [[parser doc] root]];
if ([result writeToFile: htmlfile atomically: YES] == NO)
{
NSLog(@"Sorry unable to write %@", htmlfile);
}
}
else
{
/*
* We only accumulate index info in pass 0
*/
[indexer mergeRefs: [locRefs refs]];
[prjRefs mergeRefs: [locRefs refs]];
}
RELEASE(pool);
}
else if (isDocumentation)
{
NSLog(@"No readable documentation at '%@' ... skipping",
gsdocfile);
}
} }
else else
{ {
CREATE_AUTORELEASE_POOL(pool); NSLog(@"Unknown argument '%@' ... ignored", arg);
GSXMLParser *parser;
AGSIndex *locRefs;
AGSHtml *html;
parser = [GSXMLParser parserWithContentsOfFile: ddir];
[parser substituteEntities: YES];
[parser doValidityChecking: YES];
if ([parser parse] == NO)
{
NSLog(@"WARNING %@ did not produce a valid document", arg);
}
if (![[[[parser doc] root] name] isEqualToString: @"gsdoc"])
{
NSLog(@"not a gsdoc document - because name node is %@",
[[[parser doc] root] name]);
return 1;
}
locRefs = AUTORELEASE([AGSIndex new]);
[locRefs makeRefs: [[parser doc] root]];
html = AUTORELEASE([AGSHtml new]);
[html setLocalRefs: indexer];
[html outputDocument: [[parser doc] root]];
[indexer mergeRefs: [locRefs refs]];
RELEASE(pool);
} }
} }
else if ([arg hasSuffix: @".gsdoc"] == YES) RELEASE(arp);
{ }
CREATE_AUTORELEASE_POOL(pool);
GSXMLParser *parser;
AGSHtml *html;
parser = [GSXMLParser parserWithContentsOfFile: arg]; /*
[parser substituteEntities: YES]; * Save references.
[parser doValidityChecking: YES]; */
if ([parser parse] == NO) refsFile = [documentationDirectory stringByAppendingPathComponent:
{ projectName];
NSLog(@"WARNING %@ did not produce a valid document", arg); refsFile = [refsFile stringByAppendingPathExtension: @"gsdocidx"];
} if ([[prjRefs refs] writeToFile: refsFile atomically: YES] == NO)
if (![[[[parser doc] root] name] isEqualToString: @"gsdoc"]) {
{ NSLog(@"Sorry unable to write %@", refsFile);
NSLog(@"not a gsdoc document - because name node is %@",
[[[parser doc] root] name]);
return 1;
}
html = AUTORELEASE([AGSHtml new]);
NSLog(@"%@", [html outputDocument: [[parser doc] root]]);
RELEASE(pool);
}
else
{
NSLog(@"Unknown argument '%@' ... ignored", arg);
}
} }
RELEASE(pool); RELEASE(pool);