www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - CHM (HTML Help) creator for D documentation

reply "Vladimir Panteleev" <thecybershadow gmail.com> writes:
------------g19PGZO1aKfKN0WQ4xfX7G
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: Quoted-Printable

Greetings,

In an attempt to ease the life of Windows D programmers, I decided to wr=
ite an utility which would automatically convert the D documentation, di=
stributed with DMD, to an HTML Help project. It was an interesting task,=
 and through some effort I managed at automating the creation of an usab=
le CHM file.

The advantages of using a CHM help file over the included HTML files:

1) it's one compressed file, instead of many
2) the contents is somewhat easier to navigate
3) it has instantaneous indexed search, supporting boolean operators
4) comprehensive index of literally too many keywords...

The program doesn't make assumptions on how the help files are laid out,=
 so it should work with future D releases. The only exception is that th=
e program uses Kirk McDonald's keyword index ( http://www.prowiki.org/wi=
ki4d/wiki.cgi?LanguageSpecification/KeywordIndex ), since I didn't find =
a reliable way to find where respective keywords are explained in the do=
cumentation. The full unmodified source of that wiki page is embedded in=
 the program source, so it should be just as easy to update.

When preparing the help files for the CHM format, the program does the f=
ollowing modifications:

1) remove the left navigation bar (it is replaced by the HTML Help's nav=
igation pane)
2) skip Google AdSense ads, which don't make any sense in offline media =
- browsers don't (and shouldn't) allow uploading contents of local data =
to web services, thus Google AdSense displays rubbish/Chinese ads anyway=
.

Here's the usage instructions:

1) download and install the Microsoft HTML Help Workshop from here: http=
://www.microsoft.com/downloads/details.aspx?familyid=3D00535334-c8a6-452=
f-9aa0-d597d16580cc&displaylang=3Den
2) save chmgen.d to ...\dmd\html\
3) compile and run it
4) open the d.hhp file with HTML Help Workshop and compile it
    -- or --
    run: hhc.exe d.hhp
5) enjoy your brand new d.chm !

Alternatively, you can download the CHM file from here: http://thecybers=
hadow.net/d/docs/d.chm
I am not sure about the distribution rights of the documentation, so if =
there are some legal problems, let me know and I'll remove it immediatel=
y.

Things that could still be improved:

  - inserting anchors in some places, like before every function in the =
Phobos docs
  - a cleaner/more accurate index
  - splitting the articles in categories (D syntax, Phobos, ...) to allo=
w filtering
  - adding Tango docs for an all-in-one D help file?
  - the code could be generally cleaned up in some places...

I release the attached code to the Public Domain (no rights reserved). H=
owever, the contents of the included wiki page is distributed under FDL.=


-- =

Best regards,
  Vladimir                          mailto:thecybershadow gmail.com
------------g19PGZO1aKfKN0WQ4xfX7G
Content-Disposition: attachment; filename=chmgen.d
Content-Type: text/x-dsrc; name=chmgen.d
Content-Transfer-Encoding: Quoted-Printable

import std.stdio;
import std.file;
import std.string;
import std.regexp;

// ********************************************************************

int min(int a, int b)
{
	return a < b ? a : b;
}

void backSlash(char[] s)   // replace path delimiters in-place
{
	//s=3Ds.dup;
	foreach(inout c;s)
		if(c=3D=3D'/')
			c=3D'\\';
}

bool match(char[] line, char[] pattern)
{
	return std.regexp.find(line, pattern)>=3D0;
}

char[] getAnchor(char[] s)
{
	int i =3D std.string.find(s, '#');
	if(i<0)
		return "";
	else
		return s[i..$];
}

char[] removeAnchor(char[] s)
{
	int i =3D std.string.find(s, '#');
	if(i<0)
		return s;
	else
		return s[0..i];
}

char[] absoluteUrl(char[] base, char[] url)
{
	backSlash(base);
	backSlash(url);
	=

	if (url[0]=3D=3D'#')
		return base ~ url;

	while(base[$-1]!=3D'\\')
		base =3D base[0..$-1];
	=

	while(url[0..3]=3D=3D"..\\")
	{
		url =3D url[3..$];
		do {
			base =3D base[0..$-1];
			if(base.length=3D=3D0)
				return "";
		} while(base[$-1]!=3D'\\');
	}
	return base ~ url;
}

char[] movePath(char[] s)
{
	if(s.length>1 && s[0..2]=3D=3D"d\\")
		s =3D "chm" ~ s[1..$];
	return s;
}

char[] normalize(char[] s)
{
	s =3D tolower(s);
	char[] t;
	foreach(c;s)
		if(!iswhite(c))
			t ~=3D c;
	return t;
}

// ********************************************************************

struct Link
{
	char[] url, title, text;

	static Link opCall(char[] url, char[] title, char[] text)
	{
		backSlash(url);
		Link my;
		my.url =3D strip(url);
		my.title =3D strip(title);
		my.text =3D strip(text);
		return my;
	}
}

struct LinkBlock
{
	Link caption;
	Link[] links;

	static LinkBlock opCall(char[] url, char[] title, char[] text)
	{
		backSlash(url);
		LinkBlock my;
		my.caption.url =3D strip(url);
		my.caption.title =3D strip(title);
		my.caption.text =3D strip(text);
		return my;
	}
}

class Page
{
	char[] newFileName;
	char[] title;
	char[] src;
	Link[] toctop;
	LinkBlock[] linkBlocks;
	bool[char[]] anchors;
}

struct KeyLink
{
	char[] anchor;
	char[] title;

	static KeyLink opCall(char[] anchor, char[] title)
	{
		KeyLink my;
		my.anchor =3D strip(anchor);
		my.title =3D strip(title);
		return my;
	}
}

// ********************************************************************

char[][] listdirrec(char[] pathname)
{
	char[][] files =3D null;	=


	bool listing(char[] filename)
	{
		char[] file =3D std.path.join(pathname, filename);
		if(isdir(file))
		{
			char[] oldpath =3D pathname;
			pathname =3D file;
			listdir(pathname, &listing);
			pathname =3D oldpath;
		}
		else
		{
			files ~=3D std.path.join(pathname, filename);
		}
		return true; // continue
	}
	=

	listdir(pathname, &listing);

	return files;
}

Page[char[]] pages;
KeyLink[char[]][char[]] keywords;   // keywords[normalize(keyword)][orig=
inal url w/o anchor] =3D anchor/title
char[][char[]] keyTable;

void addKeyword(char[] keyword, char[] link, char[] title =3D null)
{
	keyword =3D strip(keyword);
	char[] norm =3D normalize(keyword);
	char[] file =3D removeAnchor(link);
	backSlash(file);
	char[] anchor =3D getAnchor(link);
	if(title=3D=3Dnull && norm in keywords && file in keywords[norm])   // =
when title is present, it overrides any existing anchors/etc.
	{
		if(keywords[norm][file].anchor>anchor) // "less" is better
			keywords[norm][file] =3D KeyLink(anchor, title);
	}
	else
		keywords[norm][file] =3D KeyLink(anchor, title);
	if(title=3D=3Dnull && norm in keyTable)
	{
		if(keyTable[norm]>keyword) // "less" is better
			keyTable[norm] =3D keyword;
	}
	else
		keyTable[norm] =3D keyword;
}

