",
file, type, ref, text];
}
if (!isBareStyle)
{
[buf appendString: @""];
}
else
{
[buf appendString: @" "];
}
[buf appendString: @"\n"];
}
if (!isBareStyle)
{
[self decIndent];
[buf appendString: indent];
[buf appendString: @"\n"];
}
}
else if ([dict count] > 0)
{
NSString *sep = @"";
NSString *u = unit;
BOOL isInUnit = NO;
if (unit != nil)
{
if ([type isEqual: @"method"] || [type isEqual: @"ivariable"])
{
isInUnit = YES;
if ([type isEqual: @"ivariable"])
{
sep = @"*"; // List ivars in class
}
else if (classname != nil && category == nil)
{
NSArray *catNames;
NSDictionary *d;
/*
* For a class, we want to list methods in any associated
* categories as well as those of the class itself.
*/
d = [refs objectForKey: @"categories"];
d = [d objectForKey: classname];
catNames = [d allKeys];
if ((c = [catNames count]) > 0)
{
NSMutableDictionary *m = [dict mutableCopy];
NSDictionary *unitDict;
unitDict = [refs objectForKey: @"unitmethods"];
for (i = 0; i < c; i++)
{
NSString *catName = [catNames objectAtIndex: i];
NSDictionary *catDict;
NSString *cName;
NSEnumerator *enumerator;
NSString *mname;
cName = [classname stringByAppendingFormat: @"(%@)",
catName];
catDict = [unitDict objectForKey: cName];
enumerator = [catDict keyEnumerator];
/*
* Add category references to the dictionary,
* prefixing them with the category they belong to.
*/
while ((mname = [enumerator nextObject]) != nil)
{
NSString *file = [catDict objectForKey: mname];
NSString *ref = [NSString stringWithFormat:
@"(%@)%@", catName, mname];
[m setObject: file forKey: ref];
}
}
dict = AUTORELEASE(m);
}
}
}
}
[buf appendString: indent];
if (!isBareStyle)
{
[buf appendFormat: @"%@\n", title];
}
[buf appendString: indent];
if (!isBareStyle)
{
[buf appendString: @"
"];
[self incIndent];
}
[buf appendString: @"\n"];
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;
ref = [ref stringByReplacingString: @":" withString: @"$"];
/*
* If a reference to a method contains a leading category name,
* we don't want it in the visible method name, however if it's
* actually a formal protocol name, we need to make it look right
* by changing the round brackets to angle brackets.
*/
if ([text hasPrefix: @"("] == YES)
{
NSRange r = [text rangeOfString: @")"];
if (NSMaxRange(r) == [text length]) // A formal protocol
{
text = [text stringByReplacingString: @"("
withString: @"<"];
text = [text stringByReplacingString: @")"
withString: @">"];
}
else // Category name in brackets followed by class name
{
text = [text substringFromIndex: NSMaxRange(r)];
}
}
[buf appendString: indent];
if (!isBareStyle)
{
[buf appendString: @"
"];
}
[buf appendString: @"%@",
file, type, u, sep, ref, text];
}
else
{
if (([type isEqual: @"protocol"] == YES)
&& ([text hasPrefix: @"<"] == NO))
{
// it's an informal protocol, detected earlier as an
// unimplemented category of NSObject; make proper link
text = [text stringByDeletingPrefix: @"NSObject"];
[buf appendFormat: @"href=\"%@.html#%@$%@\">%@",
file, @"category", ref, text];
}
else
{
[buf appendFormat: @"href=\"%@.html#%@$%@\">%@",
file, type, ref, text];
}
}
if (!isBareStyle)
{
[buf appendString: @"
\n"];
[self incIndent];
[self outputNodeList: children to: buf];
// Close back division
[self decIndent];
[buf appendString: indent];
[buf appendString: @"
\n"];
}
else if ([name isEqual: @"body"] == YES)
{
/* Should already be in html body */
[self outputNodeList: children to: buf];
[buf appendString: indent];
[buf appendString: @" \n"];
if (prevFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Prev\n", prevFile];
}
if (upFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Up\n", upFile];
}
if (nextFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Next\n", nextFile];
}
[self decIndent];
[buf appendString: indent];
[buf appendString: indent];
[buf appendString: @"\n"];
[buf appendString: @"\n"];
[self incIndent];
// special formatting for table-of-contents frames; ultimately
// this should be moved to stylesheet
if (isContentsDoc)
{
[buf appendString: indent];
[buf appendFormat: @"\n", tocFont];
}
else
{
[buf appendString: indent];
[buf appendFormat: @"\n", mainFont];
}
if (prevFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Prev\n", prevFile];
}
if (upFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Up\n", upFile];
}
if (nextFile != nil)
{
[buf appendString: indent];
[buf appendFormat: @"Next\n", nextFile];
}
if (prevFile != nil || upFile != nil || nextFile != nil)
{
[buf appendString: indent];
[buf appendString: @" \n"];
}
[buf appendString: indent];
if (isContentsDoc)
{
headerTag = @"h2";
}
else
{
headerTag = @"h1";
}
[buf appendFormat: @"<%@>", headerTag, base];
[self outputText: [children firstChild] to: buf];
[buf appendFormat: @"%@>\n", headerTag];
children = [children nextElement];
if ([[children name] isEqual: @"author"] == YES)
{
[buf appendString: indent];
[buf appendString: @"
\n"];
sel = [prop objectForKey: @"factory"];
str = [prop objectForKey: @"type"];
if (sel != nil && [sel boolValue] == YES)
{
sel = @"+";
str = [NSString stringWithFormat: @"+ (%@) ",
[self typeRef: str]];
}
else
{
sel = @"-";
str = [NSString stringWithFormat: @"- (%@) ",
[self typeRef: str]];
}
children = nil;
while (tmp != nil)
{
if ([tmp type] == XML_ELEMENT_NODE)
{
if ([[tmp name] isEqual: @"sel"] == YES)
{
GSXMLNode *t = [tmp firstChild];
str = [str stringByAppendingString: @""];
while (t != nil)
{
if ([t type] == XML_TEXT_NODE)
{
NSString *content = [t escapedContent];
if (content == nil) content = @"";
sel = [sel stringByAppendingString: content];
// these nbsp added for readability, but must
// be removed below when making href link
sel = [sel stringByAppendingString: @" "];
if (hadArg == YES)
{
str = [str stringByAppendingString: @" "];
}
str = [str stringByAppendingString: content];
}
t = [t next];
}
str = [str stringByAppendingString: @""];
}
else if ([[tmp name] isEqual: @"arg"] == YES)
{
GSXMLNode *t = [tmp firstChild];
NSString *s;
s = [[tmp attributes] objectForKey: @"type"];
s = [self typeRef: s];
str = [str stringByAppendingFormat: @" (%@)", s];
while (t != nil)
{
if ([t type] == XML_TEXT_NODE)
{
NSString *content = [t escapedContent];
if (content == nil) content = @"";
str = [str stringByAppendingString: content];
}
t = [t next];
}
hadArg = YES; // Say we have found an arg.
}
else if ([[tmp name] isEqual: @"vararg"] == YES)
{
sel = [sel stringByAppendingString: @",..."];
str = [str stringByAppendingString: @",..."];
children = [tmp nextElement];
break;
}
else
{
children = tmp;
break;
}
}
tmp = [tmp nextElement];
}
if ([sel length] > 1)
{
NSString *s;
NSMutableString *linkRef;
/*
* Output selector heading.
*/
[buf appendString: indent];
[buf appendString: @"
"];
// get rid of nbsps put in for readability above
linkRef = [NSMutableString stringWithCapacity: [sel length]];
[linkRef setString:sel];
[linkRef replaceString: @" " withString: @""];
s = [self makeLink: linkRef
ofType: @"method"
inUnit: nil
isRef: NO];
if (s != nil)
{
[buf appendString: s];
[buf appendString: [sel substringFromIndex: 1]];
[buf appendString: @""];
}
else
{
[buf appendString: [sel substringFromIndex: 1]];
}
[buf appendString: @"
\n"];
[buf appendString: indent];
[buf appendString: str];
[buf appendString: @"; \n"];
node = firstElement(children);
/*
* List standards with which method complies
*/
children = node;
if ([[children name] isEqual: @"standards"])
{
node = [node nextElement];
}
[self outputVersion: prop to: buf];
if ((str = [prop objectForKey: @"init"]) != nil
&& [str boolValue] == YES)
{
[buf appendString: @"This is a designated initialiser "
@"for the class. \n"];
}
str = [prop objectForKey: @"override"];
if ([str isEqual: @"subclass"] == YES)
{
[buf appendString: @"Subclasses must "
@"override this method. \n"];
}
else if ([str isEqual: @"dummy"] == YES)
{
[buf appendString: @"An empty method provided for subclasses "
@"to override. \n"];
}
else if ([str isEqual: @"never"] == YES)
{
[buf appendString: @"Subclasses must NOT "
@"override this method. \n"];
}
if ([[node name] isEqual: @"desc"])
{
[self outputNode: node to: buf];
}
[buf appendString: indent];
[buf appendString: @"\n"];
}
[buf appendString:@"
\n"];
}
else if ([name isEqual: @"p"] == YES)
{
[self outputBlock: node to: buf inPara: NO];
}
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"];
GSXMLNode *tmp = [node firstChild];
NSString *c = [prop objectForKey: @"class"];
NSString *s;
// fill in default value
if ((type == nil) || [type isEqual: @""])
{
type = @"label";
}
if ([type isEqual: @"method"] || [type isEqual: @"ivariable"])
{
s = [self makeLink: r ofType: type inUnit: c isRef: YES];
}
else
{
s = [self makeLink: r ofType: type isRef: YES];
/**
* As a special case, if we have a reference to a function,
* and we can't find it, we check to see if there is actually
* a macro of that name and refer to that instead.
*/
if (s == nil && [type isEqual: @"function"] == YES)
{
s = [self makeLink: r ofType: @"macro" isRef: YES];
}
}
if (s == nil)
{
if (c == nil)
{
NSLog(@"Location of %@ '%@' (referenced from %@) "
@"not found or not unique.", type, r, base);
}
else
{
NSLog(@"Location of the %@ version of %@ '%@' (referenced "
@"from %@) not found.", c, type, r, base);
}
if (tmp == nil)
{
[buf appendString: r];
}
else
{
[self outputText: tmp to: buf];
}
[buf appendString: @"\n"];
}
else
{
[buf appendString: s];
if (tmp == nil)
{
[buf appendString: r];
}
else
{
[self outputText: tmp to: buf];
}
[buf appendString: @"\n"];
}
}
else if ([name isEqual: @"protocol"] == YES)
{
NSString *value = [prop objectForKey: @"name"];
unit = [NSString stringWithFormat: @"(%@)", value];
[buf appendString: indent];
[buf appendString: @"
\n"];
[self outputUnit: node to: buf];
unit = nil;
}
else if ([name isEqual: @"EOEntity"] == YES
|| [name isEqual: @"EOModel"] == YES)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
else if ([name isEqual: @"section"] == YES)
{
heading = @"h2";
sect++;
ssect = 0;
sssect = 0;
[self outputNodeList: children to: buf];
heading = @"h1";
}
else if ([name isEqual: @"site"] == YES)
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"standards"])
{
}
else if ([name isEqual: @"strong"] == YES)
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"subsect"] == YES)
{
heading = @"h3";
ssect++;
sssect = 0;
[self outputNodeList: children to: buf];
heading = @"h2";
}
else if ([name isEqual: @"subsubsect"] == YES)
{
heading = @"h4";
sssect++;
[self outputNodeList: children to: buf];
heading = @"h3";
}
else if ([name isEqual: @"type"] == YES)
{
NSString *nam;
NSString *str;
NSString *s;
nam = [prop objectForKey: @"name"];
str = [prop objectForKey: @"type"];
str = [self typeRef: str];
str = [NSString stringWithFormat: @"typedef %@ %@", str, nam];
/*
* Output typedef heading.
*/
[buf appendString: indent];
[buf appendString: @"
"];
s = [self makeLink: nam ofType: @"type" isRef: NO];
if (s != nil)
{
[buf appendString: s];
[buf appendString: nam];
[buf appendString: @""];
}
else
{
[buf appendString: nam];
}
[buf appendString: @"
\n"];
[buf appendString: indent];
[buf appendString: str];
[buf appendString: @"; \n"];
node = firstElement(children);
if (node != nil && [[node name] isEqual: @"declared"] == YES)
{
[self outputNode: node to: buf];
node = [node nextElement];
}
children = node;
if ([[children name] isEqual: @"standards"])
{
node = [node nextElement];
}
[self outputVersion: prop to: buf];
if (node != nil && [[node name] isEqual: @"desc"] == YES)
{
[self outputNode: node to: buf];
node = [node nextElement];
}
[buf appendString: indent];
[buf appendString: @"\n"];
}
else if ([name isEqual: @"uref"] == YES)
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"url"] == YES)
{
// create an HREF as before but use the URL itself as marker text
[buf appendString: @""];
[buf appendString: [prop objectForKey: @"url"]];
[buf appendString: @""];
}
else if ([name isEqual: @"var"] == YES) // %phrase
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"variable"] == YES)
{
NSString *nam;
NSString *str;
NSString *s;
nam = [prop objectForKey: @"name"];
str = [prop objectForKey: @"type"];
str = [self typeRef: str];
str = [str stringByAppendingFormat: @" %@", nam];
/*
* Output variable heading.
*/
[buf appendString: indent];
[buf appendString: @"
"];
s = [self makeLink: nam ofType: @"variable" isRef: NO];
if (s != nil)
{
[buf appendString: s];
[buf appendString: nam];
[buf appendString: @""];
}
else
{
[buf appendString: nam];
}
[buf appendString: @"
\n"];
[buf appendString: indent];
[buf appendString: str];
[buf appendString: @"; \n"];
node = firstElement(children);
if ([[node name] isEqual: @"declared"] == YES)
{
[self outputNode: node to: buf];
node = [node nextElement];
}
children = node;
if ([[children name] isEqual: @"standards"])
{
node = [node nextElement];
}
[self outputVersion: prop to: buf];
if ([[node name] isEqual: @"desc"])
{
[self outputNode: node to: buf];
}
[buf appendString: indent];
[buf appendString: @"\n"];
}
else
{
GSXMLNode *tmp;
/*
* Try outputting as any of the list elements.
*/
tmp = [self outputList: node to: buf];
if (tmp == node)
{
NSLog(@"Element '%@' not implemented", name); // FIXME
}
node = tmp;
}
}
[arp drain];
}
/**
* Output all the nodes from this one onwards ... try to output
* as text first, if not possible, call the main method to output
* each node.
*/
- (void) outputNodeList: (GSXMLNode*)node to: (NSMutableString*)buf
{
while (node != nil)
{
GSXMLNode *next = [node nextElement];
GSXMLNode *tmp;
tmp = [self outputText: node to: buf];
if (tmp == node)
{
[self outputNode: node to: buf];
node = next;
}
else
{
node = tmp;
}
}
}
/**
* Outputs zero or more nodes at the same level as long as the nodes
* are valid %block elements. Returns nil or the first node not output.
* The value of flag is used to control paragraph nesting ... if YES
* we close a paragraph before opening a new one, and open again once
* the new paragraph closes.
*/
- (GSXMLNode*) outputBlock: (GSXMLNode*)node
to: (NSMutableString*)buf
inPara: (BOOL)flag
{
if (node != nil && [node type] == XML_ELEMENT_NODE)
{
GSXMLNode *tmp = node;
NSString *n;
node = [self outputList: node to: buf];
if (node != tmp)
{
return node;
}
n = [node name];
if ([n isEqual: @"p"] == YES)
{
if (flag == YES)
{
[self decIndent];
[buf appendString: indent];
[buf appendString: @"\n"];
}
[buf appendString: indent];
[buf appendString: @"
{\n"];
[self incIndent];
// all children should be dictionaryItems w/key and value attributes;
// if the value attribute is absent, the content is the value
for (; children != nil; children = [children nextElement])
{
GSXMLNode *dItem = children;
NSDictionary *dProp = [dItem attributes];
NSString *value = [dProp objectForKey: @"value"];
GSXMLNode *dChild;
if (![@"dictionaryItem" isEqualToString: [dItem name]])
{
continue;
}
[buf appendString: indent];
[buf appendString: @"
\n"];
[buf appendString: @" \n"];
}
}
/**
* 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];
s = [self makeLink: n ofType: @"protocol" isRef: YES];
if (s != nil)
{
s = [s stringByAppendingString: t];
t = [s stringByAppendingString: @""];
}
return t;
}
- (void) setGlobalRefs: (AGSIndex*)r
{
ASSIGN(globalRefs, r);
}
- (void) setLocalRefs: (AGSIndex*)r
{
ASSIGN(localRefs, r);
}
- (void) setProjectRefs: (AGSIndex*)r
{
ASSIGN(projectRefs, r);
}
- (void) setInstanceVariablesAtEnd: (BOOL)val
{
ivarsAtEnd = val;
}
/**
* 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 *str = [t stringByTrimmingSpaces];
NSString *s;
unsigned end = [str length];
unsigned start;
NSMutableString *ms = nil;
NSRange er;
NSRange sr;
if (end == 0)
{
return nil;
}
t = str;
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 = [str substringWithRange: NSMakeRange(start, end - start)];
s = [self makeLink: t ofType: @"type" isRef: YES];
if (s == nil)
{
s = [self makeLink: t ofType: @"class" isRef: YES];
}
s = [s stringByAppendingFormat: @"%@", t];
if (s != nil && [str length] == [t length])
{
return s;
}
/*
* Look for protocol spec.
*/
sr = [str rangeOfString: @"<"];
if (sr.length == 0)
{
sr = [str rangeOfString: @"<"];
}
if (sr.length == 0)
{
sr = [str rangeOfString: @"<"];
}
er = [str rangeOfString: @">"];
if (er.length == 0)
{
er = [str rangeOfString: @">"];
}
if (er.length == 0)
{
er = [str rangeOfString: @">"];
}
/*
* Substitute in protocol references.
*/
if (sr.length > 0 && er.length > 0 && er.location > sr.location)
{
NSString *pString;
NSRange r;
NSArray *protocols;
unsigned i;
r = NSMakeRange(NSMaxRange(sr), er.location - NSMaxRange(sr));
pString = [str substringWithRange: r];
protocols = [pString componentsSeparatedByString: @","];
ms = [str mutableCopy];
pString = @"";
for (i = 0; i < [protocols count]; i++)
{
NSString *p = [protocols objectAtIndex: i];
NSString *l;
l = [self makeLink: [NSString stringWithFormat: @"(%@)", p]
ofType: @"protocol"
isRef: YES];
if (l != nil)
{
p = [l stringByAppendingFormat: @"%@", p];
}
if (i > 0)
{
pString = [pString stringByAppendingString: @","];
}
pString = [pString stringByAppendingString: p];
}
[ms replaceCharactersInRange: r withString: pString];
}
/*
* Substitute in basic type reference.
*/
if (s != nil)
{
if (ms == nil)
{
ms = [str mutableCopy];
}
[ms replaceCharactersInRange: NSMakeRange(start, end - start)
withString: s];
}
if (ms != nil)
{
str = AUTORELEASE(ms);
}
return str;
}
@end
\n"];
[self incIndent];
while (children != nil)
{
children = [self outputBlock: children to: buf inPara: YES];
}
[self decIndent];
[buf appendString: indent];
[buf appendString: @"
\n"];
}
else if ([name isEqual: @"em"] == YES)
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"email"] == YES)
{
NSString *ename;
ename = [prop objectForKey: @"address"];
if (ename == nil)
{
[buf appendString: @""];
}
else
{
[buf appendFormat: @"", ename];
}
//
// [node firstChild] doesn't look like it points to
// the mail address.
// not sure _where_ it points to though...
//
#if 0
[self outputText: [node firstChild] to: buf];
#endif
if (ename == nil)
{
[buf appendString: @""];
}
else
{
[buf appendFormat: @"%@", ename];
}
}
else if ([name isEqual: @"embed"] == YES)
{
[self outputBlock: node to: buf inPara: NO];
}
else if ([name isEqual: @"entry"])
{
NSString *text;
NSString *val;
text = [children escapedContent];
val = [prop objectForKey: @"id"];
if (val == nil)
{
val = text;
if (val == nil) val = @"";
}
[buf appendString: [self makeAnchor: val ofType: @"label" name: @""]];
}
else if ([name isEqual: @"example"] == YES)
{
[self outputBlock: node to: buf inPara: NO];
}
else if ([name isEqual: @"file"] == YES)
{
[buf appendString: @""];
[self outputText: children to: buf];
[buf appendString: @""];
}
else if ([name isEqual: @"footnote"] == YES)
{
[buf appendString: @"
"];
[self outputText: children to: buf];
[buf appendString: @"
"];
}
else if ([name isEqual: @"front"] == YES)
{
// Open front division
[buf appendString: indent];
[buf appendString: @"
\n"];
[self incIndent];
[self outputNodeList: children to: buf];
// Close front division
[self decIndent];
[buf appendString: indent];
[buf appendString: @"