/* This tool converts documentation in gsdoc format to another format
At present (and for the forseeable future), the only format supported
is HTML.
Copyright (C) 2000 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald \r\n%@\r\n"];
for (i = 0; i < count; i++)
{
NSDictionary *dict = [array objectAtIndex: i];
NSString *title = [dict objectForKey: @"Title"];
NSString *ref = [dict objectForKey: @"Ref"];
NSArray *sub = [dict objectForKey: @"Contents"];
[text appendFormat: @"
\r\n"];
}
}
- (void) appendFootnotesToString: (NSMutableString*)text
{
unsigned count = [footnotes count];
if (count > 0)
{
unsigned i;
[text appendString: @"Footnotes
\r\n"];
for (i = 0; i < count; i++)
{
NSString *note = [footnotes objectAtIndex: i];
NSString *ref = [NSString stringWithFormat: @"foot-%u", i];
[text appendFormat: @"footnote %u -\r\n", ref, i];
[text appendString: note];
[text appendString: @"
\r\n"];
}
}
}
- (void) appendIndex: (NSString*)type toString: (NSMutableString*)text
{
NSDictionary *dict = [self indexForType: type];
NSEnumerator *enumerator;
NSArray *keys;
NSString *key;
keys = [dict keysSortedByValueUsingSelector: @selector(compare:)];
enumerator = [keys objectEnumerator];
[text appendString: @"\r\n"];
while ((key = [enumerator nextObject]) != nil)
{
NSString *name = [dict objectForKey: key];
[text appendFormat: @"
\r\n"];
}
- (void) dealloc
{
DESTROY(contents);
DESTROY(footnotes);
[super dealloc];
}
- (id) initWithFileName: (NSString*)name
{
self = [super initWithFileName: name];
if (self != nil)
{
mgr = RETAIN([NSFileManager defaultManager]);
refToFile = [NSMutableDictionary new];
contents = [NSMutableArray new];
footnotes = [NSMutableArray new];
if ([defs boolForKey: @"Monolithic"] == YES)
{
ASSIGN(currName, [baseName stringByAppendingPathExtension: @"html"]);
}
else
{
BOOL flag = NO;
if ([mgr fileExistsAtPath: baseName isDirectory: &flag] == NO)
{
if ([mgr createDirectoryAtPath: baseName attributes: nil] == NO)
{
NSLog(@"Unable to create directory '%@'", baseName);
RELEASE(self);
return nil;
}
}
else if (flag == NO)
{
NSLog(@"The file '%@' is not a directory", baseName);
RELEASE(self);
return nil;
}
ASSIGN(currName,
[baseName stringByAppendingPathComponent: @"index.html"]);
}
}
return self;
}
- (NSString*) parseAuthor: (xmlNodePtr)node
{
NSMutableString *text = [NSMutableString string];
NSString *name = [self getProp: "name" fromNode: node];
NSString *email = nil;
NSString *ename = nil;
NSString *url = nil;
NSString *desc = nil;
if (name == nil)
{
NSLog(@"Missing or illegal author name");
return nil;
}
node = node->childs;
if (node != 0 && strcmp(node->name, "email") == 0)
{
email = [self getProp: "email" fromNode: node];
ename = [self parseText: node->childs];
node = node->next;
}
if (node != 0 && strcmp(node->name, "url") == 0)
{
url = [self getProp: "url" fromNode: node];
node = node->next;
}
if (node != 0 && strcmp(node->name, "desc") == 0)
{
desc = [self parseDesc: node];
node = node->next;
}
[text appendString: @"%@
)\r\n",
email, ename];
}
[text appendString: @"Contents
\r\n"];
[self appendContents: contents toString: text];
}
/*
* Now output all the chapters.
*/
count = [front count];
for (i = 0; i < count; i++)
{
chapter = [front objectAtIndex: i];
[text appendString: chapter];
}
count = [body count];
for (i = 0; i < count; i++)
{
chapter = [body objectAtIndex: i];
[text appendString: chapter];
}
count = [back count];
for (i = 0; i < count; i++)
{
chapter = [back objectAtIndex: i];
[text appendString: chapter];
}
/*
* Now output any indices requested.
*/
while (node != 0 && strcmp(node->name, "index") == 0)
{
NSString *type = [self getProp: "type" fromNode: node];
if (type != nil)
{
[text appendFormat: @"%@ index
\r\n", type];
[self appendIndex: type toString: text];
}
node = node->next;
}
[self appendFootnotesToString: text];
[text appendString: @"
Version: %@
\r\n", version]; } if (node != 0 && strcmp(node->name, "date") == 0) { date = [self parseText: node->childs]; node = node->next; [text appendFormat: @"Date: %@
\r\n", date]; } if (node != 0 && strcmp(node->name, "abstract") == 0) { abstract = [self parseText: node->childs]; node = node->next; [text appendFormat: @"%@\r\n", abstract]; } if (node != 0 && strcmp(node->name, "copy") == 0) { copyright = [self parseText: node->childs]; node = node->next; [text appendFormat: @"
Copyright: %@
\r\n", copyright]; } return text; } - (NSString*) parseItem: (xmlNodePtr)node { node = node->childs; if (strcmp(node->name, "class") == 0 || strcmp(node->name, "category") == 0 || strcmp(node->name, "protocol") == 0 || strcmp(node->name, "function") == 0 || strcmp(node->name, "macro") == 0 || strcmp(node->name, "type") == 0 || strcmp(node->name, "variable") == 0) { return [self parseDef: node]; } if (strcmp(node->name, "list") == 0 || strcmp(node->name, "enum") == 0 || strcmp(node->name, "deflist") == 0 || strcmp(node->name, "qalist") == 0) { return [self parseList: node]; } if (strcmp(node->name, "p") == 0) { NSString *elem = [self parseText: node->childs]; if (elem == nil) { return nil; } return [NSString stringWithFormat: @"\r\n%@
\r\n", elem]; } if (strcmp(node->name, "example") == 0) { return [self parseExample: node]; } if (strcmp(node->name, "embed") == 0) { return [self parseEmbed: node]; } return [self parseText: node]; } - (NSString*) parseList: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; if (strcmp(node->name, "list") == 0) { [text appendString: @"Declared in: %@
\r\n", declared]; } if (args == nil) { [text appendFormat: @"Declaration: %@\r\n"]; RELEASE(arp); return text; } - (NSString*) parseChapter: (xmlNodePtr)node contents: (NSMutableArray*)array { CREATE_AUTORELEASE_POOL(arp); NSMutableString *text = [NSMutableString string]; const char *type = node->name; const char *next; const char *h; NSString *head; NSString *ref; NSMutableDictionary *dict; NSMutableArray *subs; ref = [self getProp: "id" fromNode: node]; if (ref == nil) { ref = [NSString stringWithFormat: @"cont-%u", contentsIndex++]; } node = node->childs; if (node == 0 || strcmp(node->name, "heading") != 0) { NSLog(@"%s without heading", type); return nil; } head = [self parseText: node->childs]; node = node->next; if (strcmp(type, "chapter") == 0) { next = "section"; h = "h2"; } else if (strcmp(type, "section") == 0) { next = "subsect"; h = "h3"; } else if (strcmp(type, "subsect") == 0) { next = "subsubsect"; h = "h4"; } else { next = ""; h = "h5"; } /* * Build content information and add it to the array at this level. */ subs = [NSMutableArray new]; dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: head, @"Title", ref, @"Ref", subs, @"Contents", nil]; RELEASE(subs); [array addObject: dict]; /* * Put heading in string. */ [text appendFormat: @"<%s>%@%s>\r\n", h, ref, head, h]; /* * Try to parse block data up to the next subsection. */ while (node != 0 && strcmp(node->name, next) != 0) { NSString *block = [self parseBlock: node]; if (block == nil) { return nil; } [text appendString: block]; node = node->next; } while (node != 0 && strcmp(node->name, next) == 0) { NSString *chapter = [self parseChapter: node contents: subs]; if (chapter == nil) { return nil; } [text appendString: chapter]; node = node->next; } [dict setObject: text forKey: @"Text"]; RELEASE(arp); return text; } - (NSString*) parseDef: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; if (strcmp(node->name, "class") == 0) { NSString *className = [self getProp: "name" fromNode: node]; NSString *superName = [self getProp: "super" fromNode: node]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *declared = nil; NSString *desc = nil; NSMutableArray *conform = [NSMutableArray array]; NSMutableArray *methods = [NSMutableArray array]; NSMutableArray *standards = [NSMutableArray array]; if (className == nil) { NSLog(@"Missing class name"); return nil; } if (ref == nil) { ref = className; } /* * Clear the methods index so it will contain only values from this class. */ [[self indexForType: @"method"] removeAllObjects]; node = node->childs; if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } while (node != 0 && strcmp(node->name, "conform") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [conform addObject: s]; } node = node->next; } if (node != 0 && strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; node = node->next; } while (node != 0 && strcmp(node->name, "method") == 0) { NSString *s = [self parseMethod: node]; if (s != nil) { [methods addObject: s]; } node = node->next; } while (node != 0 && strcmp(node->name, "standard") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [standards addObject: s]; } node = node->next; } [self setEntry: className withRef: ref inIndexOfType: @"class"]; [text appendFormat: @"
\r\n", ref, className]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared]; } if (superName != nil) { [text appendFormat: @"
Inherits from: %@
\r\n", superName]; } if ([conform count] > 0) { unsigned i; [text appendFormat: @"
Conforms to: %@\r\n", [conform objectAtIndex: 0]]; for (i = 1; i < [conform count]; i++) { [text appendFormat: @", %@\r\n", [conform objectAtIndex: i]]; } [text appendString: @"
\r\n"]; } if ([standards count] > 0) { unsigned i; [text appendFormat: @"
Standards: %@\r\n", [standards objectAtIndex: 0]]; for (i = 1; i < [standards count]; i++) { [text appendFormat: @", %@\r\n", [standards objectAtIndex: i]]; } [text appendString: @"
\r\n"]; } if (desc != nil) { [text appendFormat: @"
\r\n%@\r\n", desc]; } [self appendIndex: @"method" toString: text]; if ([methods count] > 0) { unsigned i; [text appendString: @"
\r\n"]; for (i = 0; i < [methods count]; i++) { [text appendString: [methods objectAtIndex: i]]; } } return text; } else if (strcmp(node->name, "category") == 0) { NSString *className = [self getProp: "class" fromNode: node]; NSString *catName = [self getProp: "name" fromNode: node]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *declared = nil; NSString *desc = nil; NSMutableArray *methods = [NSMutableArray array]; NSMutableArray *standards = [NSMutableArray array]; NSString *name; if (className == nil || catName == nil) { NSLog(@"Missing category or class name"); return nil; } name = [NSString stringWithFormat: @"%@ (%@)", catName, className]; if (ref == nil) { ref = name; } /* * Clear the methods index so it will contain only values from this class. */ [[self indexForType: @"method"] removeAllObjects]; node = node->childs; if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } if (node != 0 && strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; node = node->next; } while (node != 0 && strcmp(node->name, "method") == 0) { NSString *s = [self parseMethod: node]; if (s != nil) { [methods addObject: s]; } node = node->next; } while (node != 0 && strcmp(node->name, "standard") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [standards addObject: s]; } node = node->next; } [self setEntry: name withRef: ref inIndexOfType: @"category"]; [text appendFormat: @"
\r\n", ref, name]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared]; } if ([standards count] > 0) { unsigned i; [text appendFormat: @"
Standards: %@\r\n", [standards objectAtIndex: 0]]; for (i = 1; i < [standards count]; i++) { [text appendFormat: @", %@\r\n", [standards objectAtIndex: i]]; } [text appendString: @"
\r\n"]; } if (desc != nil) { [text appendFormat: @"
\r\n%@\r\n", desc]; } [self appendIndex: @"method" toString: text]; if ([methods count] > 0) { unsigned i; [text appendString: @"
\r\n"]; for (i = 0; i < [methods count]; i++) { [text appendString: [methods objectAtIndex: i]]; } } return text; } else if (strcmp(node->name, "protocol") == 0) { NSString *protName = [self getProp: "name" fromNode: node]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *declared = nil; NSString *desc = nil; NSMutableArray *methods = [NSMutableArray array]; NSMutableArray *standards = [NSMutableArray array]; if (protName == nil) { NSLog(@"Missing protocol name"); return nil; } if (ref == nil) { ref = protName; } /* * Clear the methods index so it will contain only values from this class. */ [[self indexForType: @"method"] removeAllObjects]; node = node->childs; if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } if (node != 0 && strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; node = node->next; } while (node != 0 && strcmp(node->name, "method") == 0) { NSString *s = [self parseMethod: node]; if (s != nil) { [methods addObject: s]; } node = node->next; } while (node != 0 && strcmp(node->name, "standard") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [standards addObject: s]; } node = node->next; } [self setEntry: protName withRef: ref inIndexOfType: @"protocol"]; [text appendFormat: @"
\r\n", ref, protName]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared]; } if ([standards count] > 0) { unsigned i; [text appendFormat: @"
Standards: %@\r\n", [standards objectAtIndex: 0]]; for (i = 1; i < [standards count]; i++) { [text appendFormat: @", %@\r\n", [standards objectAtIndex: i]]; } [text appendString: @"
\r\n"]; } if (desc != nil) { [text appendFormat: @"
\r\n%@\r\n", desc]; } [self appendIndex: @"method" toString: text]; if ([methods count] > 0) { unsigned i; [text appendString: @"
\r\n"]; for (i = 0; i < [methods count]; i++) { [text appendString: [methods objectAtIndex: i]]; } } return text; } else if (strcmp(node->name, "function") == 0) { return [self parseFunction: node]; } else if (strcmp(node->name, "macro") == 0) { return [self parseMacro: node]; } else if (strcmp(node->name, "type") == 0) { NSString *typeName = [self getProp: "name" fromNode: node]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *declared = nil; NSString *desc = nil; NSString *spec = nil; NSMutableArray *standards = [NSMutableArray array]; if (typeName == nil) { NSLog(@"Missing type name"); return nil; } if (ref == nil) { ref = typeName; } node = node->childs; if (node != 0 && strcmp(node->name, "typespec") == 0) { spec = [self parseText: node->childs]; node = node->next; } if (spec == nil) { NSLog(@"Missing type specification"); return nil; } if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } if (node != 0 && strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; node = node->next; } while (node != 0 && strcmp(node->name, "standard") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [standards addObject: s]; } node = node->next; } [self setEntry: typeName withRef: ref inIndexOfType: @"type"]; [text appendFormat: @"
\r\n", ref, typeName]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared]; } if ([standards count] > 0) { unsigned i; [text appendFormat: @"
Standards: %@\r\n", [standards objectAtIndex: 0]]; for (i = 1; i < [standards count]; i++) { [text appendFormat: @", %@\r\n", [standards objectAtIndex: i]]; } [text appendString: @"
\r\n"];
}
[text appendFormat: @"typedef %@ %@
\r\n", spec, typeName];
if (desc != nil)
{
[text appendFormat: @"
\r\n%@\r\n", desc]; } return text; } else if (strcmp(node->name, "variable") == 0) { NSString *name = [self getProp: "name" fromNode: node]; NSString *type = [self getProp: "type" fromNode: node]; NSString *value = [self getProp: "value" fromNode: node]; NSString *role = [self getProp: "role" fromNode: node]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *declared = nil; NSString *desc = nil; NSMutableArray *standards = [NSMutableArray array]; if (name == nil || type == nil) { NSLog(@"Missing variable type or name"); return nil; } if (ref == nil) { ref = name; } node = node->childs; if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } if (node != 0 && strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; node = node->next; } while (node != 0 && strcmp(node->name, "standard") == 0) { NSString *s = [self parseText: node->childs]; if (s != nil) { [standards addObject: s]; } node = node->next; } [self setEntry: name withRef: ref inIndexOfType: @"variable"]; [text appendFormat: @"
\r\n", ref, name]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared]; } if ([standards count] > 0) { unsigned i; [text appendFormat: @"
Standards: %@\r\n", [standards objectAtIndex: 0]]; for (i = 1; i < [standards count]; i++) { [text appendFormat: @", %@\r\n", [standards objectAtIndex: i]]; } [text appendString: @"
\r\n"]; } if ([role isEqual: @"except"]) { [text appendString: @"
Exception name
\r\n"]; } else if ([role isEqual: @"defaults"]) { [text appendString: @"
Defaults system key
\r\n"]; } else if ([role isEqual: @"notify"]) { [text appendString: @"
Notification name
\r\n"]; } else if ([role isEqual: @"key"]) { [text appendString: @"
Dictionary key
\r\n"];
}
if (value == nil)
{
[text appendFormat: @"%@ %@
\r\n", type, name];
}
else
{
[text appendFormat: @"%@ %@ = %@
\r\n", type, name, value];
}
if (desc != nil)
{
[text appendFormat: @"
\r\n%@\r\n", desc]; } return text; } else { NSLog(@"Definition of unknown type - %s", node->name); return nil; } } - (NSString*) parseDesc: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; node = node->childs; if (node == 0) { return @""; } while (node != 0) { if (strcmp(node->name, "list") == 0 || strcmp(node->name, "enum") == 0 || strcmp(node->name, "deflist") == 0 || strcmp(node->name, "qalist") == 0) { [text appendString: [self parseList: node]]; } else if (strcmp(node->name, "p") == 0) { NSString *elem = [self parseText: node->childs]; if (elem != nil) { [text appendFormat: @"
\r\n%@
\r\n", elem]; } } else if (strcmp(node->name, "example") == 0) { [text appendString: [self parseExample: node]]; } else if (strcmp(node->name, "embed") == 0) { [text appendString: [self parseEmbed: node]]; } else { [text appendString: [self parseText: node]]; } node = node->next; } return text; } - (NSString*) parseDocument { xmlNodePtr cur = doc->root->childs; NSString *text; NSString *body; NSString *head; if (cur == 0 || strcmp(cur->name, "head") != 0) { NSLog(@"head missing from document"); return nil; } if ((head = [self parseHead: cur]) == nil) { return nil; } cur = cur->next; if (cur == 0 || strcmp(cur->name, "body") != 0) { NSLog(@"body missing from document"); return nil; } if ((body = [self parseBody: cur]) == nil) { return nil; } text = [NSString stringWithFormat: @"%@%@\r\n\r\n", head, body]; if ([defs boolForKey: @"Monolithic"] == YES) { [text writeToFile: currName atomically: YES]; } return text; } - (NSString*) parseEmbed: (xmlNodePtr)node { return @"An Embed"; } - (NSString*) parseExample: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; NSString *elem = [self parseText: node->childs]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *cap = [self getProp: "caption" fromNode: node]; if (ref == nil) { ref = [NSString stringWithFormat: @"label-%u", labelIndex++]; } if (elem == nil) { return nil; } if (cap == nil) { [self setEntry: @"example" withRef: ref inIndexOfType: @"label"]; [text appendFormat: @"example\r\n", ref]; } else { [self setEntry: cap withRef: ref inIndexOfType: @"label"]; [text appendFormat: @"%@\r\n", ref, cap]; } [text appendFormat: @"
\r\n%@\r\n
\r\n", elem]; return text; } - (NSString*) parseFunction: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; NSString *ref = [self getProp: "id" fromNode: node]; NSString *type = [self getProp: "type" fromNode: node]; NSString *name = [self getProp: "name" fromNode: node]; NSString *desc = nil; NSString *declared = nil; NSMutableString *args = [NSMutableString stringWithString: @"("]; if (ref == nil) { ref = [NSString stringWithFormat: @"function-%u", labelIndex++]; } if (type == nil) { type = @"int"; } node = node->childs; while (node != 0 && strcmp(node->name, "arg") == 0) { NSString *arg = [self parseText: node->childs]; NSString *typ = [self getProp: "type" fromNode: node]; if (arg == nil) return nil; if ([args length] > 1) { [args appendString: @", "]; } if (typ != nil) { [args appendString: typ]; [args appendString: @" "]; } [args appendString: arg]; node = node->next; } if (node != 0 && strcmp(node->name, "vararg") == 0) { if ([args length] > 1) { [args appendString: @", ..."]; } else { [args appendString: @"..."]; } node = node->next; } [args appendString: @")"]; if (node != 0 && strcmp(node->name, "declared") == 0) { declared = [self parseText: node->childs]; node = node->next; } if (node != 0) { if (strcmp(node->name, "desc") == 0) { desc = [self parseDesc: node]; } else { NSLog(@"Unexpected node in function definition - %s", node->name); return nil; } } [self setEntry: name withRef: ref inIndexOfType: @"function"]; [text appendFormat: @"
\r\n", ref, name]; if (declared != nil) { [text appendFormat: @"
Declared in: %@
\r\n", declared];
}
[text appendFormat: @"Prototype: %@ %@%@
\r\n", type, name, args];
if (desc != nil)
{
[text appendString: desc];
}
[text appendString: @"\r\n
\r\n"]; return text; } - (NSString*) parseHead: (xmlNodePtr)node { NSMutableString *text = [NSMutableString string]; NSString *abstract; NSString *title; NSString *copyright; NSString *date; NSString *version; BOOL hadAuthor = NO; node = node->childs; if (node == 0 || strcmp(node->name, "title") != 0 || (title = [self parseText: node->childs]) == nil) { NSLog(@"head without title"); return nil; } [text appendFormat: @"
\r\n
\r\n", title]; [text appendString: @"\r\n"]; [text appendString: @"