void main()
{
	// clean up
	if(exists("chm"))
		foreach(file;listdirrec("chm\\"))
			std.file.remove(file);
	else
		mkdir("chm");
	=

	char[][] files =3D listdirrec("d\\");
	=

	foreach(i,file;files)
		pages[file] =3D new Page;

	RegExp re_title =3D new RegExp(`<title>(Digital Mars - The )?D Programm=
ing Language - (.*)</title>`);
	RegExp re_title2 =3D new RegExp(`<h1>(.*)</h1>`);
	RegExp re_heading =3D new RegExp(`<h2>(.*)</h2>`);
	RegExp re_heading_link =3D new RegExp(`<h2><a href=3D"([^"]*)"( title=3D=
"([^"]*)")?>(.*)</a></h2>`);
	RegExp re_nav_link =3D new RegExp(`<li><a href=3D"([^"]*)"( title=3D"(.=
*)")?>(.*)</a></li>`);
	RegExp re_anchor =3D new RegExp(`<a name=3D"([^"]*)">(<.>)*([^<]+)<`);
	RegExp re_anchor_2 =3D new RegExp(`<a name=3D([^>]*)>(<.>)*([^<]+)<`);
	RegExp re_link   =3D new RegExp(`<a href=3D"([^"]*)">(<.>)*([^<]+)<`);
	RegExp re_def =3D new RegExp(`<dt><big>.*<u>([^<]+)<`);

	foreach(fileName,page;pages)
		with(page)
		{
			char[] destdir =3D movePath(std.path.getDirName(fileName));
			if(!exists(destdir))
				mkdir(destdir);

			newFileName =3D movePath(fileName);

			if(match(fileName, `\.html$`))
			{
				writefln("Processing "~fileName);
				src =3D cast(char[])read(fileName);
				char[][] lines =3D splitlines(src);
				char[][] newlines =3D null;
				bool skip =3D false, intoctop =3D false, innavblock =3D false, innav=
block2 =3D false;
				int dl =3D 0;
				char[] anchor =3D null;
				anchors[""] =3D true;
				foreach(line;lines)
				{
					bool nextSkip =3D skip;
					=

					if (re_title.find(line)>=3D0)
					{
						title =3D strip(re_title.match(2));
						line =3D re_title.replace(`<title>` ~ title ~ `</title>`);
					}
					if (re_title2.find(line)>=3D0)
						if(title=3D=3D"")
							title =3D strip(re_title2.match(1));
					=

					if (re_anchor.find(line)>=3D0)
					{
						anchor =3D '#' ~ re_anchor.match(1);
						anchors[anchor] =3D true;
					}
					else
					if (re_anchor_2.find(line)>=3D0)
					{
						anchor =3D '#' ~ re_anchor.match(1);
						anchors[anchor] =3D true;
					}

					if(match(line, `<div id=3D"toctop">`))
						intoctop =3D true;
					if(match(line, `<div class=3D"navblock">`))
						if(innavblock)
						{
							innavblock2 =3D true;
							linkBlocks ~=3D LinkBlock("", "", "");
						}
						else
							innavblock =3D true;
					if(match(line, `</div>`))
						intoctop =3D innavblock2 =3D false;

					if(std.string.find(line, `<dl>`)>=3D0)
						dl++;
					if(dl=3D=3D1)
					{
						if(re_def.find(line)>=3D0)
							addKeyword(re_def.match(1), fileName ~ anchor);
					}
					if(std.string.find(line, `</dl>`)>=3D0)
						dl--;

					if(re_heading_link.find(line)>=3D0)
					{
						if(innavblock2)
							linkBlocks ~=3D LinkBlock(re_heading_link.match(1), re_heading_li=
nk.match(3), re_heading_link.match(4));
					}
					else
					if(re_heading.find(line)>=3D0)
					{
						if(innavblock2)
							linkBlocks ~=3D LinkBlock("", "", re_heading.match(1));
					}

					if(re_nav_link.find(line)>=3D0)
						if(intoctop)
							toctop   ~=3D Link(re_nav_link.match(1), re_nav_link.match(3), re=
_nav_link.match(4));
						else
						if(innavblock2)
							if(re_nav_link.match(1)[0..7]!=3D"http://" && exists(absoluteUrl(=
fileName, re_nav_link.match(1))))
								linkBlocks[$-1].links ~=3D Link(re_nav_link.match(1), re_nav_lin=
k.match(3), re_nav_link.match(4));
						//else
						//	writefln("Displaced link: ", line);
					=

					if(re_anchor.find(line)>=3D0)
						addKeyword(re_anchor.match(3), fileName ~ "#" ~ re_anchor.match(1)=
);
					else
					if(re_anchor_2.find(line)>=3D0)
						addKeyword(re_anchor_2.match(3), fileName ~ "#" ~ re_anchor_2.matc=
h(1));
					=

					if(re_link.find(line)>=3D0)
						if(re_link.match(1)[0..min($,7)]!=3D"http://")
							addKeyword(re_link.match(3), absoluteUrl(fileName, re_link.match(=
1)));
					=

					// skip Google ads
					if(match(line, `^<!-- Google ad -->$`))
						skip =3D nextSkip =3D true;
					if(match(line, `^</script>$`))
						nextSkip =3D false;

					// skip navigation bar
					if(match(line, `^<div id=3D"navigation">$`))
						skip =3D nextSkip =3D true;
					if(match(line, `^<div id=3D"content">$`))
						skip =3D nextSkip =3D false;

					if(!skip)
						newlines ~=3D line;
					skip =3D nextSkip;
				}
				src =3D join(newlines, newline);
				write(newFileName, src);
			}
			else
			if(match(fileName, `\.css$`))
			{
				writefln("Processing "~fileName);
				src =3D cast(char[])read(fileName);
				char[][] lines =3D splitlines(src);
				char[][] newlines =3D null;
				foreach(line;lines)
				{
					// skip #div.content positioning
					if(!match(line, `margin-left:13em;`))
						newlines ~=3D line;
				}
				src =3D join(newlines, newline);
				write(newFileName, src);
			}
			else
			{
				copy(fileName, newFileName);
			}
		} =


	// ************************************************************

	Link[] topLinks;
	bool[char[]] gotLink;

	foreach(fileName,page;pages)
		foreach(link;page.toctop)
		{
			char[] url =3D absoluteUrl(fileName, link.url);
			if(!(url in gotLink))
			{
				topLinks ~=3D Link(url, link.title, link.text);
				gotLink[url] =3D true;
			}
		}

	// retreive keyword link titles
	foreach(keyNorm,urls;keywords)
		foreach(url,inout link;urls)
			if(url in pages)
				link.title =3D pages[url].title;

	// ************************************************************

	RegExp re_key_new =3D new RegExp(`<tt>(.*)</tt>`);
	RegExp re_key_link =3D new RegExp(`^\* (.*)\[http://www\.digitalmars\.c=
om/([^ ]*) (.*)\]`);

	char[][] keywordLines =3D splitlines(keywordIndex);
	char[] keyword;
	foreach(line;keywordLines)
	{
		if(re_key_new.find(line)>=3D0)
			keyword =3D re_key_new.match(1);
		if(re_key_link.find(line)>=3D0)
		{
			char[] url =3D re_key_link.match(2);
			char[] file =3D removeAnchor(url);
			char[] anchor =3D getAnchor(url);
			backSlash(url);
			=

			if(file in pages)
			{
				if(!(anchor in pages[file].anchors))
				{
					char[] cmp1 =3D normalize(anchor);
					foreach(realAnchor,b;pages[file].anchors)
					{
						char[] cmp2 =3D normalize(realAnchor);
						int n =3D min(cmp1.length, cmp2.length);
						if(n>=3D3 && cmp1[0..n] =3D=3D cmp2[0..n])
						{
							//writefln("Fixing broken anchor " ~ anchor ~ " to " ~ realAnchor=
);
							anchor =3D realAnchor;
							break;
						}	=

					}
				}

				if(anchor in pages[file].anchors)
				{
					addKeyword(keyword, file ~ anchor, re_key_link.match(1) ~ re_key_li=
nk.match(3));
				//	writefln("Adding keyword " ~ keyword ~ " to " ~ file ~ anchor ~ "=
 as " ~ re_key_link.match(1) ~ re_key_link.match(3));
				}
				//else
				//	writefln("Broken anchor link to keyword "~ keyword ~ " to " ~ re_=
key_link.match(2) ~ " as " ~ re_key_link.match(1) ~ re_key_link.match(3)=
);
			}
			//else
			//	writefln("Unfound URL: " ~ url);
		}
	}

	// ************************************************************

	FILE* f =3D fopen("d.hhp", "wt");
	fwritefln(f, =

`[OPTIONS]
Compatibility=3D1.1 or later
Compiled file=3Dd.chm
Contents file=3Dd.hhc
Default Window=3Dmain
Default topic=3D` ~ movePath(topLinks[0].url) ~ `
Display compile progress=3DNo
Full-text search=3DYes
Index file=3Dd.hhk
Language=3D0x409 English (United States)
Title=3DD

[WINDOWS]
main=3D"D","d.hhc","d.hhk","chm\index.html","chm\index.html",,,,,0x63520=
,,0x380e,[271,372,593,566],0x918f0000,,,,,,0

[FILES]`);
	char[][] htmlList;
	foreach(page;pages)
		if(match(page.newFileName, `\.html$`))
			htmlList ~=3D page.newFileName;
	htmlList.sort;
	foreach(s;htmlList)
		fwritefln(f, s);
	fwritefln(f, `
[INFOTYPES]`);
	fclose(f);

	// ************************************************************

	f =3D fopen("d.hhc", "wt");
	fwritefln(f, =

`<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML><BODY>
<OBJECT type=3D"text/site properties"><param name=3D"Window Styles" valu=
e=3D"0x800025"></OBJECT>
<UL>`);
	foreach(toplink;topLinks)
	{
		fwritefln(f, =

`	<LI><OBJECT type=3D"text/sitemap">
		<param name=3D"Name" value=3D"` ~ toplink.title ~ `">
		<param name=3D"Local" value=3D"` ~ movePath(toplink.url) ~ `">
		</OBJECT>
	<UL>`);
		Page topPage =3D pages[toplink.url];
		foreach(link;topPage.linkBlocks[0].links)
			fwritefln(f, =

`		<LI> <OBJECT type=3D"text/sitemap">
			<param name=3D"Name" value=3D"` ~ link.text ~ `">
			<param name=3D"Local" value=3D"` ~ movePath(absoluteUrl(toplink.url, =
link.url)) ~ `">
			</OBJECT>`);
		foreach(linkBlock;topPage.linkBlocks[1..$])
		{
			fwritefln(f, =

`		<LI> <OBJECT type=3D"text/sitemap">
			<param name=3D"Name" value=3D"` ~ linkBlock.caption.text ~ `">`);
			if(linkBlock.caption.url!=3D"")
				fwritefln(f, =

`			<param name=3D"Local" value=3D"` ~ movePath(absoluteUrl(toplink.url,=
 linkBlock.caption.url)) ~ `">`);
			fwritefln(f, =

`			</OBJECT>
		<UL>`);
			foreach(link;linkBlock.links)
				fwritefln(f, =

`			<LI> <OBJECT type=3D"text/sitemap">
				<param name=3D"Name" value=3D"` ~ link.text ~ `">
				<param name=3D"Local" value=3D"` ~ movePath(absoluteUrl(toplink.url,=
 link.url)) ~ `">
				</OBJECT>`);
			fwritefln(f, =

`		</UL>`);
		}
		fwritefln(f, =

`	</UL>`);
	}
	fwritefln(f, `</UL>
</BODY></HTML>`);
	fclose(f);

	// ************************************************************

	f =3D fopen("d.hhk", "wt");
	fwritefln(f, =

`<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML><BODY>
<UL>`);
	foreach(keyNorm,urlList;keywords)
	{
		fwritefln(f, =

`	<LI> <OBJECT type=3D"text/sitemap">
		<param name=3D"Name" value=3D"` ~ keyTable[keyNorm] ~ `">`);
		foreach(url,link;urlList)
			if(url in pages)
			{
				fwritefln(f, =

`		<param name=3D"Name" value=3D"` ~ link.title ~ `">
		<param name=3D"Local" value=3D"` ~ movePath(url) ~ link.anchor ~ `">`)=
;
			}
		fwritefln(f, =

`		</OBJECT>`);
	}
	fwritefln(f, =

`</UL>
</BODY></HTML>`);
	fclose(f);
}

