diff --git a/mozilla/htmlparser/tests/htmlgen/htmlgen.cpp b/mozilla/htmlparser/tests/htmlgen/htmlgen.cpp
new file mode 100644
index 00000000000..a896e9eebc9
--- /dev/null
+++ b/mozilla/htmlparser/tests/htmlgen/htmlgen.cpp
@@ -0,0 +1,512 @@
+/*========================================================
+ To Do:
+ 1. Tag sequences on the command line p..table
+ 2. Dumping documents into the right place
+ *========================================================*/
+
+
+/*========================================================
+ Special keywords:
+ $0..$9: represent command line arguments
+ @file: the name of the file being writtent
+ @nextfile: the name of the next file to be written
+ @htmlgen: runs the app recursively with given arguments.
+ *========================================================*/
+
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+static char* tagTable[] = {
+ "A", "ABBR", "ACRONYM", "ADDRESS", "APPLET", "AREA",
+ "B", "BASE", "BASEFONT", "BDO", "BGSOUND", "BIG", "BLINK", "BLOCKQUOTE", "BODY", "BR", "BUTTON",
+ "CAPTION", "CENTER", "CITE", "CODE", "COL", "COLGROUP",
+ "DD", "DEL", "DFN", "DIR", "DIV", "DL", "DT",
+ "EM", "EMBED",
+ "FIELDSET", "FONT", "FORM", "FRAME", "FRAMESET",
+ "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML",
+ "I", "IFRAME", "ILAYER", "IMG", "INPUT", "INS", "ISINDEX",
+ "KBD", "KEYGEN",
+ "LABEL", "LAYER", "LEGEND", "LI", "LINK", "LISTING",
+ "MAP", "MENU", "META", "MULTICOL",
+ "NOBR", "NOEMBED", "NOFRAMES", "NOLAYER", "NOSCRIPT",
+ "OBJECT", "OL", "OPTGROUP", "OPTION",
+ "P", "PARAM", "PLAINTEXT", "PRE",
+ "Q",
+ "S","SAMP","SCRIPT","SELECT","SERVER","SMALL","SOUND","SPACER","SPAN","STRIKE","STRONG","STYLE","SUB","SUP",
+ "TABLE", "TBODY", "TD", "TEXTAREA", "TFOOT", "TH", "THEAD", "TITLE", "TR", "TT",
+ "U", "UL",
+ "VAR",
+ "WBR",
+ "XMP",
+ 0
+};
+static char gCWD[1025];
+static char gPrevFile[128];
+static char gThisFile[128];
+static char gNextFile[128];
+static int gFileIndex=0;
+
+
+int findTag(const char* aTagName) {
+ int low = 0;
+ int high = 107;
+ while (low <= high) {
+ int middle = (low + high) >> 1;
+ int result = stricmp(aTagName, tagTable[middle]);
+ if (result == 0)
+ return middle;
+ if (result < 0)
+ high = middle - 1;
+ else
+ low = middle + 1;
+ }
+ return -1;
+}
+
+
+/**
+ * Call this to find a tag that closely resembles the given tag.
+ * Note that we match based on the first char.
+ * @update gess12/23/98
+ * @param
+ * @return
+ */
+int findNearestTag(char* aTag){
+ int result=-1;
+ if(aTag){
+ char theChar=toupper(aTag[0]);
+ int theIndex=-1;
+ while(tagTable[++theIndex]){
+ if(toupper(tagTable[theIndex][0])==theChar) {
+ return theIndex;
+ }
+ }
+ }
+ if(toupper(aTag[0])<'A')
+ result=0;
+ else result=107;
+ return result;
+}
+
+char* getNthTagAfter(int aRangeIndex,char* aStartTag){
+ int theIndex=findTag(aStartTag);
+ if(-1==theIndex){
+ theIndex=findNearestTag(aStartTag);
+ }
+ if(-10){
+ if((strchr(aString,',')) || (strchr(aString,'-'))) {
+ mRanges[mCount]=new char[sLen+1];
+ strcpy(mRanges[mCount++],aString);
+ }
+ else {
+ mKeys[mCount]=new char[sLen+1];
+ strcpy(mKeys[mCount++],aString);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int getCount() {return mCount;}
+
+ char* getMacro(int anIndex) {
+ if(anIndex> theBuffer;
+ if(!stricmp(theBuffer,"-F")){
+ //copy the filename...
+ aStream >> theBuffer;
+ strcpy(mFilename,theBuffer);
+ readDefs=false;
+ }
+ else if(!stricmp(theBuffer,"-D")){
+ readDefs=true;
+ }
+ else if(!stricmp(theBuffer,"-O")){
+ aStream >> theBuffer;
+ readDefs=false;
+ }
+ else if(readDefs){
+ if(theBuffer[0]){
+ addMacro(theBuffer);
+ theBuffer[0]=0;
+ }
+ }
+ }
+ return true;
+ }
+
+ void buildArgBuffer(char* aBuffer) {
+ aBuffer[0]=0;
+ if(mFilename[0]) {
+ sprintf(aBuffer,"-0 %s -f %s -d ",gThisFile,mFilename);
+ }
+ for(int i=0;i>theWord;
+ char* thePos=strchr(theWord,'@');
+ if(thePos){
+ strncat(temp,theWord,thePos-theWord);
+ if(!strnicmp(thePos,"@file",5)){
+ strcat(temp,gThisFile);
+ thePos+=5;
+ }
+ else if(!strnicmp(thePos,"@nextfile",9)){
+ strcat(temp,gNextFile);
+ thePos+=9;
+ }
+ else if(!strnicmp(thePos,"@prevfile",9)){
+ strcat(temp,gPrevFile);
+ thePos+=9;
+ }
+ strcat(temp,thePos);
+ }
+ else strcat(temp,theWord);
+ strcat(temp," ");
+ }
+ strcpy(aBuffer,temp);
+ }
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+void expandMacros(char* aBuffer,CMacros& aMacroSet){
+ char temp[1024];
+ int rPos=-1;
+ int wPos=0;
+
+ if(aBuffer){
+ while(aBuffer[++rPos]){
+ if('$'==aBuffer[rPos]){
+ temp[wPos]=0;
+ rPos++; //skip the $...
+ int theIndex=aBuffer[rPos]-'0';
+ char* theMacro=aMacroSet.getMacro(theIndex);
+ if(theMacro){
+ strcat(temp,theMacro);
+ wPos=strlen(temp);
+ }
+ }
+ else temp[wPos++]=aBuffer[rPos];
+ }
+ temp[wPos]=0;
+ strcpy(aBuffer,temp);
+ }
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+int processFile(char* aDir,fstream& anOutputStream,istrstream& aInputArgs){
+ int result=0;
+
+ CMacros theMacros;
+ theMacros.consume(aInputArgs);
+
+ char* theFilename=theMacros.getFilename();
+ fstream theInputStream(theFilename,ios::in);
+ if(theInputStream.is_open()){
+ bool done=false;
+ char theBuffer[1024];
+ char theWord[600];
+
+ while((!done) && (0==result)){
+
+ theInputStream.getline(theBuffer,sizeof(theBuffer)-1);
+ if(theInputStream.gcount()){
+
+ //before doing anything else, expand the macros and keywords...
+ expandMacros(theBuffer,theMacros);
+ expandKeywords(theBuffer,theMacros);
+
+ //Now process each line:
+ if(strchr(theBuffer,'@')) {
+
+ //First, see if the line is an htmlgen statement; if so, recurse to read new file...
+ istrstream iStr(theBuffer);
+ iStr>>theWord;
+ if(!stricmp(theWord,"@htmlgen")){
+
+ //If you're here, we found an htmlgen statement.
+ // To handle this, we have to:
+ // 1. strip off the @htmlgen
+ // 2. grab the filename and collect the args,
+ // 3. and recurse...
+
+ result=processFile(aDir,anOutputStream,iStr);
+ }
+ }
+ else anOutputStream << theBuffer << endl;
+ }
+ else done=true;
+ }
+ }
+ return result;
+}
+
+
+/**
+ * This is where the different combinations of arguments
+ * gets constructed and passed on for processing.
+ * Note that this is even called when the args have only 1 value.
+ * @return error code
+ */
+int iterate(istrstream& aInputArgs){
+ int result=0;
+
+ CMacros theArgs;
+ theArgs.consume(aInputArgs);
+
+ char theBuffer[1024];
+ char theFilename[1024];
+
+ bool done=!theArgs.first();
+ while((!done) && (0==result)){
+ CMacros theTempArgs(theArgs);
+ theTempArgs.buildArgBuffer(theBuffer);
+ istrstream theArgStream(theBuffer);
+ sprintf(theFilename,"%s\\%s",gCWD,gThisFile);
+ fstream theOutStream(theFilename,ios::trunc);
+ result=processFile(gCWD,theOutStream,theArgStream);
+ theArgs.dump();
+ done=!theArgs.next();
+ }
+ return result;
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+int main(int argc,char* argv[]){
+ int result=0;
+
+ gPrevFile[0]=gThisFile[0]=gNextFile[0];
+ if(argc>1){
+ char theBuffer[1024];
+ theBuffer[0]=0;
+
+ for(int i=1;i
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+static char* tagTable[] = {
+ "A", "ABBR", "ACRONYM", "ADDRESS", "APPLET", "AREA",
+ "B", "BASE", "BASEFONT", "BDO", "BGSOUND", "BIG", "BLINK", "BLOCKQUOTE", "BODY", "BR", "BUTTON",
+ "CAPTION", "CENTER", "CITE", "CODE", "COL", "COLGROUP",
+ "DD", "DEL", "DFN", "DIR", "DIV", "DL", "DT",
+ "EM", "EMBED",
+ "FIELDSET", "FONT", "FORM", "FRAME", "FRAMESET",
+ "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML",
+ "I", "IFRAME", "ILAYER", "IMG", "INPUT", "INS", "ISINDEX",
+ "KBD", "KEYGEN",
+ "LABEL", "LAYER", "LEGEND", "LI", "LINK", "LISTING",
+ "MAP", "MENU", "META", "MULTICOL",
+ "NOBR", "NOEMBED", "NOFRAMES", "NOLAYER", "NOSCRIPT",
+ "OBJECT", "OL", "OPTGROUP", "OPTION",
+ "P", "PARAM", "PLAINTEXT", "PRE",
+ "Q",
+ "S","SAMP","SCRIPT","SELECT","SERVER","SMALL","SOUND","SPACER","SPAN","STRIKE","STRONG","STYLE","SUB","SUP",
+ "TABLE", "TBODY", "TD", "TEXTAREA", "TFOOT", "TH", "THEAD", "TITLE", "TR", "TT",
+ "U", "UL",
+ "VAR",
+ "WBR",
+ "XMP",
+ 0
+};
+static char gCWD[1025];
+static char gPrevFile[128];
+static char gThisFile[128];
+static char gNextFile[128];
+static int gFileIndex=0;
+
+
+int findTag(const char* aTagName) {
+ int low = 0;
+ int high = 107;
+ while (low <= high) {
+ int middle = (low + high) >> 1;
+ int result = stricmp(aTagName, tagTable[middle]);
+ if (result == 0)
+ return middle;
+ if (result < 0)
+ high = middle - 1;
+ else
+ low = middle + 1;
+ }
+ return -1;
+}
+
+
+/**
+ * Call this to find a tag that closely resembles the given tag.
+ * Note that we match based on the first char.
+ * @update gess12/23/98
+ * @param
+ * @return
+ */
+int findNearestTag(char* aTag){
+ int result=-1;
+ if(aTag){
+ char theChar=toupper(aTag[0]);
+ int theIndex=-1;
+ while(tagTable[++theIndex]){
+ if(toupper(tagTable[theIndex][0])==theChar) {
+ return theIndex;
+ }
+ }
+ }
+ if(toupper(aTag[0])<'A')
+ result=0;
+ else result=107;
+ return result;
+}
+
+char* getNthTagAfter(int aRangeIndex,char* aStartTag){
+ int theIndex=findTag(aStartTag);
+ if(-1==theIndex){
+ theIndex=findNearestTag(aStartTag);
+ }
+ if(-10){
+ if((strchr(aString,',')) || (strchr(aString,'-'))) {
+ mRanges[mCount]=new char[sLen+1];
+ strcpy(mRanges[mCount++],aString);
+ }
+ else {
+ mKeys[mCount]=new char[sLen+1];
+ strcpy(mKeys[mCount++],aString);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int getCount() {return mCount;}
+
+ char* getMacro(int anIndex) {
+ if(anIndex> theBuffer;
+ if(!stricmp(theBuffer,"-F")){
+ //copy the filename...
+ aStream >> theBuffer;
+ strcpy(mFilename,theBuffer);
+ readDefs=false;
+ }
+ else if(!stricmp(theBuffer,"-D")){
+ readDefs=true;
+ }
+ else if(!stricmp(theBuffer,"-O")){
+ aStream >> theBuffer;
+ readDefs=false;
+ }
+ else if(readDefs){
+ if(theBuffer[0]){
+ addMacro(theBuffer);
+ theBuffer[0]=0;
+ }
+ }
+ }
+ return true;
+ }
+
+ void buildArgBuffer(char* aBuffer) {
+ aBuffer[0]=0;
+ if(mFilename[0]) {
+ sprintf(aBuffer,"-0 %s -f %s -d ",gThisFile,mFilename);
+ }
+ for(int i=0;i>theWord;
+ char* thePos=strchr(theWord,'@');
+ if(thePos){
+ strncat(temp,theWord,thePos-theWord);
+ if(!strnicmp(thePos,"@file",5)){
+ strcat(temp,gThisFile);
+ thePos+=5;
+ }
+ else if(!strnicmp(thePos,"@nextfile",9)){
+ strcat(temp,gNextFile);
+ thePos+=9;
+ }
+ else if(!strnicmp(thePos,"@prevfile",9)){
+ strcat(temp,gPrevFile);
+ thePos+=9;
+ }
+ strcat(temp,thePos);
+ }
+ else strcat(temp,theWord);
+ strcat(temp," ");
+ }
+ strcpy(aBuffer,temp);
+ }
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+void expandMacros(char* aBuffer,CMacros& aMacroSet){
+ char temp[1024];
+ int rPos=-1;
+ int wPos=0;
+
+ if(aBuffer){
+ while(aBuffer[++rPos]){
+ if('$'==aBuffer[rPos]){
+ temp[wPos]=0;
+ rPos++; //skip the $...
+ int theIndex=aBuffer[rPos]-'0';
+ char* theMacro=aMacroSet.getMacro(theIndex);
+ if(theMacro){
+ strcat(temp,theMacro);
+ wPos=strlen(temp);
+ }
+ }
+ else temp[wPos++]=aBuffer[rPos];
+ }
+ temp[wPos]=0;
+ strcpy(aBuffer,temp);
+ }
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+int processFile(char* aDir,fstream& anOutputStream,istrstream& aInputArgs){
+ int result=0;
+
+ CMacros theMacros;
+ theMacros.consume(aInputArgs);
+
+ char* theFilename=theMacros.getFilename();
+ fstream theInputStream(theFilename,ios::in);
+ if(theInputStream.is_open()){
+ bool done=false;
+ char theBuffer[1024];
+ char theWord[600];
+
+ while((!done) && (0==result)){
+
+ theInputStream.getline(theBuffer,sizeof(theBuffer)-1);
+ if(theInputStream.gcount()){
+
+ //before doing anything else, expand the macros and keywords...
+ expandMacros(theBuffer,theMacros);
+ expandKeywords(theBuffer,theMacros);
+
+ //Now process each line:
+ if(strchr(theBuffer,'@')) {
+
+ //First, see if the line is an htmlgen statement; if so, recurse to read new file...
+ istrstream iStr(theBuffer);
+ iStr>>theWord;
+ if(!stricmp(theWord,"@htmlgen")){
+
+ //If you're here, we found an htmlgen statement.
+ // To handle this, we have to:
+ // 1. strip off the @htmlgen
+ // 2. grab the filename and collect the args,
+ // 3. and recurse...
+
+ result=processFile(aDir,anOutputStream,iStr);
+ }
+ }
+ else anOutputStream << theBuffer << endl;
+ }
+ else done=true;
+ }
+ }
+ return result;
+}
+
+
+/**
+ * This is where the different combinations of arguments
+ * gets constructed and passed on for processing.
+ * Note that this is even called when the args have only 1 value.
+ * @return error code
+ */
+int iterate(istrstream& aInputArgs){
+ int result=0;
+
+ CMacros theArgs;
+ theArgs.consume(aInputArgs);
+
+ char theBuffer[1024];
+ char theFilename[1024];
+
+ bool done=!theArgs.first();
+ while((!done) && (0==result)){
+ CMacros theTempArgs(theArgs);
+ theTempArgs.buildArgBuffer(theBuffer);
+ istrstream theArgStream(theBuffer);
+ sprintf(theFilename,"%s\\%s",gCWD,gThisFile);
+ fstream theOutStream(theFilename,ios::trunc);
+ result=processFile(gCWD,theOutStream,theArgStream);
+ theArgs.dump();
+ done=!theArgs.next();
+ }
+ return result;
+}
+
+/**
+ *
+ * @update gess12/20/98
+ * @param
+ * @return
+ */
+int main(int argc,char* argv[]){
+ int result=0;
+
+ gPrevFile[0]=gThisFile[0]=gNextFile[0];
+ if(argc>1){
+ char theBuffer[1024];
+ theBuffer[0]=0;
+
+ for(int i=1;i