#include "Smart.hpp"
#define FLAG_BOLD 0x0001
#define FLAG_ITALIC 0x0002
#define FLAG_UNDERLINE 0x0004
#define FLAG_STRIKED 0x0008
#define FLAG_PARAGRAPH 0x1000
static DWORD gMode;
static LPSTR gTargetSave;
static LPSTR gTargetData;
static LPSTR gSourceData;
static SIZE_T gSourceSize;
static LPCSTR* gHashTable;
static HANDLE gProcessHeap;
template <size_t size> inline void AppendString(LPCSTR ptr)
{
AppendString<4>(ptr);
AppendString<size - 4>(ptr + 4);
}
template <> inline void AppendString<1>(LPCSTR ptr)
{
*LPBYTE(gTargetSave) = *LPBYTE(ptr);
gTargetSave = gTargetSave + 1;
}
template <> inline void AppendString<2>(LPCSTR ptr)
{
*LPWORD(gTargetSave) = *LPWORD(ptr);
gTargetSave = gTargetSave + 2;
}
template <> inline void AppendString<3>(LPCSTR ptr)
{
AppendString<1>(ptr);
AppendString<2>(ptr + 1);
}
template <> inline void AppendString<4>(LPCSTR ptr)
{
*LPDWORD(gTargetSave) = *LPDWORD(ptr);
gTargetSave = gTargetSave + 4;
}
#define AppendString(text) AppendString<sizeof(text) - 1>(text);
static inline bool IsBlank(BYTE ch)
{
return (' ' == ch) || ('\t' == ch);
}
static inline bool IsBreak(BYTE ch)
{
return ('\r' == ch) || ('\n' == ch);
}
static inline bool IsWhite(BYTE ch)
{
return IsBlank(ch) || IsBreak(ch);
}
static inline void AppendSymbol(CHAR ch)
{
*gTargetSave++ = ch;
}
static inline void AppendBuffer(LPCSTR pHead, LPCSTR pTail)
{
#if 1
while((pHead < pTail) && (3 & BYTE(gTargetSave)))
*gTargetSave++ = *pHead++;
while((pHead + 4) < pTail)
{
*LPDWORD(gTargetSave) = *LPDWORD(pHead);
pHead = pHead + 4;
gTargetSave = gTargetSave + 4;
}
#endif
while(pHead < pTail)
*gTargetSave++ = *pHead++;
}
static void Write(HANDLE hTarget, DWORD dwPage)
{
DWORD count;
LPSTR pArray = gTargetData;
SIZE_T uCount = gTargetSave - gTargetData;
while((0 != uCount) && WriteFile(hTarget, pArray, uCount < dwPage ? uCount : dwPage, &count, NULL))
{
pArray = pArray + count;
uCount = uCount - count;
}
gTargetSave = gTargetData;
}
static inline LPCSTR Last(LPCSTR pHead)
{
while((0 != *pHead) && !IsBreak(*pHead)) pHead++;
return pHead;
}
static LPCSTR Next(LPCSTR pHead)
{
CHAR last = *pHead++;
if (IsBreak(*pHead) && (last != *pHead))
pHead++;
return pHead;
}
static inline LPCSTR Skip(LPCSTR pHead)
{
while(IsBlank(*pHead)) pHead++;
return pHead;
}
static inline LPCSTR Head(LPCSTR pHead, DWORD dwID, bool toc)
{
BYTE count = 0;
while(('#' == *pHead))
{
pHead++;
count++;
}
CHAR data[16];
LPSTR save = data;
do
{
*save++ = CHAR('A' + (dwID & 0x0F));
dwID = dwID >> 4;
} while(0 != dwID);
LPCSTR pTail = Last(pHead = Skip(pHead));
if (toc)
{
AppendString("<a dwID='toc_");
AppendBuffer(data, save);
AppendString("' href='#");
AppendBuffer(data, save);
AppendString("'>");
AppendBuffer(pHead, pTail);
AppendString("</a>");
}
else
{
LPSTR head = gTargetSave;
AppendString("<h0 dwID='");
head[2] = BYTE(head[2] + count);
AppendBuffer(data, save);
AppendString("'>");
AppendBuffer(pHead, pTail);
AppendString("<a dwID='");
AppendBuffer(data, save);
AppendString("' href='#toc_");
AppendBuffer(data, save);
AppendString("'>^</a>");
LPSTR tail = gTargetSave;
AppendString("</h0>");
tail[3] = BYTE(tail[3] + count);
}
AppendString("<br/>\r\n");
return Next(pTail);
}
static LPCSTR Hash(LPCSTR pHead, bool set)
{
DWORD dwHash = 0x811C9DC5;
for (NOOP; (']' != *pHead) && !IsBreak(*pHead); pHead++)
if (!IsWhite(*pHead))
dwHash = (dwHash ^ BYTE(*pHead)) * 0x1000193;
UINT uIndex = WORD(((dwHash >> 16) ^ dwHash) & 0xFFFF);
if (set)
return Last(gHashTable[uIndex] = Skip(pHead + 1));
LPCSTR rv = gHashTable[uIndex];
return rv ? rv : "\r\n";
}
static void _fastcall First(LPCSTR pHead, LPCSTR pTail)
{
DWORD id = 0;
CHAR last = 0x0D;
while(pHead < pTail)
{
CHAR ch = *pHead;
if (!IsBreak(last))
pHead++;
else if ('[' == ch)
pHead = Hash(pHead + 1, true);
else if ('#' == ch)
pHead = Head(pHead, id++, true);
else
pHead++;
last = ch;
}
}
static LPCSTR Mode(LPCSTR pLine, LPCSTR pHead, CHAR last, CHAR tag, UINT flag)
{
AppendBuffer(pLine, pHead);
if (last == *pHead)
{
AppendSymbol(last);
}
else if (flag & gMode)
{
AppendString("</");
AppendSymbol(tag);
AppendSymbol('>');
gMode = gMode ^ flag;
}
else if (!IsWhite(last))
{
AppendSymbol(*pHead);
}
else
{
AppendSymbol('<');
AppendSymbol(tag);
AppendSymbol('>');
gMode = gMode ^ flag;
}
return pHead + 1;
}
static LPCSTR Text(LPCSTR pHead, LPCSTR pTail)
{
CHAR last = 0;
LPCSTR pLine = pHead;
while((pHead < pTail) && !IsBreak(*pHead))
{
CHAR ch = *pHead;
if ('[' == ch)
{
AppendBuffer(pLine, pHead);
pHead = pLine = pHead + 1;
AppendString("<a href='");
LPCSTR pLink = Hash(pHead, false);
AppendBuffer(pLink, Last(pLink));
AppendString("'>");
}
else if (']' == ch)
{
AppendBuffer(pLine, pHead);
pHead = pLine = pHead + 1;
AppendString("<a/>");
}
else if ('*' == ch)
{
pHead = pLine = Mode(pLine, pHead, last, 'b', FLAG_BOLD);
}
else if ('/' == ch)
{
pHead = pLine = Mode(pLine, pHead, last, 'i', FLAG_ITALIC);
}
else if ('_' == ch)
{
pHead = pLine = Mode(pLine, pHead, last, 'u', FLAG_UNDERLINE);
}
else if ('-' == ch)
{
pHead = pLine = Mode(pLine, pHead, last, 's', FLAG_STRIKED);
}
else
{
pHead = pHead + 1;
}
last = ch;
}
AppendBuffer(pLine, pHead);
return Next(pHead);
}
static void Second(LPCSTR pHead, LPCSTR pTail)
{
DWORD id = 0;
while(pHead < pTail)
{
CHAR ch = *pHead;
if ('[' == ch)
{
pHead = Next(Last(pHead));
}
else if ('#' == ch)
{
pHead = Head(pHead, id++, false);
}
else if (IsBreak(ch))
{
pHead = Next(pHead);
if (FLAG_PARAGRAPH & gMode)
{
AppendString("</p>\r\n");
gMode = gMode ^ FLAG_PARAGRAPH;
}
}
else
{
if (!(FLAG_PARAGRAPH & gMode))
{
AppendString("\r\n<p>");
gMode = gMode ^ FLAG_PARAGRAPH;
}
pHead = Text(pHead, pTail);
}
}
}
static void Save(HANDLE hTarget, DWORD dwPage)
{
gTargetSave = gTargetData = LPSTR(HeapAlloc(gProcessHeap, HEAP_NO_SERIALIZE, gSourceSize * 2));
LPCSTR pTail = gSourceData + gSourceSize;
AppendString("<html><head><meta charset='charset=utf-8'/></head><body>\r\n");
First(gSourceData, gSourceData + gSourceSize);
Write(hTarget, dwPage);
Second(gSourceData, gSourceData + gSourceSize);
AppendString("</body></html>");
Write(hTarget, dwPage);
}
static void Save(HANDLE hTarget)
{
Save(hTarget, FILE_TYPE_DISK != GetFileType(hTarget) ? 0x1000 : MAXDWORD);
}
static void Load(HANDLE hSource)
{
DWORD count;
SIZE_T uCount = 0;
gHashTable = (LPCSTR*) HeapAlloc(gProcessHeap, HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY, 0x10000 * sizeof(LPCSTR));
gSourceData = LPSTR(HeapAlloc(gProcessHeap, HEAP_NO_SERIALIZE, (gSourceSize = 0x1000) + 2));
while(ReadFile(hSource, gSourceData + uCount, 0x1000, &count, NULL) && (0 != count))
{
uCount = uCount + count;
if (uCount == gSourceSize)
gSourceData = LPSTR(HeapReAlloc(gProcessHeap, HEAP_NO_SERIALIZE, gSourceData, (gSourceSize = gSourceSize * 2) + 2));
}
gSourceData = LPSTR(HeapReAlloc(gProcessHeap, HEAP_NO_SERIALIZE, gSourceData, uCount));
gSourceData[gSourceSize = uCount] = 0;
}
#include <mmsystem.h>
#pragma comment(lib, "WINMM")
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
gProcessHeap = GetProcessHeap();
Load(GetStdHandle(STD_INPUT_HANDLE));
Save(GetStdHandle(STD_OUTPUT_HANDLE));
return 0;
}