// ********************************************************************

// retreived on 2007.03.25 from http://www.prowiki.org/wiki4d/wiki.cgi?L=
anguageSpecification/KeywordIndex
const keywordIndex =3D `
<tt>abstract</tt>
* [http://www.digitalmars.com/d/attribute.html#abstract Attributes]
<tt>alias</tt>
* [http://www.digitalmars.com/d/declaration.html#alias Declarations]
* template parameters: [http://www.digitalmars.com/d/template.html#alias=
parameters Templates]
<tt>align</tt>
* [http://www.digitalmars.com/d/attribute.html#align Attributes]
<tt>asm</tt>
* [http://www.digitalmars.com/d/statement.html#asm Statements]
* x86 inline assembler:  [http://www.digitalmars.com/d/iasm.html Inline =
Assembler]
<tt>assert</tt>
* [http://www.digitalmars.com/d/expression.html#AssertExpression Express=
ions]
* static assert:  [http://www.digitalmars.com/d/version.html#staticasser=
t Conditional Compilation]

<tt>auto</tt>
* class attribute:  [http://www.digitalmars.com/d/class.html#auto Classe=
s]
* RAII attribute:  [http://www.digitalmars.com/d/attribute.html#auto Att=
ributes]
* type inference:  [http://www.digitalmars.com/d/declaration.html#AutoDe=
claration Declarations]

----

<tt>body</tt>
* in function contract:  [http://www.digitalmars.com/d/dbc.html Contract=
s]

<tt>bool</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>break</tt>
* in switch:  [http://www.digitalmars.com/d/statement.html#switch Statem=
ents]
* statement:  [http://www.digitalmars.com/d/statement.html#break Stateme=
nts]

<tt>byte</tt>
* [http://www.digitalmars.com/d/type.html Types]

----

<tt>case</tt>
* in switch:  [http://www.digitalmars.com/d/statement.html#switch Statem=
ents]

<tt>cast</tt>
* [http://www.digitalmars.com/d/expression.html#CastExpression Expressio=
ns]

<tt>catch</tt>
* [http://www.digitalmars.com/d/statement.html#try Statements]

<tt>cdouble</tt>
* [http://www.digitalmars.com/d/type.html Types]
* complex types:  [http://www.digitalmars.com/d/float.html Floating Poin=
t]

<tt>cent</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>cfloat</tt>
* [http://www.digitalmars.com/d/type.html Types]
* complex types:  [http://www.digitalmars.com/d/float.html Floating Poin=
t]

<tt>char</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>class</tt>
* [http://www.digitalmars.com/d/class.html Classes]
* properties of:  [http://www.digitalmars.com/d/property.html#classprope=
rties Properties]

<tt>const</tt>
* [http://www.digitalmars.com/d/attribute.html#const Attributes]

<tt>continue</tt>
* [http://www.digitalmars.com/d/statement.html#continue Statements]

<tt>creal</tt>
* [http://www.digitalmars.com/d/type.html Types]
* complex types:  [http://www.digitalmars.com/d/float.html Floating Poin=
t]

----

<tt>dchar</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>debug</tt>
* [http://www.digitalmars.com/d/version.html#debug Conditional Compilati=
on]

<tt>default</tt>
* in switch:  [http://www.digitalmars.com/d/statement.html#switch Statem=
ents]

<tt>delegate</tt>
* as datatype and replacement for pointer-to-member-function:  [http://w=
ww.digitalmars.com/d/type.html#delegates Types]
* as dynamic closure:  [http://www.digitalmars.com/d/function.html#closu=
res Functions]
* in function literal:  [http://www.digitalmars.com/d/expression.html#Fu=
nctionLiteral Expressions]

<tt>delete</tt>
* expression:  [http://www.digitalmars.com/d/expression.html#DeleteExpre=
ssion Expressions]
* overloading:  [http://www.digitalmars.com/d/class.html#deallocators Cl=
asses]

<tt>deprecated</tt>
* [http://www.digitalmars.com/d/attribute.html#deprecated Attributes]

<tt>do</tt>
* [http://www.digitalmars.com/d/statement.html#do Statements]

<tt>double</tt>
* [http://www.digitalmars.com/d/type.html Types]
* floating point types:  [http://www.digitalmars.com/d/float.html Floati=
ng Point]

----

<tt>else</tt>
* [http://www.digitalmars.com/d/statement.html#if Statements]

<tt>enum</tt>
* [http://www.digitalmars.com/d/enum.html Enums]

<tt>export</tt>
* protection attribute:  [http://www.digitalmars.com/d/attribute.html At=
tributes]

<tt>extern</tt>
* linkage attribute:  [http://www.digitalmars.com/d/attribute.html#linka=
ge Attributes]
* interfacing to C:  [http://www.digitalmars.com/d/interfaceToC.html Int=
erfacing to C]
* in variable declaration:  [http://www.digitalmars.com/d/declaration.ht=
ml#extern Declarations]

----

<tt>false</tt>
* [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expres=
sions]

<tt>final</tt>
* [http://www.digitalmars.com/d/function.html Functions]

<tt>finally</tt>
* [http://www.digitalmars.com/d/statement.html#try Statements]

<tt>float</tt>
* [http://www.digitalmars.com/d/type.html Types]
* floating point types:  [http://www.digitalmars.com/d/float.html Floati=
ng Point]

<tt>for</tt>
* [http://www.digitalmars.com/d/statement.html#for Statements]

<tt>foreach</tt>
* [http://www.digitalmars.com/d/statement.html#foreach Statements]

<tt>foreach_reverse</tt>
* [http://www.digitalmars.com/d/statement.html#foreach Statements]

<tt>function</tt>
* as datatype:  [http://www.digitalmars.com/d/type.html Types]
* in function literal:  [http://www.digitalmars.com/d/expression.html#Fu=
nctionLiteral Expressions]
* function pointers:  [http://www.digitalmars.com/d/function.html#closur=
es Functions]


----


<tt>goto</tt>
* [http://www.digitalmars.com/d/statement.html#goto Statements]


----


<tt>idouble</tt>
* [http://www.digitalmars.com/d/type.html Types]
* imaginary types:  [http://www.digitalmars.com/d/float.html Floating Po=
int]

<tt>if</tt>
* [http://www.digitalmars.com/d/statement.html#if Statements]
* static if:  [http://www.digitalmars.com/d/version.html#staticif Condit=
ional Compilation]

<tt>ifloat</tt>
* [http://www.digitalmars.com/d/type.html Types]
* imaginary types:  [http://www.digitalmars.com/d/float.html Floating Po=
int]

<tt>import</tt>
* [http://www.digitalmars.com/d/module.html#ImportDeclaration Modules]
* import expression:  [http://digitalmars.com/d/expression.html#ImportEx=
pression Expressions]

<tt>in</tt>
* in pre contract:  [http://www.digitalmars.com/d/dbc.html Contracts]
* containment test:  [http://www.digitalmars.com/d/expression.html#InExp=
ression Expressions]
* function parameter:  [http://www.digitalmars.com/d/function.html#param=
eters Functions]

<tt>inout</tt>
* in foreach statement:  [http://www.digitalmars.com/d/statement.html#fo=
reach Statements]
* function parameter:  [http://www.digitalmars.com/d/function.html#param=
eters Functions]

<tt>int</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>interface</tt>
* [http://www.digitalmars.com/d/interface.html Interfaces]

<tt>invariant</tt>
* [http://www.digitalmars.com/d/class.html#invariants Classes]

<tt>ireal</tt>
* [http://www.digitalmars.com/d/type.html Types]
* imaginary types:  [http://www.digitalmars.com/d/float.html Floating Po=
int]

<tt>is</tt>
* identity comparison:  [http://www.digitalmars.com/d/expression.html#Eq=
ualExpression Expressions]
* type comparison:  [http://www.digitalmars.com/d/expression.html#IsExpr=
ession Expressions]


----


<tt>lazy</tt>
* function parameter:  [http://www.digitalmars.com/d/function.html#param=
eters Functions]

<tt>long</tt>
* [http://www.digitalmars.com/d/type.html Types]


----


<tt>mixin</tt>
* [http://www.digitalmars.com/d/template-mixin.html Template Mixins]
* Mixin declarations:  [http://digitalmars.com/d/module.html#MixinDeclar=
ation Modules]
* Mixin expressions:  [http://digitalmars.com/d/expression.html#MixinExp=
ression Expressions]
* Mixin statements:  [http://digitalmars.com/d/statement.html#MixinState=
ment Statements]

<tt>module</tt>
* [http://www.digitalmars.com/d/module.html Modules]


----


<tt>new</tt>
* anonymous nested classes and:  [http://www.digitalmars.com/d/class.htm=
l#anonymous Classes]
* expression:  [http://www.digitalmars.com/d/expression.html#NewExpressi=
on Expressions]
* overloading:  [http://www.digitalmars.com/d/class.html#allocators Clas=
ses]

<tt>null</tt>
* [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expres=
sions]


----


<tt>out</tt>
* in post contract:  [http://www.digitalmars.com/d/dbc.html Contracts]
* function parameter:  [http://www.digitalmars.com/d/function.html#param=
eters Functions]

<tt>override</tt>
* [http://www.digitalmars.com/d/attribute.html#override Attributes]


----


<tt>package</tt>
* [http://www.digitalmars.com/d/attribute.html Attributes]

<tt>pragma</tt>
* [http://www.digitalmars.com/d/pragma.html Pragmas]

<tt>private</tt>
* and import:  [http://www.digitalmars.com/d/module.html Modules]
* protection attribute:  [http://www.digitalmars.com/d/attribute.html At=
tributes]

<tt>protected</tt>
* [http://www.digitalmars.com/d/attribute.html Attributes]

<tt>public</tt>
* [http://www.digitalmars.com/d/attribute.html Attributes]


----


<tt>real</tt>
* [http://www.digitalmars.com/d/type.html Types]
* floating point types:  [http://www.digitalmars.com/d/float.html Floati=
ng Point]

<tt>return</tt>
* [http://www.digitalmars.com/d/statement.html#return Statements]


----


<tt>scope</tt>
* statement: [http://www.digitalmars.com/d/statement.html#ScopeGuardStat=
ement Statements]
* RAII attribute:  [http://www.digitalmars.com/d/attribute.html#scope At=
tributes]

<tt>short</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>static</tt>
* attribute:  [http://www.digitalmars.com/d/attribute.html Attributes]
* constructors:  [http://www.digitalmars.com/d/class.html#staticconstruc=
tor Classes]
* destructors:  [http://www.digitalmars.com/d/class.html#staticdestructo=
r Classes]
* order of static constructors and destructors:  [http://www.digitalmars=
.com/d/module.html#staticorder Modules]
* static assert:  [http://www.digitalmars.com/d/version.html#staticasser=
t Conditional Compilation]
* static if:  [http://www.digitalmars.com/d/version.html#staticif Condit=
ional Compilation]
* static import:  [http://www.digitalmars.com/d/module.html#ImportDeclar=
ation Modules]

<tt>struct</tt>
* [http://www.digitalmars.com/d/struct.html Structs & Unions]
* properties of:  [http://www.digitalmars.com/d/property.html#classprope=
rties Properties]

<tt>super</tt>
* [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expres=
sions]
* as name of superclass constructor:  [http://www.digitalmars.com/d/clas=
s.html#constructors Classes]

<tt>switch</tt>
* [http://www.digitalmars.com/d/statement.html#switch Statements]

<tt>synchronized</tt>
* [http://www.digitalmars.com/d/statement.html#synchronize Statements]


----


<tt>template</tt>
* [http://www.digitalmars.com/d/template.html Templates]

<tt>this</tt>
* [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expres=
sions]
* as constructor name:  [http://www.digitalmars.com/d/class.html#constru=
ctors Classes]
* with ~, as destructor name:  [http://www.digitalmars.com/d/class.html#=
destructors Classes]

<tt>throw</tt>
* [http://www.digitalmars.com/d/statement.html#throw Statements]

<tt>true</tt>
* [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expres=
sions]

<tt>try</tt>
* [http://www.digitalmars.com/d/statement.html#try Statements]

<tt>typedef</tt>
* [http://www.digitalmars.com/d/declaration.html#typedef Declarations]

<tt>typeid</tt>
* [http://www.digitalmars.com/d/expression.html#typeidexpression Express=
ions]

<tt>typeof</tt>
* [http://www.digitalmars.com/d/declaration.html#typeof Declarations]


----


<tt>ubyte</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>ucent</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>uint</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>ulong</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>union</tt>
* [http://www.digitalmars.com/d/struct.html Structs & Unions]

<tt>unittest</tt>
* in classes:  [http://www.digitalmars.com/d/class.html#unittest Classes=
]

<tt>ushort</tt>
* [http://www.digitalmars.com/d/type.html Types]


----


<tt>version</tt>
* [http://www.digitalmars.com/d/version.html#version Conditional Compila=
tion]

<tt>void</tt>
* as initializer:  [http://www.digitalmars.com/d/declaration.html Declar=
ations]
* as type:  [http://www.digitalmars.com/d/type.html Types]

<tt>volatile</tt>
* [http://www.digitalmars.com/d/statement.html#volatile Statements]


----


<tt>wchar</tt>
* [http://www.digitalmars.com/d/type.html Types]

<tt>while</tt>
* [http://www.digitalmars.com/d/statement.html#while Statements]

<tt>with</tt>
* [http://www.digitalmars.com/d/statement.html#with Statements]



----

Source: Kirk <n>McDonald</n>, http://216.190.88.10:8087/media/d_index.ht=
ml (NG:digitalmars.D/38550)
`;
------------g19PGZO1aKfKN0WQ4xfX7G--
Mar 25 2007
next sibling parent reply =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Vladimir Panteleev kirjoitti:
 Greetings,
 
 In an attempt to ease the life of Windows D programmers, I decided to
 write an utility which would automatically convert the D
 documentation, distributed with DMD, to an HTML Help project.

