home *** CD-ROM | disk | FTP | other *** search
Wrap
/*************************************************************** ** ** ** GuideML -- Converts AmigaGuide into HTML ** ** ** ***************************************************************/ /* ** Copyright (C) 1997-98 Richard Körber -- All Rights Reserved ** E-Mail: shred@eratosthenes.starfleet.de ** URL: http://shredzone.home.pages.de ** ***************************************************************/ /* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** The author (Richard Körber) reserves the right to revoke the ** GNU General Public License whenever he feels that it is necessary, ** especially when he found out that the licence has been abused, ** ignored or violated, and without prior notice. ** ** You must not use this source code to gain profit of any kind! ** ***************************************************************/ /* ** If you use an editor that is capable of text folding, use ** "//>" and "//<" as begin and end fold markers, respectively. */ #include <stdio.h> #include <string.h> #include <clib/alib_protos.h> #include <clib/exec_protos.h> #include <clib/dos_protos.h> #include <pragmas/exec_pragmas.h> #include <pragmas/dos_pragmas.h> #include <exec/lists.h> #include <exec/nodes.h> #include <exec/memory.h> #include <dos/dos.h> #include <libraries/dos.h> #define VERSIONSTR "V1.6" /* Version Nr */ #define VERSIONDATE "26.04.98" /* Version Date */ #define LINELEN (1024) /* Maximum length of a line */ extern struct Library *DOSBase; char VerStr[] = "\0$VER: GuideML "VERSIONSTR" ("VERSIONDATE")"; struct Parameter /* Structure of Shell parameters */ { STRPTR from; STRPTR to; STRPTR homeurl; STRPTR prev; STRPTR next; STRPTR index; STRPTR toc; STRPTR home; STRPTR bar; STRPTR bodyext; LONG verbatim; LONG images; LONG footer; LONG nolink; LONG noemail; LONG nowarn; LONG msdos; }param = {NULL}; struct Entry /* List of all nodes and links */ { struct MinNode link; ULONG Count; char Node[100]; char Prev[100]; char Next[100]; char TOC[100]; }; struct MinList entries; struct LinkStr /* Link bar alternative texts */ { char Prev[100]; char Next[100]; char Index[100]; char Toc[100]; char Home[100]; }; char Index[100]; /* Index page name */ //> UBYTE Img#?[] = {...}; /* ** This are the navigation bar images, in GIF format */ UBYTE ImgHome[] = { 0x47,0x49,0x46,0x38,0x39,0x61,0x19,0x00,0x1B,0x00,0x82,0x00,0x00,0x9E,0x9E,0x9E, 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x50,0x70,0xA0,0x90,0x90,0x90,0xB0,0xB0,0xB0,0xB0, 0xA0,0x90,0xF0,0xB0,0xA0,0x21,0xF9,0x04,0x01,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, 0x00,0x00,0x19,0x00,0x1B,0x00,0x00,0x03,0xA5,0x18,0xBA,0xDC,0xBE,0x20,0x88,0x49, 0xAB,0xBD,0x25,0x44,0x51,0xBA,0xFF,0x20,0x48,0x68,0x52,0xD8,0x8D,0x84,0x79,0x92, 0x9C,0xB7,0x8C,0x0A,0x91,0x86,0xE3,0xF6,0x05,0xC3,0x22,0xC4,0xF3,0x57,0x97,0xAE, 0x9C,0x64,0xC2,0x13,0xB1,0x6E,0x0A,0x4B,0xD1,0xF3,0x6B,0x15,0x60,0x97,0x5D,0x40, 0xC6,0x3C,0x3E,0x93,0x51,0x29,0xF5,0x6A,0xCB,0x48,0x18,0xD2,0x64,0xB1,0xE9,0xDA, 0x19,0x0C,0xDF,0xC3,0xE1,0x2B,0x4B,0x91,0x3B,0xDF,0x73,0x7A,0xBD,0xEB,0xBD,0x33, 0x66,0x74,0x98,0x5D,0xED,0xE2,0x03,0x72,0x17,0x53,0x7D,0x40,0x5E,0x0F,0x0C,0x76, 0x56,0x27,0x6D,0x8C,0x8D,0x84,0x4E,0x2A,0x91,0x3F,0x4F,0x8D,0x95,0x96,0x32,0x24, 0x87,0x9A,0x0E,0x00,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0x1A,0x11,0x9D,0x0A,0xA6,0x9E, 0x99,0xA7,0x9F,0xA4,0x24,0xA8,0xA7,0xB0,0xA2,0x11,0x10,0xAD,0xA5,0xAE,0x10,0xA0, 0xB5,0xBA,0xA9,0xA5,0xA3,0xA8,0xB3,0xBF,0xB6,0xB8,0xB2,0xC4,0xC4,0x09,0x00,0x3B }; #define LEN_IMGHOME (0xE0) UBYTE ImgIndex[] = { 0x47,0x49,0x46,0x38,0x39,0x61,0x19,0x00,0x1B,0x00,0x82,0x00,0x00,0x9E,0x9E,0x9E, 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x50,0x70,0xA0,0x90,0x90,0x90,0xB0,0xB0,0xB0,0xB0, 0xA0,0x90,0xF0,0xB0,0xA0,0x21,0xF9,0x04,0x01,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, 0x00,0x00,0x19,0x00,0x1B,0x00,0x00,0x03,0xA7,0x18,0xBA,0xDC,0xBE,0x20,0x88,0x49, 0xAB,0xBD,0x25,0x44,0x51,0xBA,0xFF,0x20,0x48,0x68,0x52,0xD8,0x05,0xE6,0x37,0x6E, 0x67,0x73,0x38,0x22,0xC9,0x65,0x03,0x31,0x04,0x47,0x1E,0xD4,0x37,0xA1,0xCA,0x27, 0x1B,0x2E,0xA7,0xAB,0x05,0x7C,0x9E,0x55,0x89,0x36,0x72,0x08,0x91,0x1D,0xE5,0xEC, 0xC8,0xB3,0x59,0x8D,0xD0,0x82,0xF4,0x54,0xE5,0x3D,0x50,0x5A,0x60,0xE6,0x6A,0x95, 0x58,0x8E,0x61,0x16,0xB3,0x2B,0x19,0x8D,0x04,0xE8,0xED,0xB8,0xFB,0x3E,0xFB,0xE4, 0x3B,0xF2,0x0D,0xEE,0xE6,0xA7,0x97,0x5F,0x66,0x15,0x71,0x62,0x5A,0x04,0x87,0x88, 0x5F,0x77,0x85,0x29,0x88,0x8E,0x8B,0x6A,0x29,0x92,0x7F,0x86,0x8F,0x96,0x97,0x4A, 0x81,0x9A,0x0C,0x00,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0x24,0x9D,0x24,0x1A,0x11,0x10, 0xA7,0xA7,0x9E,0xA6,0x11,0xAE,0xA4,0x9F,0xB0,0xAC,0xAF,0xA4,0xA6,0xAB,0x0A,0xA1, 0xB0,0xB5,0xAE,0xB3,0xAB,0xBD,0xA5,0xA8,0xA5,0xA9,0xC0,0xA2,0xC5,0xC6,0x9E,0x09, 0x00,0x3B }; #define LEN_IMGINDEX (0xE2) UBYTE ImgNext[] = { 0x47,0x49,0x46,0x38,0x39,0x61,0x19,0x00,0x1B,0x00,0x82,0x00,0x00,0x9E,0x9E,0x9E, 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x50,0x70,0xA0,0x90,0x90,0x90,0xB0,0xB0,0xB0,0xB0, 0xA0,0x90,0xF0,0xB0,0xA0,0x21,0xF9,0x04,0x01,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, 0x00,0x00,0x19,0x00,0x1B,0x00,0x00,0x03,0x94,0x18,0xBA,0xDC,0xBE,0x20,0x88,0x49, 0xAB,0xBD,0x25,0x44,0x51,0xBA,0xFF,0x20,0x48,0x68,0x52,0x68,0x9A,0xE3,0x76,0x7A, 0x01,0x81,0x92,0xDC,0x9A,0xB5,0x61,0x5A,0xCA,0x12,0xFD,0xD9,0x71,0xF7,0x04,0x07, 0x81,0xAE,0xC3,0xFB,0x48,0x2E,0x87,0xE0,0xB0,0xC8,0x12,0x24,0x9F,0x50,0xA1,0xAB, 0xC0,0xF4,0x19,0xAE,0xD8,0xEB,0xC1,0xD0,0x9A,0x56,0x67,0x8E,0x6B,0xD7,0xF3,0xA5, 0x12,0xCE,0xE7,0x00,0xF7,0xBC,0x83,0xC9,0x66,0xEC,0xB6,0x0A,0x17,0x97,0xDF,0x64, 0x53,0x91,0xFB,0x7D,0x2A,0xF3,0xC9,0x24,0x66,0x68,0x83,0x84,0x85,0x36,0x3F,0x88, 0x0E,0x00,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x1A,0x11,0x11,0x10,0x92,0x24,0x0C,0x8E, 0x0A,0x93,0x92,0x8C,0x24,0x9D,0x91,0x94,0x94,0x9C,0x9A,0x9F,0x8F,0x96,0x93,0x9F, 0x9C,0xA8,0x99,0x8B,0x97,0x9A,0xA7,0xAD,0x90,0xB2,0xB3,0x8F,0x09,0x00,0x3B }; #define LEN_IMGNEXT (0xCE) UBYTE ImgPrev[] = { 0x47,0x49,0x46,0x38,0x39,0x61,0x19,0x00,0x1B,0x00,0x82,0x00,0x00,0x9E,0x9E,0x9E, 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x50,0x70,0xA0,0x90,0x90,0x90,0xB0,0xB0,0xB0,0xB0, 0xA0,0x90,0xF0,0xB0,0xA0,0x21,0xF9,0x04,0x01,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, 0x00,0x00,0x19,0x00,0x1B,0x00,0x00,0x03,0x94,0x18,0xBA,0xDC,0xBE,0x20,0x88,0x49, 0xAB,0xBD,0x25,0x44,0x51,0xBA,0xFF,0x20,0x48,0x68,0x52,0x68,0x9A,0xE3,0x86,0x06, 0xA7,0x97,0x96,0xA2,0x42,0xB4,0xC5,0xCB,0x7D,0xA3,0x10,0xCC,0xAD,0x8D,0x4B,0x87, 0x07,0xCB,0x45,0xBA,0xD5,0x80,0x87,0x8B,0x61,0x47,0x54,0x1D,0x05,0x87,0xA8,0x54, 0xBA,0xE4,0x1D,0x9D,0x47,0xC3,0xC1,0xC0,0xED,0x72,0x99,0x1D,0x1F,0xF1,0xFB,0xB0, 0x8A,0xC7,0x3B,0x82,0x7A,0x6D,0x2E,0x86,0x46,0xE0,0xD3,0xF9,0x67,0x5D,0x61,0xDF, 0xB4,0x39,0xED,0xED,0xDE,0xCB,0x49,0x35,0x6C,0x82,0x83,0x82,0x24,0x42,0x87,0x0E, 0x00,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x10,0x11,0x0A,0x8A,0x0C,0x11,0x8B,0x1A,0x8C, 0x98,0x24,0x94,0x96,0x97,0x9E,0x99,0x93,0x92,0x9A,0xA1,0x98,0x9D,0x9F,0x9C,0x96, 0xA5,0x9C,0xAA,0xA8,0xA8,0x86,0xA1,0xA6,0x8F,0xB2,0xB3,0x8B,0x09,0x00,0x3B }; #define LEN_IMGPREV (0xCE) UBYTE ImgTOC[] = { 0x47,0x49,0x46,0x38,0x39,0x61,0x19,0x00,0x1B,0x00,0x82,0x00,0x00,0x9E,0x9E,0x9E, 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x50,0x70,0xA0,0x90,0x90,0x90,0xB0,0xB0,0xB0,0xB0, 0xA0,0x90,0xF0,0xB0,0xA0,0x21,0xF9,0x04,0x01,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, 0x00,0x00,0x19,0x00,0x1B,0x00,0x00,0x03,0x93,0x18,0xBA,0xDC,0xBE,0x20,0x88,0x49, 0xAB,0xBD,0x25,0x44,0x51,0xBA,0xFF,0x20,0x48,0x68,0x52,0xE8,0x11,0xE6,0x49,0x72, 0xE6,0x88,0xA6,0xE3,0xD6,0x4A,0x01,0xF1,0x8A,0x6B,0x38,0x0A,0x87,0x51,0xDF,0x2A, 0xD9,0x67,0x77,0x28,0xFA,0x6C,0x38,0x61,0x87,0x68,0x34,0x1C,0x81,0xB1,0x92,0x87, 0xC1,0xF3,0x2D,0x90,0xCB,0x5C,0x48,0xD2,0xFB,0xD9,0x6E,0x51,0x16,0x88,0x7B,0x9C, 0x29,0x3F,0xE4,0x9A,0x59,0x3A,0xAE,0xAA,0x75,0xDA,0x76,0x17,0x18,0x64,0xA3,0x19, 0xF4,0xEC,0x79,0xF8,0xCD,0x17,0xC2,0x29,0x81,0x75,0x7F,0x7D,0x85,0x86,0x85,0x24, 0x0F,0x8A,0x8A,0x00,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x11,0x1A,0x8D,0x0A,0x96,0x98, 0x0D,0x90,0x95,0x24,0x99,0x9D,0x98,0x91,0x95,0xA0,0x9D,0x97,0xA0,0x9B,0x8F,0x9C, 0x11,0xA6,0xA2,0x9B,0xA5,0xAE,0xAB,0x93,0xB1,0xB2,0x8E,0x09,0x00,0x3B }; #define LEN_IMGTOC (0xCD) //< //> STRPTR entity[96] = {...}; /* ** This are the full names of all HTML entities */ STRPTR entity[96] = { "nbsp","iexcl","cent","pound","curren","yen","brvbar","sect","uml", "copy","ordf","laquo","not","shy","reg","macr","deg","plusmn","sup2", "sup3","acute","micro","para","middot","cedil","sup1","ordm","raquo", "frac14","frac12","frac34","iquest","Agrave","Aacute","Acirc","Atilde", "Auml","Aring","AElig","Ccedil","Egrave","Eacute","Ecirc","Euml","Igrave", "Iacute","Icirc","Iuml","ETH","Ntilde","Ograve","Oacute","Ocirc","Otilde", "Ouml","times","Oslash","Ugrave","Uacute","Ucirc","Uuml","Yacute","THORN", "szlig","agrave","aacute","acirc","atilde","auml","aring","aelig","ccedil", "egrave","eacute","ecirc","euml","igrave","iacute","acirc","iuml","eth", "ntilde","ograve","oacute","ocirc","otilde","ouml","divide","oslash", "ugrave","uacute","ucirc","uuml","yacute","thorn","yuml" }; //< //> STRPTR agpens[] , htmlpens[] /* ** This are the pen names in AmigaGuide documents */ STRPTR agpens[] = { "text}","shine}","shadow}","fill}","filltext}","background}","highlight}", NULL }; /* ** And this are the appropriate HTML colors */ STRPTR htmlpens[] = { "#000000","#ffffff","#000000","#3864a0","#000000","#949494","#ffffff" }; //< //> SaveImg() /*------------------------------------------------------------* * SaveImg() Saves one image * * -> file File Name * * -> data Data buffer * * -> len Length * * <- Success * */ LONG SaveImg(STRPTR file, UBYTE *data, ULONG len) { BPTR lock; if(lock = Lock(file,ACCESS_READ)) // Already existing? { UnLock(lock); return(1); // then leave with success } if(param.verbatim) Printf("Creating image '%s'\n",file); // Report if(lock = Open(file,MODE_NEWFILE)) // Open the image file { if(-1 == Write(lock,data,len)) // Write the image { Close(lock); // Write failed, so return(0); // return without success } Close(lock); // Write succeeded, so return(1); // return with success } return(0); // No lock, no success } //< //> SaveImages() /*------------------------------------------------------------* * SaveImages() Saves all required images * * <- Success * */ LONG SaveImages(void) { for(;;) { if(param.homeurl) if(!SaveImg("home.gif" ,ImgHome ,LEN_IMGHOME )) break; if(*Index) if(!SaveImg("index.gif",ImgIndex,LEN_IMGINDEX)) break; if(!SaveImg("next.gif" ,ImgNext ,LEN_IMGNEXT )) break; if(!SaveImg("prev.gif" ,ImgPrev ,LEN_IMGPREV )) break; if(!SaveImg("toc.gif" ,ImgTOC ,LEN_IMGTOC )) break; return(1); } return(0); } //< //> CopyLink() /*------------------------------------------------------------* * CopyLink() Copies a link file name into a variable * * -> link Link * * -> var String-Var * */ void CopyLink(STRPTR link, STRPTR var) { char ch; var[0] = '\0'; // Init while(*link && *link==' ') link++; // Suppress spaces if(!*link) return; // there were only spaces! if(*link != '\"') { // Quick Mode while((ch = *link++)!=' ' && ch!='\n') { if(ch==':') ch='_'; if(ch>='A' && ch<='Z') ch+=32; *var++ = ch; } } else { // Quote Mode link++; // we had a leading quote if(!*link) return; while((ch = *link++)!='\"' && ch!='\n') { if(ch==' ' || ch==':') ch = '_'; if(ch>='A' && ch<='Z') ch+=32; *var++ = ch; } } *var++ = '.'; // Add html suffix *var++ = 'h'; *var++ = 't'; *var++ = 'm'; if(!param.msdos) *var++ = 'l'; *var = '\0'; } //< //> MyPutCh() /*------------------------------------------------------------* * MyPutCh() Writes single chars into HTML * * -> fh output file handle * * -> ch Amiga char to be written * * <- -1 for failure * */ LONG MyPutCh(BPTR fh, unsigned char ch) { if(ch<' ' && ch!='\n') // Is it a control char? { return FPrintf(fh,"%03ld;",ch); // yes: return them as number } else if(ch < 128) // Is it an ASCII char? { if(ch=='\"') return FPuts(fh,"""); // Convert some exceptions else if(ch=='&') return FPuts(fh,"&"); else if(ch=='<') return FPuts(fh,"<"); else if(ch=='>') return FPuts(fh,">"); else return FPutC(fh,ch); // else put char directly } else // Chars >127 ? { if(ch>=160) // Do we have an entity name? return FPrintf(fh,"&%s;",entity[ch-160]); // yes: use this one else return FPrintf(fh,"%03ld;",ch); // no: use it's number } } //< //> MyPuts() /*------------------------------------------------------------* * MyPuts() Writes a string into HTML * * -> fh Output file handle * * -> str String to be output * * <- -1 for failure * */ LONG MyPuts(BPTR fh, STRPTR str) { unsigned char ch; while(ch = *str++) // go through the string { if(ch=='\"' || ch=='<' || ch=='>') // do NOT convert them { // since they are also used if(-1 == FPutC(fh,ch)) return(-1); // in HTML tags } else { if(-1 == MyPutCh(fh,ch)) return(-1); } } return(0); } //< //> ConvLine() /*------------------------------------------------------------* * ConvLine() Converts an AmigaGuide line * * -> fh output file handle * * -> buf Source buffer * * -> linenr line number * * <- Success * */ LONG ConvLine(BPTR fh, STRPTR buf, ULONG linenr) { unsigned char ch; char linkstr[100]; register UWORD dolink = !param.nolink; register UWORD doemail = !param.noemail; while(ch = *buf++) // while chars available { if('\\'==ch) // backslash escape character? { switch(*buf) { case '\\': // '\\' -> '\' case '@': // '\@' -> '@' if(-1 == MyPutCh(fh,*buf)) return(0); buf++; break; } continue; } if(doemail) // email recognition activated? { if( (ch>='a' && ch<='z') // Could this be a valid email? ||(ch>='A' && ch<='Z') ||(ch>='0' && ch<='9')) { UWORD length = 0; // length of the email string UWORD atfound = 0; // how many '@' were found? UWORD charcnt = 0; // how many characters in total? UWORD dotfound = 0; // how many dots? UWORD atdot = 0; // how many dots after the '@'? UWORD chardot = 0; // how many chars after the last dot? STRPTR index = --buf; UWORD i; unsigned char ech; while(ech = *index++) { if( !(ech>='a' && ech<='z') // still a valid email char? && !(ech>='A' && ech<='Z') && !(ech>='0' && ech<='9') && !(ech=='@' || ech=='.' || ech=='_' || ech=='-')) break; length++; if(ech=='@') // count '@' { if(*index=='{') // is it an AmigaGuide attribute? { length--; // exclude the '@' break; // the address is finished } atfound++; atdot = 0; continue; } if(ech=='.') // count '.' { dotfound++; atdot++; chardot = 0; continue; } charcnt++; // one more char chardot++; } if( atfound==1 // exactly one '@' && dotfound>0 // at least one '.' (domain.country) && atdot>0 // this dot must be after the '@' && chardot>=2 && chardot<=3 // domain must have two or three chars && charcnt>6) // and we have also some chars { if(-1 == FPuts(fh,"<a href=\"mailto:")) return(0); // Generate email link for(i=0;i<length;i++) { if(-1 == FPutC(fh,buf[i])) return(0); } if(-1 == FPuts(fh,"\">")) return(0); for(;length;length--) { if(-1 == FPutC(fh,*buf++)) return(0); } if(-1 == FPuts(fh,"</a>")) return(0); continue; } buf++; } } if(dolink) // internet link recognition { if( (!strnicmp(buf-1,"ftp://" ,6)) // ftp://... - Link ? ||(!strnicmp(buf-1,"gopher:" ,7)) // gopher:... - Link ? ||(!strnicmp(buf-1,"http://" ,7)) // http://... - Link ? ||(!strnicmp(buf-1,"https://",8)) // https://... - Link ? ||(!strnicmp(buf-1,"mailto:" ,7)) // mailto:... - Link ? ||(!strnicmp(buf-1,"news:" ,5)) // news:... - Link ? ||(!strnicmp(buf-1,"nntp:" ,5)) // nntp:... - Link ? ||(!strnicmp(buf-1,"telnet:" ,7)) // telnet:... - Link ? ||(!strnicmp(buf-1,"www." ,4))) // www. - Link? { STRPTR bufstart; if(-1 == FPuts(fh,"<a href=\"")) return(0); if(!strnicmp(buf-1,"www.",4)) if(-1 == FPuts(fh,"http://")) return(0); bufstart = --buf; while(ch = *buf++) { if(' '==ch || '\n'==ch || ')'==ch || ('@'==ch && '{'==*buf)) break; if(-1 == FPutC(fh,ch)) return(0); } if(-1 == FPuts(fh,"\">")) return(0); for(;bufstart<buf-1;bufstart++) // followed by a verbatim copy { if(-1 == FPutC(fh,*bufstart)) return(0); } if(-1 == FPuts(fh,"</a>")) return(0); } } if('@'==ch && '{'==*buf) // AmigaGuide command? { buf++; // read the command? for(;;) { if('\"' == *buf) // is it a link? { STRPTR link; UWORD linkpos=0; BOOL linkquot=0; buf++; // skip the quotation marks link = buf; while(*link && *link!='\"') link++; if(!*link) return(0); link++; while(*link && (*link==' ' || *link==',' || *link=='\t')) link++; if(!*link) return(0); if(strnicmp(link,"link",4)) { // this is NO link command! if(-1 == FPuts(fh,"<u>")) return(0); while((ch = *buf++) != '\"') if(-1 == MyPutCh(fh,ch)) return(0); if(-1 == FPuts(fh,"</u>")) return(0); buf = link; while(*buf && *buf!=' ') buf++; *buf++ = '\0'; if(!param.nowarn) Printf("Line %ld: WARNING: '%s' command skipped!\n",linenr,link); while(*buf && *buf!='}') buf++; if(*buf =='}') buf++; break; } link+=4; while(*link && *link==' ') link++; if(!*link) return(0); if(*link == '\"') { link++; linkquot=1; } while(*link && *link!='}') { ch = *link++; if(ch=='\"' && linkquot) break; if(ch>='A' && ch<='Z') ch+=32; linkstr[linkpos++] = (ch==' ' || ch==':' ? '_' : ch); } while(*link && *link!='}') link++; while(linkpos>0 && linkstr[linkpos-1] == '_') linkpos--; if(linkstr[linkpos-1] == '\"') linkpos--; linkstr[linkpos] = '\0'; if(!*link) return(0); link++; if(-1 == FPuts(fh,"<a href=\"")) return(0); if(-1 == FPuts(fh,linkstr)) return(0); if(param.msdos) { if(-1 == FPuts(fh,".htm\">")) return(0); } else { if(-1 == FPuts(fh,".html\">")) return(0); } while((ch = *buf++) != '\"') if(-1 == MyPutCh(fh,ch)) return(0); if(-1 == FPuts(fh,"</a>")) return(0); buf = link; break; } if(!strnicmp(buf,"b}",2)) // @{B} { if(-1 == FPuts(fh,"<b>")) return(0); buf += 2; break; } if(!strnicmp(buf,"ub}",3)) // @{UB} { if(-1 == FPuts(fh,"</b>")) return(0); buf += 3; break; } if(!strnicmp(buf,"i}",2)) // @{I} { if(-1 == FPuts(fh,"<i>")) return(0); buf += 2; break; } if(!strnicmp(buf,"ui}",3)) // @{UI} { if(-1 == FPuts(fh,"</i>")) return(0); buf += 3; break; } if(!strnicmp(buf,"u}",2)) // @{U} { if(-1 == FPuts(fh,"<u>")) return(0); buf += 2; break; } if(!strnicmp(buf,"uu}",3)) // @{UU} { if(-1 == FPuts(fh,"</u>")) return(0); buf += 3; break; } if(!strnicmp(buf,"fg ",3)) // @{FG ...} { UWORD i=0; buf += 3; while(*buf == ' ') buf++; while(agpens[i]) { if(!strnicmp(buf,agpens[i],strlen(agpens[i]))) { if(-1 == FPrintf(fh,"<font color=\"%s\">",htmlpens[i])) return(0); buf += strlen(agpens[i]); break; } i++; } if(agpens[i]) break; } while(*buf && *buf!='}') buf++; // Skip an unknown command! buf++; break; } } else if(-1 == MyPutCh(fh,ch)) return(0); // Error! } return(1); } //< //> NavBar() /*------------------------------------------------------------* * NavBar() Produces the navigation bar * * -> tfh output file handle * * -> enode node with link data * * <- Success * */ LONG NavBar(BPTR tfh, struct Entry *enode) { short before = 0; for(;;) { if(enode->Count) // main page does not have a TOC link { if(param.msdos) { if(-1 == FPrintf(tfh,"<a href=\"%s\">",(*enode->TOC ? enode->TOC : "main.htm"))) break; } else { if(-1 == FPrintf(tfh,"<a href=\"%s\">",(*enode->TOC ? enode->TOC : "main.html"))) break; } if(-1 == MyPuts(tfh,param.toc)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } if(*Index) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",Index)) break; if(-1 == MyPuts(tfh,param.index)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } if(*enode->Prev) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",enode->Prev)) break; if(-1 == MyPuts(tfh,param.prev)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } else { struct Entry *pred = (struct Entry *)enode->link.mln_Pred; if(pred->link.mln_Pred) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",pred->Node)) break; if(-1 == MyPuts(tfh,param.prev)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } } if(*enode->Next) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",enode->Next)) break; if(-1 == MyPuts(tfh,param.next)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } else { struct Entry *next = (struct Entry *)enode->link.mln_Succ; if(next->link.mln_Succ) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",next->Node)) break; if(-1 == MyPuts(tfh,param.next)) break; if(-1 == FPuts(tfh,"</a>")) break; before = 1; } } if(param.homeurl) { if(before) if(-1 == MyPuts(tfh,param.bar)) break; if(-1 == FPrintf(tfh,"<a href=\"%s\">",param.homeurl)) break; if(-1 == MyPuts(tfh,param.home)) break; if(-1 == FPuts(tfh,"</a>")) break; } if(-1 == FPutC(tfh,'\n')) break; return(1); // ALL OK } return(0); // ERROR } //< //> Convert() /*------------------------------------------------------------* * Convert() Reads guide and creates HTML files * * -> fh input file handle * * <- Success * */ LONG Convert(BPTR fh) { STRPTR buffer = AllocVec(LINELEN,MEMF_ANY); // allocate line buffer STRPTR node, title, line; char nodename[100]; BPTR tfh = NULL; ULONG linenr = 0; short firstpage = 1; struct Entry *enode = (struct Entry *)entries.mlh_Head; if(!buffer) return(0); PutStr("Converting into HTML\n"); /* search for @node */ do { linenr++; if(FGets(fh,buffer,LINELEN) == NULL) goto Done; } while(strnicmp(buffer,"@node ",strlen("@node "))); /* and go... */ for(;;) { if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) goto ErrorBrk; /* search the node name */ node = buffer+strlen("@node "); while(*node == ' ') node++; // skip leading spaces if(*node == '\"') { // Quote Mode node++; line = node; while(*line!='\"' && *line!='\n') { if(*line==' ' || *line==':') *line='_'; // space -> '_' line++; } *line++ = '\0'; } else { line = node; while(*line!=' ' && *line!='\n') { if(*line==':') *line='_'; // ':' -> '_' line++; } *line++ = '\0'; } /* search node title */ if(*line == '\0') title = line; // Node does not have a title else { while(*line == ' ') line++; // Skip spaces if(*line == '\"') line++; // Skip quotation mark title = line; while(*line != '\n') line++; // search EOL do line--; while(*line==' '); // skip trailing spaces if(*line == '\"') line--; // skip trailing quotation mark *++line = '\0'; // terminate the line } strlwr(node); // node name to lowercase strcpy(nodename,node); if(param.msdos) { strcat(nodename,".htm"); } else { strcat(nodename,".html"); } if(tfh = Open(nodename,MODE_NEWFILE)) { if(param.verbatim) Printf("Creating page '%s' (Title: '%s')\n",nodename,title); if(-1 == FPuts(tfh,"<html>\n<head>\n <title>")) goto ErrorFile; if(-1 == MyPuts(tfh,title)) goto ErrorFile; if(-1 == FPuts(tfh,"</title>\n" " <meta name=\"Generator\" content=\"GuideML " VERSIONSTR "\">\n" " <meta http-equiv=\"Content-Type\" content=\"text/html\">\n" "</head>\n<body")) goto ErrorFile; if(param.bodyext) { if(-1 == FPutC(tfh,' ')) goto ErrorFile; if(-1 == MyPuts(tfh,param.bodyext)) goto ErrorFile; } if(-1 == FPuts(tfh,">\n")) goto ErrorFile; if(!NavBar(tfh,enode)) goto ErrorFile; if(-1 == FPuts(tfh,"<hr>\n<pre>\n")) goto ErrorFile; for(;;) { linenr++; if(FGets(fh,buffer,LINELEN) == NULL) goto ErrorEOF; if(buffer[0]=='@' && buffer[1]!='{') // is it an AmigaGuide command { if(!strnicmp(buffer,"@node ",strlen("@node "))) break; if(!strnicmp(buffer,"@endnode",strlen("@endnode"))) break; continue; // unknown command } if(!ConvLine(tfh,buffer,linenr)) { Printf("Line %ld: Couldn't convert!\n",linenr); goto Error; } } if(-1 == FPuts(tfh,"</pre>\n")) goto ErrorFile; if(param.footer) { if(-1 == FPuts(tfh,"<hr>\n")) goto ErrorFile; if(!NavBar(tfh,enode)) goto ErrorFile; } if(firstpage) { firstpage = 0; if(-1 == FPuts(tfh,"<hr>\n<address>Converted using <tt>GuideML</tt> "VERSIONSTR", a converter written by Richard Körber <<a href=\"mailto:shred@chessy.aworld.de\">shred@chessy.aworld.de</a>></address>\n")) goto ErrorFile; } if(-1 == FPuts(tfh,"</body>\n</html>\n")) goto ErrorFile; enode = (struct Entry *)enode->link.mln_Succ; Close(tfh); tfh = NULL; } else { Printf("Line %ld: Couldn't open %s for writing!\n",linenr,nodename); goto Error; } while(strnicmp(buffer,"@node ",strlen("@node "))) { linenr++; if(FGets(fh,buffer,LINELEN) == NULL) goto Done; } } Done: FreeVec(buffer); return(1); ErrorBrk: Printf("Line %ld: <CTRL-C> pressed!\n",linenr); goto Error; ErrorFile: Printf("Line %ld: Error writing file!\n",linenr); goto Error; ErrorEOF: Printf("Line %ld: Unexpected EOF!\n",linenr); Error: if(tfh) Close(tfh); FreeVec(buffer); return(0); } //< //> PreScan() /*------------------------------------------------------------* * PreScan() Scans the AmigaGuide file * * -> fh input file handle * * <- Success * */ LONG PreScan(BPTR fh) { STRPTR buffer = AllocVec(LINELEN,MEMF_ANY); // allocate line buffer STRPTR parse; ULONG linenr = 0; ULONG nodectr = 0; struct Entry *currentry = NULL; if(!buffer) return(0); PutStr("Scanning AmigaGuide document\n"); /* Is it an AmigaGuide document ? */ linenr++; if(NULL == FGets(fh,buffer,LINELEN)) goto ErrorEOF; if(strnicmp(buffer,"@database",strlen("@database"))) { PutStr("This is no valid AmigaGuide file!\n"); goto Error; } /* Search for commands */ for(;;) { if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) goto ErrorBrk; linenr++; if(!FGets(fh,buffer,LINELEN)) break; // Scan all lines if(buffer[0]!='@') continue; // no command line if(buffer[1]=='{') continue; // a text command at first column? parse = buffer+1; if(!strnicmp(parse,"index ",strlen("index "))) // @index <index> { CopyLink(parse+strlen("index "), Index); } if(!strnicmp(parse,"node ",strlen("node "))) // @node <name> { if(currentry) AddTail((struct List *)&entries,(struct Node *)currentry); currentry = AllocVec(sizeof(struct Entry),MEMF_ANY|MEMF_CLEAR); if(!currentry) goto ErrorMem; currentry->Count = nodectr++; CopyLink(parse+strlen("node "), currentry->Node); } if(!strnicmp(parse,"prev ",strlen("prev "))) // @prev <name> { if(currentry) { CopyLink(parse+strlen("prev "), currentry->Prev); } } if(!strnicmp(parse,"next ",strlen("next "))) // @next <name> { if(currentry) { CopyLink(parse+strlen("next "), currentry->Next); } } if(!strnicmp(parse,"toc ",strlen("toc "))) // @toc <name> { if(currentry) { CopyLink(parse+strlen("toc "), currentry->TOC); } } if(!strnicmp(parse,"endnode",strlen("endnode"))) // @endnode { if(currentry) { AddTail((struct List *)&entries,(struct Node *)currentry); currentry = NULL; } } } if(currentry) { AddTail((struct List *)&entries,(struct Node *)currentry); if(!param.nowarn) Printf("Line %ld: WARNING: No closing @endnode found!\n",linenr); //* currentry = NULL; } FreeVec(buffer); return(1); ErrorMem: Printf("Line %ld: Not enough memory!\n",linenr); goto Error; ErrorBrk: Printf("Line %ld: <CTRL-C> pressed!\n",linenr); goto Error; ErrorEOF: Printf("Line %ld: Unexpected EOF!\n",linenr); Error: FreeVec(buffer); return(0); } //< //> main() /*------------------------------------------------------------* * main() M A I N P R O G R A M * */ int main(void) { struct RDArgs *args; static char template[] = "FILE/A,TO/K,URL=HOMEURL/K,PREV/K,NEXT/K,INDEX/K,TOC/K,HOME/K,BAR/K,BODY/K,VER=VERBATIM/S,IMG=IMAGES/S,FTR=FOOTER/S,NL=NOLINKS/S,NE=NOEMAIL/S,NW=NOWARN/S,MSDOS/S"; static unsigned char defbar[] = " | "; BPTR fh; BPTR oldlock = NULL; struct Entry *node, *next; struct LinkStr *lstr = NULL; NewList((struct List *)&entries); param.prev = "PREV"; param.next = "NEXT"; param.index = "INDEX"; param.toc = "CONTENTS"; param.home = "HOME"; param.bar = defbar; if(args = (struct RDArgs *)ReadArgs(template,(LONG *)¶m,NULL)) { PutStr("GuideML "VERSIONSTR"\n"); if(param.images) { lstr = AllocVec(sizeof(struct LinkStr),MEMF_ANY); if(!lstr) { PutStr("**ERROR: Out of memory.\n"); goto Flush; } sprintf(lstr->Prev ,"<img src=\"prev.gif\" alt=\"%s\" border=0>" ,param.prev ); sprintf(lstr->Next ,"<img src=\"next.gif\" alt=\"%s\" border=0>" ,param.next ); sprintf(lstr->Index,"<img src=\"index.gif\" alt=\"%s\" border=0>",param.index); sprintf(lstr->Toc ,"<img src=\"toc.gif\" alt=\"%s\" border=0>" ,param.toc ); sprintf(lstr->Home ,"<img src=\"home.gif\" alt=\"%s\" border=0>" ,param.home ); param.prev = lstr->Prev; param.next = lstr->Next; param.index = lstr->Index; param.toc = lstr->Toc; param.home = lstr->Home; if(param.bar == defbar) param.bar = ""; } if(fh = Open(param.from,MODE_OLDFILE)) { if(param.to) { BPTR destlock; destlock = Lock(param.to,ACCESS_READ); if(!destlock) { PutStr("**ERROR: Couldn't lock destination drawer.\n"); Close(fh); goto Flush; } oldlock = CurrentDir(destlock); } if(!PreScan(fh)) { PutStr("**ERROR: Scanning failed.\n"); Close(fh); goto Flush; } Seek(fh,0,OFFSET_BEGINNING); if(!Convert(fh)) { PutStr("**ERROR: Conversion failed.\n"); Close(fh); goto Flush; } Close(fh); } else Printf("**ERROR: couldn't open file %s!\n",param.from); if(param.images) { PutStr("Saveing images\n"); if(!SaveImages()) PutStr("**ERROR: couldn't save image files\n"); } Flush: for (node = (struct Entry *)entries.mlh_Head; next = (struct Entry *)node->link.mln_Succ; node = next) { Remove((struct Node *)node); FreeVec(node); } if(lstr) FreeVec(lstr); if(oldlock) UnLock(CurrentDir(oldlock)); FreeArgs(args); } else PutStr("GuideML "VERSIONSTR"\n" "© 1997-98 by Richard Körber <shred@eratosthenes.starfleet.de>\n" "Yet Another (tm) AmigaGuide to HTML Converter!\n\n" "USAGE:\tFILE/A\t\tAmigaGuide file to be converted\n" "\tTO/K\t\tDestination drawer for the html pages\n" "\tURL=HOMEURL/K\tURL accessed by the 'HOME' button\n" "\tPREV/K\t\t'PREV' button text/image\n" "\tNEXT/K\t\t'NEXT' button text/image\n" "\tINDEX/K\t\t'INDEX' button text/image\n" "\tTOC/K\t\t'CONTENTS' button text/image\n" "\tHOME/K\t\t'HOME' button text/image\n" "\tBAR/K\t\tBar text between navigation buttons\n" "\tBODY/K\t\tAddition to the body tag of every page\n" "\tVER=VERBATIM/S\tList of created files\n" "\tIMG=IMAGES/S\tCreate image navigation bar\n" "\tFTR=FOOTER/S\tNavigation bar also at end of page\n" "\tNL=NOLINKS/S\tIgnore internet links\n" "\tNE=NOEMAIL/S\tIgnore e-mail addresses\n" "\tNW=NOWARN/S\tDon't show warnings\n" "\tMSDOS/S\t\tCreate MS-DOS filenames (*.htm)\n" "\n"); return(0); } //< /**************************************************************/