For users of Linux (and other POSIX compatible OS's) there is a program called kchmviewer that is a CHM reader. It should work without KDE, but probably still needs Qt. For GNOME users there is gnochm and maybe some viewers too.
Mar 25 2007
next sibling parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Jari-Matti Mäkelä wrote a stupid typo:
 and maybe some (other) viewers too.

Mar 25 2007
prev sibling next sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Jari-Matti Mäkelä wrote:

 In an attempt to ease the life of Windows D programmers, I decided to
 write an utility which would automatically convert the D
 documentation, distributed with DMD, to an HTML Help project.

For users of Linux (and other POSIX compatible OS's) there is a program called kchmviewer that is a CHM reader. It should work without KDE, but probably still needs Qt. For GNOME users there is gnochm and maybe some viewers too.

For Mac OS X users there is http://chmox.sourceforge.net/ --anders
Mar 25 2007
prev sibling parent Alexander Panek <a.panek brainsware.org> writes:
Jari-Matti Mäkelä wrote:
 Vladimir Panteleev kirjoitti:
 Greetings,

 In an attempt to ease the life of Windows D programmers, I decided to
 write an utility which would automatically convert the D
 documentation, distributed with DMD, to an HTML Help project.

For users of Linux (and other POSIX compatible OS's) there is a program called kchmviewer that is a CHM reader. It should work without KDE, but probably still needs Qt. For GNOME users there is gnochm and maybe some viewers too.

xCHM is also a very nice tool, seems pretty fast, too.
Mar 25 2007
prev sibling next sibling parent torhu <fake address.dude> writes:
Vladimir Panteleev wrote:
 Greetings,
 
 In an attempt to ease the life of Windows D programmers, I decided to write an
utility which would automatically convert the D documentation, distributed with
DMD, to an HTML Help project. It was an interesting task, and through some
effort I managed at automating the creation of an usable CHM file.

This is great, thanks!
Mar 25 2007
prev sibling next sibling parent Alexander Panek <a.panek brainsware.org> writes:
Even though I'm a Linux user, this is very very handy. Thanks for the 
effort!

Vladimir Panteleev wrote:
 [...]

Mar 25 2007
prev sibling next sibling parent Charlie <charlie.fats gmail.com> writes:
Very nice!


Vladimir Panteleev wrote:
 Greetings,
 
 In an attempt to ease the life of Windows D programmers, I decided to write an
utility which would automatically convert the D documentation, distributed with
DMD, to an HTML Help project. It was an interesting task, and through some
effort I managed at automating the creation of an usable CHM file.
 
 The advantages of using a CHM help file over the included HTML files:
 
 1) it's one compressed file, instead of many
 2) the contents is somewhat easier to navigate
 3) it has instantaneous indexed search, supporting boolean operators
 4) comprehensive index of literally too many keywords...
 
 The program doesn't make assumptions on how the help files are laid out, so it
should work with future D releases. The only exception is that the program uses
Kirk McDonald's keyword index (
http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex ),
since I didn't find a reliable way to find where respective keywords are
explained in the documentation. The full unmodified source of that wiki page is
embedded in the program source, so it should be just as easy to update.
 
 When preparing the help files for the CHM format, the program does the
following modifications:
 
 1) remove the left navigation bar (it is replaced by the HTML Help's
navigation pane)
 2) skip Google AdSense ads, which don't make any sense in offline media -
browsers don't (and shouldn't) allow uploading contents of local data to web
services, thus Google AdSense displays rubbish/Chinese ads anyway.
 
 Here's the usage instructions:
 
 1) download and install the Microsoft HTML Help Workshop from here:
http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en
 2) save chmgen.d to ...\dmd\html\
 3) compile and run it
 4) open the d.hhp file with HTML Help Workshop and compile it
     -- or --
     run: hhc.exe d.hhp
 5) enjoy your brand new d.chm !
 
 Alternatively, you can download the CHM file from here:
http://thecybershadow.net/d/docs/d.chm
 I am not sure about the distribution rights of the documentation, so if there
are some legal problems, let me know and I'll remove it immediately.
 
 Things that could still be improved:
 
   - inserting anchors in some places, like before every function in the Phobos
docs
   - a cleaner/more accurate index
   - splitting the articles in categories (D syntax, Phobos, ...) to allow
filtering
   - adding Tango docs for an all-in-one D help file?
   - the code could be generally cleaned up in some places...
 
 I release the attached code to the Public Domain (no rights reserved).
However, the contents of the included wiki page is distributed under FDL.
 
 
 
 ------------------------------------------------------------------------
 
 import std.stdio;
 import std.file;
 import std.string;
 import std.regexp;
 
 // ********************************************************************
 
 int min(int a, int b)
 {
 	return a < b ? a : b;
 }
 
 void backSlash(char[] s)   // replace path delimiters in-place
 {
 	//s=s.dup;
 	foreach(inout c;s)
 		if(c=='/')
 			c='\\';
 }
 
 bool match(char[] line, char[] pattern)
 {
 	return std.regexp.find(line, pattern)>=0;
 }
 
 char[] getAnchor(char[] s)
 {
 	int i = std.string.find(s, '#');
 	if(i<0)
 		return "";
 	else
 		return s[i..$];
 }
 
 char[] removeAnchor(char[] s)
 {
 	int i = std.string.find(s, '#');
 	if(i<0)
 		return s;
 	else
 		return s[0..i];
 }
 
 char[] absoluteUrl(char[] base, char[] url)
 {
 	backSlash(base);
 	backSlash(url);
 	
 	if (url[0]=='#')
 		return base ~ url;
 
 	while(base[$-1]!='\\')
 		base = base[0..$-1];
 	
 	while(url[0..3]=="..\\")
 	{
 		url = url[3..$];
 		do {
 			base = base[0..$-1];
 			if(base.length==0)
 				return "";
 		} while(base[$-1]!='\\');
 	}
 	return base ~ url;
 }
 
 char[] movePath(char[] s)
 {
 	if(s.length>1 && s[0..2]=="d\\")
 		s = "chm" ~ s[1..$];
 	return s;
 }
 
 char[] normalize(char[] s)
 {
 	s = tolower(s);
 	char[] t;
 	foreach(c;s)
 		if(!iswhite(c))
 			t ~= c;
 	return t;
 }
 
 // ********************************************************************
 
 struct Link
 {
 	char[] url, title, text;
 
 	static Link opCall(char[] url, char[] title, char[] text)
 	{
 		backSlash(url);
 		Link my;
 		my.url = strip(url);
 		my.title = strip(title);
 		my.text = strip(text);
 		return my;
 	}
 }
 
 struct LinkBlock
 {
 	Link caption;
 	Link[] links;
 
 	static LinkBlock opCall(char[] url, char[] title, char[] text)
 	{
 		backSlash(url);
 		LinkBlock my;
 		my.caption.url = strip(url);
 		my.caption.title = strip(title);
 		my.caption.text = strip(text);
 		return my;
 	}
 }
 
 class Page
 {
 	char[] newFileName;
 	char[] title;
 	char[] src;
 	Link[] toctop;
 	LinkBlock[] linkBlocks;
 	bool[char[]] anchors;
 }
 
 struct KeyLink
 {
 	char[] anchor;
 	char[] title;
 
 	static KeyLink opCall(char[] anchor, char[] title)
 	{
 		KeyLink my;
 		my.anchor = strip(anchor);
 		my.title = strip(title);
 		return my;
 	}
 }
 
 // ********************************************************************
 
 char[][] listdirrec(char[] pathname)
 {
 	char[][] files = null;	
 
 	bool listing(char[] filename)
 	{
 		char[] file = std.path.join(pathname, filename);
 		if(isdir(file))
 		{
 			char[] oldpath = pathname;
 			pathname = file;
 			listdir(pathname, &listing);
 			pathname = oldpath;
 		}
 		else
 		{
 			files ~= std.path.join(pathname, filename);
 		}
 		return true; // continue
 	}
 	
 	listdir(pathname, &listing);
 
 	return files;
 }
 
 Page[char[]] pages;
 KeyLink[char[]][char[]] keywords;   // keywords[normalize(keyword)][original
url w/o anchor] = anchor/title
 char[][char[]] keyTable;
 
 void addKeyword(char[] keyword, char[] link, char[] title = null)
 {
 	keyword = strip(keyword);
 	char[] norm = normalize(keyword);
 	char[] file = removeAnchor(link);
 	backSlash(file);
 	char[] anchor = getAnchor(link);
 	if(title==null && norm in keywords && file in keywords[norm])   // when title
is present, it overrides any existing anchors/etc.
 	{
 		if(keywords[norm][file].anchor>anchor) // "less" is better
 			keywords[norm][file] = KeyLink(anchor, title);
 	}
 	else
 		keywords[norm][file] = KeyLink(anchor, title);
 	if(title==null && norm in keyTable)
 	{
 		if(keyTable[norm]>keyword) // "less" is better
 			keyTable[norm] = keyword;
 	}
 	else
 		keyTable[norm] = keyword;
 }
 
 void main()
 {
 	// clean up
 	if(exists("chm"))
 		foreach(file;listdirrec("chm\\"))
 			std.file.remove(file);
 	else
 		mkdir("chm");
 	
 	char[][] files = listdirrec("d\\");
 	
 	foreach(i,file;files)
 		pages[file] = new Page;
 
 	RegExp re_title = new RegExp(`<title>(Digital Mars - The )?D Programming
Language - (.*)</title>`);
 	RegExp re_title2 = new RegExp(`<h1>(.*)</h1>`);
 	RegExp re_heading = new RegExp(`<h2>(.*)</h2>`);
 	RegExp re_heading_link = new RegExp(`<h2><a href="([^"]*)"(
title="([^"]*)")?>(.*)</a></h2>`);
 	RegExp re_nav_link = new RegExp(`<li><a href="([^"]*)"(
title="(.*)")?>(.*)</a></li>`);
 	RegExp re_anchor = new RegExp(`<a name="([^"]*)">(<.>)*([^<]+)<`);
 	RegExp re_anchor_2 = new RegExp(`<a name=([^>]*)>(<.>)*([^<]+)<`);
 	RegExp re_link   = new RegExp(`<a href="([^"]*)">(<.>)*([^<]+)<`);
 	RegExp re_def = new RegExp(`<dt><big>.*<u>([^<]+)<`);
 
 	foreach(fileName,page;pages)
 		with(page)
 		{
 			char[] destdir = movePath(std.path.getDirName(fileName));
 			if(!exists(destdir))
 				mkdir(destdir);
 
 			newFileName = movePath(fileName);
 
 			if(match(fileName, `\.html$`))
 			{
 				writefln("Processing "~fileName);
 				src = cast(char[])read(fileName);
 				char[][] lines = splitlines(src);
 				char[][] newlines = null;
 				bool skip = false, intoctop = false, innavblock = false, innavblock2 =
false;
 				int dl = 0;
 				char[] anchor = null;
 				anchors[""] = true;
 				foreach(line;lines)
 				{
 					bool nextSkip = skip;
 					
 					if (re_title.find(line)>=0)
 					{
 						title = strip(re_title.match(2));
 						line = re_title.replace(`<title>` ~ title ~ `</title>`);
 					}
 					if (re_title2.find(line)>=0)
 						if(title=="")
 							title = strip(re_title2.match(1));
 					
 					if (re_anchor.find(line)>=0)
 					{
 						anchor = '#' ~ re_anchor.match(1);
 						anchors[anchor] = true;
 					}
 					else
 					if (re_anchor_2.find(line)>=0)
 					{
 						anchor = '#' ~ re_anchor.match(1);
 						anchors[anchor] = true;
 					}
 
 					if(match(line, `<div id="toctop">`))
 						intoctop = true;
 					if(match(line, `<div class="navblock">`))
 						if(innavblock)
 						{
 							innavblock2 = true;
 							linkBlocks ~= LinkBlock("", "", "");
 						}
 						else
 							innavblock = true;
 					if(match(line, `</div>`))
 						intoctop = innavblock2 = false;
 
 					if(std.string.find(line, `<dl>`)>=0)
 						dl++;
 					if(dl==1)
 					{
 						if(re_def.find(line)>=0)
 							addKeyword(re_def.match(1), fileName ~ anchor);
 					}
 					if(std.string.find(line, `</dl>`)>=0)
 						dl--;
 
 					if(re_heading_link.find(line)>=0)
 					{
 						if(innavblock2)
 							linkBlocks ~= LinkBlock(re_heading_link.match(1),
re_heading_link.match(3), re_heading_link.match(4));
 					}
 					else
 					if(re_heading.find(line)>=0)
 					{
 						if(innavblock2)
 							linkBlocks ~= LinkBlock("", "", re_heading.match(1));
 					}
 
 					if(re_nav_link.find(line)>=0)
 						if(intoctop)
 							toctop   ~= Link(re_nav_link.match(1), re_nav_link.match(3),
re_nav_link.match(4));
 						else
 						if(innavblock2)
 							if(re_nav_link.match(1)[0..7]!="http://" &&
exists(absoluteUrl(fileName, re_nav_link.match(1))))
 								linkBlocks[$-1].links ~= Link(re_nav_link.match(1),
re_nav_link.match(3), re_nav_link.match(4));
 						//else
 						//	writefln("Displaced link: ", line);
 					
 					if(re_anchor.find(line)>=0)
 						addKeyword(re_anchor.match(3), fileName ~ "#" ~ re_anchor.match(1));
 					else
 					if(re_anchor_2.find(line)>=0)
 						addKeyword(re_anchor_2.match(3), fileName ~ "#" ~ re_anchor_2.match(1));
 					
 					if(re_link.find(line)>=0)
 						if(re_link.match(1)[0..min($,7)]!="http://")
 							addKeyword(re_link.match(3), absoluteUrl(fileName, re_link.match(1)));
 					
 					// skip Google ads
 					if(match(line, `^<!-- Google ad -->$`))
 						skip = nextSkip = true;
 					if(match(line, `^</script>$`))
 						nextSkip = false;
 
 					// skip navigation bar
 					if(match(line, `^<div id="navigation">$`))
 						skip = nextSkip = true;
 					if(match(line, `^<div id="content">$`))
 						skip = nextSkip = false;
 
 					if(!skip)
 						newlines ~= line;
 					skip = nextSkip;
 				}
 				src = join(newlines, newline);
 				write(newFileName, src);
 			}
 			else
 			if(match(fileName, `\.css$`))
 			{
 				writefln("Processing "~fileName);
 				src = cast(char[])read(fileName);
 				char[][] lines = splitlines(src);
 				char[][] newlines = null;
 				foreach(line;lines)
 				{
 					// skip #div.content positioning
 					if(!match(line, `margin-left:13em;`))
 						newlines ~= line;
 				}
 				src = join(newlines, newline);
 				write(newFileName, src);
 			}
 			else
 			{
 				copy(fileName, newFileName);
 			}
 		} 
 
 	// ************************************************************
 
 	Link[] topLinks;
 	bool[char[]] gotLink;
 
 	foreach(fileName,page;pages)
 		foreach(link;page.toctop)
 		{
 			char[] url = absoluteUrl(fileName, link.url);
 			if(!(url in gotLink))
 			{
 				topLinks ~= Link(url, link.title, link.text);
 				gotLink[url] = true;
 			}
 		}
 
 	// retreive keyword link titles
 	foreach(keyNorm,urls;keywords)
 		foreach(url,inout link;urls)
 			if(url in pages)
 				link.title = pages[url].title;
 
 	// ************************************************************
 
 	RegExp re_key_new = new RegExp(`<tt>(.*)</tt>`);
 	RegExp re_key_link = new RegExp(`^\* (.*)\[http://www\.digitalmars\.com/([^
]*) (.*)\]`);
 
 	char[][] keywordLines = splitlines(keywordIndex);
 	char[] keyword;
 	foreach(line;keywordLines)
 	{
 		if(re_key_new.find(line)>=0)
 			keyword = re_key_new.match(1);
 		if(re_key_link.find(line)>=0)
 		{
 			char[] url = re_key_link.match(2);
 			char[] file = removeAnchor(url);
 			char[] anchor = getAnchor(url);
 			backSlash(url);
 			
 			if(file in pages)
 			{
 				if(!(anchor in pages[file].anchors))
 				{
 					char[] cmp1 = normalize(anchor);
 					foreach(realAnchor,b;pages[file].anchors)
 					{
 						char[] cmp2 = normalize(realAnchor);
 						int n = min(cmp1.length, cmp2.length);
 						if(n>=3 && cmp1[0..n] == cmp2[0..n])
 						{
 							//writefln("Fixing broken anchor " ~ anchor ~ " to " ~ realAnchor);
 							anchor = realAnchor;
 							break;
 						}	
 					}
 				}
 
 				if(anchor in pages[file].anchors)
 				{
 					addKeyword(keyword, file ~ anchor, re_key_link.match(1) ~
re_key_link.match(3));
 				//	writefln("Adding keyword " ~ keyword ~ " to " ~ file ~ anchor ~ " as "
~ re_key_link.match(1) ~ re_key_link.match(3));
 				}
 				//else
 				//	writefln("Broken anchor link to keyword "~ keyword ~ " to " ~
re_key_link.match(2) ~ " as " ~ re_key_link.match(1) ~ re_key_link.match(3));
 			}
 			//else
 			//	writefln("Unfound URL: " ~ url);
 		}
 	}
 
 	// ************************************************************
 
 	FILE* f = fopen("d.hhp", "wt");
 	fwritefln(f, 
 `[OPTIONS]
 Compatibility=1.1 or later
 Compiled file=d.chm
 Contents file=d.hhc
 Default Window=main
 Default topic=` ~ movePath(topLinks[0].url) ~ `
 Display compile progress=No
 Full-text search=Yes
 Index file=d.hhk
 Language=0x409 English (United States)
 Title=D
 
 [WINDOWS]
 main="D","d.hhc","d.hhk","chm\index.html","chm\index.html",,,,,0x63520,,0x380e,[271,372,593,566],0x918f0000,,,,,,0
 
 [FILES]`);
 	char[][] htmlList;
 	foreach(page;pages)
 		if(match(page.newFileName, `\.html$`))
 			htmlList ~= page.newFileName;
 	htmlList.sort;
 	foreach(s;htmlList)
 		fwritefln(f, s);
 	fwritefln(f, `
 [INFOTYPES]`);
 	fclose(f);
 
 	// ************************************************************
 
 	f = fopen("d.hhc", "wt");
 	fwritefln(f, 
 `<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML><BODY>
 <OBJECT type="text/site properties"><param name="Window Styles"
value="0x800025"></OBJECT>
 <UL>`);
 	foreach(toplink;topLinks)
 	{
 		fwritefln(f, 
 `	<LI><OBJECT type="text/sitemap">
 		<param name="Name" value="` ~ toplink.title ~ `">
 		<param name="Local" value="` ~ movePath(toplink.url) ~ `">
 		</OBJECT>
 	<UL>`);
 		Page topPage = pages[toplink.url];
 		foreach(link;topPage.linkBlocks[0].links)
 			fwritefln(f, 
 `		<LI> <OBJECT type="text/sitemap">
 			<param name="Name" value="` ~ link.text ~ `">
 			<param name="Local" value="` ~ movePath(absoluteUrl(toplink.url, link.url))
~ `">
 			</OBJECT>`);
 		foreach(linkBlock;topPage.linkBlocks[1..$])
 		{
 			fwritefln(f, 
 `		<LI> <OBJECT type="text/sitemap">
 			<param name="Name" value="` ~ linkBlock.caption.text ~ `">`);
 			if(linkBlock.caption.url!="")
 				fwritefln(f, 
 `			<param name="Local" value="` ~ movePath(absoluteUrl(toplink.url,
linkBlock.caption.url)) ~ `">`);
 			fwritefln(f, 
 `			</OBJECT>
 		<UL>`);
 			foreach(link;linkBlock.links)
 				fwritefln(f, 
 `			<LI> <OBJECT type="text/sitemap">
 				<param name="Name" value="` ~ link.text ~ `">
 				<param name="Local" value="` ~ movePath(absoluteUrl(toplink.url,
link.url)) ~ `">
 				</OBJECT>`);
 			fwritefln(f, 
 `		</UL>`);
 		}
 		fwritefln(f, 
 `	</UL>`);
 	}
 	fwritefln(f, `</UL>
 </BODY></HTML>`);
 	fclose(f);
 
 	// ************************************************************
 
 	f = fopen("d.hhk", "wt");
 	fwritefln(f, 
 `<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML><BODY>
 <UL>`);
 	foreach(keyNorm,urlList;keywords)
 	{
 		fwritefln(f, 
 `	<LI> <OBJECT type="text/sitemap">
 		<param name="Name" value="` ~ keyTable[keyNorm] ~ `">`);
 		foreach(url,link;urlList)
 			if(url in pages)
 			{
 				fwritefln(f, 
 `		<param name="Name" value="` ~ link.title ~ `">
 		<param name="Local" value="` ~ movePath(url) ~ link.anchor ~ `">`);
 			}
 		fwritefln(f, 
 `		</OBJECT>`);
 	}
 	fwritefln(f, 
 `</UL>
 </BODY></HTML>`);
 	fclose(f);
 }
 
 // ********************************************************************
 
 // retreived on 2007.03.25 from
http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex
 const keywordIndex = `
 <tt>abstract</tt>
 * [http://www.digitalmars.com/d/attribute.html#abstract Attributes]
 <tt>alias</tt>
 * [http://www.digitalmars.com/d/declaration.html#alias Declarations]
 * template parameters:
[http://www.digitalmars.com/d/template.html#aliasparameters Templates]
 <tt>align</tt>
 * [http://www.digitalmars.com/d/attribute.html#align Attributes]
 <tt>asm</tt>
 * [http://www.digitalmars.com/d/statement.html#asm Statements]
 * x86 inline assembler:  [http://www.digitalmars.com/d/iasm.html Inline
Assembler]
 <tt>assert</tt>
 * [http://www.digitalmars.com/d/expression.html#AssertExpression Expressions]
 * static assert:  [http://www.digitalmars.com/d/version.html#staticassert
Conditional Compilation]
 
 <tt>auto</tt>
 * class attribute:  [http://www.digitalmars.com/d/class.html#auto Classes]
 * RAII attribute:  [http://www.digitalmars.com/d/attribute.html#auto
Attributes]
 * type inference:  [http://www.digitalmars.com/d/declaration.
tml#AutoDeclaration Declarations]
 
 ----
 
 <tt>body</tt>
 * in function contract:  [http://www.digitalmars.com/d/dbc.html Contracts]
 
 <tt>bool</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>break</tt>
 * in switch:  [http://www.digitalmars.com/d/statement.html#switch Statements]
 * statement:  [http://www.digitalmars.com/d/statement.html#break Statements]
 
 <tt>byte</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 ----
 
 <tt>case</tt>
 * in switch:  [http://www.digitalmars.com/d/statement.html#switch Statements]
 
 <tt>cast</tt>
 * [http://www.digitalmars.com/d/expression.html#CastExpression Expressions]
 
 <tt>catch</tt>
 * [http://www.digitalmars.com/d/statement.html#try Statements]
 
 <tt>cdouble</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * complex types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 <tt>cent</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>cfloat</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * complex types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 <tt>char</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>class</tt>
 * [http://www.digitalmars.com/d/class.html Classes]
 * properties of:  [http://www.digitalmars.com/d/property.html#classproperties
Properties]
 
 <tt>const</tt>
 * [http://www.digitalmars.com/d/attribute.html#const Attributes]
 
 <tt>continue</tt>
 * [http://www.digitalmars.com/d/statement.html#continue Statements]
 
 <tt>creal</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * complex types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 ----
 
 <tt>dchar</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>debug</tt>
 * [http://www.digitalmars.com/d/version.html#debug Conditional Compilation]
 
 <tt>default</tt>
 * in switch:  [http://www.digitalmars.com/d/statement.html#switch Statements]
 
 <tt>delegate</tt>
 * as datatype and replacement for pointer-to-member-function: 
[http://www.digitalmars.com/d/type.html#delegates Types]
 * as dynamic closure:  [http://www.digitalmars.com/d/function.html#closures
Functions]
 * in function literal: 
[http://www.digitalmars.com/d/expression.html#FunctionLiteral Expressions]
 
 <tt>delete</tt>
 * expression:  [http://www.digitalmars.com/d/expression.html#DeleteExpression
Expressions]
 * overloading:  [http://www.digitalmars.com/d/class.html#deallocators Classes]
 
 <tt>deprecated</tt>
 * [http://www.digitalmars.com/d/attribute.html#deprecated Attributes]
 
 <tt>do</tt>
 * [http://www.digitalmars.com/d/statement.html#do Statements]
 
 <tt>double</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * floating point types:  [http://www.digitalmars.com/d/float.html Floating
Point]
 
 ----
 
 <tt>else</tt>
 * [http://www.digitalmars.com/d/statement.html#if Statements]
 
 <tt>enum</tt>
 * [http://www.digitalmars.com/d/enum.html Enums]
 
 <tt>export</tt>
 * protection attribute:  [http://www.digitalmars.com/d/attribute.html
Attributes]
 
 <tt>extern</tt>
 * linkage attribute:  [http://www.digitalmars.com/d/attribute.html#linkage
Attributes]
 * interfacing to C:  [http://www.digitalmars.com/d/interfaceToC.html
Interfacing to C]
 * in variable declaration: 
[http://www.digitalmars.com/d/declaration.html#extern Declarations]
 
 ----
 
 <tt>false</tt>
 * [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expressions]
 
 <tt>final</tt>
 * [http://www.digitalmars.com/d/function.html Functions]
 
 <tt>finally</tt>
 * [http://www.digitalmars.com/d/statement.html#try Statements]
 
 <tt>float</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * floating point types:  [http://www.digitalmars.com/d/float.html Floating
Point]
 
 <tt>for</tt>
 * [http://www.digitalmars.com/d/statement.html#for Statements]
 
 <tt>foreach</tt>
 * [http://www.digitalmars.com/d/statement.html#foreach Statements]
 
 <tt>foreach_reverse</tt>
 * [http://www.digitalmars.com/d/statement.html#foreach Statements]
 
 <tt>function</tt>
 * as datatype:  [http://www.digitalmars.com/d/type.html Types]
 * in function literal: 
[http://www.digitalmars.com/d/expression.html#FunctionLiteral Expressions]
 * function pointers:  [http://www.digitalmars.com/d/function.html#closures
Functions]
 
 
 ----
 
 
 <tt>goto</tt>
 * [http://www.digitalmars.com/d/statement.html#goto Statements]
 
 
 ----
 
 
 <tt>idouble</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * imaginary types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 <tt>if</tt>
 * [http://www.digitalmars.com/d/statement.html#if Statements]
 * static if:  [http://www.digitalmars.com/d/version.html#staticif Conditional
Compilation]
 
 <tt>ifloat</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * imaginary types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 <tt>import</tt>
 * [http://www.digitalmars.com/d/module.html#ImportDeclaration Modules]
 * import expression: 
[http://digitalmars.com/d/expression.html#ImportExpression Expressions]
 
 <tt>in</tt>
 * in pre contract:  [http://www.digitalmars.com/d/dbc.html Contracts]
 * containment test: 
[http://www.digitalmars.com/d/expression.html#InExpression Expressions]
 * function parameter:  [http://www.digitalmars.com/d/function.html#parameters
Functions]
 
 <tt>inout</tt>
 * in foreach statement:  [http://www.digitalmars.com/d/statement.html#foreach
Statements]
 * function parameter:  [http://www.digitalmars.com/d/function.html#parameters
Functions]
 
 <tt>int</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>interface</tt>
 * [http://www.digitalmars.com/d/interface.html Interfaces]
 
 <tt>invariant</tt>
 * [http://www.digitalmars.com/d/class.html#invariants Classes]
 
 <tt>ireal</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * imaginary types:  [http://www.digitalmars.com/d/float.html Floating Point]
 
 <tt>is</tt>
 * identity comparison: 
[http://www.digitalmars.com/d/expression.html#EqualExpression Expressions]
 * type comparison:  [http://www.digitalmars.com/d/expression.html#IsExpression
Expressions]
 
 
 ----
 
 
 <tt>lazy</tt>
 * function parameter:  [http://www.digitalmars.com/d/function.html#parameters
Functions]
 
 <tt>long</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 
 ----
 
 
 <tt>mixin</tt>
 * [http://www.digitalmars.com/d/template-mixin.html Template Mixins]
 * Mixin declarations:  [http://digitalmars.com/d/module.html#MixinDeclaration
Modules]
 * Mixin expressions: 
[http://digitalmars.com/d/expression.html#MixinExpression Expressions]
 * Mixin statements:  [http://digitalmars.com/d/statement.html#MixinStatement
Statements]
 
 <tt>module</tt>
 * [http://www.digitalmars.com/d/module.html Modules]
 
 
 ----
 
 
 <tt>new</tt>
 * anonymous nested classes and: 
[http://www.digitalmars.com/d/class.html#anonymous Classes]
 * expression:  [http://www.digitalmars.com/d/expression.html#NewExpression
Expressions]
 * overloading:  [http://www.digitalmars.com/d/class.html#allocators Classes]
 
 <tt>null</tt>
 * [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expressions]
 
 
 ----
 
 
 <tt>out</tt>
 * in post contract:  [http://www.digitalmars.com/d/dbc.html Contracts]
 * function parameter:  [http://www.digitalmars.com/d/function.html#parameters
Functions]
 
 <tt>override</tt>
 * [http://www.digitalmars.com/d/attribute.html#override Attributes]
 
 
 ----
 
 
 <tt>package</tt>
 * [http://www.digitalmars.com/d/attribute.html Attributes]
 
 <tt>pragma</tt>
 * [http://www.digitalmars.com/d/pragma.html Pragmas]
 
 <tt>private</tt>
 * and import:  [http://www.digitalmars.com/d/module.html Modules]
 * protection attribute:  [http://www.digitalmars.com/d/attribute.html
Attributes]
 
 <tt>protected</tt>
 * [http://www.digitalmars.com/d/attribute.html Attributes]
 
 <tt>public</tt>
 * [http://www.digitalmars.com/d/attribute.html Attributes]
 
 
 ----
 
 
 <tt>real</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 * floating point types:  [http://www.digitalmars.com/d/float.html Floating
Point]
 
 <tt>return</tt>
 * [http://www.digitalmars.com/d/statement.html#return Statements]
 
 
 ----
 
 
 <tt>scope</tt>
 * statement: [http://www.digitalmars.com/d/statement.html#ScopeGuardStatement
Statements]
 * RAII attribute:  [http://www.digitalmars.com/d/attribute.html#scope
Attributes]
 
 <tt>short</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>static</tt>
 * attribute:  [http://www.digitalmars.com/d/attribute.html Attributes]
 * constructors:  [http://www.digitalmars.com/d/class.html#staticconstructor
Classes]
 * destructors:  [http://www.digitalmars.com/d/class.html#staticdestructor
Classes]
 * order of static constructors and destructors: 
[http://www.digitalmars.com/d/module.html#staticorder Modules]
 * static assert:  [http://www.digitalmars.com/d/version.html#staticassert
Conditional Compilation]
 * static if:  [http://www.digitalmars.com/d/version.html#staticif Conditional
Compilation]
 * static import:  [http://www.digitalmars.com/d/module.html#ImportDeclaration
Modules]
 
 <tt>struct</tt>
 * [http://www.digitalmars.com/d/struct.html Structs & Unions]
 * properties of:  [http://www.digitalmars.com/d/property.html#classproperties
Properties]
 
 <tt>super</tt>
 * [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expressions]
 * as name of superclass constructor: 
[http://www.digitalmars.com/d/class.html#constructors Classes]
 
 <tt>switch</tt>
 * [http://www.digitalmars.com/d/statement.html#switch Statements]
 
 <tt>synchronized</tt>
 * [http://www.digitalmars.com/d/statement.html#synchronize Statements]
 
 
 ----
 
 
 <tt>template</tt>
 * [http://www.digitalmars.com/d/template.html Templates]
 
 <tt>this</tt>
 * [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expressions]
 * as constructor name:  [http://www.digitalmars.com/d/class.html#constructors
Classes]
 * with ~, as destructor name: 
[http://www.digitalmars.com/d/class.html#destructors Classes]
 
 <tt>throw</tt>
 * [http://www.digitalmars.com/d/statement.html#throw Statements]
 
 <tt>true</tt>
 * [http://www.digitalmars.com/d/expression.html#PrimaryExpression Expressions]
 
 <tt>try</tt>
 * [http://www.digitalmars.com/d/statement.html#try Statements]
 
 <tt>typedef</tt>
 * [http://www.digitalmars.com/d/declaration.html#typedef Declarations]
 
 <tt>typeid</tt>
 * [http://www.digitalmars.com/d/expression.html#typeidexpression Expressions]
 
 <tt>typeof</tt>
 * [http://www.digitalmars.com/d/declaration.html#typeof Declarations]
 
 
 ----
 
 
 <tt>ubyte</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>ucent</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>uint</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>ulong</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>union</tt>
 * [http://www.digitalmars.com/d/struct.html Structs & Unions]
 
 <tt>unittest</tt>
 * in classes:  [http://www.digitalmars.com/d/class.html#unittest Classes]
 
 <tt>ushort</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 
 ----
 
 
 <tt>version</tt>
 * [http://www.digitalmars.com/d/version.html#version Conditional Compilation]
 
 <tt>void</tt>
 * as initializer:  [http://www.digitalmars.com/d/declaration.html Declarations]
 * as type:  [http://www.digitalmars.com/d/type.html Types]
 
 <tt>volatile</tt>
 * [http://www.digitalmars.com/d/statement.html#volatile Statements]
 
 
 ----
 
 
 <tt>wchar</tt>
 * [http://www.digitalmars.com/d/type.html Types]
 
 <tt>while</tt>
 * [http://www.digitalmars.com/d/statement.html#while Statements]
 
 <tt>with</tt>
 * [http://www.digitalmars.com/d/statement.html#with Statements]
 
 
 
 ----
 
 Source: Kirk <n>McDonald</n>, http://216.190.88.10:8087/media/d_index.html
(NG:digitalmars.D/38550)
 `;

Mar 26 2007
prev sibling next sibling parent reply "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Vladimir Panteleev" <thecybershadow gmail.com> wrote in message 
news:op.tprgxqyjm02fvl cybershadow...
Greetings,

 In an attempt to ease the life of Windows D programmers, I decided
 to write an utility which would automatically convert the D
 documentation, distributed with DMD, to an HTML Help project.

Really? Are you planning to release it any time soon?
 1) download and install the Microsoft HTML Help Workshop from
 here:
 http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en

Is it just me, or does nobody know the difference between htmlhelp.exe and htmlhelpj.exe (apart from the name and size)? Stewart.
Mar 28 2007
parent reply torhu <fake address.dude> writes:
Stewart Gordon wrote:
 "Vladimir Panteleev" <thecybershadow gmail.com> wrote in message 
 news:op.tprgxqyjm02fvl cybershadow...
 Greetings,
 
 In an attempt to ease the life of Windows D programmers, I decided
 to write an utility which would automatically convert the D
 documentation, distributed with DMD, to an HTML Help project.

Really? Are you planning to release it any time soon?

It's attached to the original post.
 1) download and install the Microsoft HTML Help Workshop from
 here:
 http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en

Is it just me, or does nobody know the difference between htmlhelp.exe and htmlhelpj.exe (apart from the name and size)?

j = Japanese language version.
Mar 28 2007
parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"torhu" <fake address.dude> wrote in message 
news:eue8ap$vna$1 digitalmars.com...
 Stewart Gordon wrote:

 Really?  Are you planning to release it any time soon?

It's attached to the original post.

Oops. I must be just not used to this so-renamed Windows Mail program.... Stewart.
Mar 29 2007
prev sibling parent Jussi Jumppanen <jussij zeusedit.com> writes:
Vladimir Panteleev Wrote:

 In an attempt to ease the life of Windows D programmers, I 
 decided to write an utility which would automatically convert 
 the D documentation, distributed with DMD, to an HTML Help 
 project.

Nice work. I tested your D CHM help file and found it works well with the Zeus Quick Help: http://www.zeusedit.com/forum/viewtopic.php?t=1078 My only suggestion would be to change the title of the D help file from its current: D to something a bit longer, maybe: D Programming Language or possibly: D Programmer's Manual The title is what is displayed in the caption space of the CHM help viewer. Cheers Jussi Author: Zeus for Windows IDE
Mar 28 2007